162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <errno.h>
462306a36Sopenharmony_ci#include <stdbool.h>
562306a36Sopenharmony_ci#include <stdio.h>
662306a36Sopenharmony_ci#include <stdlib.h>
762306a36Sopenharmony_ci#include <string.h>
862306a36Sopenharmony_ci#include <sys/stat.h>
962306a36Sopenharmony_ci#include <unistd.h>
1062306a36Sopenharmony_ci#include <linux/limits.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "../kselftest.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define MIN_TTY_PATH_LEN 8
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic bool tty_valid(char *tty)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	if (strlen(tty) < MIN_TTY_PATH_LEN)
1962306a36Sopenharmony_ci		return false;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	if (strncmp(tty, "/dev/tty", MIN_TTY_PATH_LEN) == 0 ||
2262306a36Sopenharmony_ci	    strncmp(tty, "/dev/pts", MIN_TTY_PATH_LEN) == 0)
2362306a36Sopenharmony_ci		return true;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	return false;
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic int write_dev_tty(void)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	FILE *f;
3162306a36Sopenharmony_ci	int r = 0;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	f = fopen("/dev/tty", "r+");
3462306a36Sopenharmony_ci	if (!f)
3562306a36Sopenharmony_ci		return -errno;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	r = fprintf(f, "hello, world!\n");
3862306a36Sopenharmony_ci	if (r != strlen("hello, world!\n"))
3962306a36Sopenharmony_ci		r = -EIO;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	fclose(f);
4262306a36Sopenharmony_ci	return r;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ciint main(int argc, char **argv)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	int r;
4862306a36Sopenharmony_ci	char tty[PATH_MAX] = {};
4962306a36Sopenharmony_ci	struct stat st1, st2;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	ksft_print_header();
5262306a36Sopenharmony_ci	ksft_set_plan(1);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	r = readlink("/proc/self/fd/0", tty, PATH_MAX);
5562306a36Sopenharmony_ci	if (r < 0)
5662306a36Sopenharmony_ci		ksft_exit_fail_msg("readlink on /proc/self/fd/0 failed: %m\n");
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (!tty_valid(tty))
5962306a36Sopenharmony_ci		ksft_exit_skip("invalid tty path '%s'\n", tty);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	r = stat(tty, &st1);
6262306a36Sopenharmony_ci	if (r < 0)
6362306a36Sopenharmony_ci		ksft_exit_fail_msg("stat failed on tty path '%s': %m\n", tty);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	/* We need to wait at least 8 seconds in order to observe timestamp change */
6662306a36Sopenharmony_ci	/* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fbf47635315ab308c9b58a1ea0906e711a9228de */
6762306a36Sopenharmony_ci	sleep(10);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	r = write_dev_tty();
7062306a36Sopenharmony_ci	if (r < 0)
7162306a36Sopenharmony_ci		ksft_exit_fail_msg("failed to write to /dev/tty: %s\n",
7262306a36Sopenharmony_ci				   strerror(-r));
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	r = stat(tty, &st2);
7562306a36Sopenharmony_ci	if (r < 0)
7662306a36Sopenharmony_ci		ksft_exit_fail_msg("stat failed on tty path '%s': %m\n", tty);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/* We wrote to the terminal so timestamps should have been updated */
7962306a36Sopenharmony_ci	if (st1.st_atim.tv_sec == st2.st_atim.tv_sec &&
8062306a36Sopenharmony_ci	    st1.st_mtim.tv_sec == st2.st_mtim.tv_sec) {
8162306a36Sopenharmony_ci		ksft_test_result_fail("tty timestamps not updated\n");
8262306a36Sopenharmony_ci		ksft_exit_fail();
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	ksft_test_result_pass(
8662306a36Sopenharmony_ci		"timestamps of terminal '%s' updated after write to /dev/tty\n", tty);
8762306a36Sopenharmony_ci	return EXIT_SUCCESS;
8862306a36Sopenharmony_ci}
89