xref: /linux/tools/testing/selftests/tty/tty_tstamp_update.c (revision 36ec807b627b4c0a0a382f0ae48eac7187d14b2b)
1e8cc3348SMichal Sekletar // SPDX-License-Identifier: GPL-2.0
2e8cc3348SMichal Sekletar 
3e8cc3348SMichal Sekletar #include <errno.h>
4e8cc3348SMichal Sekletar #include <stdbool.h>
5e8cc3348SMichal Sekletar #include <stdio.h>
6e8cc3348SMichal Sekletar #include <stdlib.h>
7e8cc3348SMichal Sekletar #include <string.h>
8e8cc3348SMichal Sekletar #include <sys/stat.h>
9e8cc3348SMichal Sekletar #include <unistd.h>
10e8cc3348SMichal Sekletar #include <linux/limits.h>
11e8cc3348SMichal Sekletar 
12e8cc3348SMichal Sekletar #include "../kselftest.h"
13e8cc3348SMichal Sekletar 
14e8cc3348SMichal Sekletar #define MIN_TTY_PATH_LEN 8
15e8cc3348SMichal Sekletar 
tty_valid(char * tty)16e8cc3348SMichal Sekletar static bool tty_valid(char *tty)
17e8cc3348SMichal Sekletar {
18e8cc3348SMichal Sekletar 	if (strlen(tty) < MIN_TTY_PATH_LEN)
19e8cc3348SMichal Sekletar 		return false;
20e8cc3348SMichal Sekletar 
21e8cc3348SMichal Sekletar 	if (strncmp(tty, "/dev/tty", MIN_TTY_PATH_LEN) == 0 ||
22e8cc3348SMichal Sekletar 	    strncmp(tty, "/dev/pts", MIN_TTY_PATH_LEN) == 0)
23e8cc3348SMichal Sekletar 		return true;
24e8cc3348SMichal Sekletar 
25e8cc3348SMichal Sekletar 	return false;
26e8cc3348SMichal Sekletar }
27e8cc3348SMichal Sekletar 
write_dev_tty(void)28e8cc3348SMichal Sekletar static int write_dev_tty(void)
29e8cc3348SMichal Sekletar {
30e8cc3348SMichal Sekletar 	FILE *f;
31e8cc3348SMichal Sekletar 	int r = 0;
32e8cc3348SMichal Sekletar 
33e8cc3348SMichal Sekletar 	f = fopen("/dev/tty", "r+");
34e8cc3348SMichal Sekletar 	if (!f)
35e8cc3348SMichal Sekletar 		return -errno;
36e8cc3348SMichal Sekletar 
37e8cc3348SMichal Sekletar 	r = fprintf(f, "hello, world!\n");
38e8cc3348SMichal Sekletar 	if (r != strlen("hello, world!\n"))
39e8cc3348SMichal Sekletar 		r = -EIO;
40e8cc3348SMichal Sekletar 
41e8cc3348SMichal Sekletar 	fclose(f);
42e8cc3348SMichal Sekletar 	return r;
43e8cc3348SMichal Sekletar }
44e8cc3348SMichal Sekletar 
main(int argc,char ** argv)45e8cc3348SMichal Sekletar int main(int argc, char **argv)
46e8cc3348SMichal Sekletar {
47e8cc3348SMichal Sekletar 	int r;
48e8cc3348SMichal Sekletar 	char tty[PATH_MAX] = {};
49e8cc3348SMichal Sekletar 	struct stat st1, st2;
50*d6283d08SMark Brown 	int result = KSFT_FAIL;
51e8cc3348SMichal Sekletar 
52e8cc3348SMichal Sekletar 	ksft_print_header();
53e8cc3348SMichal Sekletar 	ksft_set_plan(1);
54e8cc3348SMichal Sekletar 
55e8cc3348SMichal Sekletar 	r = readlink("/proc/self/fd/0", tty, PATH_MAX);
56*d6283d08SMark Brown 	if (r < 0) {
57*d6283d08SMark Brown 		ksft_print_msg("readlink on /proc/self/fd/0 failed: %m\n");
58*d6283d08SMark Brown 		goto out;
59*d6283d08SMark Brown 	}
60e8cc3348SMichal Sekletar 
61*d6283d08SMark Brown 	if (!tty_valid(tty)) {
62*d6283d08SMark Brown 		ksft_print_msg("invalid tty path '%s'\n", tty);
63*d6283d08SMark Brown 		result = KSFT_SKIP;
64*d6283d08SMark Brown 		goto out;
65*d6283d08SMark Brown 
66*d6283d08SMark Brown 	}
67e8cc3348SMichal Sekletar 
68e8cc3348SMichal Sekletar 	r = stat(tty, &st1);
69*d6283d08SMark Brown 	if (r < 0) {
70*d6283d08SMark Brown 		ksft_print_msg("stat failed on tty path '%s': %m\n", tty);
71*d6283d08SMark Brown 		goto out;
72*d6283d08SMark Brown 	}
73e8cc3348SMichal Sekletar 
74e8cc3348SMichal Sekletar 	/* We need to wait at least 8 seconds in order to observe timestamp change */
75e8cc3348SMichal Sekletar 	/* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fbf47635315ab308c9b58a1ea0906e711a9228de */
76e8cc3348SMichal Sekletar 	sleep(10);
77e8cc3348SMichal Sekletar 
78e8cc3348SMichal Sekletar 	r = write_dev_tty();
79*d6283d08SMark Brown 	if (r < 0) {
80*d6283d08SMark Brown 		ksft_print_msg("failed to write to /dev/tty: %s\n",
81e8cc3348SMichal Sekletar 			       strerror(-r));
82*d6283d08SMark Brown 		goto out;
83*d6283d08SMark Brown 	}
84e8cc3348SMichal Sekletar 
85e8cc3348SMichal Sekletar 	r = stat(tty, &st2);
86*d6283d08SMark Brown 	if (r < 0) {
87*d6283d08SMark Brown 		ksft_print_msg("stat failed on tty path '%s': %m\n", tty);
88*d6283d08SMark Brown 		goto out;
89*d6283d08SMark Brown 	}
90e8cc3348SMichal Sekletar 
91e8cc3348SMichal Sekletar 	/* We wrote to the terminal so timestamps should have been updated */
92e8cc3348SMichal Sekletar 	if (st1.st_atim.tv_sec == st2.st_atim.tv_sec &&
93e8cc3348SMichal Sekletar 	    st1.st_mtim.tv_sec == st2.st_mtim.tv_sec) {
94*d6283d08SMark Brown 		ksft_print_msg("tty timestamps not updated\n");
95*d6283d08SMark Brown 		goto out;
96e8cc3348SMichal Sekletar 	}
97e8cc3348SMichal Sekletar 
98*d6283d08SMark Brown 	ksft_print_msg(
99e8cc3348SMichal Sekletar 		"timestamps of terminal '%s' updated after write to /dev/tty\n", tty);
100*d6283d08SMark Brown 	result = KSFT_PASS;
101*d6283d08SMark Brown 
102*d6283d08SMark Brown out:
103*d6283d08SMark Brown 	ksft_test_result_report(result, "tty_tstamp_update\n");
104*d6283d08SMark Brown 
105*d6283d08SMark Brown 	ksft_finished();
106e8cc3348SMichal Sekletar }
107