Mercurial > projects > pwm
view proc.c @ 21:ee4d36c85287
Make EOF in interactive mode equivalent to the q command
author | Guido Berhoerster <guido+pwm@berhoerster.name> |
---|---|
date | Wed, 06 Sep 2017 16:41:58 +0200 |
parents | 5c6155c8e9b6 |
children |
line wrap: on
line source
/* * Copyright (C) 2017 Guido Berhoerster <guido+pwm@berhoerster.name> * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "compat.h" #ifdef HAVE_ERR_H #include <err.h> #endif /* HAVE_ERR_H */ #include <errno.h> #include <setjmp.h> #include <signal.h> #include <string.h> #include <sys/wait.h> #include <unistd.h> #include "util.h" #include "proc.h" #include "pwm.h" #define PIPE_R 0 #define PIPE_W 1 static sigjmp_buf signal_env; static void signal_handler(int signal_no) { siglongjmp(signal_env, signal_no); } enum io_status proc_open(struct proc *proc, const char *command, const char *type) { int pipe_fds[2]; pid_t pid; if ((strlen(type) != 1) || ((*type != 'r') && (*type != 'w'))) { return (IO_ERROR); } if (pipe(pipe_fds) < 0) { return (IO_ERROR); } switch (pid = fork()) { case -1: return (IO_ERROR); case 0: if (*type == 'r') { close(pipe_fds[PIPE_R]); dup2(pipe_fds[PIPE_W], STDOUT_FILENO); } else { close(pipe_fds[PIPE_W]); dup2(pipe_fds[PIPE_R], STDIN_FILENO); } closefrom(STDERR_FILENO + 1); execlp("sh", "sh", "-c", command, (char *)0); err(1, "execlp"); default: if (*type == 'r') { close(pipe_fds[PIPE_W]); proc->fd = pipe_fds[PIPE_R]; } else { close(pipe_fds[PIPE_R]); proc->fd = pipe_fds[PIPE_W]; } proc->pid = pid; return (IO_OK); } } enum io_status proc_close(struct proc *proc) { struct sigaction action; struct sigaction oaction; int signal_no = 0; pid_t wpid; int status; close(proc->fd); /* install signal handlers */ action.sa_handler = signal_handler; action.sa_flags = 0; sigemptyset(&action.sa_mask); sigaddset(&action.sa_mask, SIGINT); sigaddset(&action.sa_mask, SIGTERM); sigaddset(&action.sa_mask, SIGHUP); sigaddset(&action.sa_mask, SIGQUIT); if ((sigaction(SIGINT, &action, &oaction) != 0) || (sigaction(SIGTERM, &action, &oaction) != 0) || (sigaction(SIGHUP, &action, &oaction) != 0) || (sigaction(SIGQUIT, &action, &oaction) != 0)) { err(1, "sigaction"); } if ((signal_no = sigsetjmp(signal_env, 1)) != 0) { /* * signal received, signal mask has been restored, send SIGTERM * to the child process, wait 500 ms and send a SIGKILL if the * child still exists */ kill(proc->pid, SIGTERM); nanosleep(&(struct timespec){ .tv_nsec = 500 * 1000 * 1000 }, NULL); do { wpid = waitpid(proc->pid, &status, WNOHANG); } while ((wpid == -1) && (errno == EINTR)); if (wpid == proc->pid) { goto out; } kill(proc->pid, SIGKILL); do { wpid = waitpid(proc->pid, &status, 0); } while ((wpid == -1) && (errno == EINTR)); goto out; } pwm_unblock_signals(); do { wpid = waitpid(proc->pid, &status, 0); } while ((wpid == -1) && (errno == EINTR)); pwm_block_signals(); out: /* restore signal handlers */ if ((sigaction(SIGINT, &oaction, NULL) != 0) || (sigaction(SIGTERM, &oaction, NULL) != 0) || (sigaction(SIGHUP, &oaction, NULL) != 0) || (sigaction(SIGQUIT, &oaction, NULL) != 0)) { err(1, "sigaction"); } proc->fd = -1; proc->pid = (pid_t)-1; return ((signal_no == 0) ? IO_OK : IO_SIGNAL); }