1 /*
2 * Check decoding of wait4 syscall.
3 *
4 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@strace.io>
5 * Copyright (c) 2016-2020 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 "scno.h"
13
14 #ifdef __NR_wait4
15
16 # include <assert.h>
17 # include <signal.h>
18 # include <stdio.h>
19 # include <unistd.h>
20 # include <sys/wait.h>
21 # include "kernel_rusage.h"
22
23 static const char *
24 sprint_rusage(const kernel_rusage_t *const ru)
25 {
26 static char buf[1024];
27 snprintf(buf, sizeof(buf),
28 "{ru_utime={tv_sec=%llu, tv_usec=%llu}"
29 ", ru_stime={tv_sec=%llu, tv_usec=%llu}"
30 # if VERBOSE
31 ", ru_maxrss=%llu"
32 ", ru_ixrss=%llu"
33 ", ru_idrss=%llu"
34 ", ru_isrss=%llu"
35 ", ru_minflt=%llu"
36 ", ru_majflt=%llu"
37 ", ru_nswap=%llu"
38 ", ru_inblock=%llu"
39 ", ru_oublock=%llu"
40 ", ru_msgsnd=%llu"
41 ", ru_msgrcv=%llu"
42 ", ru_nsignals=%llu"
43 ", ru_nvcsw=%llu"
44 ", ru_nivcsw=%llu}"
45 # else
46 ", ...}"
47 # endif
48 , zero_extend_signed_to_ull(ru->ru_utime.tv_sec)
49 , zero_extend_signed_to_ull(ru->ru_utime.tv_usec)
50 , zero_extend_signed_to_ull(ru->ru_stime.tv_sec)
51 , zero_extend_signed_to_ull(ru->ru_stime.tv_usec)
52 # if VERBOSE
53 , zero_extend_signed_to_ull(ru->ru_maxrss)
54 , zero_extend_signed_to_ull(ru->ru_ixrss)
55 , zero_extend_signed_to_ull(ru->ru_idrss)
56 , zero_extend_signed_to_ull(ru->ru_isrss)
57 , zero_extend_signed_to_ull(ru->ru_minflt)
58 , zero_extend_signed_to_ull(ru->ru_majflt)
59 , zero_extend_signed_to_ull(ru->ru_nswap)
60 , zero_extend_signed_to_ull(ru->ru_inblock)
61 , zero_extend_signed_to_ull(ru->ru_oublock)
62 , zero_extend_signed_to_ull(ru->ru_msgsnd)
63 , zero_extend_signed_to_ull(ru->ru_msgrcv)
64 , zero_extend_signed_to_ull(ru->ru_nsignals)
65 , zero_extend_signed_to_ull(ru->ru_nvcsw)
66 , zero_extend_signed_to_ull(ru->ru_nivcsw)
67 # endif
68 );
69 return buf;
70 }
71
72 static const char *errstr;
73
74 static long
75 k_wait4(const unsigned int pid, void const *wstatus,
76 const unsigned int options, void const *ru)
77 {
78 const kernel_ulong_t fill = (kernel_ulong_t) 0xdefaced00000000ULL;
79 const kernel_ulong_t bad = (kernel_ulong_t) 0xbadc0dedbadc0dedULL;
80 const kernel_ulong_t arg1 = fill | pid;
81 const kernel_ulong_t arg2 = (uintptr_t) wstatus;
82 const kernel_ulong_t arg3 = fill | options;
83 const kernel_ulong_t arg4 = (uintptr_t) ru;
84 const long rc = syscall(__NR_wait4, arg1, arg2, arg3, arg4, bad, bad);
85 errstr = sprintrc(rc);
86 return rc;
87 }
88
89 static pid_t
90 do_wait4(pid_t pid, int *wstatus, int options, kernel_rusage_t *ru)
91 {
92 sigset_t mask = {};
93 sigaddset(&mask, SIGCHLD);
94
95 assert(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
96 pid_t rc = k_wait4(pid, wstatus, options, ru);
97 assert(sigprocmask(SIG_UNBLOCK, &mask, NULL) == 0);
98 return rc;
99 }
100
101 int
102 main(void)
103 {
104 tprintf("%s", "");
105
106 int fds[2];
107 if (pipe(fds))
108 perror_msg_and_fail("pipe");
109
110 pid_t pid;
111 pid = fork();
112 if (pid < 0)
113 perror_msg_and_fail("fork");
114
115 if (!pid) {
116 char c;
117 (void) close(1);
118 assert(read(0, &c, sizeof(c)) == 1);
119 return 42;
120 }
121
122 (void) close(0);
123
124 TAIL_ALLOC_OBJECT_CONST_PTR(int, s);
125 if (k_wait4(pid, s, WNOHANG|__WALL, NULL))
126 perror_msg_and_fail("wait4 #1");
127 tprintf("wait4(%d, %p, WNOHANG|__WALL, NULL) = 0\n", pid, s);
128
129 TAIL_ALLOC_OBJECT_CONST_PTR(kernel_rusage_t, rusage);
130 if (k_wait4(pid, s, WNOHANG|__WALL, rusage))
131 perror_msg_and_fail("wait4 #2");
132 tprintf("wait4(%d, %p, WNOHANG|__WALL, %p) = 0\n", pid, s, rusage);
133
134 assert(write(1, "", 1) == 1);
135 (void) close(1);
136
137 assert(do_wait4(pid, s, 0, rusage) == pid);
138 assert(WIFEXITED(*s) && WEXITSTATUS(*s) == 42);
139 tprintf("wait4(%d, [{WIFEXITED(s) && WEXITSTATUS(s) == 42}], 0, %s)"
140 " = %d\n", pid, sprint_rusage(rusage), pid);
141
142 pid = fork();
143 if (pid < 0)
144 perror_msg_and_fail("fork");
145
146 if (!pid) {
147 (void) raise(SIGUSR1);
148 return 1;
149 }
150
151 assert(do_wait4(pid, s, __WALL, rusage) == pid);
152 assert(WIFSIGNALED(*s) && WTERMSIG(*s) == SIGUSR1);
153 tprintf("wait4(%d, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGUSR1}]"
154 ", __WALL, %s) = %d\n", pid, sprint_rusage(rusage), pid);
155
156 if (pipe(fds))
157 perror_msg_and_fail("pipe");
158 pid = fork();
159 if (pid < 0)
160 perror_msg_and_fail("fork");
161
162 if (!pid) {
163 (void) close(1);
164 raise(SIGSTOP);
165 char c;
166 assert(read(0, &c, sizeof(c)) == 1);
167 return 0;
168 }
169
170 (void) close(0);
171
172 assert(do_wait4(pid, s, WSTOPPED, rusage) == pid);
173 assert(WIFSTOPPED(*s) && WSTOPSIG(*s) == SIGSTOP);
174 tprintf("wait4(%d, [{WIFSTOPPED(s) && WSTOPSIG(s) == SIGSTOP}]"
175 ", WSTOPPED, %s) = %d\n", pid, sprint_rusage(rusage), pid);
176
177 if (kill(pid, SIGCONT))
178 perror_msg_and_fail("kill(SIGCONT)");
179
180 # if defined WCONTINUED && defined WIFCONTINUED
181 assert(do_wait4(pid, s, WCONTINUED, rusage) == pid);
182 assert(WIFCONTINUED(*s));
183 tprintf("wait4(%d, [{WIFCONTINUED(s)}], WCONTINUED"
184 ", %s) = %d\n", pid, sprint_rusage(rusage), pid);
185 # endif /* WCONTINUED && WIFCONTINUED */
186
187 assert(write(1, "", 1) == 1);
188 (void) close(1);
189
190 assert(do_wait4(pid, s, 0, rusage) == pid);
191 assert(WIFEXITED(*s) && WEXITSTATUS(*s) == 0);
192 tprintf("wait4(%d, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0"
193 ", %s) = %d\n", pid, sprint_rusage(rusage), pid);
194
195 assert(k_wait4(-1, s, WNOHANG|WSTOPPED|__WALL, rusage) == -1);
196 tprintf("wait4(-1, %p, WNOHANG|WSTOPPED|__WALL, %p) = %s\n",
197 s, rusage, errstr);
198
199 tprintf("%s\n", "+++ exited with 0 +++");
200 return 0;
201 }
202
203 #else
204
205 SKIP_MAIN_UNDEFINED("__NR_wait4")
206
207 #endif /* __NR_wait4 */