Gentoo Archives: gentoo-commits

From: William Hubbs <williamh@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/openrc:master commit in: src/rc/, src/includes/
Date: Tue, 24 Oct 2017 15:33:57
Message-Id: 1508858778.fdce4769f2e0f4175163ffa181c7b3b2192f7b22.williamh@OpenRC
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 }