1/*
2 * Check decoding of wait4 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 <unistd.h>
35#include <sys/wait.h>
36#include <sys/resource.h>
37
38static const char *
39sprint_rusage(const struct rusage *const ru)
40{
41	static char buf[1024];
42	snprintf(buf, sizeof(buf),
43		 "{ru_utime={tv_sec=%lu, tv_usec=%lu}"
44		 ", ru_stime={tv_sec=%lu, tv_usec=%lu}"
45#if VERBOSE
46		 ", ru_maxrss=%lu"
47		 ", ru_ixrss=%lu"
48		 ", ru_idrss=%lu"
49		 ", ru_isrss=%lu"
50		 ", ru_minflt=%lu"
51		 ", ru_majflt=%lu"
52		 ", ru_nswap=%lu"
53		 ", ru_inblock=%lu"
54		 ", ru_oublock=%lu"
55		 ", ru_msgsnd=%lu"
56		 ", ru_msgrcv=%lu"
57		 ", ru_nsignals=%lu"
58		 ", ru_nvcsw=%lu"
59		 ", ru_nivcsw=%lu}"
60#else
61		 ", ...}"
62#endif
63		 , (long) ru->ru_utime.tv_sec
64		 , (long) ru->ru_utime.tv_usec
65		 , (long) ru->ru_stime.tv_sec
66		 , (long) ru->ru_stime.tv_usec
67#if VERBOSE
68		 , (long) ru->ru_maxrss
69		 , (long) ru->ru_ixrss
70		 , (long) ru->ru_idrss
71		 , (long) ru->ru_isrss
72		 , (long) ru->ru_minflt
73		 , (long) ru->ru_majflt
74		 , (long) ru->ru_nswap
75		 , (long) ru->ru_inblock
76		 , (long) ru->ru_oublock
77		 , (long) ru->ru_msgsnd
78		 , (long) ru->ru_msgrcv
79		 , (long) ru->ru_nsignals
80		 , (long) ru->ru_nvcsw
81		 , (long) ru->ru_nivcsw
82#endif
83		 );
84	return buf;
85}
86
87static pid_t
88do_wait4(pid_t pid, int *wstatus, int options, struct rusage *ru)
89{
90	sigset_t mask = {};
91	sigaddset(&mask, SIGCHLD);
92
93	assert(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
94	pid_t rc = wait4(pid, wstatus, options, ru);
95	assert(sigprocmask(SIG_UNBLOCK, &mask, NULL) == 0);
96	return rc;
97}
98
99int
100main(void)
101{
102	tprintf("%s", "");
103
104	int fds[2];
105	if (pipe(fds))
106		perror_msg_and_fail("pipe");
107
108	pid_t pid;
109	pid = fork();
110	if (pid < 0)
111		perror_msg_and_fail("fork");
112
113	if (!pid) {
114		char c;
115		(void) close(1);
116		assert(read(0, &c, sizeof(c)) == 1);
117		return 42;
118	}
119
120	(void) close(0);
121
122	int *const s = tail_alloc(sizeof(*s));
123	if (wait4(pid, s, WNOHANG|__WALL, NULL))
124		perror_msg_and_fail("wait4 #1");
125	tprintf("wait4(%d, %p, WNOHANG|__WALL, NULL) = 0\n", pid, s);
126
127	struct rusage *const rusage = tail_alloc(sizeof(*rusage));
128	if (wait4(pid, s, WNOHANG|__WALL, rusage))
129		perror_msg_and_fail("wait4 #2");
130	tprintf("wait4(%d, %p, WNOHANG|__WALL, %p) = 0\n", pid, s, rusage);
131
132	assert(write(1, "", 1) == 1);
133	(void) close(1);
134
135	assert(do_wait4(pid, s, 0, rusage) == pid);
136	assert(WIFEXITED(*s) && WEXITSTATUS(*s) == 42);
137	tprintf("wait4(%d, [{WIFEXITED(s) && WEXITSTATUS(s) == 42}], 0, %s)"
138		" = %d\n", pid, sprint_rusage(rusage), pid);
139
140	pid = fork();
141	if (pid < 0)
142		perror_msg_and_fail("fork");
143
144	if (!pid) {
145		(void) raise(SIGUSR1);
146		return 1;
147	}
148
149	assert(do_wait4(pid, s, __WALL, rusage) == pid);
150	assert(WIFSIGNALED(*s) && WTERMSIG(*s) == SIGUSR1);
151	tprintf("wait4(%d, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGUSR1}]"
152		", __WALL, %s) = %d\n", pid, sprint_rusage(rusage), pid);
153
154	if (pipe(fds))
155		perror_msg_and_fail("pipe");
156	pid = fork();
157	if (pid < 0)
158		perror_msg_and_fail("fork");
159
160	if (!pid) {
161		(void) close(1);
162		raise(SIGSTOP);
163		char c;
164		assert(read(0, &c, sizeof(c)) == 1);
165		return 0;
166	}
167
168	(void) close(0);
169
170	assert(do_wait4(pid, s, WSTOPPED, rusage) == pid);
171	assert(WIFSTOPPED(*s) && WSTOPSIG(*s) == SIGSTOP);
172	tprintf("wait4(%d, [{WIFSTOPPED(s) && WSTOPSIG(s) == SIGSTOP}]"
173		", WSTOPPED, %s) = %d\n", pid, sprint_rusage(rusage), pid);
174
175	if (kill(pid, SIGCONT))
176		perror_msg_and_fail("kill(SIGCONT)");
177
178#if defined WCONTINUED && defined WIFCONTINUED
179	assert(do_wait4(pid, s, WCONTINUED, rusage) == pid);
180	assert(WIFCONTINUED(*s));
181	tprintf("wait4(%d, [{WIFCONTINUED(s)}], WCONTINUED"
182		", %s) = %d\n", pid, sprint_rusage(rusage), pid);
183#endif /* WCONTINUED && WIFCONTINUED */
184
185	assert(write(1, "", 1) == 1);
186	(void) close(1);
187
188	assert(do_wait4(pid, s, 0, rusage) == pid);
189	assert(WIFEXITED(*s) && WEXITSTATUS(*s) == 0);
190	tprintf("wait4(%d, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0"
191		", %s) = %d\n", pid, sprint_rusage(rusage), pid);
192
193	assert(wait4(-1, s, WNOHANG|WSTOPPED|__WALL, rusage) == -1);
194	tprintf("wait4(-1, %p, WNOHANG|WSTOPPED|__WALL, %p) = -1 %s (%m)\n",
195		s, rusage, errno2name());
196
197	tprintf("%s\n", "+++ exited with 0 +++");
198	return 0;
199}
200