1 | /* Copyright (C) 2017-2024 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public License as |
6 | published by the Free Software Foundation; either version 2.1 of the |
7 | License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; see the file COPYING.LIB. If |
16 | not, see <https://www.gnu.org/licenses/>. */ |
17 | |
18 | #include <sched.h> |
19 | #include <sys/prctl.h> |
20 | |
21 | #include <support/namespace.h> |
22 | |
23 | #include "tst-ttyname-common.c" |
24 | |
25 | /* These chroot setup functions put the TTY at at "/console" (where it |
26 | won't be found by ttyname), and create "/dev/console" as an |
27 | ordinary file. This way, it's easier to write test-cases that |
28 | expect ttyname to fail; test-cases that expect it to succeed need |
29 | to explicitly remount it at "/dev/console". */ |
30 | |
31 | static int |
32 | do_in_chroot_1 (int (*cb)(const char *, int)) |
33 | { |
34 | printf (format: "info: entering chroot 1\n" ); |
35 | |
36 | /* Open the PTS that we'll be testing on. */ |
37 | int master; |
38 | char *slavename; |
39 | master = posix_openpt (O_RDWR|O_NOCTTY|O_NONBLOCK); |
40 | if (master < 0) |
41 | { |
42 | if (errno == ENOENT) |
43 | FAIL_UNSUPPORTED ("posix_openpt: %m" ); |
44 | else |
45 | FAIL_EXIT1 ("posix_openpt: %m" ); |
46 | } |
47 | VERIFY ((slavename = ptsname (master))); |
48 | VERIFY (unlockpt (master) == 0); |
49 | if (strncmp (slavename, "/dev/pts/" , 9) != 0) |
50 | FAIL_UNSUPPORTED ("slave pseudo-terminal is not under /dev/pts/: %s" , |
51 | slavename); |
52 | adjust_file_limit (pty: slavename); |
53 | int slave = xopen (path: slavename, O_RDWR, 0); |
54 | if (!doit (fd: slave, testname: "basic smoketest" , |
55 | expected_r: (struct result_r){.name=slavename, .ret=0, .err=0})) |
56 | return 1; |
57 | |
58 | pid_t pid = xfork (); |
59 | if (pid == 0) |
60 | { |
61 | xclose (master); |
62 | |
63 | if (!support_enter_mount_namespace ()) |
64 | FAIL_UNSUPPORTED ("could not enter new mount namespace" ); |
65 | |
66 | VERIFY (mount ("tmpfs" , chrootdir, "tmpfs" , 0, "mode=755" ) == 0); |
67 | VERIFY (chdir (chrootdir) == 0); |
68 | |
69 | xmkdir (path: "proc" , 0755); |
70 | xmkdir (path: "dev" , 0755); |
71 | xmkdir (path: "dev/pts" , 0755); |
72 | |
73 | VERIFY (mount ("/proc" , "proc" , NULL, MS_BIND|MS_REC, NULL) == 0); |
74 | VERIFY (mount ("devpts" , "dev/pts" , "devpts" , |
75 | MS_NOSUID|MS_NOEXEC, |
76 | "newinstance,ptmxmode=0666,mode=620" ) == 0); |
77 | VERIFY (symlink ("pts/ptmx" , "dev/ptmx" ) == 0); |
78 | |
79 | touch (path: "console" , mode: 0); |
80 | touch (path: "dev/console" , mode: 0); |
81 | VERIFY (mount (slavename, "console" , NULL, MS_BIND, NULL) == 0); |
82 | |
83 | xchroot (path: "." ); |
84 | |
85 | char *linkname = xasprintf (format: "/proc/self/fd/%d" , slave); |
86 | char *target = proc_fd_readlink (linkname); |
87 | VERIFY (strcmp (target, slavename) == 0); |
88 | free (ptr: linkname); |
89 | |
90 | _exit (cb (slavename, slave)); |
91 | } |
92 | int status; |
93 | xwaitpid (pid, status: &status, flags: 0); |
94 | VERIFY (WIFEXITED (status)); |
95 | xclose (master); |
96 | xclose (slave); |
97 | return WEXITSTATUS (status); |
98 | } |
99 | |
100 | static int |
101 | do_test (void) |
102 | { |
103 | support_become_root (); |
104 | |
105 | do_in_chroot_1 (cb: run_chroot_tests); |
106 | |
107 | return 0; |
108 | } |
109 | |
110 | #include <support/test-driver.c> |
111 | |