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