diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-05-15 08:50:08 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-05-15 09:05:31 +0300 |
commit | b5f4388a2da1b94ce8c8e45a990fd51b2f52dae4 (patch) | |
tree | 28bcf8cf313309636357c470faed4456837db7c8 /src/com_start.c | |
download | genrc-b5f4388a2da1b94ce8c8e45a990fd51b2f52dae4.tar.gz genrc-b5f4388a2da1b94ce8c8e45a990fd51b2f52dae4.tar.bz2 |
Initial commit
Diffstat (limited to 'src/com_start.c')
-rw-r--r-- | src/com_start.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/com_start.c b/src/com_start.c new file mode 100644 index 0000000..73bb2ec --- /dev/null +++ b/src/com_start.c @@ -0,0 +1,121 @@ +#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 ((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; +} |