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