1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2001
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;  if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 /*
21  * NAME
22  *	waitpid13.c
23  *
24  * DESCRIPTION
25  *	Tests to see if pid's returned from fork and waitpid are same
26  *
27  * ALGORITHM
28  *	Check proper functioning of waitpid with pid = 0 and < -1 with arg
29  *	WUNTRACED
30  *
31  * USAGE:  <for command-line>
32  *      waitpid13 [-c n] [-t]
33  *      where,  -c n : Run n copies concurrently.
34  *              -t   : Turn on syscall timing.
35  *
36  * History
37  *	07/2001 John George
38  *		-Ported
39  *      04/2002 wjhuie sigset cleanups
40  *
41  * Restrictions
42  *	None
43  */
44 
45 #include <sys/types.h>
46 #include <signal.h>
47 #include <errno.h>
48 #include <sys/wait.h>
49 #include "test.h"
50 
51 #define	MAXKIDS	8
52 
53 char *TCID = "waitpid13";
54 int TST_TOTAL = 1;
55 
56 volatile int intintr;
57 static void setup(void);
58 static void cleanup(void);
59 static void inthandlr();
60 static void wait_for_parent(void);
61 static void do_exit(void);
62 static void setup_sigint(void);
63 #ifdef UCLINUX
64 static void do_exit_uclinux(void);
65 #endif
66 
67 static int fail;
68 
main(int ac,char ** av)69 int main(int ac, char **av)
70 {
71 	int kid_count, ret_val, status;
72 	int i, j, k, found;
73 	int group1, group2;
74 	int fork_kid_pid[MAXKIDS], wait_kid_pid[MAXKIDS];
75 	int pid;
76 
77 	tst_parse_opts(ac, av, NULL, NULL);
78 
79 #ifdef UCLINUX
80 	maybe_run_child(&do_exit_uclinux, "");
81 #endif
82 
83 	setup();
84 
85 	tst_count = 0;
86 	fail = 0;
87 
88 	/*
89 	 * Need to have test run from child as test driver causes
90 	 * test to be a session leader and setpgrp fails.
91 	 */
92 	pid = FORK_OR_VFORK();
93 	if (pid > 0) {
94 		waitpid(pid, &status, 0);
95 		if (WEXITSTATUS(status) != 0) {
96 			tst_resm(TFAIL, "child returned bad status");
97 			fail = 1;
98 		}
99 		if (fail)
100 			tst_resm(TFAIL, "%s FAILED", TCID);
101 		else
102 			tst_resm(TPASS, "%s PASSED", TCID);
103 
104 		cleanup();
105 		tst_exit();
106 	} else if (pid < 0) {
107 		tst_brkm(TBROK, cleanup, "fork failed");
108 	}
109 
110 	/*
111 	 * Set up to catch SIGINT.  The kids will wait till a SIGINT
112 	 * has been received before they proceed.
113 	 */
114 	setup_sigint();
115 
116 	group1 = getpgrp();
117 
118 	for (kid_count = 0; kid_count < MAXKIDS; kid_count++) {
119 		if (kid_count == (MAXKIDS / 2))
120 			group2 = setpgrp();
121 
122 		intintr = 0;
123 		ret_val = FORK_OR_VFORK();
124 		if (ret_val == 0) {
125 #ifdef UCLINUX
126 			if (self_exec(av[0], "") < 0) {
127 				tst_resm(TFAIL | TERRNO, "self_exec kid %d "
128 					 "failed", kid_count);
129 
130 			}
131 #else
132 			do_exit();
133 #endif
134 		}
135 
136 		if (ret_val < 0)
137 			tst_resm(TFAIL | TERRNO, "forking kid %d failed",
138 				 kid_count);
139 
140 		/* parent */
141 		fork_kid_pid[kid_count] = ret_val;
142 	}
143 
144 	/* Check that waitpid with WNOHANG|WUNTRACED returns zero */
145 	ret_val = waitpid(0, &status, WNOHANG | WUNTRACED);
146 	if (ret_val != 0) {
147 		tst_resm(TFAIL, "Waitpid returned wrong value"
148 			 "from waitpid(WNOHANG|WUNTRACED)");
149 		tst_resm(TFAIL, "Expected 0 got %d", ret_val);
150 		fail = 1;
151 	}
152 #ifdef UCLINUX
153 	/* Give the kids a chance to setup SIGINT again, since this is
154 	 * cleared by exec().
155 	 */
156 	sleep(3);
157 #endif
158 
159 	/* Now send all the kids a SIGINT to tell them to proceed */
160 	for (i = 0; i < MAXKIDS; i++) {
161 		if (kill(fork_kid_pid[i], SIGINT) < 0) {
162 			tst_resm(TFAIL | TERRNO, "killing child %d failed", i);
163 			fail = 1;
164 		}
165 	}
166 
167 	/*
168 	 * Wait till all kids have terminated.  Stash away their
169 	 * pid's in an array.
170 	 */
171 	kid_count = 0;
172 	errno = 0;
173 	while (((ret_val = waitpid(0, &status, WUNTRACED)) != -1) ||
174 	       (errno == EINTR)) {
175 		if (ret_val == -1)
176 			continue;
177 
178 		if (!WIFEXITED(status)) {
179 			if (!WIFSTOPPED(status)) {
180 				tst_resm(TFAIL, "Child %d is not "
181 					 "stopped", ret_val);
182 				fail = 1;
183 			} else {
184 				if (WSTOPSIG(status) != SIGSTOP) {
185 					tst_resm(TFAIL, "Child %d "
186 						 "exited with wrong "
187 						 "status", ret_val);
188 					tst_resm(TFAIL, "Expected "
189 						 "SIGSTOP got %d",
190 						 WEXITSTATUS(status));
191 					fail = 1;
192 				}
193 			}
194 			if (kill(ret_val, SIGCONT) < 0) {
195 				tst_resm(TFAIL | TERRNO,
196 					 "killing child %d failed", ret_val);
197 				fail = 1;
198 			}
199 		}
200 		found = 0;
201 		for (j = 0; j < kid_count; j++) {
202 			if (ret_val == wait_kid_pid[j]) {
203 				found = 1;
204 				break;
205 			}
206 		}
207 		if (!found)
208 			wait_kid_pid[kid_count++] = ret_val;
209 	}
210 
211 	/*
212 	 * Check that for every entry in the fork_kid_pid array,
213 	 * there is a matching pid in the wait_kid_pid array.  If
214 	 * not, it's an error.
215 	 */
216 	for (i = 0; i < kid_count; i++) {
217 		found = 0;
218 		for (j = (MAXKIDS / 2); j < MAXKIDS; j++) {
219 			if (fork_kid_pid[j] == wait_kid_pid[i]) {
220 				found = 1;
221 				break;
222 			}
223 		}
224 		if (!found) {
225 			tst_resm(TFAIL, "Did not find a wait_kid_pid "
226 				 "for the fork_kid_pid of %d", wait_kid_pid[i]);
227 			for (k = 0; k < MAXKIDS; k++)
228 				tst_resm(TFAIL, "fork_kid_pid[%d] = "
229 					 "%d", k, fork_kid_pid[k]);
230 			for (k = 0; k < kid_count; k++)
231 				tst_resm(TFAIL, "wait_kid_pid[%d] = "
232 					 "%d", k, wait_kid_pid[k]);
233 			fail = 1;
234 		}
235 	}
236 
237 	if (kid_count != (MAXKIDS / 2)) {
238 		tst_resm(TFAIL, "Wrong number of children waited on "
239 			 "for pid = 0");
240 		tst_resm(TFAIL, "Expected %d got %d", MAXKIDS, kid_count);
241 		fail = 1;
242 	}
243 
244 	/* Make sure can pickup children in a diff. process group */
245 
246 	kid_count = 0;
247 	errno = 0;
248 	while (((ret_val = waitpid(-(group1), &status, WUNTRACED)) !=
249 		-1) || (errno == EINTR)) {
250 		if (ret_val == -1)
251 			continue;
252 		if (!WIFEXITED(status)) {
253 			if (!WIFSTOPPED(status)) {
254 				tst_resm(TFAIL, "Child %d is not "
255 					 "stopped", ret_val);
256 				fail = 1;
257 			} else {
258 				if (WSTOPSIG(status) != SIGSTOP) {
259 					tst_resm(TFAIL, "Child %d "
260 						 "exited with wrong "
261 						 "status", ret_val);
262 					tst_resm(TFAIL, "Expected "
263 						 "SIGSTOP got %d",
264 						 WEXITSTATUS(status));
265 					fail = 1;
266 				}
267 			}
268 			if (kill(ret_val, SIGCONT) < 0) {
269 				tst_resm(TFAIL | TERRNO,
270 					 "Killing child %d failed", ret_val);
271 				fail = 1;
272 			}
273 		}
274 		found = 0;
275 		for (j = 0; j < kid_count; j++) {
276 			if (ret_val == wait_kid_pid[j]) {
277 				found = 1;
278 				break;
279 			}
280 		}
281 		if (!found)
282 			wait_kid_pid[kid_count++] = ret_val;
283 	}
284 
285 	/*
286 	 * Check that for every entry in the fork_kid_pid array,
287 	 * there is a matching pid in the wait_kid_pid array.  If
288 	 * not, it's an error.
289 	 */
290 	for (i = 0; i < kid_count; i++) {
291 		found = 0;
292 		for (j = 0; j < (MAXKIDS / 2); j++) {
293 			if (fork_kid_pid[j] == wait_kid_pid[i]) {
294 				found = 1;
295 				break;
296 			}
297 		}
298 		if (!found) {
299 			tst_resm(TFAIL, "Did not find a wait_kid_pid "
300 				 "for the fork_kid_pid of %d", fork_kid_pid[j]);
301 			for (k = 0; k < MAXKIDS; k++)
302 				tst_resm(TFAIL, "fork_kid_pid[%d] = "
303 					 "%d", k, fork_kid_pid[k]);
304 			for (k = 0; k < kid_count; k++)
305 				tst_resm(TFAIL, "wait_kid_pid[%d] = "
306 					 "%d", k, wait_kid_pid[k]);
307 			fail = 1;
308 		}
309 	}
310 	if (kid_count != (MAXKIDS / 2)) {
311 		tst_resm(TFAIL, "Wrong number of children waited on "
312 			 "for pid = 0");
313 		tst_resm(TFAIL, "Expected %d got %d", MAXKIDS, kid_count);
314 		fail = 1;
315 	}
316 
317 	/*
318 	 * Check that waitpid(WUNTRACED) returns -1 when no stopped
319 	 * children
320 	 */
321 	ret_val = waitpid(-1, &status, WUNTRACED);
322 	if (ret_val != -1) {
323 		tst_resm(TFAIL, "Waitpid returned wrong value.");
324 		tst_resm(TFAIL, "Expected -1 got %d", ret_val);
325 		fail = 1;
326 	}
327 
328 	if (errno != ECHILD) {
329 		tst_resm(TFAIL, "Expected ECHILD from waitpid(WUNTRACED)");
330 		fail = 1;
331 	}
332 
333 	if (fail)
334 		tst_resm(TFAIL, "Test FAILED");
335 	else
336 		tst_resm(TPASS, "Test PASSED");
337 
338 	tst_exit();
339 }
340 
setup_sigint(void)341 static void setup_sigint(void)
342 {
343 	if (signal(SIGINT, inthandlr) == SIG_ERR)
344 		tst_brkm(TFAIL | TERRNO, NULL, "signal SIGINT failed");
345 }
346 
setup(void)347 static void setup(void)
348 {
349 	TEST_PAUSE;
350 }
351 
cleanup(void)352 static void cleanup(void)
353 {
354 }
355 
inthandlr(void)356 static void inthandlr(void)
357 {
358 	intintr++;
359 }
360 
wait_for_parent(void)361 static void wait_for_parent(void)
362 {
363 	int testvar;
364 
365 	while (!intintr)
366 		testvar = 0;
367 }
368 
do_exit(void)369 static void do_exit(void)
370 {
371 	wait_for_parent();
372 	kill(getpid(), SIGSTOP);
373 	exit(3);
374 }
375 
376 #ifdef UCLINUX
do_exit_uclinux(void)377 static void do_exit_uclinux(void)
378 {
379 	setup_sigint();
380 	do_exit();
381 }
382 #endif
383