Update copyright notices with scripts/update-copyrights
[jlayton/glibc.git] / posix / tst-waitid.c
1 /* Tests for waitid.
2    Copyright (C) 2004-2014 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library 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 the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <sys/wait.h>
24 #include <signal.h>
25
26 #define TIMEOUT 15
27
28 static void
29 test_child (void)
30 {
31   /* Wait a second to be sure the parent set his variables before we
32      produce a SIGCHLD.  */
33   sleep (1);
34
35   /* First thing, we stop ourselves.  */
36   raise (SIGSTOP);
37
38   /* Hey, we got continued!  */
39   while (1)
40     pause ();
41 }
42
43 #ifndef WEXITED
44 # define WEXITED        0
45 # define WCONTINUED     0
46 # define WSTOPPED       WUNTRACED
47 #endif
48
49 static sig_atomic_t expecting_sigchld, spurious_sigchld;
50 #ifdef SA_SIGINFO
51 static siginfo_t sigchld_info;
52
53 static void
54 sigchld (int signo, siginfo_t *info, void *ctx)
55 {
56   if (signo != SIGCHLD)
57     {
58       printf ("SIGCHLD handler got signal %d instead!\n", signo);
59       _exit (EXIT_FAILURE);
60     }
61
62   if (! expecting_sigchld)
63     {
64       spurious_sigchld = 1;
65       printf ("spurious SIGCHLD: signo %d code %d status %d pid %d\n",
66               info->si_signo, info->si_code, info->si_status, info->si_pid);
67     }
68   else
69     {
70       sigchld_info = *info;
71       expecting_sigchld = 0;
72     }
73 }
74
75 static void
76 check_sigchld (const char *phase, int *ok, int code, int status, pid_t pid)
77 {
78   if (expecting_sigchld)
79     {
80       printf ("missing SIGCHLD on %s\n", phase);
81       *ok = EXIT_FAILURE;
82       expecting_sigchld = 0;
83       return;
84     }
85
86   if (sigchld_info.si_signo != SIGCHLD)
87     {
88       printf ("SIGCHLD for %s signal %d\n", phase, sigchld_info.si_signo);
89       *ok = EXIT_FAILURE;
90     }
91   if (sigchld_info.si_code != code)
92     {
93       printf ("SIGCHLD for %s code %d\n", phase, sigchld_info.si_code);
94       *ok = EXIT_FAILURE;
95     }
96   if (sigchld_info.si_status != status)
97     {
98       printf ("SIGCHLD for %s status %d\n", phase, sigchld_info.si_status);
99       *ok = EXIT_FAILURE;
100     }
101   if (sigchld_info.si_pid != pid)
102     {
103       printf ("SIGCHLD for %s pid %d\n", phase, sigchld_info.si_pid);
104       *ok = EXIT_FAILURE;
105     }
106 }
107 # define CHECK_SIGCHLD(phase, code_check, status_check) \
108   check_sigchld ((phase), &status, (code_check), (status_check), pid)
109 #else
110 # define CHECK_SIGCHLD(phase, code, status) ((void) 0)
111 #endif
112
113 static int
114 do_test (int argc, char *argv[])
115 {
116 #ifdef SA_SIGINFO
117   struct sigaction sa;
118   sa.sa_flags = SA_SIGINFO|SA_RESTART;
119   sa.sa_sigaction = &sigchld;
120   if (sigemptyset (&sa.sa_mask) < 0 || sigaction (SIGCHLD, &sa, NULL) < 0)
121     {
122       printf ("setting SIGCHLD handler: %m\n");
123       return EXIT_FAILURE;
124     }
125 #endif
126
127   expecting_sigchld = 1;
128
129   pid_t pid = fork ();
130   if (pid < 0)
131     {
132       printf ("fork: %m\n");
133       return EXIT_FAILURE;
134     }
135   else if (pid == 0)
136     {
137       test_child ();
138       _exit (127);
139     }
140
141   int status = EXIT_SUCCESS;
142 #define RETURN(ok) \
143     do { if (status == EXIT_SUCCESS) status = (ok); goto out; } while (0)
144
145   /* Give the child a chance to stop.  */
146   sleep (3);
147
148   CHECK_SIGCHLD ("stopped (before waitid)", CLD_STOPPED, SIGSTOP);
149
150   /* Now try a wait that should not succeed.  */
151   siginfo_t info;
152   info.si_signo = 0;            /* A successful call sets it to SIGCHLD.  */
153   int fail = waitid (P_PID, pid, &info, WEXITED|WCONTINUED|WNOHANG);
154   switch (fail)
155     {
156     default:
157       printf ("waitid returned bogus value %d\n", fail);
158       RETURN (EXIT_FAILURE);
159     case -1:
160       printf ("waitid WNOHANG on stopped: %m\n");
161       RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
162     case 0:
163       if (info.si_signo == 0)
164         break;
165       if (info.si_signo == SIGCHLD)
166         printf ("waitid WNOHANG on stopped status %d\n", info.si_status);
167       else
168         printf ("waitid WNOHANG on stopped signal %d\n", info.si_signo);
169       RETURN (EXIT_FAILURE);
170     }
171
172   /* Next the wait that should succeed right away.  */
173   info.si_signo = 0;            /* A successful call sets it to SIGCHLD.  */
174   info.si_pid = -1;
175   info.si_status = -1;
176   fail = waitid (P_PID, pid, &info, WSTOPPED|WNOHANG);
177   switch (fail)
178     {
179     default:
180       printf ("waitid WSTOPPED|WNOHANG returned bogus value %d\n", fail);
181       RETURN (EXIT_FAILURE);
182     case -1:
183       printf ("waitid WSTOPPED|WNOHANG on stopped: %m\n");
184       RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
185     case 0:
186       if (info.si_signo != SIGCHLD)
187         {
188           printf ("waitid WSTOPPED|WNOHANG on stopped signal %d\n",
189                   info.si_signo);
190           RETURN (EXIT_FAILURE);
191         }
192       if (info.si_code != CLD_STOPPED)
193         {
194           printf ("waitid WSTOPPED|WNOHANG on stopped code %d\n",
195                   info.si_code);
196           RETURN (EXIT_FAILURE);
197         }
198       if (info.si_status != SIGSTOP)
199         {
200           printf ("waitid WSTOPPED|WNOHANG on stopped status %d\n",
201                   info.si_status);
202           RETURN (EXIT_FAILURE);
203         }
204       if (info.si_pid != pid)
205         {
206           printf ("waitid WSTOPPED|WNOHANG on stopped pid %d != %d\n",
207                   info.si_pid, pid);
208           RETURN (EXIT_FAILURE);
209         }
210     }
211
212   expecting_sigchld = WCONTINUED != 0;
213
214   if (kill (pid, SIGCONT) != 0)
215     {
216       printf ("kill (%d, SIGCONT): %m\n", pid);
217       RETURN (EXIT_FAILURE);
218     }
219
220   /* Wait for the child to have continued.  */
221   sleep (2);
222
223 #if WCONTINUED != 0
224   if (expecting_sigchld)
225     {
226       printf ("no SIGCHLD seen for SIGCONT (optional)\n");
227       expecting_sigchld = 0;
228     }
229   else
230     CHECK_SIGCHLD ("continued (before waitid)", CLD_CONTINUED, SIGCONT);
231
232   info.si_signo = 0;            /* A successful call sets it to SIGCHLD.  */
233   info.si_pid = -1;
234   info.si_status = -1;
235   fail = waitid (P_PID, pid, &info, WCONTINUED|WNOWAIT);
236   switch (fail)
237     {
238     default:
239       printf ("waitid WCONTINUED|WNOWAIT returned bogus value %d\n", fail);
240       RETURN (EXIT_FAILURE);
241     case -1:
242       printf ("waitid WCONTINUED|WNOWAIT on continued: %m\n");
243       RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
244     case 0:
245       if (info.si_signo != SIGCHLD)
246         {
247           printf ("waitid WCONTINUED|WNOWAIT on continued signal %d\n",
248                   info.si_signo);
249           RETURN (EXIT_FAILURE);
250         }
251       if (info.si_code != CLD_CONTINUED)
252         {
253           printf ("waitid WCONTINUED|WNOWAIT on continued code %d\n",
254                   info.si_code);
255           RETURN (EXIT_FAILURE);
256         }
257       if (info.si_status != SIGCONT)
258         {
259           printf ("waitid WCONTINUED|WNOWAIT on continued status %d\n",
260                   info.si_status);
261           RETURN (EXIT_FAILURE);
262         }
263       if (info.si_pid != pid)
264         {
265           printf ("waitid WCONTINUED|WNOWAIT on continued pid %d != %d\n",
266                   info.si_pid, pid);
267           RETURN (EXIT_FAILURE);
268         }
269     }
270
271   /* That should leave the CLD_CONTINUED state waiting to be seen again.  */
272   info.si_signo = 0;            /* A successful call sets it to SIGCHLD.  */
273   info.si_pid = -1;
274   info.si_status = -1;
275   fail = waitid (P_PID, pid, &info, WCONTINUED);
276   switch (fail)
277     {
278     default:
279       printf ("waitid WCONTINUED returned bogus value %d\n", fail);
280       RETURN (EXIT_FAILURE);
281     case -1:
282       printf ("waitid WCONTINUED on continued: %m\n");
283       RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
284     case 0:
285       if (info.si_signo != SIGCHLD)
286         {
287           printf ("waitid WCONTINUED on continued signal %d\n", info.si_signo);
288           RETURN (EXIT_FAILURE);
289         }
290       if (info.si_code != CLD_CONTINUED)
291         {
292           printf ("waitid WCONTINUED on continued code %d\n", info.si_code);
293           RETURN (EXIT_FAILURE);
294         }
295       if (info.si_status != SIGCONT)
296         {
297           printf ("waitid WCONTINUED on continued status %d\n",
298                   info.si_status);
299           RETURN (EXIT_FAILURE);
300         }
301       if (info.si_pid != pid)
302         {
303           printf ("waitid WCONTINUED on continued pid %d != %d\n",
304                   info.si_pid, pid);
305           RETURN (EXIT_FAILURE);
306         }
307     }
308
309   /* Now try a wait that should not succeed.  */
310   info.si_signo = 0;            /* A successful call sets it to SIGCHLD.  */
311   fail = waitid (P_PID, pid, &info, WCONTINUED|WNOHANG);
312   switch (fail)
313     {
314     default:
315       printf ("waitid returned bogus value %d\n", fail);
316       RETURN (EXIT_FAILURE);
317     case -1:
318       printf ("waitid WCONTINUED|WNOHANG on waited continued: %m\n");
319       RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
320     case 0:
321       if (info.si_signo == 0)
322         break;
323       if (info.si_signo == SIGCHLD)
324         printf ("waitid WCONTINUED|WNOHANG on waited continued status %d\n",
325                 info.si_status);
326       else
327         printf ("waitid WCONTINUED|WNOHANG on waited continued signal %d\n",
328                 info.si_signo);
329       RETURN (EXIT_FAILURE);
330     }
331
332   /* Now stop him again and test waitpid with WCONTINUED.  */
333   expecting_sigchld = 1;
334   if (kill (pid, SIGSTOP) != 0)
335     {
336       printf ("kill (%d, SIGSTOP): %m\n", pid);
337       RETURN (EXIT_FAILURE);
338     }
339
340   /* Give the child a chance to stop.  The waitpid call below will block
341      until it has stopped, but if we are real quick and enter the waitpid
342      system call before the SIGCHLD has been generated, then it will be
343      discarded and never delivered.  */
344   sleep (3);
345
346   pid_t wpid = waitpid (pid, &fail, WUNTRACED);
347   if (wpid < 0)
348     {
349       printf ("waitpid WUNTRACED on stopped: %m\n");
350       RETURN (EXIT_FAILURE);
351     }
352   else if (wpid != pid)
353     {
354       printf ("waitpid WUNTRACED on stopped returned %d != %d (status %x)\n",
355               wpid, pid, fail);
356       RETURN (EXIT_FAILURE);
357     }
358   else if (!WIFSTOPPED (fail) || WIFSIGNALED (fail) || WIFEXITED (fail)
359            || WIFCONTINUED (fail) || WSTOPSIG (fail) != SIGSTOP)
360     {
361       printf ("waitpid WUNTRACED on stopped: status %x\n", fail);
362       RETURN (EXIT_FAILURE);
363     }
364   CHECK_SIGCHLD ("stopped (after waitpid)", CLD_STOPPED, SIGSTOP);
365
366   expecting_sigchld = 1;
367   if (kill (pid, SIGCONT) != 0)
368     {
369       printf ("kill (%d, SIGCONT): %m\n", pid);
370       RETURN (EXIT_FAILURE);
371     }
372
373   /* Wait for the child to have continued.  */
374   sleep (2);
375
376   if (expecting_sigchld)
377     {
378       printf ("no SIGCHLD seen for SIGCONT (optional)\n");
379       expecting_sigchld = 0;
380     }
381   else
382     CHECK_SIGCHLD ("continued (before waitpid)", CLD_CONTINUED, SIGCONT);
383
384   wpid = waitpid (pid, &fail, WCONTINUED);
385   if (wpid < 0)
386     {
387       if (errno == EINVAL)
388         printf ("waitpid does not support WCONTINUED\n");
389       else
390         {
391           printf ("waitpid WCONTINUED on continued: %m\n");
392           RETURN (EXIT_FAILURE);
393         }
394     }
395   else if (wpid != pid)
396     {
397       printf ("\
398 waitpid WCONTINUED on continued returned %d != %d (status %x)\n",
399              wpid, pid, fail);
400       RETURN (EXIT_FAILURE);
401     }
402   else if (WIFSTOPPED (fail) || WIFSIGNALED (fail) || WIFEXITED (fail)
403            || !WIFCONTINUED (fail))
404     {
405       printf ("waitpid WCONTINUED on continued: status %x\n", fail);
406       RETURN (EXIT_FAILURE);
407     }
408 #endif
409
410   expecting_sigchld = 1;
411
412   /* Die, child, die!  */
413   if (kill (pid, SIGKILL) != 0)
414     {
415       printf ("kill (%d, SIGKILL): %m\n", pid);
416       RETURN (EXIT_FAILURE);
417     }
418
419 #ifdef WNOWAIT
420   info.si_signo = 0;            /* A successful call sets it to SIGCHLD.  */
421   info.si_pid = -1;
422   info.si_status = -1;
423   fail = waitid (P_PID, pid, &info, WEXITED|WNOWAIT);
424   switch (fail)
425     {
426     default:
427       printf ("waitid WNOWAIT returned bogus value %d\n", fail);
428       RETURN (EXIT_FAILURE);
429     case -1:
430       printf ("waitid WNOWAIT on killed: %m\n");
431       RETURN (errno == ENOTSUP ? EXIT_SUCCESS : EXIT_FAILURE);
432     case 0:
433       if (info.si_signo != SIGCHLD)
434         {
435           printf ("waitid WNOWAIT on killed signal %d\n", info.si_signo);
436           RETURN (EXIT_FAILURE);
437         }
438       if (info.si_code != CLD_KILLED)
439         {
440           printf ("waitid WNOWAIT on killed code %d\n", info.si_code);
441           RETURN (EXIT_FAILURE);
442         }
443       if (info.si_status != SIGKILL)
444         {
445           printf ("waitid WNOWAIT on killed status %d\n", info.si_status);
446           RETURN (EXIT_FAILURE);
447         }
448       if (info.si_pid != pid)
449         {
450           printf ("waitid WNOWAIT on killed pid %d != %d\n", info.si_pid, pid);
451           RETURN (EXIT_FAILURE);
452         }
453     }
454 #else
455   /* Allow enough time to be sure the child died; we didn't synchronize.  */
456   sleep (2);
457 #endif
458
459   CHECK_SIGCHLD ("killed", CLD_KILLED, SIGKILL);
460
461   info.si_signo = 0;            /* A successful call sets it to SIGCHLD.  */
462   info.si_pid = -1;
463   info.si_status = -1;
464   fail = waitid (P_PID, pid, &info, WEXITED|WNOHANG);
465   switch (fail)
466     {
467     default:
468       printf ("waitid WNOHANG returned bogus value %d\n", fail);
469       RETURN (EXIT_FAILURE);
470     case -1:
471       printf ("waitid WNOHANG on killed: %m\n");
472       RETURN (EXIT_FAILURE);
473     case 0:
474       if (info.si_signo != SIGCHLD)
475         {
476           printf ("waitid WNOHANG on killed signal %d\n", info.si_signo);
477           RETURN (EXIT_FAILURE);
478         }
479       if (info.si_code != CLD_KILLED)
480         {
481           printf ("waitid WNOHANG on killed code %d\n", info.si_code);
482           RETURN (EXIT_FAILURE);
483         }
484       if (info.si_status != SIGKILL)
485         {
486           printf ("waitid WNOHANG on killed status %d\n", info.si_status);
487           RETURN (EXIT_FAILURE);
488         }
489       if (info.si_pid != pid)
490         {
491           printf ("waitid WNOHANG on killed pid %d != %d\n", info.si_pid, pid);
492           RETURN (EXIT_FAILURE);
493         }
494     }
495
496   fail = waitid (P_PID, pid, &info, WEXITED);
497   if (fail == -1)
498     {
499       if (errno != ECHILD)
500         {
501           printf ("waitid WEXITED on killed: %m\n");
502           RETURN (EXIT_FAILURE);
503         }
504     }
505   else
506     {
507       printf ("waitid WEXITED returned bogus value %d\n", fail);
508       RETURN (EXIT_FAILURE);
509     }
510
511 #undef RETURN
512  out:
513   if (spurious_sigchld)
514     status = EXIT_FAILURE;
515   signal (SIGCHLD, SIG_IGN);
516   kill (pid, SIGKILL);          /* Make sure it's dead if we bailed early.  */
517   return status;
518 }
519
520 #include "../test-skeleton.c"