1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2026 Oxide Computer Company
14 */
15
16 /*
17 * Helper program for posix_spawn tests. This is exec()d by the test programs
18 * via posix_spawn() and reports back process state through stdout (which the
19 * parent has wired to a pipe via file actions).
20 *
21 * Usage:
22 * posix_spawn_child fds <fd0> [fd1 ...]
23 * Report whether each fd is open and its access mode flags.
24 *
25 * posix_spawn_child ids
26 * Report uid, euid, gid, egid.
27 *
28 * posix_spawn_child sched
29 * Report scheduling policy and priority.
30 *
31 * posix_spawn_child sidpgid
32 * Report session ID and process group ID as raw pid_t values.
33 *
34 * posix_spawn_child sigmask
35 * Report the current signal mask as a raw sigset_t.
36 *
37 * posix_spawn_child sigs <sig0> [sig1 ...]
38 * Report the disposition (SIG_DFL or SIG_IGN) of each signal.
39 */
40
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include <fcntl.h>
44 #include <sched.h>
45 #include <signal.h>
46 #include <string.h>
47 #include <errno.h>
48
49 #include "posix_spawn_common.h"
50
51 static int
do_fds(int argc,char * argv[])52 do_fds(int argc, char *argv[])
53 {
54 for (int i = 2; i < argc; i++) {
55 spawn_fd_result_t res;
56 int fd = (int)strtol(argv[i], NULL, 10);
57 int flags;
58
59 (void) memset(&res, 0, sizeof (res));
60 res.srf_fd = fd;
61
62 flags = fcntl(fd, F_GETFL);
63 if (flags == -1) {
64 res.srf_open = 0;
65 res.srf_flags = -1;
66 res.srf_err = errno;
67 } else {
68 res.srf_open = 1;
69 res.srf_flags = flags & O_ACCMODE;
70 res.srf_err = 0;
71 }
72
73 if (write(STDOUT_FILENO, &res, sizeof (res)) != sizeof (res))
74 return (EXIT_FAILURE);
75 }
76
77 return (EXIT_SUCCESS);
78 }
79
80 static int
do_ids(void)81 do_ids(void)
82 {
83 spawn_id_result_t res;
84
85 (void) memset(&res, 0, sizeof (res));
86 res.sir_uid = getuid();
87 res.sir_euid = geteuid();
88 res.sir_gid = getgid();
89 res.sir_egid = getegid();
90
91 if (write(STDOUT_FILENO, &res, sizeof (res)) != sizeof (res))
92 return (EXIT_FAILURE);
93
94 return (EXIT_SUCCESS);
95 }
96
97 static int
do_sched(void)98 do_sched(void)
99 {
100 spawn_sched_result_t res;
101 struct sched_param param;
102
103 (void) memset(&res, 0, sizeof (res));
104 res.ssr_policy = sched_getscheduler(0);
105 if (res.ssr_policy == -1)
106 return (EXIT_FAILURE);
107
108 if (sched_getparam(0, ¶m) != 0)
109 return (EXIT_FAILURE);
110 res.ssr_priority = param.sched_priority;
111
112 if (write(STDOUT_FILENO, &res, sizeof (res)) != sizeof (res))
113 return (EXIT_FAILURE);
114
115 return (EXIT_SUCCESS);
116 }
117
118 static int
do_sidpgid(void)119 do_sidpgid(void)
120 {
121 spawn_sidpgid_result_t res;
122
123 (void) memset(&res, 0, sizeof (res));
124 res.sspr_sid = getsid(0);
125 res.sspr_pgid = getpgid(0);
126
127 if (write(STDOUT_FILENO, &res, sizeof (res)) != sizeof (res))
128 return (EXIT_FAILURE);
129
130 return (EXIT_SUCCESS);
131 }
132
133 static int
do_sigmask(void)134 do_sigmask(void)
135 {
136 sigset_t mask;
137
138 if (sigprocmask(SIG_BLOCK, NULL, &mask) != 0)
139 return (EXIT_FAILURE);
140
141 if (write(STDOUT_FILENO, &mask, sizeof (mask)) != sizeof (mask))
142 return (EXIT_FAILURE);
143
144 return (EXIT_SUCCESS);
145 }
146
147 static int
do_sigs(int argc,char * argv[])148 do_sigs(int argc, char *argv[])
149 {
150 for (int i = 2; i < argc; i++) {
151 spawn_sig_result_t res;
152 struct sigaction sa;
153 int sig = (int)strtol(argv[i], NULL, 10);
154
155 (void) memset(&res, 0, sizeof (res));
156 res.ssr_sig = sig;
157
158 if (sigaction(sig, NULL, &sa) != 0)
159 return (EXIT_FAILURE);
160
161 if (sa.sa_handler == SIG_DFL)
162 res.ssr_disp = 0;
163 else if (sa.sa_handler == SIG_IGN)
164 res.ssr_disp = 1;
165 else
166 res.ssr_disp = 2;
167
168 if (write(STDOUT_FILENO, &res, sizeof (res)) != sizeof (res))
169 return (EXIT_FAILURE);
170 }
171
172 return (EXIT_SUCCESS);
173 }
174
175 int
main(int argc,char * argv[])176 main(int argc, char *argv[])
177 {
178 if (argc < 2)
179 return (EXIT_FAILURE);
180
181 if (strcmp(argv[1], "fds") == 0) {
182 if (argc < 3)
183 return (EXIT_FAILURE);
184 return (do_fds(argc, argv));
185 }
186
187 if (strcmp(argv[1], "ids") == 0)
188 return (do_ids());
189
190 if (strcmp(argv[1], "sched") == 0)
191 return (do_sched());
192
193 if (strcmp(argv[1], "sidpgid") == 0)
194 return (do_sidpgid());
195
196 if (strcmp(argv[1], "sigmask") == 0)
197 return (do_sigmask());
198
199 if (strcmp(argv[1], "sigs") == 0) {
200 if (argc < 3)
201 return (EXIT_FAILURE);
202 return (do_sigs(argc, argv));
203 }
204
205 return (EXIT_FAILURE);
206 }
207