diff --git a/.gitignore b/.gitignore index a0967e2..6c13aba 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ service reboot shutdown killall5 +runsvc services/sigkill services/sigterm diff --git a/cmd/Makemodule.am b/cmd/Makemodule.am index f0ae3f9..83d6174 100644 --- a/cmd/Makemodule.am +++ b/cmd/Makemodule.am @@ -10,6 +10,12 @@ reboot_CFLAGS = $(AM_CFLAGS) reboot_LDFLAGS = $(AM_LDFLAGS) reboot_LDADD = libinit.a +runsvc_SOURCES = cmd/runsvc/runsvc.c cmd/runsvc/env.c cmd/runsvc/runsvc.h +runsvc_CPPFLAGS = $(AM_CPPFLAGS) +runsvc_CFLAGS = $(AM_CFLAGS) +runsvc_LDFLAGS = $(AM_LDFLAGS) +runsvc_LDADD = libinit.a + killall5_SOURCES = cmd/killall5.c killall5_CPPFLAGS = $(AM_CPPFLAGS) killall5_CFLAGS = $(AM_CFLAGS) @@ -29,4 +35,4 @@ service_LDADD = libinit.a EXTRA_DIST += $(SRVHEADERS) sbin_PROGRAMS += service reboot shutdown -helper_PROGRAMS += killall5 +helper_PROGRAMS += killall5 runsvc diff --git a/initd/env.c b/cmd/runsvc/env.c similarity index 95% rename from initd/env.c rename to cmd/runsvc/env.c index c6a9e65..4fe2368 100644 --- a/initd/env.c +++ b/cmd/runsvc/env.c @@ -15,14 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include -#include -#include -#include -#include - -#include "init.h" -#include "util.h" +#include "runsvc.h" struct entry { struct entry *next; diff --git a/initd/runlst.c b/cmd/runsvc/runsvc.c similarity index 63% rename from initd/runlst.c rename to cmd/runsvc/runsvc.c index 83823f9..a8e5bb2 100644 --- a/initd/runlst.c +++ b/cmd/runsvc/runsvc.c @@ -15,21 +15,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include -#include -#include -#include -#include -#include +#include "runsvc.h" -#include "init.h" - -static int child_setup(const char *ctty) +static int setup_tty(const char *ctty) { int fd; - sigreset(); - if (ctty != NULL) { fd = open(ctty, O_RDWR); if (fd < 0) { @@ -52,6 +43,8 @@ static int child_setup(const char *ctty) return 0; } +/*****************************************************************************/ + static NORETURN void argv_exec(exec_t *e) { char **argv = alloca(e->argc + 1), *ptr; @@ -66,7 +59,7 @@ static NORETURN void argv_exec(exec_t *e) exit(EXIT_FAILURE); } -int runlst_wait(exec_t *list, const char *ctty) +static int runlst_wait(exec_t *list) { pid_t ret, pid; int status; @@ -74,11 +67,8 @@ int runlst_wait(exec_t *list, const char *ctty) for (; list != NULL; list = list->next) { pid = fork(); - if (pid == 0) { - if (child_setup(ctty)) - exit(EXIT_FAILURE); + if (pid == 0) argv_exec(list); - } if (pid == -1) { perror("fork"); @@ -99,22 +89,50 @@ int runlst_wait(exec_t *list, const char *ctty) return EXIT_SUCCESS; } -pid_t runlst(exec_t *list, const char *ctty) +/*****************************************************************************/ + +int main(int argc, char **argv) { - pid_t pid = fork(); + int dirfd, ret = EXIT_FAILURE; + service_t *svc = NULL; - if (pid == 0) { - if (child_setup(ctty)) - exit(EXIT_FAILURE); - - if (list->next != NULL) - exit(runlst_wait(list, NULL)); - - argv_exec(list); + if (argc != 3) { + fputs("usage: runsvc \n", stderr); + goto out; } - if (pid == -1) - perror("fork"); + if (getppid() != 1) { + fputs("must be run by init!\n", stderr); + goto out; + } - return pid; + dirfd = open(argv[1], O_RDONLY | O_DIRECTORY); + if (dirfd < 0) { + perror(argv[1]); + goto out; + } + + svc = rdsvc(dirfd, argv[2], RDSVC_NO_FNAME | RDSVC_NO_DEPS); + close(dirfd); + if (svc == NULL) + goto out; + + if (svc->exec == NULL) { + ret = EXIT_SUCCESS; + goto out; + } + + if (initenv()) + goto out; + + if (setup_tty(svc->ctty)) + goto out; + + if (svc->exec->next == NULL) + argv_exec(svc->exec); + + ret = runlst_wait(svc->exec); +out: + delsvc(svc); + return ret; } diff --git a/cmd/runsvc/runsvc.h b/cmd/runsvc/runsvc.h new file mode 100644 index 0000000..15785d3 --- /dev/null +++ b/cmd/runsvc/runsvc.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * Copyright (C) 2018 - David Oberhollenzer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef RUNSVC_H +#define RUNSVC_H + +#include +#include +#include +#include +#include +#include +#include + +#include "service.h" +#include "util.h" + +#define ENVFILE ETCPATH "/initd.env" + +int initenv(void); + +#endif /* RUNSVC_H */ diff --git a/initd/Makemodule.am b/initd/Makemodule.am index 67515cc..f188c80 100644 --- a/initd/Makemodule.am +++ b/initd/Makemodule.am @@ -1,5 +1,5 @@ -init_SOURCES = initd/main.c initd/runlst.c initd/init.h initd/signal_linux.c -init_SOURCES += initd/status.c initd/mksock.c initd/svclist.c initd/env.c +init_SOURCES = initd/main.c initd/init.h initd/signal_linux.c initd/runsvc.c +init_SOURCES += initd/status.c initd/mksock.c initd/svclist.c init_CPPFLAGS = $(AM_CPPFLAGS) init_CFLAGS = $(AM_CFLAGS) init_LDFLAGS = $(AM_LDFLAGS) diff --git a/initd/init.h b/initd/init.h index 3510073..d07f310 100644 --- a/initd/init.h +++ b/initd/init.h @@ -27,7 +27,7 @@ #include "telinit.h" #include "util.h" -#define ENVFILE ETCPATH "/initd.env" +#define RUNSVCBIN SCRIPTDIR "/runsvc" enum { STATUS_OK = 0, @@ -36,35 +36,20 @@ enum { STATUS_STARTED, }; -/********** runlst.c **********/ +/********** runsvc.c **********/ /* - Plow through an array of strings and execute each one, i.e. do - a fork() and exec(). + Invoke the runsvc command to execute the comands of a service. - In the parent process, wait() until the child is done before - continuing through the list. - - If ctty is not NULL, open it and redirect all I/O of the child - process to that file. - - If everyhing works, the function returns EXIT_SUCCESS. If one child - does not exit with EXIT_SUCCESS, processing of the list is aborted - and the function returns the exit status of the failed process. + Returns the pid of the child process containing the runsvc instance. */ -int runlst_wait(exec_t *list, const char *ctty); +pid_t runsvc(service_t *svc); /* - Does basically the same as runlst_wait, but asynchronously. - - A child process is created that calls runlst_wait exits with the - result of runlst_wait. In the parent process, the function returns - immediately with the PID of the child process. - - Alternatively, if num is 1, the child process directly exec()s the - given command. + Start a service using runsvc, but wait until the child process + terminats and return its exit status. */ -pid_t runlst(exec_t *list, const char *ctty); +int runsvc_wait(service_t *svc); /********** status.c **********/ @@ -111,14 +96,6 @@ void svclist_add(service_t *svc); */ service_t *svclist_remove(pid_t pid); -/********** env.c **********/ - -/* - Read /etc/initd.env (actually ENVFILE defined above) - and setup environment variables for init. -*/ -int initenv(void); - /********** signal_.c **********/ /* diff --git a/initd/main.c b/initd/main.c index a1d6906..8adbe2f 100644 --- a/initd/main.c +++ b/initd/main.c @@ -48,7 +48,7 @@ static void handle_exited(service_t *svc) } } - svc->pid = runlst(svc->exec, svc->ctty); + svc->pid = runsvc(svc); if (svc->pid == -1) { print_status(svc->desc, STATUS_FAIL, false); break; @@ -104,16 +104,10 @@ static void start_runlevel(int level) svc = cfg.targets[level]; cfg.targets[level] = svc->next; - if (svc->exec == NULL) { - print_status(svc->desc, STATUS_OK, false); - delsvc(svc); - continue; - } - if (svc->type == SVC_WAIT) { print_status(svc->desc, STATUS_WAIT, false); - status = runlst_wait(svc->exec, svc->ctty); + status = runsvc_wait(svc); print_status(svc->desc, status == EXIT_SUCCESS ? @@ -121,7 +115,7 @@ static void start_runlevel(int level) true); delsvc(svc); } else { - svc->pid = runlst(svc->exec, svc->ctty); + svc->pid = runsvc(svc); if (svc->pid == -1) { print_status(svc->desc, STATUS_FAIL, false); delsvc(svc); @@ -193,7 +187,7 @@ int main(void) return EXIT_FAILURE; } - if (svcscan(SVCDIR, &cfg, 0)) { + if (svcscan(SVCDIR, &cfg, RDSVC_NO_EXEC | RDSVC_NO_CTTY)) { fputs("Error reading service list from " SVCDIR "\n" "Trying to continue anyway\n", stderr); } diff --git a/initd/runsvc.c b/initd/runsvc.c new file mode 100644 index 0000000..aba83b1 --- /dev/null +++ b/initd/runsvc.c @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * Copyright (C) 2018 - David Oberhollenzer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include +#include + +#include "init.h" + +pid_t runsvc(service_t *svc) +{ + char *argv[4], *envp[1]; + 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) + perror("fork"); + + if (pid == 0) { + sigreset(); + execve(argv[0], argv, envp); + perror(argv[0]); + exit(EXIT_FAILURE); + } + + return pid; +} + +int runsvc_wait(service_t *svc) +{ + pid_t ret, pid = runsvc(svc); + int status; + + if (pid == -1) + return EXIT_FAILURE; + + do { + ret = waitpid(pid, &status, 0); + } while (ret != pid); + + return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE; +} diff --git a/services/sysinit b/services/sysinit index cb5eb6b..0429dfe 100644 --- a/services/sysinit +++ b/services/sysinit @@ -1,3 +1,3 @@ description basic system initialization -type once +type wait target boot diff --git a/services/vfs b/services/vfs index 27cc9e9..471d8c1 100644 --- a/services/vfs +++ b/services/vfs @@ -1,3 +1,3 @@ description VFS setup done -type once +type wait target boot