diff --git a/cmd/Makemodule.am b/cmd/Makemodule.am index 4011b6c..7b8296f 100644 --- a/cmd/Makemodule.am +++ b/cmd/Makemodule.am @@ -3,12 +3,6 @@ shutdown_CPPFLAGS = $(AM_CPPFLAGS) shutdown_CFLAGS = $(AM_CFLAGS) shutdown_LDFLAGS = $(AM_LDFLAGS) -runsvc_SOURCES = cmd/runsvc.c -runsvc_CPPFLAGS = $(AM_CPPFLAGS) -runsvc_CFLAGS = $(AM_CFLAGS) -runsvc_LDFLAGS = $(AM_LDFLAGS) -runsvc_LDADD = libinit.a libcfg.a - killall5_SOURCES = cmd/killall5.c killall5_CPPFLAGS = $(AM_CPPFLAGS) killall5_CFLAGS = $(AM_CFLAGS) @@ -37,4 +31,4 @@ dist_man8_MANS += cmd/shutdown.8 cmd/service/service.8 EXTRA_DIST += $(SRVHEADERS) sbin_PROGRAMS += service shutdown -helper_PROGRAMS += killall5 runsvc waitfile +helper_PROGRAMS += killall5 waitfile diff --git a/cmd/runsvc.c b/cmd/runsvc.c deleted file mode 100644 index ab07b4a..0000000 --- a/cmd/runsvc.c +++ /dev/null @@ -1,195 +0,0 @@ -/* SPDX-License-Identifier: ISC */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "service.h" -#include "libcfg.h" -#include "config.h" - -#define ENVFILE ETCPATH "/initd.env" -#define PROCFDDIR "/proc/self/fd" - -static int setup_env(void) -{ - int status = -1; - ssize_t ret; - FILE *fp; - - clearenv(); - - fp = fopen(ENVFILE, "r"); - if (fp == NULL) { - perror(ENVFILE); - return -1; - } - - do { - char *line = NULL; - size_t n = 0; - - errno = 0; - ret = getline(&line, &n, fp); - - if (ret < 0) { - if (errno == 0) { - status = 0; - } else { - perror(ENVFILE); - } - } else if (ret > 0 && putenv(line) != 0) { - perror("putenv"); - ret = -1; - } - - free(line); - } while (ret >= 0); - - fclose(fp); - return status; -} - -static int close_all_files(void) -{ - struct dirent *ent; - DIR *dir; - int fd; - - dir = opendir(PROCFDDIR); - if (dir == NULL) { - perror(PROCFDDIR); - return -1; - } - - while ((ent = readdir(dir)) != NULL) { - if (!isdigit(ent->d_name[0])) - continue; - - fd = atoi(ent->d_name); - close(fd); - } - - closedir(dir); - return 0; -} - -static int setup_tty(const char *tty, bool truncate) -{ - int fd; - - if (tty == NULL) - return 0; - - fd = open(tty, O_RDWR); - if (fd < 0) { - perror(tty); - return -1; - } - - if (truncate) - ftruncate(fd, 0); - - setsid(); - - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - close(fd); - return 0; -} - -static __attribute__((noreturn)) void argv_exec(exec_t *e) -{ - char **argv = alloca(sizeof(char *) * (e->argc + 1)), *ptr; - int i; - - for (ptr = e->args, i = 0; i < e->argc; ++i, ptr += strlen(ptr) + 1) - argv[i] = ptr; - - argv[i] = NULL; - execvp(argv[0], argv); - perror(argv[0]); - exit(EXIT_FAILURE); -} - -static int run_sequentially(exec_t *list) -{ - pid_t ret, pid; - int status; - - for (; list != NULL; list = list->next) { - if (list->next == NULL) - argv_exec(list); - - pid = fork(); - - if (pid == 0) - argv_exec(list); - - if (pid == -1) { - perror("fork"); - return EXIT_FAILURE; - } - - do { - ret = waitpid(pid, &status, 0); - } while (ret != pid); - - if (!WIFEXITED(status)) - return EXIT_FAILURE; - - if (WEXITSTATUS(status) != EXIT_SUCCESS) - return WEXITSTATUS(status); - } - - return EXIT_SUCCESS; -} - -/*****************************************************************************/ - -int main(int argc, char **argv) -{ - service_t *svc = NULL; - int dirfd; - - if (argc != 3) { - fputs("usage: runsvc \n", stderr); - return EXIT_FAILURE; - } - - if (getppid() != 1) { - fputs("must be run by init!\n", stderr); - return EXIT_FAILURE; - } - - dirfd = open(argv[1], O_RDONLY | O_DIRECTORY); - if (dirfd < 0) { - perror(argv[1]); - return EXIT_FAILURE; - } - - svc = rdsvc(dirfd, argv[2], RDSVC_NO_FNAME | RDSVC_NO_DEPS); - close(dirfd); - if (svc == NULL) - return EXIT_FAILURE; - - if (setup_env()) - return EXIT_FAILURE; - - if (close_all_files()) - return EXIT_FAILURE; - - if (setup_tty(svc->ctty, (svc->flags & SVC_FLAG_TRUNCATE_OUT) != 0)) - return EXIT_FAILURE; - - return run_sequentially(svc->exec); -} diff --git a/initd/init.h b/initd/init.h index 9e8a1fd..c8b1c1d 100644 --- a/initd/init.h +++ b/initd/init.h @@ -24,7 +24,8 @@ #include "service.h" #include "config.h" -#define RUNSVCBIN SCRIPTDIR "/runsvc" +#define ENVFILE ETCPATH "/initd.env" +#define PROCFDDIR "/proc/self/fd" enum { STATUS_OK = 0, diff --git a/initd/runsvc.c b/initd/runsvc.c index 7c1dc36..c45f8ab 100644 --- a/initd/runsvc.c +++ b/initd/runsvc.c @@ -3,23 +3,154 @@ #include #include #include +#include #include +#include +#include +#include #include "init.h" +static int setup_env(void) +{ + int status = -1; + ssize_t ret; + FILE *fp; + + clearenv(); + + fp = fopen(ENVFILE, "r"); + if (fp == NULL) { + perror(ENVFILE); + return -1; + } + + do { + char *line = NULL; + size_t n = 0; + + errno = 0; + ret = getline(&line, &n, fp); + + if (ret < 0) { + if (errno == 0) { + status = 0; + } else { + perror(ENVFILE); + } + } else if (ret > 0 && putenv(line) != 0) { + perror("putenv"); + ret = -1; + } + + free(line); + } while (ret >= 0); + + fclose(fp); + return status; +} + +static int close_all_files(void) +{ + struct dirent *ent; + DIR *dir; + int fd; + + dir = opendir(PROCFDDIR); + if (dir == NULL) { + perror(PROCFDDIR); + return -1; + } + + while ((ent = readdir(dir)) != NULL) { + if (!isdigit(ent->d_name[0])) + continue; + + fd = atoi(ent->d_name); + close(fd); + } + + closedir(dir); + return 0; +} + +static int setup_tty(const char *tty, bool truncate) +{ + int fd; + + if (tty == NULL) + return 0; + + fd = open(tty, O_RDWR); + if (fd < 0) { + perror(tty); + return -1; + } + + if (truncate) + ftruncate(fd, 0); + + setsid(); + + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + close(fd); + return 0; +} + +static __attribute__((noreturn)) void argv_exec(exec_t *e) +{ + char **argv = alloca(sizeof(char *) * (e->argc + 1)), *ptr; + int i; + + for (ptr = e->args, i = 0; i < e->argc; ++i, ptr += strlen(ptr) + 1) + argv[i] = ptr; + + argv[i] = NULL; + execvp(argv[0], argv); + perror(argv[0]); + exit(EXIT_FAILURE); +} + +static int run_sequentially(exec_t *list) +{ + pid_t ret, pid; + int status; + + for (; list != NULL; list = list->next) { + if (list->next == NULL) + argv_exec(list); + + pid = fork(); + + if (pid == 0) + argv_exec(list); + + if (pid == -1) { + perror("fork"); + return EXIT_FAILURE; + } + + do { + ret = waitpid(pid, &status, 0); + } while (ret != pid); + + if (!WIFEXITED(status)) + return EXIT_FAILURE; + + if (WEXITSTATUS(status) != EXIT_SUCCESS) + return WEXITSTATUS(status); + } + + return EXIT_SUCCESS; +} + pid_t runsvc(service_t *svc) { - char *argv[4], *envp[1]; sigset_t mask; pid_t pid; - argv[0] = (char *)RUNSVCBIN; - argv[1] = (char *)SVCDIR; - argv[2] = svc->fname; - argv[3] = NULL; - - envp[0] = NULL; - pid = fork(); if (pid == -1) @@ -29,9 +160,18 @@ pid_t runsvc(service_t *svc) sigemptyset(&mask); sigprocmask(SIG_SETMASK, &mask, NULL); - execve(argv[0], argv, envp); - perror(argv[0]); - exit(EXIT_FAILURE); + if (setup_env()) + exit(EXIT_FAILURE); + + if (close_all_files()) + exit(EXIT_FAILURE); + + if (setup_tty(svc->ctty, + (svc->flags & SVC_FLAG_TRUNCATE_OUT) != 0)) { + exit(EXIT_FAILURE); + } + + exit(run_sequentially(svc->exec)); } return pid; diff --git a/initd/supervisor.c b/initd/supervisor.c index 8ac69af..8d53416 100644 --- a/initd/supervisor.c +++ b/initd/supervisor.c @@ -175,7 +175,7 @@ void supervisor_init(void) { int status = STATUS_OK; - if (svcscan(SVCDIR, &cfg, RDSVC_NO_EXEC | RDSVC_NO_CTTY)) + if (svcscan(SVCDIR, &cfg, 0)) status = STATUS_FAIL; target = TGT_BOOT; @@ -191,7 +191,7 @@ void supervisor_reload_config(void) service_t *svc; int i; - if (svcscan(SVCDIR, &newcfg, RDSVC_NO_EXEC | RDSVC_NO_CTTY)) + if (svcscan(SVCDIR, &newcfg, 0)) return; for (i = 0; i < TGT_MAX; ++i) {