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