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