diff options
author | Roy Marples <roy@marples.name> | 2008-03-28 08:42:05 +0000 |
---|---|---|
committer | Roy Marples <roy@marples.name> | 2008-03-28 08:42:05 +0000 |
commit | 11e33e81c855395cbd931e99f7452ed6b3fef357 (patch) | |
tree | 2af516723abe43f67f38b5419867288913e85169 /src/rc | |
parent | 5e8ed2aecabf48895e6d3d090591ffb59fc7588b (diff) |
Remove rc_service_start/stop from librc as they block and unmask signals. The application may not wish this behaviour and should fork/exec the service itself.
Diffstat (limited to 'src/rc')
-rw-r--r-- | src/rc/rc-misc.c | 63 | ||||
-rw-r--r-- | src/rc/rc.c | 55 | ||||
-rw-r--r-- | src/rc/runscript.c | 10 |
3 files changed, 98 insertions, 30 deletions
diff --git a/src/rc/rc-misc.c b/src/rc/rc-misc.c index 32fe50e3..afe7893c 100644 --- a/src/rc/rc-misc.c +++ b/src/rc/rc-misc.c @@ -43,6 +43,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include "einfo.h" #include "rc.h" @@ -310,3 +311,65 @@ int signal_setup(int sig, void (*handler)(int)) sa.sa_handler = handler; return sigaction(sig, &sa, NULL); } + +pid_t exec_service(const char *service, const char *arg) +{ + char *file; + char fifo[PATH_MAX]; + pid_t pid = -1; + sigset_t full; + sigset_t old; + struct sigaction sa; + + file = rc_service_resolve(service); + if (! exists(file)) { + rc_service_mark(service, RC_SERVICE_STOPPED); + free(file); + return 0; + } + + /* We create a fifo so that other services can wait until we complete */ + snprintf(fifo, sizeof(fifo), RC_SVCDIR "/exclusive/%s", + basename_c(service)); + if (mkfifo(fifo, 0600) != 0 && errno != EEXIST) { + free(file); + return -1; + } + + /* We need to block signals until we have forked */ + memset(&sa, 0, sizeof (sa)); + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + sigfillset(&full); + sigprocmask(SIG_SETMASK, &full, &old); + + if ((pid = fork()) == 0) { + /* Restore default handlers */ + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGWINCH, &sa, NULL); + + /* Unmask signals */ + sigprocmask(SIG_SETMASK, &old, NULL); + + /* Safe to run now */ + execl(file, file, arg, (char *) NULL); + fprintf(stderr, "unable to exec `%s': %s\n", + file, strerror(errno)); + unlink(fifo); + _exit(EXIT_FAILURE); + } + + if (pid == -1) + fprintf(stderr, "fork: %s\n",strerror (errno)); + + sigprocmask(SIG_SETMASK, &old, NULL); + + free(file); + + return pid; +} diff --git a/src/rc/rc.c b/src/rc/rc.c index a6f58b4f..43bcb48e 100644 --- a/src/rc/rc.c +++ b/src/rc/rc.c @@ -771,6 +771,7 @@ static void do_stop_services(const char *newlevel, bool going_down, bool paralle pid_t pid; RC_STRING *service, *svc1, *svc2; RC_STRINGLIST *deporder, *tmplist; + RC_SERVICE state; if (! types_n) { types_n = rc_stringlist_new(); @@ -779,12 +780,13 @@ static void do_stop_services(const char *newlevel, bool going_down, bool paralle TAILQ_FOREACH_REVERSE(service, stop_services, rc_stringlist, entries) { - if (rc_service_state(service->value) & RC_SERVICE_STOPPED) + state = rc_service_state(service->value); + if (state & RC_SERVICE_STOPPED || state & RC_SERVICE_FAILED) continue; /* We always stop the service when in these runlevels */ if (going_down || ! start_services) { - pid = rc_service_stop(service->value); + pid = service_stop(service->value); if (pid > 0 && ! parallel) rc_waitpid(pid); continue; @@ -832,7 +834,7 @@ static void do_stop_services(const char *newlevel, bool going_down, bool paralle } /* After all that we can finally stop the blighter! */ - pid = rc_service_stop(service->value); + pid = service_stop(service->value); if (pid > 0) { add_pid(pid); if (! parallel) { @@ -848,44 +850,47 @@ static void do_start_services(bool parallel) RC_STRING *service; pid_t pid; bool interactive = false; + RC_SERVICE state; if (! rc_yesno(getenv("EINFO_QUIET"))) interactive = exists(INTERACTIVE); TAILQ_FOREACH(service, start_services, entries) { - if (rc_service_state(service->value) & RC_SERVICE_STOPPED) { - if (! interactive) - interactive = want_interactive(); + state = rc_service_state(service->value); + if (!(state & RC_SERVICE_STOPPED) || state & RC_SERVICE_FAILED) + continue; + + if (! interactive) + interactive = want_interactive(); - if (interactive) { + if (interactive) { interactive_retry: - printf("\n"); - einfo("About to start the service %s", - service->value); - eindent(); - einfo("1) Start the service\t\t2) Skip the service"); - einfo("3) Continue boot process\t\t4) Exit to shell"); - eoutdent(); + printf("\n"); + einfo("About to start the service %s", + service->value); + eindent(); + einfo("1) Start the service\t\t2) Skip the service"); + einfo("3) Continue boot process\t\t4) Exit to shell"); + eoutdent(); interactive_option: - switch (read_key(true)) { + switch (read_key(true)) { case '1': break; case '2': continue; case '3': interactive = false; break; case '4': sulogin(true); goto interactive_retry; default: goto interactive_option; - } } + } - pid = rc_service_start(service->value); - - /* Remember the pid if we're running in parallel */ - if (pid > 0) { - add_pid(pid); + pid = service_start(service->value); - if (! parallel) { - rc_waitpid(pid); - remove_pid(pid); - } + /* Remember the pid if we're running in parallel */ + if (pid > 0) { + add_pid(pid); + + if (! parallel) { + rc_waitpid(pid); + remove_pid(pid); } } } diff --git a/src/rc/runscript.c b/src/rc/runscript.c index 8720c02f..421f432f 100644 --- a/src/rc/runscript.c +++ b/src/rc/runscript.c @@ -273,7 +273,7 @@ static void start_services(RC_STRINGLIST *list) { " when %s has started", svc->value, applet); } else - rc_service_start(svc->value); + service_start(svc->value); } } } @@ -727,7 +727,7 @@ static void svc_start(bool deps) if (! rc_runlevel_starting() && use_services) TAILQ_FOREACH(svc, use_services, entries) if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) { - pid_t pid = rc_service_start(svc->value); + pid_t pid = service_start(svc->value); if (! rc_conf_yesno("rc_parallel")) rc_waitpid(pid); } @@ -851,7 +851,7 @@ static void svc_start(bool deps) if (services) { TAILQ_FOREACH(svc, services, entries) if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) - rc_service_start(svc->value); + service_start(svc->value); rc_stringlist_free(services); services = NULL; } @@ -864,7 +864,7 @@ static void svc_start(bool deps) if (services) { TAILQ_FOREACH(svc2, services, entries) if (rc_service_state(svc2->value) & RC_SERVICE_STOPPED) - rc_service_start(svc2->value); + service_start(svc2->value); rc_stringlist_free(services); services = NULL; } @@ -939,7 +939,7 @@ static void svc_stop(bool deps) if (svcs & RC_SERVICE_STARTED || svcs & RC_SERVICE_INACTIVE) { - pid_t pid = rc_service_stop(svc->value); + pid_t pid = service_stop(svc->value); if (! rc_conf_yesno("rc_parallel")) rc_waitpid(pid); if (! tmplist) |