1 /******************************************************************************/
2 /* Copyright (c) Crackerjack Project., 2007                                   */
3 /*                                                                            */
4 /* This program is free software;  you can redistribute it and/or modify      */
5 /* it under the terms of the GNU General Public License as published by       */
6 /* the Free Software Foundation; either version 2 of the License, or          */
7 /* (at your option) any later version.                                        */
8 /*                                                                            */
9 /* This program is distributed in the hope that it will be useful,            */
10 /* but WITHOUT ANY WARRANTY;  without even the implied warranty of            */
11 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                  */
12 /* the GNU General Public License for more details.                           */
13 /*                                                                            */
14 /* You should have received a copy of the GNU General Public License along    */
15 /* with this program; if not, write to the Free Software Foundation,  Inc.,   */
16 /* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA                 */
17 /*                                                                            */
18 /******************************************************************************/
19 /******************************************************************************/
20 /*                                                                            */
21 /* File:        waitid02.c                                           	      */
22 /*                                                                            */
23 /* Description: This tests the waitid() syscall                               */
24 /*                                                                            */
25 /* Usage:  <for command-line>                                                 */
26 /* waitid02 [-c n] [-e][-i n] [-I x] [-p x] [-t]                              */
27 /*      where,  -c n : Run n copies concurrently.                             */
28 /*              -e   : Turn on errno logging.                                 */
29 /*              -i n : Execute test n times.                                  */
30 /*              -I x : Execute test for x seconds.                            */
31 /*              -P x : Pause for x seconds between iterations.                */
32 /*              -t   : Turn on syscall timing.                                */
33 /*                                                                            */
34 /* Total Tests: 1                                                             */
35 /*                                                                            */
36 /* Test Name:   waitid02                                                      */
37 /* History:     Porting from Crackerjack to LTP is done by                    */
38 /*              Manas Kumar Nayak maknayak@in.ibm.com>                        */
39 /******************************************************************************/
40 
41 #include <stdio.h>
42 #include <errno.h>
43 #include <stdlib.h>
44 #include <sys/wait.h>
45 #include <sys/types.h>
46 #include <unistd.h>
47 #include <sys/stat.h>
48 
49 #include "test.h"
50 #include "linux_syscall_numbers.h"
51 
52 struct testcase_t {
53 	const char *msg;
54 	idtype_t idtype;
55 	id_t id;
56 	pid_t child;
57 	int options;
58 	int exp_ret;
59 	int exp_errno;
60 	void (*setup) (struct testcase_t *);
61 	void (*cleanup) (struct testcase_t *);
62 };
63 
64 static void setup(void);
65 static void cleanup(void);
66 
67 static void setup2(struct testcase_t *);
68 static void setup3(struct testcase_t *);
69 static void setup4(struct testcase_t *);
70 static void setup5(struct testcase_t *);
71 static void setup6(struct testcase_t *);
72 static void cleanup2(struct testcase_t *);
73 static void cleanup5(struct testcase_t *);
74 static void cleanup6(struct testcase_t *);
75 
76 struct testcase_t tdat[] = {
77 	{
78 		.msg = "WNOHANG",
79 		.idtype = P_ALL,
80 		.id = 0,
81 		.options = WNOHANG,
82 		.exp_ret = -1,
83 		.exp_errno = EINVAL,
84 	},
85 	{
86 		.msg = "WNOHANG | WEXITED no child",
87 		.idtype = P_ALL,
88 		.id = 0,
89 		.options = WNOHANG | WEXITED,
90 		.exp_ret = -1,
91 		.exp_errno = ECHILD,
92 	},
93 	{
94 		.msg = "WNOHANG | WEXITED with child",
95 		.idtype = P_ALL,
96 		.id = 0,
97 		.options = WNOHANG | WEXITED,
98 		.exp_ret = 0,
99 		.setup = setup2,
100 		.cleanup = cleanup2
101 	},
102 	{
103 		.msg = "P_PGID, WEXITED wait for child",
104 		.idtype = P_PGID,
105 		.options = WEXITED,
106 		.exp_ret = 0,
107 		.setup = setup3,
108 	},
109 	{
110 		.msg = "P_PID, WEXITED wait for child",
111 		.idtype = P_PID,
112 		.options = WEXITED,
113 		.exp_ret = 0,
114 		.setup = setup4,
115 	},
116 	{
117 		.msg = "P_PID, WSTOPPED | WNOWAIT",
118 		.idtype = P_PID,
119 		.options = WSTOPPED | WNOWAIT,
120 		.exp_ret = 0,
121 		.setup = setup5,
122 		.cleanup = cleanup5
123 	},
124 	{
125 		.msg = "P_PID, WCONTINUED",
126 		.idtype = P_PID,
127 		.options = WCONTINUED,
128 		.exp_ret = 0,
129 		.setup = setup6,
130 		.cleanup = cleanup6
131 	},
132 	{
133 		.msg = "P_PID, WEXITED not a child of the calling process",
134 		.idtype = P_PID,
135 		.id = 1,
136 		.options = WEXITED,
137 		.exp_ret = -1,
138 		.exp_errno = ECHILD,
139 		.setup = setup2,
140 		.cleanup = cleanup2
141 	},
142 
143 };
144 
145 char *TCID = "waitid02";
146 static int TST_TOTAL = ARRAY_SIZE(tdat);
147 
makechild(struct testcase_t * t,void (* childfn)(void))148 static void makechild(struct testcase_t *t, void (*childfn)(void))
149 {
150 	t->child = fork();
151 	switch (t->child) {
152 	case -1:
153 		tst_brkm(TBROK | TERRNO, cleanup, "fork");
154 		break;
155 	case 0:
156 		childfn();
157 		exit(0);
158 	}
159 }
160 
wait4child(pid_t pid)161 static void wait4child(pid_t pid)
162 {
163 	int status;
164 	if (waitpid(pid, &status, 0) == -1)
165 		tst_brkm(TBROK | TERRNO, cleanup, "waitpid");
166 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
167 		tst_resm(TFAIL, "child returns %d", status);
168 }
169 
dummy_child(void)170 static void dummy_child(void)
171 {
172 }
173 
waiting_child(void)174 static void waiting_child(void)
175 {
176 	TST_SAFE_CHECKPOINT_WAIT(NULL, 0);
177 }
178 
stopped_child(void)179 static void stopped_child(void)
180 {
181 	kill(getpid(), SIGSTOP);
182 	TST_SAFE_CHECKPOINT_WAIT(NULL, 0);
183 }
184 
setup2(struct testcase_t * t)185 static void setup2(struct testcase_t *t)
186 {
187 	makechild(t, waiting_child);
188 }
189 
cleanup2(struct testcase_t * t)190 static void cleanup2(struct testcase_t *t)
191 {
192 	TST_SAFE_CHECKPOINT_WAKE(cleanup, 0);
193 	wait4child(t->child);
194 }
195 
setup3(struct testcase_t * t)196 static void setup3(struct testcase_t *t)
197 {
198 	t->id = getpgid(0);
199 	makechild(t, dummy_child);
200 }
201 
setup4(struct testcase_t * t)202 static void setup4(struct testcase_t *t)
203 {
204 	makechild(t, dummy_child);
205 	t->id = t->child;
206 }
207 
setup5(struct testcase_t * t)208 static void setup5(struct testcase_t *t)
209 {
210 	makechild(t, stopped_child);
211 	t->id = t->child;
212 }
213 
cleanup5(struct testcase_t * t)214 static void cleanup5(struct testcase_t *t)
215 {
216 	kill(t->child, SIGCONT);
217 	TST_SAFE_CHECKPOINT_WAKE(cleanup, 0);
218 	wait4child(t->child);
219 }
220 
setup6(struct testcase_t * t)221 static void setup6(struct testcase_t *t)
222 {
223 	siginfo_t infop;
224 	makechild(t, stopped_child);
225 	t->id = t->child;
226 	if (waitid(P_PID, t->child, &infop, WSTOPPED) != 0)
227 		tst_brkm(TBROK | TERRNO, cleanup, "waitpid setup6");
228 	kill(t->child, SIGCONT);
229 }
230 
cleanup6(struct testcase_t * t)231 static void cleanup6(struct testcase_t *t)
232 {
233 	TST_SAFE_CHECKPOINT_WAKE(cleanup, 0);
234 	wait4child(t->child);
235 }
236 
setup(void)237 static void setup(void)
238 {
239 	TEST_PAUSE;
240 	tst_tmpdir();
241 	TST_CHECKPOINT_INIT(tst_rmdir);
242 }
243 
cleanup(void)244 static void cleanup(void)
245 {
246 	tst_rmdir();
247 	tst_exit();
248 }
249 
test_waitid(struct testcase_t * t)250 static void test_waitid(struct testcase_t *t)
251 {
252 	siginfo_t infop;
253 
254 	if (t->setup)
255 		t->setup(t);
256 
257 	tst_resm(TINFO, "%s", t->msg);
258 	tst_resm(TINFO, "(%d) waitid(%d, %d, %p, %d)", getpid(), t->idtype,
259 			t->id, &infop, t->options);
260 	memset(&infop, 0, sizeof(infop));
261 
262 	TEST(waitid(t->idtype, t->id, &infop, t->options));
263 	if (TEST_RETURN == t->exp_ret) {
264 		if (TEST_RETURN == -1) {
265 			if (TEST_ERRNO == t->exp_errno)
266 				tst_resm(TPASS, "exp_errno=%d", t->exp_errno);
267 			else
268 				tst_resm(TFAIL|TTERRNO, "exp_errno=%d",
269 					t->exp_errno);
270 		} else {
271 			tst_resm(TPASS, "ret: %d", t->exp_ret);
272 		}
273 	} else {
274 		tst_resm(TFAIL|TTERRNO, "ret=%ld expected=%d",
275 			TEST_RETURN, t->exp_ret);
276 	}
277 	tst_resm(TINFO, "si_pid = %d ; si_code = %d ; si_status = %d",
278 			infop.si_pid, infop.si_code,
279 			infop.si_status);
280 
281 	if (t->cleanup)
282 		t->cleanup(t);
283 }
284 
main(int ac,char ** av)285 int main(int ac, char **av)
286 {
287 	int lc, testno;
288 
289 	tst_parse_opts(ac, av, NULL, NULL);
290 
291 	setup();
292 	for (lc = 0; TEST_LOOPING(lc); ++lc) {
293 		tst_count = 0;
294 		for (testno = 0; testno < TST_TOTAL; testno++)
295 			test_waitid(&tdat[testno]);
296 	}
297 	cleanup();
298 	tst_exit();
299 }
300