diff --git a/rust/chg/build.rs b/rust/chg/build.rs --- a/rust/chg/build.rs +++ b/rust/chg/build.rs @@ -4,5 +4,6 @@ fn main() { cc::Build::new() .warnings(true) .file("src/sendfds.c") + .file("src/sighandlers.c") .compile("procutil"); } diff --git a/contrib/chg/procutil.c b/rust/chg/src/sighandlers.c copy from contrib/chg/procutil.c copy to rust/chg/src/sighandlers.c --- a/contrib/chg/procutil.c +++ b/rust/chg/src/sighandlers.c @@ -1,7 +1,7 @@ /* - * Utilities about process handling - signal and subprocess (ex. pager) + * Signal handlers for cHg * - * Copyright (c) 2011 Yuya Nishihara + * Copyright 2011, 2018 Yuya Nishihara * * This software may be used and distributed according to the terms of the * GNU General Public License version 2 or any later version. @@ -10,13 +10,15 @@ #include #include #include -#include #include #include #include -#include "procutil.h" -#include "util.h" +#ifdef __GNUC__ +#define UNUSED_ __attribute__((unused)) +#else +#define UNUSED_ +#endif static pid_t pagerpid = 0; static pid_t peerpgid = 0; @@ -25,18 +27,14 @@ static pid_t peerpid = 0; static void forwardsignal(int sig) { assert(peerpid > 0); - if (kill(peerpid, sig) < 0) - abortmsgerrno("cannot kill %d", peerpid); - debugmsg("forward signal %d", sig); + (void)kill(peerpid, sig); } static void forwardsignaltogroup(int sig) { /* prefer kill(-pgid, sig), fallback to pid if pgid is invalid */ pid_t killpid = peerpgid > 1 ? -peerpgid : peerpid; - if (kill(killpid, sig) < 0) - abortmsgerrno("cannot kill %d", killpid); - debugmsg("forward signal %d to %d", sig, killpid); + (void)kill(killpid, sig); } static void handlestopsignal(int sig) @@ -44,31 +42,27 @@ static void handlestopsignal(int sig) sigset_t unblockset, oldset; struct sigaction sa, oldsa; if (sigemptyset(&unblockset) < 0) - goto error; + return; if (sigaddset(&unblockset, sig) < 0) - goto error; + return; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_DFL; sa.sa_flags = SA_RESTART; if (sigemptyset(&sa.sa_mask) < 0) - goto error; + return; forwardsignal(sig); if (raise(sig) < 0) /* resend to self */ - goto error; + return; if (sigaction(sig, &sa, &oldsa) < 0) - goto error; + return; if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0) - goto error; + return; /* resent signal will be handled before sigprocmask() returns */ if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0) - goto error; + return; if (sigaction(sig, &oldsa, NULL) < 0) - goto error; - return; - -error: - abortmsgerrno("failed to handle stop signal"); + return; } static void handlechildsignal(int sig UNUSED_) @@ -82,10 +76,18 @@ static void handlechildsignal(int sig UN kill(peerpid, SIGPIPE); } -void setupsignalhandler(pid_t pid, pid_t pgid) +/* + * Installs signal handlers. + * + * Returns 0 on success, -1 on error and errno is set appropriately. + * Installed handlers wouldn't be cleaned up on error. + */ +int setupsignalhandler(pid_t pid, pid_t pgid) { - if (pid <= 0) - return; + if (pid <= 0) { + errno = EINVAL; + return -1; + } peerpid = pid; peerpgid = (pgid <= 1 ? 0 : pgid); @@ -99,139 +101,77 @@ void setupsignalhandler(pid_t pid, pid_t sa.sa_handler = forwardsignaltogroup; sa.sa_flags = SA_RESTART; if (sigemptyset(&sa.sa_mask) < 0) - goto error; + return -1; if (sigaction(SIGHUP, &sa, NULL) < 0) - goto error; + return -1; if (sigaction(SIGINT, &sa, NULL) < 0) - goto error; + return -1; /* terminate frontend by double SIGTERM in case of server freeze */ sa.sa_handler = forwardsignal; sa.sa_flags |= SA_RESETHAND; if (sigaction(SIGTERM, &sa, NULL) < 0) - goto error; + return -1; /* notify the worker about window resize events */ sa.sa_flags = SA_RESTART; if (sigaction(SIGWINCH, &sa, NULL) < 0) - goto error; + return -1; /* forward user-defined signals */ if (sigaction(SIGUSR1, &sa, NULL) < 0) - goto error; + return -1; if (sigaction(SIGUSR2, &sa, NULL) < 0) - goto error; + return -1; /* propagate job control requests to worker */ sa.sa_handler = forwardsignal; sa.sa_flags = SA_RESTART; if (sigaction(SIGCONT, &sa, NULL) < 0) - goto error; + return -1; sa.sa_handler = handlestopsignal; sa.sa_flags = SA_RESTART; if (sigaction(SIGTSTP, &sa, NULL) < 0) - goto error; + return -1; /* get notified when pager exits */ sa.sa_handler = handlechildsignal; sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) < 0) - goto error; + return -1; - return; - -error: - abortmsgerrno("failed to set up signal handlers"); + return 0; } -void restoresignalhandler(void) +/* + * Restores signal handlers to the default, and masks SIGINT. + * + * Returns 0 on success, -1 on error and errno is set appropriately. + */ +int restoresignalhandler(void) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_DFL; sa.sa_flags = SA_RESTART; if (sigemptyset(&sa.sa_mask) < 0) - goto error; + return -1; if (sigaction(SIGHUP, &sa, NULL) < 0) - goto error; + return -1; if (sigaction(SIGTERM, &sa, NULL) < 0) - goto error; + return -1; if (sigaction(SIGWINCH, &sa, NULL) < 0) - goto error; + return -1; if (sigaction(SIGCONT, &sa, NULL) < 0) - goto error; + return -1; if (sigaction(SIGTSTP, &sa, NULL) < 0) - goto error; + return -1; if (sigaction(SIGCHLD, &sa, NULL) < 0) - goto error; + return -1; /* ignore Ctrl+C while shutting down to make pager exits cleanly */ sa.sa_handler = SIG_IGN; if (sigaction(SIGINT, &sa, NULL) < 0) - goto error; + return -1; peerpid = 0; - return; - -error: - abortmsgerrno("failed to restore signal handlers"); -} - -/* This implementation is based on hgext/pager.py (post 369741ef7253) - * Return 0 if pager is not started, or pid of the pager */ -pid_t setuppager(const char *pagercmd, const char *envp[]) -{ - assert(pagerpid == 0); - if (!pagercmd) - return 0; - - int pipefds[2]; - if (pipe(pipefds) < 0) - return 0; - pid_t pid = fork(); - if (pid < 0) - goto error; - if (pid > 0) { - close(pipefds[0]); - if (dup2(pipefds[1], fileno(stdout)) < 0) - goto error; - if (isatty(fileno(stderr))) { - if (dup2(pipefds[1], fileno(stderr)) < 0) - goto error; - } - close(pipefds[1]); - pagerpid = pid; - return pid; - } else { - dup2(pipefds[0], fileno(stdin)); - close(pipefds[0]); - close(pipefds[1]); - - int r = - execle("/bin/sh", "/bin/sh", "-c", pagercmd, NULL, envp); - if (r < 0) { - abortmsgerrno("cannot start pager '%s'", pagercmd); - } - return 0; - } - -error: - close(pipefds[0]); - close(pipefds[1]); - abortmsgerrno("failed to prepare pager"); return 0; } - -void waitpager(void) -{ - if (pagerpid == 0) - return; - - /* close output streams to notify the pager its input ends */ - fclose(stdout); - fclose(stderr); - while (1) { - pid_t ret = waitpid(pagerpid, NULL, 0); - if (ret == -1 && errno == EINTR) - continue; - break; - } -}