• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define _XOPEN_SOURCE 500
42 #include <stdio.h>
43 #include <errno.h>
44 #include <stdlib.h>
45 #include <sys/wait.h>
46 #include <sys/types.h>
47 #include <unistd.h>
48 #include <sys/stat.h>
49 
50 #include "test.h"
51 #include "safe_macros.h"
52 #include "lapi/syscalls.h"
53 
54 struct testcase_t {
55 	const char *msg;
56 	idtype_t idtype;
57 	id_t id;
58 	pid_t child;
59 	int options;
60 	int exp_ret;
61 	int exp_errno;
62 	void (*setup) (struct testcase_t *);
63 	void (*cleanup) (struct testcase_t *);
64 };
65 
66 static void setup(void);
67 static void cleanup(void);
68 
69 static void setup2(struct testcase_t *);
70 static void setup3(struct testcase_t *);
71 static void setup4(struct testcase_t *);
72 static void setup5(struct testcase_t *);
73 static void setup6(struct testcase_t *);
74 static void cleanup2(struct testcase_t *);
75 static void cleanup5(struct testcase_t *);
76 static void cleanup6(struct testcase_t *);
77 
78 struct testcase_t tdat[] = {
79 	{
80 		.msg = "WNOHANG",
81 		.idtype = P_ALL,
82 		.id = 0,
83 		.options = WNOHANG,
84 		.exp_ret = -1,
85 		.exp_errno = EINVAL,
86 	},
87 	{
88 		.msg = "WNOHANG | WEXITED no child",
89 		.idtype = P_ALL,
90 		.id = 0,
91 		.options = WNOHANG | WEXITED,
92 		.exp_ret = -1,
93 		.exp_errno = ECHILD,
94 	},
95 	{
96 		.msg = "WNOHANG | WEXITED with child",
97 		.idtype = P_ALL,
98 		.id = 0,
99 		.options = WNOHANG | WEXITED,
100 		.exp_ret = 0,
101 		.setup = setup2,
102 		.cleanup = cleanup2
103 	},
104 	{
105 		.msg = "P_PGID, WEXITED wait for child",
106 		.idtype = P_PGID,
107 		.options = WEXITED,
108 		.exp_ret = 0,
109 		.setup = setup3,
110 	},
111 	{
112 		.msg = "P_PID, WEXITED wait for child",
113 		.idtype = P_PID,
114 		.options = WEXITED,
115 		.exp_ret = 0,
116 		.setup = setup4,
117 	},
118 	{
119 		.msg = "P_PID, WSTOPPED | WNOWAIT",
120 		.idtype = P_PID,
121 		.options = WSTOPPED | WNOWAIT,
122 		.exp_ret = 0,
123 		.setup = setup5,
124 		.cleanup = cleanup5
125 	},
126 	{
127 		.msg = "P_PID, WCONTINUED",
128 		.idtype = P_PID,
129 		.options = WCONTINUED,
130 		.exp_ret = 0,
131 		.setup = setup6,
132 		.cleanup = cleanup6
133 	},
134 	{
135 		.msg = "P_PID, WEXITED not a child of the calling process",
136 		.idtype = P_PID,
137 		.id = 1,
138 		.options = WEXITED,
139 		.exp_ret = -1,
140 		.exp_errno = ECHILD,
141 		.setup = setup2,
142 		.cleanup = cleanup2
143 	},
144 
145 };
146 
147 char *TCID = "waitid02";
148 static int TST_TOTAL = ARRAY_SIZE(tdat);
149 
makechild(struct testcase_t * t,void (* childfn)(void))150 static void makechild(struct testcase_t *t, void (*childfn)(void))
151 {
152 	t->child = fork();
153 	switch (t->child) {
154 	case -1:
155 		tst_brkm(TBROK | TERRNO, cleanup, "fork");
156 		break;
157 	case 0:
158 		childfn();
159 		exit(0);
160 	}
161 }
162 
wait4child(pid_t pid)163 static void wait4child(pid_t pid)
164 {
165 	int status;
166 	SAFE_WAITPID(cleanup, pid, &status, 0);
167 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
168 		tst_resm(TFAIL, "child returns %d", status);
169 }
170 
dummy_child(void)171 static void dummy_child(void)
172 {
173 }
174 
waiting_child(void)175 static void waiting_child(void)
176 {
177 	TST_SAFE_CHECKPOINT_WAIT(NULL, 0);
178 }
179 
stopped_child(void)180 static void stopped_child(void)
181 {
182 	kill(getpid(), SIGSTOP);
183 	TST_SAFE_CHECKPOINT_WAIT(NULL, 0);
184 }
185 
setup2(struct testcase_t * t)186 static void setup2(struct testcase_t *t)
187 {
188 	makechild(t, waiting_child);
189 }
190 
cleanup2(struct testcase_t * t)191 static void cleanup2(struct testcase_t *t)
192 {
193 	TST_SAFE_CHECKPOINT_WAKE(cleanup, 0);
194 	wait4child(t->child);
195 }
196 
setup3(struct testcase_t * t)197 static void setup3(struct testcase_t *t)
198 {
199 	t->id = getpgid(0);
200 	makechild(t, dummy_child);
201 }
202 
setup4(struct testcase_t * t)203 static void setup4(struct testcase_t *t)
204 {
205 	makechild(t, dummy_child);
206 	t->id = t->child;
207 }
208 
setup5(struct testcase_t * t)209 static void setup5(struct testcase_t *t)
210 {
211 	makechild(t, stopped_child);
212 	t->id = t->child;
213 }
214 
cleanup5(struct testcase_t * t)215 static void cleanup5(struct testcase_t *t)
216 {
217 	kill(t->child, SIGCONT);
218 	TST_SAFE_CHECKPOINT_WAKE(cleanup, 0);
219 	wait4child(t->child);
220 }
221 
setup6(struct testcase_t * t)222 static void setup6(struct testcase_t *t)
223 {
224 	siginfo_t infop;
225 	makechild(t, stopped_child);
226 	t->id = t->child;
227 	if (waitid(P_PID, t->child, &infop, WSTOPPED) != 0)
228 		tst_brkm(TBROK | TERRNO, cleanup, "waitpid setup6");
229 	kill(t->child, SIGCONT);
230 }
231 
cleanup6(struct testcase_t * t)232 static void cleanup6(struct testcase_t *t)
233 {
234 	TST_SAFE_CHECKPOINT_WAKE(cleanup, 0);
235 	wait4child(t->child);
236 }
237 
setup(void)238 static void setup(void)
239 {
240 	TEST_PAUSE;
241 	tst_tmpdir();
242 	TST_CHECKPOINT_INIT(tst_rmdir);
243 }
244 
cleanup(void)245 static void cleanup(void)
246 {
247 	tst_rmdir();
248 	tst_exit();
249 }
250 
test_waitid(struct testcase_t * t)251 static void test_waitid(struct testcase_t *t)
252 {
253 	siginfo_t infop;
254 
255 	if (t->setup)
256 		t->setup(t);
257 
258 	tst_resm(TINFO, "%s", t->msg);
259 	tst_resm(TINFO, "(%d) waitid(%d, %d, %p, %d)", getpid(), t->idtype,
260 			t->id, &infop, t->options);
261 	memset(&infop, 0, sizeof(infop));
262 
263 	TEST(waitid(t->idtype, t->id, &infop, t->options));
264 	if (TEST_RETURN == t->exp_ret) {
265 		if (TEST_RETURN == -1) {
266 			if (TEST_ERRNO == t->exp_errno)
267 				tst_resm(TPASS, "exp_errno=%d", t->exp_errno);
268 			else
269 				tst_resm(TFAIL|TTERRNO, "exp_errno=%d",
270 					t->exp_errno);
271 		} else {
272 			tst_resm(TPASS, "ret: %d", t->exp_ret);
273 		}
274 	} else {
275 		tst_resm(TFAIL|TTERRNO, "ret=%ld expected=%d",
276 			TEST_RETURN, t->exp_ret);
277 	}
278 	tst_resm(TINFO, "si_pid = %d ; si_code = %d ; si_status = %d",
279 			infop.si_pid, infop.si_code,
280 			infop.si_status);
281 
282 	if (t->cleanup)
283 		t->cleanup(t);
284 }
285 
main(int ac,char ** av)286 int main(int ac, char **av)
287 {
288 	int lc, testno;
289 
290 	tst_parse_opts(ac, av, NULL, NULL);
291 
292 	setup();
293 	for (lc = 0; TEST_LOOPING(lc); ++lc) {
294 		tst_count = 0;
295 		for (testno = 0; testno < TST_TOTAL; testno++)
296 			test_waitid(&tdat[testno]);
297 	}
298 	cleanup();
299 	tst_exit();
300 }
301