aboutsummaryrefslogtreecommitdiff
path: root/src/com_start.c
blob: 73bb2ecb1494cd72151fd099a724d644d4f750b4 (plain)
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include "genrc.h"

void
report_exec_error(int rc, char const *program)
{
	if (WIFEXITED(rc)) {
		if (WEXITSTATUS(rc)) {
			genrc_error("%s exited with status %d",
				    program, WEXITSTATUS(rc));
		}
	} else if (WIFSIGNALED(rc)) {
		char const *coremsg = "";
#ifdef WCOREDUMP
		if (WCOREDUMP(rc))
			coremsg = " (core dumped)";
#endif
		genrc_error("%s terminated on signal %d%s",
			    program, WTERMSIG(rc), coremsg);
	} else if (WIFSTOPPED(rc)) {
		genrc_error("%s stopped on signal %d",
			    program, WSTOPSIG(rc));
	} else {
		genrc_error("%s terminated with unrecognized status: %d",
			    program, rc);
	}
}

typedef void (*SIGHANDLER)(int);

void
sigchld(int sig)
{
}

int
timedwaitpid(pid_t pid, int *status)
{
	struct timeval now, stoptime, ttw;
	int rc = -1;
	SIGHANDLER oldsig;
	
	oldsig = signal(SIGCHLD, sigchld);
	gettimeofday(&stoptime, NULL);
	stoptime.tv_sec += genrc_timeout;
	while (1) {
		pid_t p;
		
		p = waitpid(pid, status, WNOHANG);
		if (p == pid) {
			rc = 0;
			break;
		}
		if (p < 0 && errno != EINTR) {
			system_error(errno, "waitpid");
			break;
		}

		gettimeofday(&now, NULL);
		if (timercmp(&now, &stoptime, >=))
			break;
		timersub(&stoptime, &now, &ttw);
		if (select(0, NULL, NULL, NULL, &ttw) < 0) {
			if (errno != EINTR) {
				system_error(errno, "select");
				break;
			}
		}

	}
	signal(SIGCHLD, oldsig);
	if (rc) {
		kill(pid, SIGKILL);
	}
	return rc;
}

int
com_start(void)
{
	pid_t pid;
	int status;
	PIDLIST pids;
	char *p;
	
	pidlist_init(&pids);
	if (get_pid_list(genrc_pid_closure, &pids) == 0) {
		int running = pids.pidc > 0;
		pidlist_free(&pids);
		if (running) {
			genrc_error("%s is already running", genrc_program);
			return 1;
		}
	}

	if ((p = getenv("GENRC_SENTINEL")) && *p == '1')
		return sentinel();
	
	pid = fork();
	if (pid == -1) {
		system_error(errno, "fork");
		return 1;
	}
	if (pid == 0) {
		char *argv[] = { SHELL, "-c", NULL, NULL };
		argv[2] = genrc_command;
		execvp(SHELL, argv);
		system_error(errno, "failed to exec %s", genrc_program);
		exit(127);
	}

	if (timedwaitpid(pid, &status)) {
		genrc_error("timed out waiting for %s to return",
			    genrc_program);
		return 1;
	}
	if (!(WIFEXITED(status) && WEXITSTATUS(status) == 0)) {
		report_exec_error(status, genrc_program);
		return 1;
	}
	return 0;
}

Return to:

Send suggestions and report system problems to the System administrator.