/* SPDX-License-Identifier: ISC */ #include "init.h" static void handle_exited(svc_run_data_t *rt, int status) { rt->pid = -1; rt->status = WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE; rt->state = (rt->status == EXIT_SUCCESS) ? STATE_COMPLETED : STATE_FAILED; if (rt->svc->type == SVC_RESPAWN && config_should_respawn()) { rt->state = STATE_FAILED; if (rt->svc->rspwn_limit > 0) { rt->rspwn_count += 1; if (rt->rspwn_count >= rt->svc->rspwn_limit) goto out_print; } rt->pid = runsvc(rt->svc); if (rt->pid == -1) goto out_print; rt->state = STATE_RUNNING; return; } out_print: print_status(rt); } static void start_service(svc_run_data_t *rt) { if (rt->svc->flags & SVC_FLAG_HAS_EXEC) { rt->pid = runsvc(rt->svc); if (rt->pid == -1) { rt->state = STATE_FAILED; } else { rt->state = STATE_RUNNING; if (rt->svc->type == SVC_WAIT) config_set_waiting(rt); } } else { rt->status = EXIT_SUCCESS; rt->state = STATE_COMPLETED; } print_status(rt); } static void handle_signal(int fd) { struct signalfd_siginfo info; svc_run_data_t *rt; int status; pid_t pid; if (read(fd, &info, sizeof(info)) < (ssize_t)sizeof(info)) return; switch (info.ssi_signo) { case SIGTERM: config_set_target(TGT_SHUTDOWN); break; case SIGINT: config_set_target(TGT_REBOOT); break; case SIGCHLD: while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { rt = config_rt_data_by_pid(pid); if (rt != NULL) handle_exited(rt, status); } break; case SIGHUP: break; case SIGUSR1: break; } } int main(void) { struct epoll_event ev; svc_run_data_t *rt; int ret, sfd, epfd; sigset_t sigmask; cli(NULL); if (config_load()) return EXIT_FAILURE; epfd = epoll_create1(EPOLL_CLOEXEC); if (epfd < 0) { perror("epoll_create"); return EXIT_FAILURE; } sigemptyset(&sigmask); sigaddset(&sigmask, SIGTERM); sigaddset(&sigmask, SIGINT); sigaddset(&sigmask, SIGHUP); sigaddset(&sigmask, SIGUSR1); sigaddset(&sigmask, SIGCHLD); sfd = signalfd(-1, &sigmask, SFD_CLOEXEC); if (sfd < 0) { perror("signalfd"); return EXIT_FAILURE; } memset(&ev, 0, sizeof(ev)); ev.events = EPOLLIN; ev.data.fd = sfd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, sfd, &ev)) { perror("adding signalfd to epoll"); return EXIT_FAILURE; } if (reboot(LINUX_REBOOT_CMD_CAD_OFF)) perror("cannot disable CTRL+ALT+DEL"); for (;;) { while ((rt = config_dequeue()) != NULL) { start_service(rt); } ret = epoll_wait(epfd, &ev, 1, -1); if (ret == 0) continue; if (ret < 0) { perror("epoll wait"); return EXIT_FAILURE; } if (ev.data.fd == sfd) { handle_signal(sfd); } } return EXIT_SUCCESS; }