/* SPDX-License-Identifier: ISC */ #include "init.h" static void respawn(svc_run_data_t *rt) { if (rt->svc->rspwn_limit > 0) { rt->rspwn_count += 1; if (rt->rspwn_count >= rt->svc->rspwn_limit) goto fail; } rt->pid = runsvc(rt->svc); if (rt->pid == -1) goto fail; rt->state = STATE_RUNNING; return; fail: rt->state = STATE_FAILED; print_status(rt); return; } static svc_run_data_t *wait_for_process(void) { svc_run_data_t *rt; int status; pid_t pid; do { pid = wait(&status); if (pid == -1) { if (errno == EINTR) return NULL; if (errno == ECHILD) exit(EXIT_FAILURE); } rt = config_rt_data_by_pid(pid); } while (rt == NULL); rt->status = WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE; rt->pid = -1; return rt; } static void handle_exited(svc_run_data_t *rt) { if (rt->svc->type == SVC_RESPAWN) { if (config_should_respawn()) respawn(rt); } else { if (rt->status == EXIT_SUCCESS) { rt->state = STATE_COMPLETED; } else { rt->state = STATE_FAILED; } 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 signo) { switch (signo) { case SIGTERM: config_set_target(TGT_SHUTDOWN); break; case SIGINT: config_set_target(TGT_REBOOT); break; case SIGHUP: break; case SIGUSR1: break; } } int main(void) { svc_run_data_t *rt; struct sigaction act; if (config_load()) return EXIT_FAILURE; memset(&act, 0, sizeof(act)); act.sa_handler = handle_signal; sigaction(SIGTERM, &act, NULL); sigaction(SIGINT, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGUSR1, &act, NULL); if (reboot(LINUX_REBOOT_CMD_CAD_OFF)) perror("cannot disable CTRL+ALT+DEL"); for (;;) { rt = config_dequeue(); if (rt == NULL) { rt = wait_for_process(); if (rt == NULL) continue; handle_exited(rt); } else { start_service(rt); } } return EXIT_SUCCESS; }