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  *	waitpid11.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 = -1 and arg = 0
29  *
30  * USAGE:  <for command-line>
31  *      waitpid11 [-c n] [-t]
32  *      where,  -c n : Run n copies concurrently.
33  *              -t   : Turn on syscall timing.
34  *
35  * History
36  *	07/2001 John George
37  *		-Ported
38  *      04/2002 wjhuie sigset cleanups
39  *
40  * Restrictions
41  *	None
42  */
43 
44 #include <sys/types.h>
45 #include <signal.h>
46 #include <errno.h>
47 #include <sys/wait.h>
48 #include "test.h"
49 
50 #define	MAXKIDS	8
51 
52 char *TCID = "waitpid11";
53 int TST_TOTAL = 1;
54 
55 volatile int intintr;
56 static void setup(void);
57 static void cleanup(void);
58 static void inthandlr();
59 static void wait_for_parent(void);
60 static void do_exit(void);
61 static void setup_sigint(void);
62 #ifdef UCLINUX
63 static void do_exit_uclinux(void);
64 #endif
65 
66 static int fail;
67 static int fork_kid_pid[MAXKIDS];
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 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 
93 	pid = FORK_OR_VFORK();
94 	if (pid > 0) {
95 		waitpid(pid, &status, 0);
96 		if (WEXITSTATUS(status) != 0) {
97 			tst_resm(TFAIL, "child returned bad status");
98 			fail = 1;
99 		}
100 		if (fail)
101 			tst_resm(TFAIL, "%s FAILED", TCID);
102 		else
103 			tst_resm(TPASS, "%s PASSED", TCID);
104 		tst_exit();
105 	} else if (pid < 0)
106 		tst_brkm(TBROK, cleanup, "fork failed");
107 
108 	/*
109 	 * Set up to catch SIGINT.  The kids will wait till a SIGINT
110 	 * has been received before they proceed.
111 	 */
112 	setup_sigint();
113 
114 	group1 = getpgrp();
115 
116 	for (kid_count = 0; kid_count < MAXKIDS; kid_count++) {
117 		if (kid_count == (MAXKIDS / 2))
118 			group2 = setpgrp();
119 
120 		intintr = 0;
121 		ret_val = FORK_OR_VFORK();
122 		if (ret_val == 0) {
123 #ifdef UCLINUX
124 			if (self_exec(av[0], "") < 0)
125 				tst_resm(TFAIL | TERRNO, "self_exec kid %d "
126 					 "failed", kid_count);
127 #else
128 			do_exit();
129 #endif
130 		}
131 
132 		if (ret_val < 0)
133 			tst_brkm(TBROK|TERRNO, cleanup, "Fork kid %d failed",
134 				 kid_count);
135 
136 		/* parent */
137 		fork_kid_pid[kid_count] = ret_val;
138 	}
139 
140 #ifdef UCLINUX
141 	/* Give the kids a chance to setup SIGINT again, since this is
142 	 * cleared by exec().
143 	 */
144 	sleep(3);
145 #endif
146 
147 	/* Now send all the kids a SIGINT to tell them to proceed */
148 	for (i = 0; i < MAXKIDS; i++)
149 		if (kill(fork_kid_pid[i], SIGINT) < 0)
150 			tst_resm(TFAIL | TERRNO, "Kill of child %d failed", i);
151 
152 	/*
153 	 * Wait till all kids have terminated.  Stash away their
154 	 * pid's in an array.
155 	 */
156 	kid_count = 0;
157 	errno = 0;
158 	while (((ret_val = waitpid(0, &status, 0)) != -1) || (errno == EINTR)) {
159 		if (ret_val == -1)
160 			continue;
161 
162 		if (!WIFEXITED(status)) {
163 			tst_resm(TFAIL, "Child %d did not exit "
164 				 "normally", ret_val);
165 			fail = 1;
166 		} else {
167 			if (WEXITSTATUS(status) != 3) {
168 				tst_resm(TFAIL, "Child %d exited with "
169 					 "wrong status", ret_val);
170 				tst_resm(TFAIL, "Expected 3 got %d",
171 					 WEXITSTATUS(status));
172 				fail = 1;
173 			}
174 		}
175 		wait_kid_pid[kid_count++] = ret_val;
176 	}
177 
178 	/*
179 	 * Check that for every entry in the fork_kid_pid array,
180 	 * there is a matching pid in the wait_kid_pid array.  If
181 	 * not, it's an error.
182 	 */
183 	for (i = 0; i < kid_count; i++) {
184 		found = 0;
185 		for (j = (MAXKIDS / 2); j < MAXKIDS; j++) {
186 			if (fork_kid_pid[j] == wait_kid_pid[i]) {
187 				found = 1;
188 				break;
189 			}
190 		}
191 		if (!found) {
192 			tst_resm(TFAIL, "Did not find a fork_kid_pid "
193 				 "for the wait_kid_pid of %d", wait_kid_pid[i]);
194 			for (k = 0; k < MAXKIDS; k++) {
195 				tst_resm(TFAIL, "fork_kid_pid[%d] = "
196 					 "%d", k, fork_kid_pid[k]);
197 			}
198 			for (k = 0; k < kid_count; k++) {
199 				tst_resm(TFAIL, "wait_kid_pid[%d] = "
200 					 "%d", k, wait_kid_pid[k]);
201 			}
202 			fail = 1;
203 		}
204 	}
205 
206 	if (kid_count != (MAXKIDS / 2)) {
207 		tst_resm(TFAIL, "Wrong number of children waited on "
208 			 "for pid = 0");
209 		tst_resm(TFAIL, "Expected 4 got %d", kid_count);
210 		fail = 1;
211 	}
212 
213 	/* Make sure can pickup children in a diff. process group */
214 
215 	kid_count = 0;
216 	errno = 0;
217 	while (((ret_val = waitpid(-(group1), &status, 0)) != -1) ||
218 	       (errno == EINTR)) {
219 		if (ret_val == -1)
220 			continue;
221 		if (!WIFEXITED(status)) {
222 			tst_resm(TFAIL, "Child %d did not exit "
223 				 "normally", ret_val);
224 			fail = 1;
225 		} else {
226 			if (WEXITSTATUS(status) != 3) {
227 				tst_resm(TFAIL, "Child %d exited with "
228 					 "wrong status", ret_val);
229 				tst_resm(TFAIL, "Expected 3 got %d",
230 					 WEXITSTATUS(status));
231 				fail = 1;
232 			}
233 		}
234 		wait_kid_pid[kid_count++] = ret_val;
235 	}
236 
237 	/*
238 	 * Check that for every entry in the fork_kid_pid array,
239 	 * there is a matching pid in the wait_kid_pid array.  If
240 	 * not, it's an error.
241 	 */
242 	for (i = 0; i < kid_count; i++) {
243 		found = 0;
244 		for (j = 0; j < (MAXKIDS / 2); j++) {
245 			if (fork_kid_pid[j] == wait_kid_pid[i]) {
246 				found = 1;
247 				break;
248 			}
249 		}
250 		if (!found) {
251 			tst_resm(TFAIL, "Did not find a fork_kid_pid "
252 				 "for the wait_kid_pid of %d", wait_kid_pid[i]);
253 			for (k = 0; k < MAXKIDS; k++)
254 				tst_resm(TFAIL, "fork_kid_pid[%d] = "
255 					 "%d", k, fork_kid_pid[k]);
256 			for (k = 0; k < kid_count; k++)
257 				tst_resm(TFAIL, "wait_kid_pid[%d] = "
258 					 "%d", k, wait_kid_pid[k]);
259 			fail = 1;
260 		}
261 	}
262 
263 	memset(fork_kid_pid, 0, sizeof(fork_kid_pid));
264 
265 	if (kid_count != (MAXKIDS / 2)) {
266 		tst_resm(TFAIL, "Wrong number of children waited on "
267 			 "for pid = 0");
268 		tst_resm(TFAIL, "Expected 4 got %d", kid_count);
269 		fail = 1;
270 	}
271 
272 	if (fail)
273 		tst_resm(TFAIL, "Test FAILED");
274 	else
275 		tst_resm(TPASS, "Test PASSED");
276 
277 	cleanup();
278 	tst_exit();
279 }
280 
setup_sigint(void)281 static void setup_sigint(void)
282 {
283 	if (signal(SIGINT, inthandlr) == SIG_ERR)
284 		tst_brkm(TFAIL | TERRNO, NULL, "signal SIGINT failed");
285 }
286 
setup(void)287 static void setup(void)
288 {
289 	TEST_PAUSE;
290 }
291 
cleanup(void)292 static void cleanup(void)
293 {
294 	int i;
295 
296 	for (i = 0; i < MAXKIDS; i++) {
297 		if (fork_kid_pid[i] > 0)
298 			kill(fork_kid_pid[i], SIGKILL);
299 	}
300 }
301 
inthandlr(void)302 static void inthandlr(void)
303 {
304 	intintr++;
305 }
306 
wait_for_parent(void)307 static void wait_for_parent(void)
308 {
309 	int testvar;
310 
311 	while (!intintr)
312 		testvar = 0;
313 }
314 
do_exit(void)315 static void do_exit(void)
316 {
317 	wait_for_parent();
318 	exit(3);
319 }
320 
321 #ifdef UCLINUX
do_exit_uclinux(void)322 static void do_exit_uclinux(void)
323 {
324 	setup_sigint();
325 	do_exit();
326 }
327 #endif
328