1 |
commit: fdce4769f2e0f4175163ffa181c7b3b2192f7b22 |
2 |
Author: William Hubbs <w.d.hubbs <AT> gmail <DOT> com> |
3 |
AuthorDate: Tue Oct 24 15:26:18 2017 +0000 |
4 |
Commit: William Hubbs <williamh <AT> gentoo <DOT> org> |
5 |
CommitDate: Tue Oct 24 15:26:18 2017 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/openrc.git/commit/?id=fdce4769 |
7 |
|
8 |
supervise-daemon: multiple fixes |
9 |
|
10 |
- Harden against dying by handling all signals that would terminate the |
11 |
program and adding --reexec support |
12 |
- factor the supervisor into its own function |
13 |
- fix test for whether we are already running |
14 |
|
15 |
src/includes/rc-misc.h | 1 + |
16 |
src/rc/rc-misc.c | 12 + |
17 |
src/rc/supervise-daemon.c | 570 +++++++++++++++++++++++++++------------------- |
18 |
3 files changed, 343 insertions(+), 240 deletions(-) |
19 |
|
20 |
diff --git a/src/includes/rc-misc.h b/src/includes/rc-misc.h |
21 |
index 9a55c413..e6789911 100644 |
22 |
--- a/src/includes/rc-misc.h |
23 |
+++ b/src/includes/rc-misc.h |
24 |
@@ -47,6 +47,7 @@ bool rc_conf_yesno(const char *var); |
25 |
void env_filter(void); |
26 |
void env_config(void); |
27 |
int signal_setup(int sig, void (*handler)(int)); |
28 |
+int signal_setup_restart(int sig, void (*handler)(int)); |
29 |
int svc_lock(const char *); |
30 |
int svc_unlock(const char *, int); |
31 |
pid_t exec_service(const char *, const char *); |
32 |
|
33 |
diff --git a/src/rc/rc-misc.c b/src/rc/rc-misc.c |
34 |
index d43f1274..33a17b35 100644 |
35 |
--- a/src/rc/rc-misc.c |
36 |
+++ b/src/rc/rc-misc.c |
37 |
@@ -218,6 +218,18 @@ signal_setup(int sig, void (*handler)(int)) |
38 |
} |
39 |
|
40 |
int |
41 |
+signal_setup_restart(int sig, void (*handler)(int)) |
42 |
+{ |
43 |
+ struct sigaction sa; |
44 |
+ |
45 |
+ memset(&sa, 0, sizeof (sa)); |
46 |
+ sigemptyset(&sa.sa_mask); |
47 |
+ sa.sa_handler = handler; |
48 |
+ sa.sa_flags = SA_RESTART; |
49 |
+ return sigaction(sig, &sa, NULL); |
50 |
+} |
51 |
+ |
52 |
+int |
53 |
svc_lock(const char *applet) |
54 |
{ |
55 |
char file[PATH_MAX]; |
56 |
|
57 |
diff --git a/src/rc/supervise-daemon.c b/src/rc/supervise-daemon.c |
58 |
index f1e8ea16..df59eb67 100644 |
59 |
--- a/src/rc/supervise-daemon.c |
60 |
+++ b/src/rc/supervise-daemon.c |
61 |
@@ -67,7 +67,7 @@ static struct pam_conv conv = { NULL, NULL}; |
62 |
|
63 |
const char *applet = NULL; |
64 |
const char *extraopts = NULL; |
65 |
-const char *getoptstring = "D:d:e:g:I:Kk:m:N:p:R:r:Su:1:2:" \ |
66 |
+const char *getoptstring = "D:d:e:g:I:Kk:m:N:p:R:r:Su:1:2:3" \ |
67 |
getoptstring_COMMON; |
68 |
const struct option longopts[] = { |
69 |
{ "respawn-delay", 1, NULL, 'D'}, |
70 |
@@ -87,6 +87,7 @@ const struct option longopts[] = { |
71 |
{ "user", 1, NULL, 'u'}, |
72 |
{ "stdout", 1, NULL, '1'}, |
73 |
{ "stderr", 1, NULL, '2'}, |
74 |
+ { "reexec", 0, NULL, '3'}, |
75 |
longopts_COMMON |
76 |
}; |
77 |
const char * const longopts_help[] = { |
78 |
@@ -107,6 +108,7 @@ const char * const longopts_help[] = { |
79 |
"Change the process user", |
80 |
"Redirect stdout to file", |
81 |
"Redirect stderr to file", |
82 |
+ "reexec (used internally)", |
83 |
longopts_help_COMMON |
84 |
}; |
85 |
const char *usagestring = NULL; |
86 |
@@ -127,6 +129,13 @@ static bool exiting = false; |
87 |
#ifdef TIOCNOTTY |
88 |
static int tty_fd = -1; |
89 |
#endif |
90 |
+static pid_t child_pid; |
91 |
+static int respawn_count = 0; |
92 |
+static int respawn_delay = 0; |
93 |
+static int respawn_max = 10; |
94 |
+static int respawn_period = 5; |
95 |
+static char *pidfile = NULL; |
96 |
+static char *svcname = NULL; |
97 |
|
98 |
extern char **environ; |
99 |
|
100 |
@@ -150,8 +159,71 @@ static void cleanup(void) |
101 |
free(changeuser); |
102 |
} |
103 |
|
104 |
-static void child_process(char *exec, char **argv, char *svcname, |
105 |
- int start_count) |
106 |
+static void re_exec(void) |
107 |
+{ |
108 |
+ syslog(LOG_WARNING, "Re-executing supervise-daemon"); |
109 |
+ execlp("supervise-daemon", "supervise-daemon", "--reexec", (char *) NULL); |
110 |
+ syslog(LOG_ERR, "Unable to execute supervise-daemon: %s", |
111 |
+ strerror(errno)); |
112 |
+ exit(EXIT_FAILURE); |
113 |
+} |
114 |
+ |
115 |
+static void handle_signal(int sig) |
116 |
+{ |
117 |
+ int serrno = errno; |
118 |
+ |
119 |
+ syslog(LOG_WARNING, "caught signal %d", sig); |
120 |
+ |
121 |
+ if (sig == SIGTERM) |
122 |
+ exiting = true; |
123 |
+ /* Restore errno */ |
124 |
+ errno = serrno; |
125 |
+ if (! exiting) |
126 |
+ re_exec(); |
127 |
+} |
128 |
+ |
129 |
+static char * expand_home(const char *home, const char *path) |
130 |
+{ |
131 |
+ char *opath, *ppath, *p, *nh; |
132 |
+ size_t len; |
133 |
+ struct passwd *pw; |
134 |
+ |
135 |
+ if (!path || *path != '~') |
136 |
+ return xstrdup(path); |
137 |
+ |
138 |
+ opath = ppath = xstrdup(path); |
139 |
+ if (ppath[1] != '/' && ppath[1] != '\0') { |
140 |
+ p = strchr(ppath + 1, '/'); |
141 |
+ if (p) |
142 |
+ *p = '\0'; |
143 |
+ pw = getpwnam(ppath + 1); |
144 |
+ if (pw) { |
145 |
+ home = pw->pw_dir; |
146 |
+ ppath = p; |
147 |
+ if (ppath) |
148 |
+ *ppath = '/'; |
149 |
+ } else |
150 |
+ home = NULL; |
151 |
+ } else |
152 |
+ ppath++; |
153 |
+ |
154 |
+ if (!home) { |
155 |
+ free(opath); |
156 |
+ return xstrdup(path); |
157 |
+ } |
158 |
+ if (!ppath) { |
159 |
+ free(opath); |
160 |
+ return xstrdup(home); |
161 |
+ } |
162 |
+ |
163 |
+ len = strlen(ppath) + strlen(home) + 1; |
164 |
+ nh = xmalloc(len); |
165 |
+ snprintf(nh, len, "%s%s", home, ppath); |
166 |
+ free(opath); |
167 |
+ return nh; |
168 |
+} |
169 |
+ |
170 |
+static void child_process(char *exec, char **argv) |
171 |
{ |
172 |
RC_STRINGLIST *env_list; |
173 |
RC_STRING *env; |
174 |
@@ -176,11 +248,13 @@ static void child_process(char *exec, char **argv, char *svcname, |
175 |
setsid(); |
176 |
|
177 |
if (svcname) { |
178 |
-start_time = time(NULL); |
179 |
-from_time_t(start_time_string, start_time); |
180 |
+ start_time = time(NULL); |
181 |
+ from_time_t(start_time_string, start_time); |
182 |
rc_service_value_set(svcname, "start_time", start_time_string); |
183 |
-sprintf(start_count_string, "%i", start_count); |
184 |
+ sprintf(start_count_string, "%i", respawn_count); |
185 |
rc_service_value_set(svcname, "start_count", start_count_string); |
186 |
+ sprintf(start_count_string, "%d", getpid()); |
187 |
+ rc_service_value_set(svcname, "child_pid", start_count_string); |
188 |
} |
189 |
|
190 |
if (nicelevel) { |
191 |
@@ -323,7 +397,7 @@ sprintf(start_count_string, "%i", start_count); |
192 |
|
193 |
*cmdline = '\0'; |
194 |
c = argv; |
195 |
- while (*c) { |
196 |
+ while (c && *c) { |
197 |
strcat(cmdline, *c); |
198 |
strcat(cmdline, " "); |
199 |
c++; |
200 |
@@ -338,108 +412,152 @@ sprintf(start_count_string, "%i", start_count); |
201 |
eerrorx("%s: failed to exec `%s': %s", applet, exec,strerror(errno)); |
202 |
} |
203 |
|
204 |
-static void handle_signal(int sig) |
205 |
+static void supervisor(char *exec, char **argv) |
206 |
{ |
207 |
- int serrno = errno; |
208 |
- char signame[10] = { '\0' }; |
209 |
- |
210 |
- switch (sig) { |
211 |
- case SIGINT: |
212 |
- snprintf(signame, sizeof(signame), "SIGINT"); |
213 |
- break; |
214 |
- case SIGTERM: |
215 |
- snprintf(signame, sizeof(signame), "SIGTERM"); |
216 |
- break; |
217 |
- case SIGQUIT: |
218 |
- snprintf(signame, sizeof(signame), "SIGQUIT"); |
219 |
- break; |
220 |
- } |
221 |
- |
222 |
- if (*signame != 0) { |
223 |
- syslog(LOG_INFO, "%s: caught signal %s, exiting", applet, signame); |
224 |
- exiting = true; |
225 |
- } else |
226 |
- syslog(LOG_INFO, "%s: caught unknown signal %d", applet, sig); |
227 |
+ FILE *fp; |
228 |
+ int i; |
229 |
+ int nkilled; |
230 |
+ time_t respawn_now= 0; |
231 |
+ time_t first_spawn= 0; |
232 |
|
233 |
- /* Restore errno */ |
234 |
- errno = serrno; |
235 |
-} |
236 |
+ openlog(applet, LOG_PID, LOG_DAEMON); |
237 |
+#ifndef RC_DEBUG |
238 |
+ signal_setup_restart(SIGHUP, handle_signal); |
239 |
+ signal_setup_restart(SIGINT, handle_signal); |
240 |
+ signal_setup_restart(SIGQUIT, handle_signal); |
241 |
+ signal_setup_restart(SIGILL, handle_signal); |
242 |
+ signal_setup_restart(SIGABRT, handle_signal); |
243 |
+ signal_setup_restart(SIGFPE, handle_signal); |
244 |
+ signal_setup_restart(SIGSEGV, handle_signal); |
245 |
+ signal_setup_restart(SIGPIPE, handle_signal); |
246 |
+ signal_setup_restart(SIGALRM, handle_signal); |
247 |
+ signal_setup(SIGTERM, handle_signal); |
248 |
+ signal_setup_restart(SIGUSR1, handle_signal); |
249 |
+ signal_setup_restart(SIGUSR2, handle_signal); |
250 |
+ signal_setup_restart(SIGBUS, handle_signal); |
251 |
+ signal_setup_restart(SIGPOLL, handle_signal); |
252 |
+ signal_setup_restart(SIGPROF, handle_signal); |
253 |
+ signal_setup_restart(SIGSYS, handle_signal); |
254 |
+ signal_setup_restart(SIGTRAP, handle_signal); |
255 |
+ signal_setup_restart(SIGVTALRM, handle_signal); |
256 |
+ signal_setup_restart(SIGXCPU, handle_signal); |
257 |
+ signal_setup_restart(SIGXFSZ, handle_signal); |
258 |
+#ifdef SIGEMT |
259 |
+ signal_setup_restart(SIGEMT, handle_signal); |
260 |
+#endif |
261 |
+ signal_setup_restart(SIGIO, handle_signal); |
262 |
+ signal_setup_restart(SIGPWR, handle_signal); |
263 |
+ signal_setup_restart(SIGUNUSED, handle_signal); |
264 |
+#ifdef SIGRTMIN |
265 |
+ for (i = SIGRTMIN; i <= SIGRTMAX; i++) |
266 |
+ signal_setup_restart(i, handle_signal); |
267 |
+#endif |
268 |
+#endif |
269 |
|
270 |
-static char * expand_home(const char *home, const char *path) |
271 |
-{ |
272 |
- char *opath, *ppath, *p, *nh; |
273 |
- size_t len; |
274 |
- struct passwd *pw; |
275 |
+ fp = fopen(pidfile, "w"); |
276 |
+ if (! fp) |
277 |
+ eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno)); |
278 |
+ fprintf(fp, "%d\n", getpid()); |
279 |
+ fclose(fp); |
280 |
|
281 |
- if (!path || *path != '~') |
282 |
- return xstrdup(path); |
283 |
+ if (svcname) |
284 |
+ rc_service_daemon_set(svcname, exec, (const char * const *) argv, |
285 |
+ pidfile, true); |
286 |
|
287 |
- opath = ppath = xstrdup(path); |
288 |
- if (ppath[1] != '/' && ppath[1] != '\0') { |
289 |
- p = strchr(ppath + 1, '/'); |
290 |
- if (p) |
291 |
- *p = '\0'; |
292 |
- pw = getpwnam(ppath + 1); |
293 |
- if (pw) { |
294 |
- home = pw->pw_dir; |
295 |
- ppath = p; |
296 |
- if (ppath) |
297 |
- *ppath = '/'; |
298 |
- } else |
299 |
- home = NULL; |
300 |
- } else |
301 |
- ppath++; |
302 |
+ /* remove the controlling tty */ |
303 |
+#ifdef TIOCNOTTY |
304 |
+ ioctl(tty_fd, TIOCNOTTY, 0); |
305 |
+ close(tty_fd); |
306 |
+#endif |
307 |
|
308 |
- if (!home) { |
309 |
- free(opath); |
310 |
- return xstrdup(path); |
311 |
- } |
312 |
- if (!ppath) { |
313 |
- free(opath); |
314 |
- return xstrdup(home); |
315 |
+ /* |
316 |
+ * Supervisor main loop |
317 |
+ */ |
318 |
+ i = 0; |
319 |
+ while (!exiting) { |
320 |
+ wait(&i); |
321 |
+ if (exiting) { |
322 |
+ signal_setup(SIGCHLD, SIG_IGN); |
323 |
+ syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid); |
324 |
+ nkilled = run_stop_schedule(applet, exec, NULL, child_pid, 0, |
325 |
+ false, false, true); |
326 |
+ if (nkilled > 0) |
327 |
+ syslog(LOG_INFO, "killed %d processes", nkilled); |
328 |
+ } else { |
329 |
+ sleep(respawn_delay); |
330 |
+ if (respawn_max > 0 && respawn_period > 0) { |
331 |
+ respawn_now = time(NULL); |
332 |
+ if (first_spawn == 0) |
333 |
+ first_spawn = respawn_now; |
334 |
+ if (respawn_now - first_spawn > respawn_period) { |
335 |
+ respawn_count = 0; |
336 |
+ first_spawn = 0; |
337 |
+ } else |
338 |
+ respawn_count++; |
339 |
+ if (respawn_count >= respawn_max) { |
340 |
+ syslog(LOG_WARNING, |
341 |
+ "respawned \"%s\" too many times, exiting", exec); |
342 |
+ exiting = true; |
343 |
+ continue; |
344 |
+ } |
345 |
+ } |
346 |
+ if (WIFEXITED(i)) |
347 |
+ syslog(LOG_WARNING, "%s, pid %d, exited with return code %d", |
348 |
+ exec, child_pid, WEXITSTATUS(i)); |
349 |
+ else if (WIFSIGNALED(i)) |
350 |
+ syslog(LOG_WARNING, "%s, pid %d, terminated by signal %d", |
351 |
+ exec, child_pid, WTERMSIG(i)); |
352 |
+ child_pid = fork(); |
353 |
+ if (child_pid == -1) |
354 |
+ eerrorx("%s: fork: %s", applet, strerror(errno)); |
355 |
+ if (child_pid == 0) |
356 |
+ child_process(exec, argv); |
357 |
+ } |
358 |
} |
359 |
|
360 |
- len = strlen(ppath) + strlen(home) + 1; |
361 |
- nh = xmalloc(len); |
362 |
- snprintf(nh, len, "%s%s", home, ppath); |
363 |
- free(opath); |
364 |
- return nh; |
365 |
+ if (pidfile && exists(pidfile)) |
366 |
+ unlink(pidfile); |
367 |
+ if (svcname) { |
368 |
+ rc_service_daemon_set(svcname, exec, (const char *const *)argv, |
369 |
+ pidfile, false); |
370 |
+ rc_service_mark(svcname, RC_SERVICE_STOPPED); |
371 |
+ } |
372 |
+ exit(EXIT_SUCCESS); |
373 |
} |
374 |
|
375 |
int main(int argc, char **argv) |
376 |
{ |
377 |
int opt; |
378 |
+ char **c; |
379 |
+ int x; |
380 |
bool start = false; |
381 |
bool stop = false; |
382 |
+ bool reexec = false; |
383 |
char *exec = NULL; |
384 |
- char *pidfile = NULL; |
385 |
char *retry = NULL; |
386 |
- int nkilled; |
387 |
int sig = SIGTERM; |
388 |
char *home = NULL; |
389 |
int tid = 0; |
390 |
- pid_t child_pid, pid; |
391 |
- char *svcname = getenv("RC_SVCNAME"); |
392 |
+ pid_t pid; |
393 |
char *tmp; |
394 |
char *p; |
395 |
char *token; |
396 |
int i; |
397 |
int n; |
398 |
char exec_file[PATH_MAX]; |
399 |
- int respawn_count = 0; |
400 |
- int respawn_delay = 0; |
401 |
- int respawn_max = 10; |
402 |
- int respawn_period = 5; |
403 |
- time_t respawn_now= 0; |
404 |
- time_t first_spawn= 0; |
405 |
+ char name[PATH_MAX]; |
406 |
struct timespec ts; |
407 |
struct passwd *pw; |
408 |
struct group *gr; |
409 |
FILE *fp; |
410 |
mode_t numask = 022; |
411 |
+ int child_argc = 0; |
412 |
+ char **child_argv = NULL; |
413 |
+ char *str = NULL; |
414 |
|
415 |
applet = basename_c(argv[0]); |
416 |
atexit(cleanup); |
417 |
+ svcname = getenv("RC_SVCNAME"); |
418 |
|
419 |
if ((tmp = getenv("SSD_NICELEVEL"))) |
420 |
if (sscanf(tmp, "%d", &nicelevel) != 1) |
421 |
@@ -493,8 +611,8 @@ int main(int argc, char **argv) |
422 |
|
423 |
case 'P': /* --respawn-period time */ |
424 |
n = sscanf(optarg, "%d", &respawn_period); |
425 |
- if (n != 1 || respawn_delay < 1) |
426 |
- eerrorx("Invalid respawn-delay value '%s'", optarg); |
427 |
+ if (n != 1 || respawn_period < 1) |
428 |
+ eerrorx("Invalid respawn-period value '%s'", optarg); |
429 |
break; |
430 |
|
431 |
case 'S': /* --start */ |
432 |
@@ -590,11 +708,14 @@ int main(int argc, char **argv) |
433 |
case '2': /* --stderr /path/to/stderr.logfile */ |
434 |
redirect_stderr = optarg; |
435 |
break; |
436 |
+ case '3': /* --reexec */ |
437 |
+ reexec = true; |
438 |
+ break; |
439 |
|
440 |
case_RC_COMMON_GETOPT |
441 |
} |
442 |
|
443 |
- if (!pidfile) |
444 |
+ if (!pidfile && !reexec) |
445 |
eerrorx("%s: --pidfile must be specified", applet); |
446 |
|
447 |
endpwent(); |
448 |
@@ -602,195 +723,165 @@ int main(int argc, char **argv) |
449 |
argv += optind; |
450 |
exec = *argv; |
451 |
|
452 |
- if (start) { |
453 |
- if (!exec) |
454 |
- eerrorx("%s: nothing to start", applet); |
455 |
- if (respawn_delay * respawn_max > respawn_period) { |
456 |
- ewarn("%s: Please increase the value of --respawn-period to more " |
457 |
- "than %d to avoid infinite respawning", applet, |
458 |
- respawn_delay * respawn_max); |
459 |
- } |
460 |
- if (retry) |
461 |
- parse_schedule(applet, retry, sig); |
462 |
- else |
463 |
- parse_schedule(applet, NULL, sig); |
464 |
- } |
465 |
- |
466 |
/* Expand ~ */ |
467 |
if (ch_dir && *ch_dir == '~') |
468 |
ch_dir = expand_home(home, ch_dir); |
469 |
if (ch_root && *ch_root == '~') |
470 |
ch_root = expand_home(home, ch_root); |
471 |
- if (exec) { |
472 |
- if (*exec == '~') |
473 |
- exec = expand_home(home, exec); |
474 |
- |
475 |
- /* Validate that the binary exists if we are starting */ |
476 |
- if (*exec == '/' || *exec == '.') { |
477 |
- /* Full or relative path */ |
478 |
- if (ch_root) |
479 |
- snprintf(exec_file, sizeof(exec_file), |
480 |
- "%s/%s", ch_root, exec); |
481 |
- else |
482 |
- snprintf(exec_file, sizeof(exec_file), |
483 |
- "%s", exec); |
484 |
- } else { |
485 |
- /* Something in $PATH */ |
486 |
- p = tmp = xstrdup(getenv("PATH")); |
487 |
- *exec_file = '\0'; |
488 |
- while ((token = strsep(&p, ":"))) { |
489 |
+ |
490 |
+ umask(numask); |
491 |
+ |
492 |
+ if (reexec) { |
493 |
+ str = rc_service_value_get(svcname, "argc"); |
494 |
+ sscanf(str, "%d", &child_argc); |
495 |
+ child_argv = xmalloc((child_argc + 1) * sizeof(char *)); |
496 |
+ memset(child_argv, 0, (child_argc + 1) * sizeof(char *)); |
497 |
+ for (x = 0; x < child_argc; x++) { |
498 |
+ sprintf(name, "argv_%d", x); |
499 |
+ str = rc_service_value_get(svcname, name); |
500 |
+ child_argv[x] = str; |
501 |
+ } |
502 |
+ free(str); |
503 |
+ str = rc_service_value_get(svcname, "child_pid"); |
504 |
+ sscanf(str, "%d", &child_pid); |
505 |
+ free(str); |
506 |
+ exec = rc_service_value_get(svcname, "exec"); |
507 |
+ pidfile = rc_service_value_get(svcname, "pidfile"); |
508 |
+ retry = rc_service_value_get(svcname, "retry"); |
509 |
+ if (retry) { |
510 |
+ parse_schedule(applet, retry, sig); |
511 |
+ rc_service_value_set(svcname, "retry", retry); |
512 |
+ } else |
513 |
+ parse_schedule(applet, NULL, sig); |
514 |
+ |
515 |
+ str = rc_service_value_get(svcname, "respawn_delay"); |
516 |
+ sscanf(str, "%d", &respawn_delay); |
517 |
+ str = rc_service_value_get(svcname, "respawn_max"); |
518 |
+ sscanf(str, "%d", &respawn_max); |
519 |
+ supervisor(exec, child_argv); |
520 |
+ } else if (start) { |
521 |
+ if (exec) { |
522 |
+ if (*exec == '~') |
523 |
+ exec = expand_home(home, exec); |
524 |
+ |
525 |
+ /* Validate that the binary exists if we are starting */ |
526 |
+ if (*exec == '/' || *exec == '.') { |
527 |
+ /* Full or relative path */ |
528 |
if (ch_root) |
529 |
snprintf(exec_file, sizeof(exec_file), |
530 |
- "%s/%s/%s", |
531 |
- ch_root, token, exec); |
532 |
+ "%s/%s", ch_root, exec); |
533 |
else |
534 |
snprintf(exec_file, sizeof(exec_file), |
535 |
- "%s/%s", token, exec); |
536 |
- if (exists(exec_file)) |
537 |
- break; |
538 |
+ "%s", exec); |
539 |
+ } else { |
540 |
+ /* Something in $PATH */ |
541 |
+ p = tmp = xstrdup(getenv("PATH")); |
542 |
*exec_file = '\0'; |
543 |
+ while ((token = strsep(&p, ":"))) { |
544 |
+ if (ch_root) |
545 |
+ snprintf(exec_file, sizeof(exec_file), |
546 |
+ "%s/%s/%s", |
547 |
+ ch_root, token, exec); |
548 |
+ else |
549 |
+ snprintf(exec_file, sizeof(exec_file), |
550 |
+ "%s/%s", token, exec); |
551 |
+ if (exists(exec_file)) |
552 |
+ break; |
553 |
+ *exec_file = '\0'; |
554 |
+ } |
555 |
+ free(tmp); |
556 |
} |
557 |
- free(tmp); |
558 |
- } |
559 |
- } |
560 |
- if (start && !exists(exec_file)) |
561 |
- eerrorx("%s: %s does not exist", applet, |
562 |
- *exec_file ? exec_file : exec); |
563 |
+ if ( !exists(exec_file)) |
564 |
+ eerrorx("%s: %s does not exist", applet, |
565 |
+ *exec_file ? exec_file : exec); |
566 |
+ } else |
567 |
+ eerrorx("%s: nothing to start", applet); |
568 |
|
569 |
- if (stop) { |
570 |
pid = get_pid(applet, pidfile); |
571 |
- if (pid != -1) { |
572 |
- i = kill(pid, SIGTERM); |
573 |
- if (i != 0) |
574 |
- /* We failed to send the signal */ |
575 |
- exit(EXIT_FAILURE); |
576 |
- |
577 |
- /* wait for the supervisor to go down */ |
578 |
- while (kill(pid, 0) == 0) { |
579 |
- ts.tv_sec = 0; |
580 |
- ts.tv_nsec = 1; |
581 |
- nanosleep(&ts, NULL); |
582 |
- } |
583 |
- } |
584 |
- |
585 |
- /* Even if we have not actually killed anything, we should |
586 |
- * remove information about it as it may have unexpectedly |
587 |
- * crashed out. We should also return success as the end |
588 |
- * result would be the same. */ |
589 |
- if (pidfile && exists(pidfile)) |
590 |
- unlink(pidfile); |
591 |
- if (svcname) { |
592 |
- rc_service_daemon_set(svcname, exec, |
593 |
- (const char *const *)argv, |
594 |
- pidfile, false); |
595 |
- rc_service_mark(svcname, RC_SERVICE_STOPPED); |
596 |
- } |
597 |
- exit(EXIT_SUCCESS); |
598 |
- } |
599 |
- |
600 |
- pid = get_pid(applet, pidfile); |
601 |
- if (pid != -1) |
602 |
- if (kill(pid, 0) == 0) |
603 |
- eerrorx("%s: %s is already running", applet, exec); |
604 |
- |
605 |
- einfov("Detaching to start `%s'", exec); |
606 |
- eindentv(); |
607 |
- |
608 |
- /* Remove existing pidfile */ |
609 |
- if (pidfile) |
610 |
- unlink(pidfile); |
611 |
- |
612 |
- /* |
613 |
- * Make sure we can write a pid file |
614 |
- */ |
615 |
- fp = fopen(pidfile, "w"); |
616 |
- if (! fp) |
617 |
- eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno)); |
618 |
- fclose(fp); |
619 |
+ if (pid != -1) |
620 |
+ if (do_stop(applet, exec, (const char * const *)argv, pid, uid, |
621 |
+ 0, false, true) > 0) |
622 |
+ eerrorx("%s: %s is already running", applet, exec); |
623 |
|
624 |
- child_pid = fork(); |
625 |
- if (child_pid == -1) |
626 |
- eerrorx("%s: fork: %s", applet, strerror(errno)); |
627 |
+ if (respawn_delay * respawn_max > respawn_period) |
628 |
+ ewarn("%s: Please increase the value of --respawn-period to more " |
629 |
+ "than %d to avoid infinite respawning", applet, |
630 |
+ respawn_delay * respawn_max); |
631 |
|
632 |
- /* first parent process, do nothing. */ |
633 |
- if (child_pid != 0) |
634 |
- exit(EXIT_SUCCESS); |
635 |
+ if (retry) { |
636 |
+ parse_schedule(applet, retry, sig); |
637 |
+ rc_service_value_set(svcname, "retry", retry); |
638 |
+ } else |
639 |
+ parse_schedule(applet, NULL, sig); |
640 |
|
641 |
-#ifdef TIOCNOTTY |
642 |
- tty_fd = open("/dev/tty", O_RDWR); |
643 |
-#endif |
644 |
- devnull_fd = open("/dev/null", O_RDWR); |
645 |
- child_pid = fork(); |
646 |
- if (child_pid == -1) |
647 |
- eerrorx("%s: fork: %s", applet, strerror(errno)); |
648 |
+ einfov("Detaching to start `%s'", exec); |
649 |
|
650 |
- if (child_pid != 0) { |
651 |
- /* this is the supervisor */ |
652 |
- umask(numask); |
653 |
- openlog(applet, LOG_PID, LOG_DAEMON); |
654 |
- signal_setup(SIGTERM, handle_signal); |
655 |
+ /* Remove existing pidfile */ |
656 |
+ if (pidfile) |
657 |
+ unlink(pidfile); |
658 |
|
659 |
+ /* Make sure we can write a pid file */ |
660 |
fp = fopen(pidfile, "w"); |
661 |
if (! fp) |
662 |
eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno)); |
663 |
- fprintf(fp, "%d\n", getpid()); |
664 |
fclose(fp); |
665 |
|
666 |
- if (svcname) |
667 |
- rc_service_daemon_set(svcname, exec, |
668 |
- (const char * const *) argv, pidfile, true); |
669 |
- |
670 |
- /* remove the controlling tty */ |
671 |
+ rc_service_value_set(svcname, "pidfile", pidfile); |
672 |
+ sprintf(name, "%i", respawn_delay); |
673 |
+ rc_service_value_set(svcname, "respawn_delay", name); |
674 |
+ sprintf(name, "%i", respawn_max); |
675 |
+ rc_service_value_set(svcname, "respawn_max", name); |
676 |
+ sprintf(name, "%i", respawn_period); |
677 |
+ rc_service_value_set(svcname, "respawn_period", name); |
678 |
+ child_pid = fork(); |
679 |
+ if (child_pid == -1) |
680 |
+ eerrorx("%s: fork: %s", applet, strerror(errno)); |
681 |
+ if (child_pid != 0) |
682 |
+ /* first parent process, do nothing. */ |
683 |
+ exit(EXIT_SUCCESS); |
684 |
#ifdef TIOCNOTTY |
685 |
- ioctl(tty_fd, TIOCNOTTY, 0); |
686 |
- close(tty_fd); |
687 |
+ tty_fd = open("/dev/tty", O_RDWR); |
688 |
#endif |
689 |
- |
690 |
- /* |
691 |
- * Supervisor main loop |
692 |
- */ |
693 |
- i = 0; |
694 |
- while (!exiting) { |
695 |
- wait(&i); |
696 |
- if (exiting) { |
697 |
- signal_setup(SIGCHLD, SIG_IGN); |
698 |
- syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid); |
699 |
- nkilled = run_stop_schedule(applet, exec, NULL, child_pid, |
700 |
- 0, false, false, true); |
701 |
- if (nkilled > 0) |
702 |
- syslog(LOG_INFO, "killed %d processes", nkilled); |
703 |
- } else { |
704 |
- sleep(respawn_delay); |
705 |
- if (respawn_max > 0 && respawn_period > 0) { |
706 |
- respawn_now = time(NULL); |
707 |
- if (first_spawn == 0) |
708 |
- first_spawn = respawn_now; |
709 |
- if (respawn_now - first_spawn > respawn_period) { |
710 |
- respawn_count = 0; |
711 |
- first_spawn = 0; |
712 |
- } else |
713 |
- respawn_count++; |
714 |
- if (respawn_count >= respawn_max) { |
715 |
- syslog(LOG_WARNING, "respawned \"%s\" too many times, " |
716 |
- "exiting", exec); |
717 |
- exiting = true; |
718 |
- continue; |
719 |
- } |
720 |
+ devnull_fd = open("/dev/null", O_RDWR); |
721 |
+ child_pid = fork(); |
722 |
+ if (child_pid == -1) |
723 |
+ eerrorx("%s: fork: %s", applet, strerror(errno)); |
724 |
+ else if (child_pid != 0) { |
725 |
+ c = argv; |
726 |
+ x = 0; |
727 |
+ while (c && *c) { |
728 |
+ snprintf(name, sizeof(name), "argv_%-d",x); |
729 |
+ rc_service_value_set(svcname, name, *c); |
730 |
+ x++; |
731 |
+ c++; |
732 |
+ } |
733 |
+ sprintf(name, "%d", x); |
734 |
+ rc_service_value_set(svcname, "argc", name); |
735 |
+ rc_service_value_set(svcname, "exec", exec); |
736 |
+ supervisor(exec, argv); |
737 |
+ } else |
738 |
+ child_process(exec, argv); |
739 |
+ } else if (stop) { |
740 |
+ pid = get_pid(applet, pidfile); |
741 |
+ if (pid != -1) { |
742 |
+ i = kill(pid, SIGTERM); |
743 |
+ if (i != 0) |
744 |
+ /* We failed to send the signal */ |
745 |
+ ewarn("Unable to shut down the supervisor"); |
746 |
+ else { |
747 |
+ /* wait for the supervisor to go down */ |
748 |
+ while (kill(pid, 0) == 0) { |
749 |
+ ts.tv_sec = 0; |
750 |
+ ts.tv_nsec = 1; |
751 |
+ nanosleep(&ts, NULL); |
752 |
} |
753 |
- if (WIFEXITED(i)) |
754 |
- syslog(LOG_WARNING, "%s, pid %d, exited with return code %d", |
755 |
- exec, child_pid, WEXITSTATUS(i)); |
756 |
- else if (WIFSIGNALED(i)) |
757 |
- syslog(LOG_WARNING, "%s, pid %d, terminated by signal %d", |
758 |
- exec, child_pid, WTERMSIG(i)); |
759 |
- child_pid = fork(); |
760 |
- if (child_pid == -1) |
761 |
- eerrorx("%s: fork: %s", applet, strerror(errno)); |
762 |
- if (child_pid == 0) |
763 |
- child_process(exec, argv, svcname, respawn_count); |
764 |
} |
765 |
} |
766 |
|
767 |
+ /* Even if we have not actually killed anything, we should |
768 |
+ * remove information about it as it may have unexpectedly |
769 |
+ * crashed out. We should also return success as the end |
770 |
+ * result would be the same. */ |
771 |
if (pidfile && exists(pidfile)) |
772 |
unlink(pidfile); |
773 |
if (svcname) { |
774 |
@@ -800,6 +891,5 @@ int main(int argc, char **argv) |
775 |
rc_service_mark(svcname, RC_SERVICE_STOPPED); |
776 |
} |
777 |
exit(EXIT_SUCCESS); |
778 |
- } else if (child_pid == 0) |
779 |
- child_process(exec, argv, svcname, respawn_count); |
780 |
+ } |
781 |
} |