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  *	waitpid12.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 = WNOHANG
29  *
30  * USAGE:  <for command-line>
31  *      waitpid12 [-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 testx for SIG_ERR not < 0, TPASS|TFAIL issued
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 = "waitpid12";
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 argc,char ** argv)69 int main(int argc, char **argv)
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(argc, argv, 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 		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(argv[0], "") < 0)
127 				tst_resm(TFAIL, "self_exec kid %d "
128 					 "failed", kid_count);
129 #else
130 			do_exit();
131 #endif
132 		}
133 
134 		if (ret_val < 0)
135 			tst_resm(TFAIL | TERRNO, "forking kid %d failed",
136 				 kid_count);
137 
138 		/* parent */
139 		fork_kid_pid[kid_count] = ret_val;
140 	}
141 
142 	/* Check that waitpid with WNOHANG returns zero */
143 	ret_val = waitpid(0, &status, WNOHANG);
144 	if (ret_val != 0) {
145 		tst_resm(TFAIL, "Waitpid returned wrong value");
146 		tst_resm(TFAIL, "Expected 0 got %d", ret_val);
147 		fail = 1;
148 	}
149 #ifdef UCLINUX
150 	/* Give the kids a chance to setup SIGINT again, since this is
151 	 * cleared by exec().
152 	 */
153 	sleep(3);
154 #endif
155 
156 	/* Now send all the kids a SIGINT to tell them to proceed */
157 	for (i = 0; i < MAXKIDS; i++)
158 		if (kill(fork_kid_pid[i], SIGINT) < 0)
159 			tst_resm(TFAIL | TERRNO, "killing child %d failed", i);
160 
161 	/*
162 	 * Wait till all kids have terminated.  Stash away their
163 	 * pid's in an array.
164 	 */
165 	kid_count = 0;
166 	errno = 0;
167 	sleep(2);
168 	while (((ret_val = waitpid(0, &status, WNOHANG)) != -1) ||
169 	       (errno == EINTR)) {
170 		if ((ret_val == -1) || (ret_val == 0))
171 			continue;
172 
173 		if (!WIFEXITED(status)) {
174 			tst_resm(TFAIL, "Child %d did not exit "
175 				 "normally", ret_val);
176 			fail = 1;
177 		} else {
178 			if (WEXITSTATUS(status) != 3) {
179 				tst_resm(TFAIL, "Child %d exited with "
180 					 "wrong status", ret_val);
181 				tst_resm(TFAIL, "Expected 3 got %d",
182 					 WEXITSTATUS(status));
183 				fail = 1;
184 			}
185 		}
186 		wait_kid_pid[kid_count++] = ret_val;
187 	}
188 
189 	/*
190 	 * Check that for every entry in the fork_kid_pid array,
191 	 * there is a matching pid in the wait_kid_pid array.  If
192 	 * not, it's an error.
193 	 */
194 	for (i = 0; i < kid_count; i++) {
195 		found = 0;
196 		for (j = (MAXKIDS / 2); j < MAXKIDS; j++) {
197 			if (fork_kid_pid[j] == wait_kid_pid[i]) {
198 				found = 1;
199 				break;
200 			}
201 		}
202 		if (!found) {
203 			tst_resm(TFAIL, "Did not find a wait_kid_pid "
204 				 "for the fork_kid_pid of %d", wait_kid_pid[i]);
205 			for (k = 0; k < MAXKIDS; k++)
206 				tst_resm(TFAIL, "fork_kid_pid[%d] = "
207 					 "%d", k, fork_kid_pid[k]);
208 			for (k = 0; k < kid_count; k++)
209 				tst_resm(TFAIL, "wait_kid_pid[%d] = "
210 					 "%d", k, wait_kid_pid[k]);
211 			fail = 1;
212 		}
213 	}
214 
215 	if (kid_count != (MAXKIDS / 2)) {
216 		tst_resm(TFAIL, "Wrong number of children waited on "
217 			 "for pid = 0");
218 		tst_resm(TFAIL, "Expected 4 got %d", kid_count);
219 		fail = 1;
220 	}
221 
222 	/* Make sure can pickup children in a diff. process group */
223 
224 	kid_count = 0;
225 	errno = 0;
226 	while (((ret_val = waitpid(-(group1), &status, WNOHANG)) !=
227 		-1) || (errno == EINTR)) {
228 		if (ret_val == -1 || ret_val == 0)
229 			continue;
230 
231 		if (!WIFEXITED(status)) {
232 			tst_resm(TFAIL, "Child %d did not exit "
233 				 "normally", ret_val);
234 			fail = 1;
235 		} else {
236 			if (WEXITSTATUS(status) != 3) {
237 				tst_resm(TFAIL, "Child %d exited with "
238 					 "wrong status", ret_val);
239 				tst_resm(TFAIL, "Expected 3 got %d",
240 					 WEXITSTATUS(status));
241 				fail = 1;
242 			}
243 		}
244 		wait_kid_pid[kid_count++] = ret_val;
245 	}
246 
247 	/*
248 	 * Check that for every entry in the fork_kid_pid array,
249 	 * there is a matching pid in the wait_kid_pid array.  If
250 	 * not, it's an error.
251 	 */
252 	for (i = 0; i < kid_count; i++) {
253 		found = 0;
254 		for (j = 0; j < (MAXKIDS / 2); j++) {
255 			if (fork_kid_pid[j] == wait_kid_pid[i]) {
256 				found = 1;
257 				break;
258 			}
259 		}
260 		if (!found) {
261 			tst_resm(TFAIL, "Did not find a wait_kid_pid "
262 				 "for the fork_kid_pid of %d", fork_kid_pid[j]);
263 			for (k = 0; k < MAXKIDS; k++)
264 				tst_resm(TFAIL, "fork_kid_pid[%d] = "
265 					 "%d", k, fork_kid_pid[k]);
266 			for (k = 0; k < kid_count; k++)
267 				tst_resm(TFAIL, "wait_kid_pid[%d] = "
268 					 "%d", k, wait_kid_pid[k]);
269 			fail = 1;
270 		}
271 	}
272 	if (kid_count != (MAXKIDS / 2)) {
273 		tst_resm(TFAIL, "Wrong number of children waited on "
274 			 "for pid = 0");
275 		tst_resm(TFAIL, "Expected 4 got %d", kid_count);
276 		fail = 1;
277 	}
278 
279 	if (fail)
280 		tst_resm(TFAIL, "Test FAILED");
281 	else
282 		tst_resm(TPASS, "Test PASSED");
283 
284 	tst_exit();
285 }
286 
setup_sigint(void)287 static void setup_sigint(void)
288 {
289 	if (signal(SIGINT, inthandlr) == SIG_ERR)
290 		tst_brkm(TFAIL | TERRNO, NULL, "signal SIGINT failed");
291 }
292 
setup(void)293 static void setup(void)
294 {
295 	tst_sig(FORK, DEF_HANDLER, cleanup);
296 
297 	TEST_PAUSE;
298 }
299 
cleanup(void)300 static void cleanup(void)
301 {
302 }
303 
inthandlr(void)304 static void inthandlr(void)
305 {
306 	intintr++;
307 }
308 
wait_for_parent(void)309 static void wait_for_parent(void)
310 {
311 	int testvar;
312 
313 	while (!intintr)
314 		testvar = 0;
315 }
316 
do_exit(void)317 static void do_exit(void)
318 {
319 	wait_for_parent();
320 	exit(3);
321 }
322 
323 #ifdef UCLINUX
do_exit_uclinux(void)324 static void do_exit_uclinux(void)
325 {
326 	setup_sigint();
327 	do_exit();
328 }
329 #endif
330