]> granicus.if.org Git - strace/blob - tests/waitid.c
Rename widen_to_ull to zero_extend_signed_to_ull
[strace] / tests / waitid.c
1 /*
2  * Check decoding of waitid syscall.
3  *
4  * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@altlinux.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "tests.h"
31 #include <assert.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <sys/wait.h>
37 #include <sys/resource.h>
38 #include <asm/unistd.h>
39
40 static const char *
41 sprint_rusage(const struct rusage *const ru)
42 {
43         static char buf[1024];
44         snprintf(buf, sizeof(buf),
45                  "{ru_utime={%llu, %llu}"
46                  ", ru_stime={%llu, %llu}"
47 #ifdef VERBOSE_RUSAGE
48                  ", ru_maxrss=%llu"
49                  ", ru_ixrss=%llu"
50                  ", ru_idrss=%llu"
51                  ", ru_isrss=%llu"
52                  ", ru_minflt=%llu"
53                  ", ru_majflt=%llu"
54                  ", ru_nswap=%llu"
55                  ", ru_inblock=%llu"
56                  ", ru_oublock=%llu"
57                  ", ru_msgsnd=%llu"
58                  ", ru_msgrcv=%llu"
59                  ", ru_nsignals=%llu"
60                  ", ru_nvcsw=%llu"
61                  ", ru_nivcsw=%llu}"
62 #else
63                  ", ...}"
64 #endif
65                  , zero_extend_signed_to_ull(ru->ru_utime.tv_sec)
66                  , zero_extend_signed_to_ull(ru->ru_utime.tv_usec)
67                  , zero_extend_signed_to_ull(ru->ru_stime.tv_sec)
68                  , zero_extend_signed_to_ull(ru->ru_stime.tv_usec)
69 #ifdef VERBOSE_RUSAGE
70                  , zero_extend_signed_to_ull(ru->ru_maxrss)
71                  , zero_extend_signed_to_ull(ru->ru_ixrss)
72                  , zero_extend_signed_to_ull(ru->ru_idrss)
73                  , zero_extend_signed_to_ull(ru->ru_isrss)
74                  , zero_extend_signed_to_ull(ru->ru_minflt)
75                  , zero_extend_signed_to_ull(ru->ru_majflt)
76                  , zero_extend_signed_to_ull(ru->ru_nswap)
77                  , zero_extend_signed_to_ull(ru->ru_inblock)
78                  , zero_extend_signed_to_ull(ru->ru_oublock)
79                  , zero_extend_signed_to_ull(ru->ru_msgsnd)
80                  , zero_extend_signed_to_ull(ru->ru_msgrcv)
81                  , zero_extend_signed_to_ull(ru->ru_nsignals)
82                  , zero_extend_signed_to_ull(ru->ru_nvcsw)
83                  , zero_extend_signed_to_ull(ru->ru_nivcsw)
84 #endif
85                  );
86         return buf;
87 }
88
89 #define CASE(x) case x: return #x
90
91 static const char *
92 si_code_2_name(const int code)
93 {
94         switch (code) {
95 #ifdef CLD_EXITED
96         CASE(CLD_EXITED);
97 #endif
98 #ifdef CLD_KILLED
99         CASE(CLD_KILLED);
100 #endif
101 #ifdef CLD_DUMPED
102         CASE(CLD_DUMPED);
103 #endif
104 #ifdef CLD_TRAPPED
105         CASE(CLD_TRAPPED);
106 #endif
107 #ifdef CLD_STOPPED
108         CASE(CLD_STOPPED);
109 #endif
110 #ifdef CLD_CONTINUED
111         CASE(CLD_CONTINUED);
112 #endif
113         default: perror_msg_and_fail("unknown si_code %d", code);
114         }
115 }
116
117 static const char *
118 sprint_siginfo(const siginfo_t *const si, const char *const status_text)
119 {
120         static char buf[1024];
121         snprintf(buf, sizeof(buf),
122                  "{si_signo=SIGCHLD"
123                  ", si_code=%s"
124                  ", si_pid=%u"
125                  ", si_uid=%u"
126                  ", si_status=%s"
127                  ", si_utime=%llu"
128                  ", si_stime=%llu}",
129                  si_code_2_name(si->si_code),
130                  si->si_pid,
131                  si->si_uid,
132                  status_text,
133                  zero_extend_signed_to_ull(si->si_utime),
134                  zero_extend_signed_to_ull(si->si_stime));
135         return buf;
136 }
137
138 static unsigned long
139 poison(unsigned int v)
140 {
141         return (unsigned long) 0xfacefeed00000000 | v;
142 }
143
144 static long
145 do_waitid(const unsigned int idtype,
146           const unsigned int id,
147           const siginfo_t const *infop,
148           const unsigned int options,
149           const struct rusage *const rusage)
150 {
151         sigset_t mask = {};
152         sigaddset(&mask, SIGCHLD);
153
154         assert(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
155         long rc = syscall(__NR_waitid, poison(idtype), poison(id),
156                           infop, poison(options), rusage);
157         assert(sigprocmask(SIG_UNBLOCK, &mask, NULL) == 0);
158         return rc;
159 }
160
161 int
162 main(void)
163 {
164         tprintf("%s", "");
165
166         int fds[2];
167         if (pipe(fds))
168                 perror_msg_and_fail("pipe");
169
170         pid_t pid;
171         pid = fork();
172         if (pid < 0)
173                 perror_msg_and_fail("fork");
174
175         if (!pid) {
176                 char c;
177                 (void) close(1);
178                 assert(read(0, &c, sizeof(c)) == 1);
179                 return 42;
180         }
181
182         (void) close(0);
183
184         if (do_waitid(P_PID, pid, 0, WNOHANG|WEXITED, 0))
185                 perror_msg_and_fail("waitid #1");
186         tprintf("waitid(P_PID, %d, NULL, WNOHANG|WEXITED, NULL) = 0\n", pid);
187
188         siginfo_t *const sinfo = tail_alloc(sizeof(*sinfo));
189         memset(sinfo, 0, sizeof(*sinfo));
190         struct rusage *const rusage = tail_alloc(sizeof(*rusage));
191         if (do_waitid(P_PID, pid, sinfo, WNOHANG|WEXITED|WSTOPPED, rusage))
192                 perror_msg_and_fail("waitid #2");
193         tprintf("waitid(P_PID, %d, {}, WNOHANG|WEXITED|WSTOPPED, %s) = 0\n",
194                 pid, sprint_rusage(rusage));
195
196         assert(write(1, "", 1) == 1);
197         (void) close(1);
198
199         if (do_waitid(P_PID, pid, sinfo, WEXITED, rusage))
200                 perror_msg_and_fail("waitid #3");
201         tprintf("waitid(P_PID, %d, %s, WEXITED, %s) = 0\n",
202                 pid, sprint_siginfo(sinfo, "42"), sprint_rusage(rusage));
203
204         pid = fork();
205         if (pid < 0)
206                 perror_msg_and_fail("fork");
207
208         if (!pid) {
209                 (void) raise(SIGUSR1);
210                 return 1;
211         }
212
213         if (do_waitid(P_PID, pid, sinfo, WEXITED, rusage))
214                 perror_msg_and_fail("waitid #4");
215         tprintf("waitid(P_PID, %d, %s, WEXITED, %s) = 0\n",
216                 pid, sprint_siginfo(sinfo, "SIGUSR1"), sprint_rusage(rusage));
217
218         if (pipe(fds))
219                 perror_msg_and_fail("pipe");
220         pid = fork();
221         if (pid < 0)
222                 perror_msg_and_fail("fork");
223
224         if (!pid) {
225                 (void) close(1);
226                 raise(SIGSTOP);
227                 char c;
228                 assert(read(0, &c, sizeof(c)) == 1);
229                 return 0;
230         }
231
232         (void) close(0);
233
234         if (do_waitid(P_PID, pid, sinfo, WSTOPPED, rusage))
235                 perror_msg_and_fail("waitid #5");
236         tprintf("waitid(P_PID, %d, %s, WSTOPPED, %s) = 0\n",
237                 pid, sprint_siginfo(sinfo, "SIGSTOP"), sprint_rusage(rusage));
238
239         if (kill(pid, SIGCONT))
240                 perror_msg_and_fail("kill(SIGCONT)");
241
242 #if defined WCONTINUED
243         if (do_waitid(P_PID, pid, sinfo, WCONTINUED, rusage))
244                 perror_msg_and_fail("waitid #6");
245         tprintf("waitid(P_PID, %d, %s, WCONTINUED, %s) = 0\n",
246                 pid, sprint_siginfo(sinfo, "SIGCONT"), sprint_rusage(rusage));
247 #endif /* WCONTINUED */
248
249         assert(write(1, "", 1) == 1);
250         (void) close(1);
251
252         if (do_waitid(P_PID, pid, sinfo, WEXITED, rusage))
253                 perror_msg_and_fail("waitid #7");
254         tprintf("waitid(P_PID, %d, %s, WEXITED, %s) = 0\n",
255                 pid, sprint_siginfo(sinfo, "0"), sprint_rusage(rusage));
256
257         long rc = do_waitid(P_ALL, -1, sinfo, WEXITED|WSTOPPED, rusage);
258         tprintf("waitid(P_ALL, -1, %p, WEXITED|WSTOPPED, %p)"
259                 " = %ld %s (%m)\n", sinfo, rusage, rc, errno2name());
260
261         tprintf("%s\n", "+++ exited with 0 +++");
262         return 0;
263 }