diff options
Diffstat (limited to 'src/librc')
-rw-r--r-- | src/librc/librc.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/src/librc/librc.c b/src/librc/librc.c index 13220d2f..6d58bf82 100644 --- a/src/librc/librc.c +++ b/src/librc/librc.c @@ -214,6 +214,13 @@ const char *rc_sys(void) return RC_SYS_JAIL; #endif +#ifdef __NetBSD__ + if (exists("/kern/xen/privcmd")) + return RC_SYS_XEN0; + if (exists("/kern/xen")) + return RC_SYS_XENU; +#endif + #ifdef __linux__ if (exists("/proc/xen")) { if (file_regex("/proc/xen/capabilities", "control_d")) @@ -673,6 +680,95 @@ bool rc_service_value_set(const char *service, const char *option, } librc_hidden_def(rc_service_value_set) +static 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; +} + +pid_t rc_service_stop(const char *service) +{ + RC_SERVICE state = rc_service_state(service); + + if (state & RC_SERVICE_FAILED) + return -1; + + if (state & RC_SERVICE_STOPPED) + return 0; + + return _exec_service(service, "stop"); +} +librc_hidden_def(rc_service_stop) + +pid_t rc_service_start(const char *service) +{ + RC_SERVICE state = rc_service_state(service); + + if (state & RC_SERVICE_FAILED) + return -1; + + if (! state & RC_SERVICE_STOPPED) + return 0; + + return _exec_service(service, "start"); +} +librc_hidden_def(rc_service_start) bool rc_service_schedule_start(const char *service, const char *service_to_start) |