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