1 | /* Test posix_spawn setsid attribute. |
2 | Copyright (C) 2017-2024 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <errno.h> |
20 | #include <fcntl.h> |
21 | #include <getopt.h> |
22 | #include <intprops.h> |
23 | #include <paths.h> |
24 | #include <spawn.h> |
25 | #include <stdbool.h> |
26 | #include <stdio.h> |
27 | #include <stdlib.h> |
28 | #include <sys/resource.h> |
29 | #include <sys/wait.h> |
30 | #include <unistd.h> |
31 | |
32 | #include <support/check.h> |
33 | #include <support/xunistd.h> |
34 | #include <support/temp_file.h> |
35 | #include <tst-spawn.h> |
36 | |
37 | /* Nonzero if the program gets called via `exec'. */ |
38 | static int restart; |
39 | |
40 | /* Hold the four initial argument used to respawn the process, plus |
41 | the extra '--direct' and '--restart', and a final NULL. */ |
42 | static char *initial_argv[7]; |
43 | static int initial_argv_count; |
44 | |
45 | #define CMDLINE_OPTIONS \ |
46 | { "restart", no_argument, &restart, 1 }, |
47 | |
48 | static char *pidfile; |
49 | |
50 | static pid_t |
51 | read_child_sid (void) |
52 | { |
53 | int pidfd = xopen (path: pidfile, O_RDONLY, 0); |
54 | |
55 | char buf[INT_STRLEN_BOUND (pid_t)]; |
56 | ssize_t n = read (pidfd, buf, sizeof (buf)); |
57 | TEST_VERIFY (n < sizeof buf && n >= 0); |
58 | buf[n] = '\0'; |
59 | |
60 | /* We only expect to read the PID. */ |
61 | char *endp; |
62 | long int rpid = strtol (buf, &endp, 10); |
63 | TEST_VERIFY (endp != buf); |
64 | |
65 | xclose (pidfd); |
66 | |
67 | return rpid; |
68 | } |
69 | |
70 | /* Called on process re-execution, write down the session id on PIDFILE. */ |
71 | static void |
72 | handle_restart (const char *pidfile) |
73 | { |
74 | int pidfd = xopen (path: pidfile, O_WRONLY, 0); |
75 | |
76 | char buf[INT_STRLEN_BOUND (pid_t)]; |
77 | int s = snprintf (s: buf, maxlen: sizeof buf, format: "%d" , getsid (0)); |
78 | size_t n = write (pidfd, buf, s); |
79 | TEST_VERIFY (n == s); |
80 | |
81 | xclose (pidfd); |
82 | } |
83 | |
84 | static void |
85 | do_test_setsid (bool test_setsid) |
86 | { |
87 | /* Current session ID. */ |
88 | pid_t sid = getsid (0); |
89 | TEST_VERIFY (sid != (pid_t) -1); |
90 | |
91 | posix_spawnattr_t attrp; |
92 | TEST_COMPARE (posix_spawnattr_init (&attrp), 0); |
93 | if (test_setsid) |
94 | TEST_COMPARE (posix_spawnattr_setflags (&attrp, POSIX_SPAWN_SETSID), 0); |
95 | |
96 | /* 1 or 4 elements from initial_argv: |
97 | + path to ld.so optional |
98 | + --library-path optional |
99 | + the library path optional |
100 | + application name |
101 | + --direct |
102 | + --restart |
103 | + pidfile */ |
104 | int argv_size = initial_argv_count + 2; |
105 | char *args[argv_size]; |
106 | int argc = 0; |
107 | |
108 | for (char **arg = initial_argv; *arg != NULL; arg++) |
109 | args[argc++] = *arg; |
110 | args[argc++] = pidfile; |
111 | args[argc] = NULL; |
112 | TEST_VERIFY (argc < argv_size); |
113 | |
114 | PID_T_TYPE pid; |
115 | TEST_COMPARE (POSIX_SPAWN (&pid, args[0], NULL, &attrp, args, environ), 0); |
116 | TEST_COMPARE (posix_spawnattr_destroy (&attrp), 0); |
117 | |
118 | siginfo_t sinfo; |
119 | TEST_COMPARE (WAITID (P_PID, pid, &sinfo, WEXITED), 0); |
120 | TEST_COMPARE (sinfo.si_code, CLD_EXITED); |
121 | TEST_COMPARE (sinfo.si_status, 0); |
122 | |
123 | pid_t child_sid = read_child_sid (); |
124 | |
125 | /* Child should have a different session ID than parent. */ |
126 | TEST_VERIFY (child_sid != (pid_t) -1); |
127 | |
128 | if (test_setsid) |
129 | TEST_VERIFY (child_sid != sid); |
130 | else |
131 | TEST_VERIFY (child_sid == sid); |
132 | } |
133 | |
134 | static int |
135 | do_test (int argc, char *argv[]) |
136 | { |
137 | /* We must have either: |
138 | |
139 | - one or four parameters if called initially: |
140 | + argv[1]: path for ld.so optional |
141 | + argv[2]: "--library-path" optional |
142 | + argv[3]: the library path optional |
143 | + argv[4]: the application name |
144 | |
145 | - six parameters left if called through re-execution: |
146 | + argv[5/1]: the application name |
147 | + argv[6/2]: the pidfile |
148 | |
149 | * When built with --enable-hardcoded-path-in-tests or issued without |
150 | using the loader directly. */ |
151 | |
152 | if (restart) |
153 | { |
154 | handle_restart (pidfile: argv[1]); |
155 | return 0; |
156 | } |
157 | |
158 | TEST_VERIFY_EXIT (argc == 2 || argc == 5); |
159 | |
160 | int i; |
161 | for (i = 0; i < argc - 1; i++) |
162 | initial_argv[i] = argv[i + 1]; |
163 | initial_argv[i++] = (char *) "--direct" ; |
164 | initial_argv[i++] = (char *) "--restart" ; |
165 | initial_argv_count = i; |
166 | |
167 | create_temp_file (base: "tst-posix_spawn-setsid-" , filename: &pidfile); |
168 | |
169 | do_test_setsid (false); |
170 | do_test_setsid (true); |
171 | |
172 | return 0; |
173 | } |
174 | |
175 | #define TEST_FUNCTION_ARGV do_test |
176 | #include <support/test-driver.c> |
177 | |