sighandlers.c
175 lines
| 3.7 KiB
| text/x-c
|
CLexer
Yuya Nishihara
|
r40154 | /* | ||
* Signal handlers for cHg | ||||
* | ||||
* Copyright 2011, 2018 Yuya Nishihara <yuya@tcha.org> | ||||
* | ||||
* This software may be used and distributed according to the terms of the | ||||
* GNU General Public License version 2 or any later version. | ||||
*/ | ||||
#include <assert.h> | ||||
#include <errno.h> | ||||
#include <signal.h> | ||||
#include <string.h> | ||||
#include <unistd.h> | ||||
static pid_t peerpgid = 0; | ||||
static pid_t peerpid = 0; | ||||
static void forwardsignal(int sig) | ||||
{ | ||||
assert(peerpid > 0); | ||||
(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; | ||||
(void)kill(killpid, sig); | ||||
} | ||||
static void handlestopsignal(int sig) | ||||
{ | ||||
sigset_t unblockset, oldset; | ||||
struct sigaction sa, oldsa; | ||||
Augie Fackler
|
r41367 | if (sigemptyset(&unblockset) < 0) { | ||
Yuya Nishihara
|
r40154 | return; | ||
Augie Fackler
|
r41367 | } | ||
if (sigaddset(&unblockset, sig) < 0) { | ||||
Yuya Nishihara
|
r40154 | return; | ||
Augie Fackler
|
r41367 | } | ||
Yuya Nishihara
|
r40154 | memset(&sa, 0, sizeof(sa)); | ||
sa.sa_handler = SIG_DFL; | ||||
sa.sa_flags = SA_RESTART; | ||||
Augie Fackler
|
r41367 | if (sigemptyset(&sa.sa_mask) < 0) { | ||
Yuya Nishihara
|
r40154 | return; | ||
Augie Fackler
|
r41367 | } | ||
Yuya Nishihara
|
r40154 | |||
forwardsignal(sig); | ||||
Augie Fackler
|
r41367 | if (raise(sig) < 0) { /* resend to self */ | ||
Yuya Nishihara
|
r40154 | return; | ||
Augie Fackler
|
r41367 | } | ||
if (sigaction(sig, &sa, &oldsa) < 0) { | ||||
Yuya Nishihara
|
r40154 | return; | ||
Augie Fackler
|
r41367 | } | ||
if (sigprocmask(SIG_UNBLOCK, &unblockset, &oldset) < 0) { | ||||
Yuya Nishihara
|
r40154 | return; | ||
Augie Fackler
|
r41367 | } | ||
Yuya Nishihara
|
r40154 | /* resent signal will be handled before sigprocmask() returns */ | ||
Augie Fackler
|
r41367 | if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0) { | ||
Yuya Nishihara
|
r40154 | return; | ||
Augie Fackler
|
r41367 | } | ||
if (sigaction(sig, &oldsa, NULL) < 0) { | ||||
Yuya Nishihara
|
r40154 | return; | ||
Augie Fackler
|
r41367 | } | ||
Yuya Nishihara
|
r40154 | } | ||
/* | ||||
* 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) { | ||||
errno = EINVAL; | ||||
return -1; | ||||
} | ||||
peerpid = pid; | ||||
peerpgid = (pgid <= 1 ? 0 : pgid); | ||||
struct sigaction sa; | ||||
memset(&sa, 0, sizeof(sa)); | ||||
/* deadly signals meant to be sent to a process group: | ||||
* - SIGHUP: usually generated by the kernel, when termination of a | ||||
* process causes that process group to become orphaned | ||||
* - SIGINT: usually generated by the terminal */ | ||||
sa.sa_handler = forwardsignaltogroup; | ||||
sa.sa_flags = SA_RESTART; | ||||
Augie Fackler
|
r41367 | if (sigemptyset(&sa.sa_mask) < 0) { | ||
return -1; | ||||
} | ||||
if (sigaction(SIGHUP, &sa, NULL) < 0) { | ||||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
if (sigaction(SIGINT, &sa, NULL) < 0) { | ||||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
Yuya Nishihara
|
r40154 | |||
/* terminate frontend by double SIGTERM in case of server freeze */ | ||||
sa.sa_handler = forwardsignal; | ||||
sa.sa_flags |= SA_RESETHAND; | ||||
Augie Fackler
|
r41367 | if (sigaction(SIGTERM, &sa, NULL) < 0) { | ||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
Yuya Nishihara
|
r40154 | |||
/* notify the worker about window resize events */ | ||||
sa.sa_flags = SA_RESTART; | ||||
Augie Fackler
|
r41367 | if (sigaction(SIGWINCH, &sa, NULL) < 0) { | ||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
Yuya Nishihara
|
r40154 | /* forward user-defined signals */ | ||
Augie Fackler
|
r41367 | if (sigaction(SIGUSR1, &sa, NULL) < 0) { | ||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
if (sigaction(SIGUSR2, &sa, NULL) < 0) { | ||||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
Yuya Nishihara
|
r40154 | /* propagate job control requests to worker */ | ||
sa.sa_handler = forwardsignal; | ||||
sa.sa_flags = SA_RESTART; | ||||
Augie Fackler
|
r41367 | if (sigaction(SIGCONT, &sa, NULL) < 0) { | ||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
Yuya Nishihara
|
r40154 | sa.sa_handler = handlestopsignal; | ||
sa.sa_flags = SA_RESTART; | ||||
Augie Fackler
|
r41367 | if (sigaction(SIGTSTP, &sa, NULL) < 0) { | ||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
Yuya Nishihara
|
r40154 | |||
return 0; | ||||
} | ||||
/* | ||||
* 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; | ||||
Augie Fackler
|
r41367 | if (sigemptyset(&sa.sa_mask) < 0) { | ||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
Yuya Nishihara
|
r40154 | |||
Augie Fackler
|
r41367 | if (sigaction(SIGHUP, &sa, NULL) < 0) { | ||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
if (sigaction(SIGTERM, &sa, NULL) < 0) { | ||||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
if (sigaction(SIGWINCH, &sa, NULL) < 0) { | ||||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
if (sigaction(SIGCONT, &sa, NULL) < 0) { | ||||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
if (sigaction(SIGTSTP, &sa, NULL) < 0) { | ||||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
Yuya Nishihara
|
r40154 | |||
/* ignore Ctrl+C while shutting down to make pager exits cleanly */ | ||||
sa.sa_handler = SIG_IGN; | ||||
Augie Fackler
|
r41367 | if (sigaction(SIGINT, &sa, NULL) < 0) { | ||
Yuya Nishihara
|
r40154 | return -1; | ||
Augie Fackler
|
r41367 | } | ||
Yuya Nishihara
|
r40154 | |||
peerpid = 0; | ||||
return 0; | ||||
} | ||||