1 /*
2 * Check decoding of waitid syscall.
3 *
4 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@strace.io>
5 * Copyright (c) 2016-2022 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12 #include <assert.h>
13 #include <signal.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <sys/wait.h>
18 #include "kernel_rusage.h"
19 #include "scno.h"
20
21 #ifndef MY_COMM
22 # define MY_COMM ""
23 #endif
24 #ifndef SKIP_IF_PROC_IS_UNAVAILABLE
25 # define SKIP_IF_PROC_IS_UNAVAILABLE
26 #endif
27
28 static const char *
29 sprint_rusage(const kernel_rusage_t *const ru)
30 {
31 static char buf[1024];
32 snprintf(buf, sizeof(buf),
33 "{ru_utime={tv_sec=%lld, tv_usec=%llu}"
34 ", ru_stime={tv_sec=%lld, tv_usec=%llu}"
35 #if VERBOSE
36 ", ru_maxrss=%llu"
37 ", ru_ixrss=%llu"
38 ", ru_idrss=%llu"
39 ", ru_isrss=%llu"
40 ", ru_minflt=%llu"
41 ", ru_majflt=%llu"
42 ", ru_nswap=%llu"
43 ", ru_inblock=%llu"
44 ", ru_oublock=%llu"
45 ", ru_msgsnd=%llu"
46 ", ru_msgrcv=%llu"
47 ", ru_nsignals=%llu"
48 ", ru_nvcsw=%llu"
49 ", ru_nivcsw=%llu}"
50 #else
51 ", ...}"
52 #endif
53 , (long long) ru->ru_utime.tv_sec
54 , zero_extend_signed_to_ull(ru->ru_utime.tv_usec)
55 , (long long) ru->ru_stime.tv_sec
56 , zero_extend_signed_to_ull(ru->ru_stime.tv_usec)
57 #if VERBOSE
58 , zero_extend_signed_to_ull(ru->ru_maxrss)
59 , zero_extend_signed_to_ull(ru->ru_ixrss)
60 , zero_extend_signed_to_ull(ru->ru_idrss)
61 , zero_extend_signed_to_ull(ru->ru_isrss)
62 , zero_extend_signed_to_ull(ru->ru_minflt)
63 , zero_extend_signed_to_ull(ru->ru_majflt)
64 , zero_extend_signed_to_ull(ru->ru_nswap)
65 , zero_extend_signed_to_ull(ru->ru_inblock)
66 , zero_extend_signed_to_ull(ru->ru_oublock)
67 , zero_extend_signed_to_ull(ru->ru_msgsnd)
68 , zero_extend_signed_to_ull(ru->ru_msgrcv)
69 , zero_extend_signed_to_ull(ru->ru_nsignals)
70 , zero_extend_signed_to_ull(ru->ru_nvcsw)
71 , zero_extend_signed_to_ull(ru->ru_nivcsw)
72 #endif
73 );
74 return buf;
75 }
76
77 #define CASE(x) case x: return #x
78
79 static const char *
80 si_code_2_name(const int code)
81 {
82 switch (code) {
83 #ifdef CLD_EXITED
84 CASE(CLD_EXITED);
85 #endif
86 #ifdef CLD_KILLED
87 CASE(CLD_KILLED);
88 #endif
89 #ifdef CLD_DUMPED
90 CASE(CLD_DUMPED);
91 #endif
92 #ifdef CLD_TRAPPED
93 CASE(CLD_TRAPPED);
94 #endif
95 #ifdef CLD_STOPPED
96 CASE(CLD_STOPPED);
97 #endif
98 #ifdef CLD_CONTINUED
99 CASE(CLD_CONTINUED);
100 #endif
101 default:
102 perror_msg_and_fail("unknown si_code %d", code);
103 }
104 }
105
106 static const char *
107 sprint_siginfo(const siginfo_t *const si, const char *const status_text,
108 const char *const comm)
109 {
110 static char buf[1024];
111 char utime_str[64];
112 char stime_str[64];
113
114 snprintf(buf, sizeof(buf),
115 "{si_signo=SIGCHLD"
116 ", si_code=%s"
117 ", si_pid=%d%s"
118 ", si_uid=%d"
119 ", si_status=%s"
120 ", si_utime=%s"
121 ", si_stime=%s}",
122 si_code_2_name(si->si_code),
123 si->si_pid,
124 comm,
125 si->si_uid,
126 status_text,
127 clock_t_str(zero_extend_signed_to_ull(si->si_utime),
128 ARRSZ_PAIR(utime_str)),
129 clock_t_str(zero_extend_signed_to_ull(si->si_stime),
130 ARRSZ_PAIR(stime_str)));
131 return buf;
132 }
133
134 static unsigned long
135 poison(unsigned int v)
136 {
137 return (unsigned long) 0xfacefeed00000000ULL | v;
138 }
139
140 static const char *errstr;
141
142 static long
143 do_waitid(const unsigned int idtype,
144 const unsigned int id,
145 const siginfo_t *const infop,
146 const unsigned int options,
147 const kernel_rusage_t *const rusage)
148 {
149 sigset_t mask = {};
150 sigaddset(&mask, SIGCHLD);
151
152 assert(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
153 long rc = syscall(__NR_waitid, poison(idtype), poison(id),
154 infop, poison(options), rusage);
155 assert(sigprocmask(SIG_UNBLOCK, &mask, NULL) == 0);
156 errstr = sprintrc(rc);
157 return rc;
158 }
159
160 int
161 main(void)
162 {
163 SKIP_IF_PROC_IS_UNAVAILABLE;
164
165 tprintf("%s", "");
166
167 int fds[2];
168 if (pipe(fds))
169 perror_msg_and_fail("pipe");
170
171 pid_t pid;
172 pid = fork();
173 if (pid < 0)
174 perror_msg_and_fail("fork");
175
176 if (!pid) {
177 char c;
178 (void) close(1);
179 assert(read(0, &c, sizeof(c)) == 1);
180 return 42;
181 }
182
183 (void) close(0);
184
185 if (do_waitid(P_PID, pid, 0, WNOHANG|WEXITED, 0))
186 perror_msg_and_fail("waitid #1");
187 tprintf("waitid(P_PID, %d%s, NULL, WNOHANG|WEXITED, NULL) = 0\n",
188 pid, MY_COMM);
189
190 TAIL_ALLOC_OBJECT_CONST_PTR(siginfo_t, sinfo);
191 memset(sinfo, 0, sizeof(*sinfo));
192 TAIL_ALLOC_OBJECT_CONST_PTR(kernel_rusage_t, rusage);
193 if (do_waitid(P_PID, pid, sinfo, WNOHANG|WEXITED|WSTOPPED, rusage))
194 perror_msg_and_fail("waitid #2");
195 tprintf("waitid(P_PID, %d%s, {}, WNOHANG|WEXITED|WSTOPPED, %s) = 0\n",
196 pid, MY_COMM, sprint_rusage(rusage));
197
198 assert(write(1, "", 1) == 1);
199 (void) close(1);
200
201 if (do_waitid(P_PID, pid, sinfo, WEXITED, rusage))
202 perror_msg_and_fail("waitid #3");
203 tprintf("waitid(P_PID, %d%s, %s, WEXITED, %s) = 0\n",
204 pid, MY_COMM, sprint_siginfo(sinfo, "42", ""), sprint_rusage(rusage));
205
206 pid = fork();
207 if (pid < 0)
208 perror_msg_and_fail("fork");
209
210 if (!pid) {
211 (void) raise(SIGUSR1);
212 return 1;
213 }
214
215 if (do_waitid(P_PID, pid, sinfo, WEXITED, rusage))
216 perror_msg_and_fail("waitid #4");
217 tprintf("waitid(P_PID, %d%s, %s, WEXITED, %s) = 0\n",
218 pid, MY_COMM, sprint_siginfo(sinfo, "SIGUSR1", ""),
219 sprint_rusage(rusage));
220
221 if (pipe(fds))
222 perror_msg_and_fail("pipe");
223 pid = fork();
224 if (pid < 0)
225 perror_msg_and_fail("fork");
226
227 if (!pid) {
228 (void) close(1);
229 raise(SIGSTOP);
230 char c;
231 assert(read(0, &c, sizeof(c)) == 1);
232 return 0;
233 }
234
235 (void) close(0);
236
237 if (do_waitid(P_PID, pid, sinfo, WSTOPPED, rusage))
238 perror_msg_and_fail("waitid #5");
239 tprintf("waitid(P_PID, %d%s, %s, WSTOPPED, %s) = 0\n",
240 pid, MY_COMM, sprint_siginfo(sinfo, "SIGSTOP", MY_COMM),
241 sprint_rusage(rusage));
242
243 if (kill(pid, SIGCONT))
244 perror_msg_and_fail("kill(SIGCONT)");
245
246 #if defined WCONTINUED
247 if (do_waitid(P_PID, pid, sinfo, WCONTINUED, rusage))
248 perror_msg_and_fail("waitid #6");
249 tprintf("waitid(P_PID, %d%s, %s, WCONTINUED, %s) = 0\n",
250 pid, MY_COMM, sprint_siginfo(sinfo, "SIGCONT", MY_COMM),
251 sprint_rusage(rusage));
252 #endif /* WCONTINUED */
253
254 assert(write(1, "", 1) == 1);
255 (void) close(1);
256
257 if (do_waitid(P_PID, pid, sinfo, WEXITED, rusage))
258 perror_msg_and_fail("waitid #7");
259 tprintf("waitid(P_PID, %d%s, %s, WEXITED, %s) = 0\n",
260 pid, MY_COMM, sprint_siginfo(sinfo, "0", ""),
261 sprint_rusage(rusage));
262
263 pid_t pgid = getpgid(pid);
264 do_waitid(P_PGID, pgid, sinfo, WEXITED, rusage);
265 tprintf("waitid(P_PGID, %d, %p, WEXITED, %p) = %s\n",
266 pgid, sinfo, rusage, errstr);
267
268 do_waitid(P_ALL, -1, sinfo, WEXITED|WSTOPPED, rusage);
269 tprintf("waitid(P_ALL, -1, %p, WEXITED|WSTOPPED, %p) = %s\n",
270 sinfo, rusage, errstr);
271
272 tprintf("%s\n", "+++ exited with 0 +++");
273 return 0;
274 }