File: async-timeout.c

package info (click to toggle)
runit 2.2.0-7
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,568 kB
  • sloc: ansic: 6,071; sh: 3,419; makefile: 399
file content (67 lines) | stat: -rw-r--r-- 1,471 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/* Runs specified command, and detach it from terminal, if it is still
 * running after DURATION.
 *
 * This utility is written specially for needs of integration `runit'
 * init system into Debian, so DURATION is hardcoded
 */

#define DURATION 90 /* seconds */

#include <assert.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define write2(x) write(2, x "", sizeof(x) - 1)

static sig_atomic_t child_finished = 0;
static void signal_handler(int num) {
	if (num == SIGCHLD)
		child_finished = 1;
}

int main(int argc, char **argv) {
	pid_t pid;

	signal(SIGCHLD, &signal_handler);
	signal(SIGALRM, &signal_handler);

	pid = fork();
	if (pid == -1) {
		write2("async-timeout: fork() failed\n");
		return 1;
	}

	if (argc < 2) {
		write2("usage: async-timeout prog [args ...]\n");
		return 1;
	}

	if (pid == 0) { /* child */
		execvp(argv[1], argv + 1);
		write2("async-timeout: exec() failed\n");
		return 1;
	} else { /* parent */
		alarm(DURATION);
		pause(); /* wait for signal, either SIGCHLD or SIGALRM */
		if (child_finished) {
			int status;
			wait(&status);
			if (WIFEXITED(status)) {
				return WEXITSTATUS(status);
			} else if (WIFSIGNALED(status)) {
				return 128 + WTERMSIG(status);
			} else { /* should not happen */
				assert("panic: unaccessible code" && 0);
				return 128;
			}
		} else {
			/* Child is reparented by pid1 */
			return 0;
		}
	};
	assert("panic: unaccessible code" && 0);

	return 0;
}