1  // SPDX-License-Identifier: GPL-2.0-only
2  /*
3   * Copyright 2013, Michael Ellerman, IBM Corp.
4   */
5  
6  #include <errno.h>
7  #include <signal.h>
8  #include <stdbool.h>
9  #include <stdio.h>
10  #include <stdlib.h>
11  #include <sys/types.h>
12  #include <sys/wait.h>
13  #include <unistd.h>
14  #include <elf.h>
15  #include <fcntl.h>
16  #include <link.h>
17  #include <sys/stat.h>
18  
19  #include "subunit.h"
20  #include "utils.h"
21  
22  #define KILL_TIMEOUT	5
23  
24  /* Setting timeout to -1 disables the alarm */
25  static uint64_t timeout = 120;
26  
run_test(int (test_function)(void),const char * name)27  int run_test(int (test_function)(void), const char *name)
28  {
29  	bool terminated;
30  	int rc, status;
31  	pid_t pid;
32  
33  	/* Make sure output is flushed before forking */
34  	fflush(stdout);
35  
36  	pid = fork();
37  	if (pid == 0) {
38  		setpgid(0, 0);
39  		exit(test_function());
40  	} else if (pid == -1) {
41  		perror("fork");
42  		return 1;
43  	}
44  
45  	setpgid(pid, pid);
46  
47  	if (timeout != -1)
48  		/* Wake us up in timeout seconds */
49  		alarm(timeout);
50  	terminated = false;
51  
52  wait:
53  	rc = waitpid(pid, &status, 0);
54  	if (rc == -1) {
55  		if (errno != EINTR) {
56  			printf("unknown error from waitpid\n");
57  			return 1;
58  		}
59  
60  		if (terminated) {
61  			printf("!! force killing %s\n", name);
62  			kill(-pid, SIGKILL);
63  			return 1;
64  		} else {
65  			printf("!! killing %s\n", name);
66  			kill(-pid, SIGTERM);
67  			terminated = true;
68  			alarm(KILL_TIMEOUT);
69  			goto wait;
70  		}
71  	}
72  
73  	/* Kill anything else in the process group that is still running */
74  	kill(-pid, SIGTERM);
75  
76  	if (WIFEXITED(status))
77  		status = WEXITSTATUS(status);
78  	else {
79  		if (WIFSIGNALED(status))
80  			printf("!! child died by signal %d\n", WTERMSIG(status));
81  		else
82  			printf("!! child died by unknown cause\n");
83  
84  		status = 1; /* Signal or other */
85  	}
86  
87  	return status;
88  }
89  
sig_handler(int signum)90  static void sig_handler(int signum)
91  {
92  	/* Just wake us up from waitpid */
93  }
94  
95  static struct sigaction sig_action = {
96  	.sa_handler = sig_handler,
97  };
98  
test_harness_set_timeout(uint64_t time)99  void test_harness_set_timeout(uint64_t time)
100  {
101  	timeout = time;
102  }
103  
test_harness(int (test_function)(void),const char * name)104  int test_harness(int (test_function)(void), const char *name)
105  {
106  	int rc;
107  
108  	test_start(name);
109  	test_set_git_version(GIT_VERSION);
110  
111  	if (sigaction(SIGINT, &sig_action, NULL)) {
112  		perror("sigaction (sigint)");
113  		test_error(name);
114  		return 1;
115  	}
116  
117  	if (sigaction(SIGALRM, &sig_action, NULL)) {
118  		perror("sigaction (sigalrm)");
119  		test_error(name);
120  		return 1;
121  	}
122  
123  	rc = run_test(test_function, name);
124  
125  	if (rc == MAGIC_SKIP_RETURN_VALUE) {
126  		test_skip(name);
127  		/* so that skipped test is not marked as failed */
128  		rc = 0;
129  	} else
130  		test_finish(name, rc);
131  
132  	return rc;
133  }
134