/* This file is part of genrc Copyryght (C) 2018 Sergey Poznyakoff License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. */ #include "genrc.h" void report_exec_error(int rc, char const *program) { if (WIFEXITED(rc)) { if (WEXITSTATUS(rc)) { genrc_error("%s exited with status %d", program, WEXITSTATUS(rc)); } } else if (WIFSIGNALED(rc)) { char const *coremsg = ""; #ifdef WCOREDUMP if (WCOREDUMP(rc)) coremsg = " (core dumped)"; #endif genrc_error("%s terminated on signal %d%s", program, WTERMSIG(rc), coremsg); } else if (WIFSTOPPED(rc)) { genrc_error("%s stopped on signal %d", program, WSTOPSIG(rc)); } else { genrc_error("%s terminated with unrecognized status: %d", program, rc); } } typedef void (*SIGHANDLER)(int); void sigchld(int sig) { } int timedwaitpid(pid_t pid, int *status) { struct timeval now, stoptime, ttw; int rc = -1; SIGHANDLER oldsig; oldsig = signal(SIGCHLD, sigchld); gettimeofday(&stoptime, NULL); stoptime.tv_sec += genrc_timeout; while (1) { pid_t p; p = waitpid(pid, status, WNOHANG); if (p == pid) { rc = 0; break; } if (p < 0 && errno != EINTR) { system_error(errno, "waitpid"); break; } gettimeofday(&now, NULL); if (timercmp(&now, &stoptime, >=)) break; timersub(&stoptime, &now, &ttw); if (select(0, NULL, NULL, NULL, &ttw) < 0) { if (errno != EINTR) { system_error(errno, "select"); break; } } } signal(SIGCHLD, oldsig); if (rc) { kill(pid, SIGKILL); } return rc; } int com_start(void) { pid_t pid; int status; PIDLIST pids; char *p; pidlist_init(&pids); if (get_pid_list(genrc_pid_closure, &pids) == 0) { int running = pids.pidc > 0; pidlist_free(&pids); if (running) { genrc_error("%s is already running", genrc_program); return 1; } } if (genrc_verbose) printf("Starting %s\n", genrc_program); if ((p = getenv("GENRC_SENTINEL")) && *p == '1') return sentinel(); pid = fork(); if (pid == -1) { system_error(errno, "fork"); return 1; } if (pid == 0) { char *argv[] = { SHELL, "-c", NULL, NULL }; argv[2] = genrc_command; execvp(SHELL, argv); system_error(errno, "failed to exec %s", genrc_program); exit(127); } if (timedwaitpid(pid, &status)) { genrc_error("timed out waiting for %s to return", genrc_program); return 1; } if (!(WIFEXITED(status) && WEXITSTATUS(status) == 0)) { report_exec_error(status, genrc_program); return 1; } return 0; }