38d2cf648bf8516a8967e465a63ae48c204cae1b
[platform/upstream/gstreamer.git] / libs / gst / check / libcheck / check_run.c
1 /*
2  * Check: a unit test framework for C
3  * Copyright (C) 2001, 2002 Arien Malec
4  *
5  * This 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  * This 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 this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "libcompat.h"
22
23 #include <sys/types.h>
24 #include <time.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <signal.h>
30 #include <setjmp.h>
31
32 #include "internal-check.h"
33 #include "check_error.h"
34 #include "check_list.h"
35 #include "check_impl.h"
36 #include "check_msg.h"
37 #include "check_log.h"
38
39 enum rinfo
40 {
41   CK_R_SIG,
42   CK_R_PASS,
43   CK_R_EXIT,
44   CK_R_FAIL_TEST,
45   CK_R_FAIL_FIXTURE
46 };
47
48 enum tf_type
49 {
50   CK_FORK_TEST,
51   CK_NOFORK_TEST,
52   CK_NOFORK_FIXTURE
53 };
54
55
56 /* all functions are defined in the same order they are declared.
57    functions that depend on forking are gathered all together.
58    non-static functions are at the end of the file. */
59 static void srunner_run_init (SRunner * sr, enum print_output print_mode);
60 static void srunner_run_end (SRunner * sr, enum print_output print_mode);
61 static void srunner_iterate_suites (SRunner * sr,
62     const char *sname, const char *tcname, enum print_output print_mode);
63 static void srunner_iterate_tcase_tfuns (SRunner * sr, TCase * tc);
64 static void srunner_add_failure (SRunner * sr, TestResult * tf);
65 static TestResult *srunner_run_setup (List * func_list,
66     enum fork_status fork_usage, const char *test_name, const char *setup_name);
67 static int srunner_run_unchecked_setup (SRunner * sr, TCase * tc);
68 static TestResult *tcase_run_checked_setup (SRunner * sr, TCase * tc);
69 static void srunner_run_teardown (List * fixture_list,
70     enum fork_status fork_usage);
71 static void srunner_run_unchecked_teardown (SRunner * sr, TCase * tc);
72 static void tcase_run_checked_teardown (TCase * tc);
73 static void srunner_run_tcase (SRunner * sr, TCase * tc);
74 static TestResult *tcase_run_tfun_nofork (SRunner * sr, TCase * tc, TF * tf,
75     int i);
76 static TestResult *receive_result_info_nofork (const char *tcname,
77     const char *tname, int iter, int duration);
78 static void set_nofork_info (TestResult * tr);
79 static char *pass_msg (void);
80
81 #if defined(HAVE_FORK) && HAVE_FORK==1
82 static TestResult *tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tf,
83     int i);
84 static TestResult *receive_result_info_fork (const char *tcname,
85     const char *tname, int iter,
86     int status, int expected_signal, signed char allowed_exit_value);
87 static void set_fork_info (TestResult * tr, int status, int expected_signal,
88     signed char allowed_exit_value);
89 static char *signal_msg (int sig);
90 static char *signal_error_msg (int signal_received, int signal_expected);
91 static char *exit_msg (int exitstatus);
92 static int waserror (int status, int expected_signal);
93
94 static int alarm_received;
95 static pid_t group_pid;
96
97 #if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
98 static struct sigaction old_action[3];
99 static struct sigaction new_action[3];
100 #endif /* HAVE_SIGACTION && HAVE_FORK */
101
102 static void CK_ATTRIBUTE_UNUSED
103 sig_handler (int sig_nr)
104 {
105   switch (sig_nr) {
106     case SIGALRM:
107       alarm_received = 1;
108       killpg (group_pid, SIGKILL);
109       break;
110     case SIGTERM:
111     case SIGINT:{
112       pid_t own_group_pid;
113       int idx;
114       int child_sig;
115
116       if (sig_nr == SIGINT) {
117         idx = 1;
118         child_sig = SIGKILL;
119       } else {                  /* if (sig_nr == SIGTERM) */
120
121         idx = 2;
122         child_sig = SIGTERM;
123       }
124
125       killpg (group_pid, child_sig);
126
127       /* Restore old signal handler... */
128       sigaction (sig_nr, &old_action[idx], NULL);
129
130       /* ... and call it. POSIX says that calling killpg(0)
131        * does not necessarily mean to call it on the callers
132        * group pid! */
133       own_group_pid = getpgrp ();
134       killpg (own_group_pid, sig_nr);
135       break;
136     }
137     default:
138       eprintf ("Unhandled signal: %d", __FILE__, __LINE__, sig_nr);
139       break;
140   }
141 }
142 #endif /* HAVE_FORK */
143
144 #define MSG_LEN 100
145
146 static void
147 srunner_run_init (SRunner * sr, enum print_output print_mode)
148 {
149   set_fork_status (srunner_fork_status (sr));
150   setup_messaging ();
151   srunner_init_logging (sr, print_mode);
152   log_srunner_start (sr);
153 }
154
155 static void
156 srunner_run_end (SRunner * sr, enum print_output CK_ATTRIBUTE_UNUSED print_mode)
157 {
158   log_srunner_end (sr);
159   srunner_end_logging (sr);
160   teardown_messaging ();
161   set_fork_status (CK_FORK);
162 }
163
164 static void
165 srunner_iterate_suites (SRunner * sr,
166     const char *sname, const char *tcname,
167     enum print_output CK_ATTRIBUTE_UNUSED print_mode)
168 {
169   List *slst;
170   List *tcl;
171   TCase *tc;
172
173   slst = sr->slst;
174
175   for (check_list_front (slst); !check_list_at_end (slst);
176       check_list_advance (slst)) {
177     Suite *s = (Suite *) check_list_val (slst);
178
179     if (((sname != NULL) && (strcmp (sname, s->name) != 0))
180         || ((tcname != NULL) && (!suite_tcase (s, tcname))))
181       continue;
182
183     log_suite_start (sr, s);
184
185     tcl = s->tclst;
186
187     for (check_list_front (tcl); !check_list_at_end (tcl);
188         check_list_advance (tcl)) {
189       tc = (TCase *) check_list_val (tcl);
190
191       if ((tcname != NULL) && (strcmp (tcname, tc->name) != 0)) {
192         continue;
193       }
194
195       srunner_run_tcase (sr, tc);
196     }
197
198     log_suite_end (sr, s);
199   }
200 }
201
202 static void
203 srunner_iterate_tcase_tfuns (SRunner * sr, TCase * tc)
204 {
205   List *tfl;
206   TF *tfun;
207   TestResult *tr = NULL;
208
209   tfl = tc->tflst;
210
211   for (check_list_front (tfl); !check_list_at_end (tfl);
212       check_list_advance (tfl)) {
213     int i;
214
215     tfun = (TF *) check_list_val (tfl);
216
217     for (i = tfun->loop_start; i < tfun->loop_end; i++) {
218       log_test_start (sr, tc, tfun);
219       switch (srunner_fork_status (sr)) {
220         case CK_FORK:
221 #if defined(HAVE_FORK) && HAVE_FORK==1
222           tr = tcase_run_tfun_fork (sr, tc, tfun, i);
223 #else /* HAVE_FORK */
224           eprintf ("This version does not support fork", __FILE__, __LINE__);
225 #endif /* HAVE_FORK */
226           break;
227         case CK_NOFORK:
228           tr = tcase_run_tfun_nofork (sr, tc, tfun, i);
229           break;
230         case CK_FORK_GETENV:
231         default:
232           eprintf ("Bad fork status in SRunner", __FILE__, __LINE__);
233       }
234
235       if (NULL != tr) {
236         srunner_add_failure (sr, tr);
237         log_test_end (sr, tr);
238       }
239     }
240   }
241 }
242
243 static void
244 srunner_add_failure (SRunner * sr, TestResult * tr)
245 {
246   check_list_add_end (sr->resultlst, tr);
247   sr->stats->n_checked++;       /* count checks during setup, test, and teardown */
248   if (tr->rtype == CK_FAILURE)
249     sr->stats->n_failed++;
250   else if (tr->rtype == CK_ERROR)
251     sr->stats->n_errors++;
252
253 }
254
255 static TestResult *
256 srunner_run_setup (List * fixture_list, enum fork_status fork_usage,
257     const char *test_name, const char *setup_name)
258 {
259   TestResult *tr = NULL;
260   Fixture *setup_fixture;
261
262   if (fork_usage == CK_FORK) {
263     send_ctx_info (CK_CTX_SETUP);
264   }
265
266   for (check_list_front (fixture_list); !check_list_at_end (fixture_list);
267       check_list_advance (fixture_list)) {
268     setup_fixture = (Fixture *) check_list_val (fixture_list);
269
270     if (fork_usage == CK_NOFORK) {
271       send_ctx_info (CK_CTX_SETUP);
272
273       if (0 == setjmp (error_jmp_buffer)) {
274         setup_fixture->fun ();
275       }
276
277       /* Stop the setup and return the failure in nofork mode. */
278       tr = receive_result_info_nofork (test_name, setup_name, 0, -1);
279       if (tr->rtype != CK_PASS) {
280         break;
281       }
282
283       free (tr->file);
284       free (tr->msg);
285       free (tr);
286       tr = NULL;
287     } else {
288       setup_fixture->fun ();
289     }
290   }
291
292   return tr;
293 }
294
295 static int
296 srunner_run_unchecked_setup (SRunner * sr, TCase * tc)
297 {
298   TestResult *tr = NULL;
299   int rval = 1;
300
301   set_fork_status (CK_NOFORK);
302   tr = srunner_run_setup (tc->unch_sflst, CK_NOFORK, tc->name,
303       "unchecked_setup");
304   set_fork_status (srunner_fork_status (sr));
305
306   if (tr != NULL && tr->rtype != CK_PASS) {
307     srunner_add_failure (sr, tr);
308     rval = 0;
309   }
310
311   return rval;
312 }
313
314 static TestResult *
315 tcase_run_checked_setup (SRunner * sr, TCase * tc)
316 {
317   TestResult *tr = srunner_run_setup (tc->ch_sflst, srunner_fork_status (sr),
318       tc->name, "checked_setup");
319
320   return tr;
321 }
322
323 static void
324 srunner_run_teardown (List * fixture_list, enum fork_status fork_usage)
325 {
326   Fixture *fixture;
327
328   for (check_list_front (fixture_list); !check_list_at_end (fixture_list);
329       check_list_advance (fixture_list)) {
330     fixture = (Fixture *) check_list_val (fixture_list);
331     send_ctx_info (CK_CTX_TEARDOWN);
332
333     if (fork_usage == CK_NOFORK) {
334       if (0 == setjmp (error_jmp_buffer)) {
335         fixture->fun ();
336       } else {
337         /* Abort the remaining teardowns */
338         break;
339       }
340     } else {
341       fixture->fun ();
342     }
343   }
344 }
345
346 static void
347 srunner_run_unchecked_teardown (SRunner * sr, TCase * tc)
348 {
349   srunner_run_teardown (tc->unch_tflst, srunner_fork_status (sr));
350 }
351
352 static void
353 tcase_run_checked_teardown (TCase * tc)
354 {
355   srunner_run_teardown (tc->ch_tflst, CK_NOFORK);
356 }
357
358 static void
359 srunner_run_tcase (SRunner * sr, TCase * tc)
360 {
361   if (srunner_run_unchecked_setup (sr, tc)) {
362     srunner_iterate_tcase_tfuns (sr, tc);
363     srunner_run_unchecked_teardown (sr, tc);
364   }
365 }
366
367 static TestResult *
368 tcase_run_tfun_nofork (SRunner * sr, TCase * tc, TF * tfun, int i)
369 {
370   TestResult *tr;
371   struct timespec ts_start = { 0, 0 }, ts_end = {
372   0, 0};
373
374   tr = tcase_run_checked_setup (sr, tc);
375   if (tr == NULL) {
376     clock_gettime (check_get_clockid (), &ts_start);
377     if (0 == setjmp (error_jmp_buffer)) {
378       tfun->fn (i);
379     }
380     clock_gettime (check_get_clockid (), &ts_end);
381     tcase_run_checked_teardown (tc);
382     return receive_result_info_nofork (tc->name, tfun->name, i,
383         DIFF_IN_USEC (ts_start, ts_end));
384   }
385
386   return tr;
387 }
388
389 static TestResult *
390 receive_result_info_nofork (const char *tcname,
391     const char *tname, int iter, int duration)
392 {
393   TestResult *tr;
394
395   tr = receive_test_result (0);
396   if (tr == NULL) {
397     eprintf ("Failed to receive test result", __FILE__, __LINE__);
398   } else {
399     tr->tcname = tcname;
400     tr->tname = tname;
401     tr->iter = iter;
402     tr->duration = duration;
403     set_nofork_info (tr);
404   }
405
406   return tr;
407 }
408
409 static void
410 set_nofork_info (TestResult * tr)
411 {
412   if (tr->msg == NULL) {
413     tr->rtype = CK_PASS;
414     tr->msg = pass_msg ();
415   } else {
416     tr->rtype = CK_FAILURE;
417   }
418 }
419
420 static char *
421 pass_msg (void)
422 {
423   return strdup ("Passed");
424 }
425
426 #if defined(HAVE_FORK) && HAVE_FORK==1
427 static TestResult *
428 tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tfun, int i)
429 {
430   pid_t pid_w;
431   pid_t pid;
432   int status = 0;
433   struct timespec ts_start = { 0, 0 }, ts_end = {
434   0, 0};
435
436   timer_t timerid;
437   struct itimerspec timer_spec;
438   TestResult *tr;
439
440
441   pid = fork ();
442   if (pid == -1)
443     eprintf ("Error in call to fork:", __FILE__, __LINE__ - 2);
444   if (pid == 0) {
445     setpgid (0, 0);
446     group_pid = getpgrp ();
447     tr = tcase_run_checked_setup (sr, tc);
448     free (tr);
449     clock_gettime (check_get_clockid (), &ts_start);
450     tfun->fn (i);
451     clock_gettime (check_get_clockid (), &ts_end);
452     tcase_run_checked_teardown (tc);
453     send_duration_info (DIFF_IN_USEC (ts_start, ts_end));
454     exit (EXIT_SUCCESS);
455   } else {
456     group_pid = pid;
457   }
458
459   alarm_received = 0;
460
461   if (timer_create (check_get_clockid (),
462           NULL /* fire SIGALRM if timer expires */ ,
463           &timerid) == 0) {
464     /* Set the timer to fire once */
465     timer_spec.it_value = tc->timeout;
466     timer_spec.it_interval.tv_sec = 0;
467     timer_spec.it_interval.tv_nsec = 0;
468     if (timer_settime (timerid, 0, &timer_spec, NULL) == 0) {
469       do {
470         pid_w = waitpid (pid, &status, 0);
471       }
472       while (pid_w == -1);
473     } else {
474       eprintf ("Error in call to timer_settime:", __FILE__, __LINE__);
475     }
476
477     /* If the timer has not fired, disable it */
478     timer_delete (timerid);
479   } else {
480     eprintf ("Error in call to timer_create:", __FILE__, __LINE__);
481   }
482
483   killpg (pid, SIGKILL);        /* Kill remaining processes. */
484
485   return receive_result_info_fork (tc->name, tfun->name, i, status,
486       tfun->signal, tfun->allowed_exit_value);
487 }
488
489 static TestResult *
490 receive_result_info_fork (const char *tcname,
491     const char *tname,
492     int iter, int status, int expected_signal, signed char allowed_exit_value)
493 {
494   TestResult *tr;
495
496   tr = receive_test_result (waserror (status, expected_signal));
497   if (tr == NULL) {
498     eprintf ("Failed to receive test result", __FILE__, __LINE__);
499   } else {
500     tr->tcname = tcname;
501     tr->tname = tname;
502     tr->iter = iter;
503     set_fork_info (tr, status, expected_signal, allowed_exit_value);
504   }
505
506   return tr;
507 }
508
509 static void
510 set_fork_info (TestResult * tr, int status, int signal_expected,
511     signed char allowed_exit_value)
512 {
513   int was_sig = WIFSIGNALED (status);
514   int was_exit = WIFEXITED (status);
515   signed char exit_status = WEXITSTATUS (status);
516   int signal_received = WTERMSIG (status);
517
518   if (was_sig) {
519     if (signal_expected == signal_received) {
520       if (alarm_received) {
521         /* Got alarm instead of signal */
522         tr->rtype = CK_ERROR;
523         if (tr->msg != NULL) {
524           free (tr->msg);
525         }
526         tr->msg = signal_error_msg (signal_received, signal_expected);
527       } else {
528         tr->rtype = CK_PASS;
529         if (tr->msg != NULL) {
530           free (tr->msg);
531         }
532         tr->msg = pass_msg ();
533       }
534     } else if (signal_expected != 0) {
535       /* signal received, but not the expected one */
536       tr->rtype = CK_ERROR;
537       if (tr->msg != NULL) {
538         free (tr->msg);
539       }
540       tr->msg = signal_error_msg (signal_received, signal_expected);
541     } else {
542       /* signal received and none expected */
543       tr->rtype = CK_ERROR;
544       if (tr->msg != NULL) {
545         free (tr->msg);
546       }
547       tr->msg = signal_msg (signal_received);
548     }
549   } else if (signal_expected == 0) {
550     if (was_exit && exit_status == allowed_exit_value) {
551       tr->rtype = CK_PASS;
552       if (tr->msg != NULL) {
553         free (tr->msg);
554       }
555       tr->msg = pass_msg ();
556     } else if (was_exit && exit_status != allowed_exit_value) {
557       if (tr->msg == NULL) {    /* early exit */
558         tr->rtype = CK_ERROR;
559         tr->msg = exit_msg (exit_status);
560       } else {
561         tr->rtype = CK_FAILURE;
562       }
563     }
564   } else {                      /* a signal was expected and none raised */
565     if (was_exit) {
566       if (tr->msg != NULL) {
567         free (tr->msg);
568       }
569       tr->msg = exit_msg (exit_status);
570       tr->rtype = CK_FAILURE;   /* normal exit status */
571     }
572   }
573 }
574
575 static char *
576 signal_msg (int signal)
577 {
578   char *msg = (char *) emalloc (MSG_LEN);       /* free'd by caller */
579
580   if (alarm_received) {
581     snprintf (msg, MSG_LEN, "Test timeout expired");
582   } else {
583     snprintf (msg, MSG_LEN, "Received signal %d (%s)",
584         signal, strsignal (signal));
585   }
586   return msg;
587 }
588
589 static char *
590 signal_error_msg (int signal_received, int signal_expected)
591 {
592   char *sig_r_str;
593   char *sig_e_str;
594   char *msg = (char *) emalloc (MSG_LEN);       /* free'd by caller */
595
596   sig_r_str = strdup (strsignal (signal_received));
597   sig_e_str = strdup (strsignal (signal_expected));
598   if (alarm_received) {
599     snprintf (msg, MSG_LEN,
600         "Test timeout expired, expected signal %d (%s)",
601         signal_expected, sig_e_str);
602   } else {
603     snprintf (msg, MSG_LEN, "Received signal %d (%s), expected %d (%s)",
604         signal_received, sig_r_str, signal_expected, sig_e_str);
605   }
606   free (sig_r_str);
607   free (sig_e_str);
608   return msg;
609 }
610
611 static char *
612 exit_msg (int exitval)
613 {
614   char *msg = (char *) emalloc (MSG_LEN);       /* free'd by caller */
615
616   snprintf (msg, MSG_LEN, "Early exit with return value %d", exitval);
617   return msg;
618 }
619
620 static int
621 waserror (int status, int signal_expected)
622 {
623   int was_sig = WIFSIGNALED (status);
624   int was_exit = WIFEXITED (status);
625   int exit_status = WEXITSTATUS (status);
626   int signal_received = WTERMSIG (status);
627
628   return ((was_sig && (signal_received != signal_expected)) ||
629       (was_exit && exit_status != 0));
630 }
631 #endif /* HAVE_FORK */
632
633 enum fork_status
634 srunner_fork_status (SRunner * sr)
635 {
636   if (sr->fstat == CK_FORK_GETENV) {
637     char *env = getenv ("CK_FORK");
638
639     if (env == NULL)
640 #if defined(HAVE_FORK) && HAVE_FORK==1
641       return CK_FORK;
642 #else
643       return CK_NOFORK;
644 #endif
645     if (strcmp (env, "no") == 0)
646       return CK_NOFORK;
647     else {
648 #if defined(HAVE_FORK) && HAVE_FORK==1
649       return CK_FORK;
650 #else /* HAVE_FORK */
651       eprintf ("This version does not support fork", __FILE__, __LINE__);
652       return CK_NOFORK;
653 #endif /* HAVE_FORK */
654     }
655   } else
656     return sr->fstat;
657 }
658
659 void
660 srunner_set_fork_status (SRunner * sr, enum fork_status fstat)
661 {
662 #if !defined(HAVE_FORK) || HAVE_FORK==0
663   /* If fork() is unavailable, do not allow a fork mode to be set */
664   if (fstat != CK_NOFORK) {
665     eprintf ("This version does not support fork", __FILE__, __LINE__);
666   }
667 #endif /* ! HAVE_FORK */
668   sr->fstat = fstat;
669 }
670
671 void
672 srunner_run_all (SRunner * sr, enum print_output print_mode)
673 {
674   srunner_run (sr, NULL,        /* All test suites.  */
675       NULL,                     /* All test cases.   */
676       print_mode);
677 }
678
679 void
680 srunner_run (SRunner * sr, const char *sname, const char *tcname,
681     enum print_output print_mode)
682 {
683   /* Get the selected test suite and test case from the
684      environment.  */
685   if (!tcname)
686     tcname = getenv ("CK_RUN_CASE");
687   if (!sname)
688     sname = getenv ("CK_RUN_SUITE");
689
690   if (sr == NULL)
691     return;
692   if (print_mode >= CK_LAST) {
693     eprintf ("Bad print_mode argument to srunner_run_all: %d",
694         __FILE__, __LINE__, print_mode);
695   }
696 #if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
697   memset (&new_action, 0, sizeof new_action);
698   new_action[0].sa_handler = sig_handler;
699   sigaction (SIGALRM, &new_action[0], &old_action[0]);
700   new_action[1].sa_handler = sig_handler;
701   sigaction (SIGINT, &new_action[1], &old_action[1]);
702   new_action[2].sa_handler = sig_handler;
703   sigaction (SIGTERM, &new_action[2], &old_action[2]);
704 #endif /* HAVE_SIGACTION && HAVE_FORK */
705   srunner_run_init (sr, print_mode);
706   srunner_iterate_suites (sr, sname, tcname, print_mode);
707   srunner_run_end (sr, print_mode);
708 #if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
709   sigaction (SIGALRM, &old_action[0], NULL);
710   sigaction (SIGINT, &old_action[1], NULL);
711   sigaction (SIGTERM, &old_action[2], NULL);
712 #endif /* HAVE_SIGACTION && HAVE_FORK */
713 }
714
715 pid_t
716 check_fork (void)
717 {
718 #if defined(HAVE_FORK) && HAVE_FORK==1
719   pid_t pid = fork ();
720
721   /* Set the process to a process group to be able to kill it easily. */
722   if (pid >= 0) {
723     setpgid (pid, group_pid);
724   }
725   return pid;
726 #else /* HAVE_FORK */
727   eprintf ("This version does not support fork", __FILE__, __LINE__);
728   return 0;
729 #endif /* HAVE_FORK */
730 }
731
732 void
733 check_waitpid_and_exit (pid_t pid CK_ATTRIBUTE_UNUSED)
734 {
735 #if defined(HAVE_FORK) && HAVE_FORK==1
736   pid_t pid_w;
737   int status;
738
739   if (pid > 0) {
740     do {
741       pid_w = waitpid (pid, &status, 0);
742     }
743     while (pid_w == -1);
744     if (waserror (status, 0)) {
745       exit (EXIT_FAILURE);
746     }
747   }
748   exit (EXIT_SUCCESS);
749 #else /* HAVE_FORK */
750   eprintf ("This version does not support fork", __FILE__, __LINE__);
751 #endif /* HAVE_FORK */
752 }