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