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
52struct 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
64static void setup(void);
65static void cleanup(void);
66
67static void setup2(struct testcase_t *);
68static void setup3(struct testcase_t *);
69static void setup4(struct testcase_t *);
70static void setup5(struct testcase_t *);
71static void setup6(struct testcase_t *);
72static void cleanup2(struct testcase_t *);
73static void cleanup5(struct testcase_t *);
74static void cleanup6(struct testcase_t *);
75
76struct 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
145char *TCID = "waitid02";
146static int TST_TOTAL = ARRAY_SIZE(tdat);
147
148static 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
161static 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
170static void dummy_child(void)
171{
172}
173
174static void waiting_child(void)
175{
176	TST_SAFE_CHECKPOINT_WAIT(NULL, 0);
177}
178
179static void stopped_child(void)
180{
181	kill(getpid(), SIGSTOP);
182	TST_SAFE_CHECKPOINT_WAIT(NULL, 0);
183}
184
185static void setup2(struct testcase_t *t)
186{
187	makechild(t, waiting_child);
188}
189
190static void cleanup2(struct testcase_t *t)
191{
192	TST_SAFE_CHECKPOINT_WAKE(cleanup, 0);
193	wait4child(t->child);
194}
195
196static void setup3(struct testcase_t *t)
197{
198	t->id = getpgid(0);
199	makechild(t, dummy_child);
200}
201
202static void setup4(struct testcase_t *t)
203{
204	makechild(t, dummy_child);
205	t->id = t->child;
206}
207
208static void setup5(struct testcase_t *t)
209{
210	makechild(t, stopped_child);
211	t->id = t->child;
212}
213
214static 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
221static 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
231static void cleanup6(struct testcase_t *t)
232{
233	TST_SAFE_CHECKPOINT_WAKE(cleanup, 0);
234	wait4child(t->child);
235}
236
237static void setup(void)
238{
239	TEST_PAUSE;
240	tst_tmpdir();
241	TST_CHECKPOINT_INIT(tst_rmdir);
242}
243
244static void cleanup(void)
245{
246	tst_rmdir();
247	tst_exit();
248}
249
250static 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
285int 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