| /* source: xiosignal.c */ |
| /* Copyright Gerhard Rieger and contributors (see file CHANGES) */ |
| /* Published under the GNU General Public License V.2, see file COPYING */ |
| |
| /* this file contains code for handling signals (except SIGCHLD) */ |
| |
| #include "config.h" |
| #include "xioconfig.h" /* what features are enabled */ |
| |
| #include "sysincludes.h" |
| |
| #include "mytypes.h" |
| #include "compat.h" |
| #include "error.h" |
| |
| #include "sycls.h" |
| |
| |
| #define SOCAT_MAXPIDS 4 |
| |
| struct socat_sig_desc { |
| int sig_use; |
| pid_t sig_pids[SOCAT_MAXPIDS]; |
| } ; |
| |
| #if 0 |
| size_t socat_sigint_use; /* how many pids are set in following array */ |
| static pid_t socat_sigint_pids[SOCAT_MAXPIDS]; |
| size_t socat_sigquit_use; /* how many pids are set in following array */ |
| static pid_t socat_sigquit_pids[SOCAT_MAXPIDS]; |
| #else |
| static struct socat_sig_desc socat_sighup; |
| static struct socat_sig_desc socat_sigint; |
| static struct socat_sig_desc socat_sigquit; |
| #endif |
| |
| |
| /* is async-signal-safe */ |
| static struct socat_sig_desc *socat_get_sig_desc(int signum) { |
| struct socat_sig_desc *sigdesc; |
| switch (signum) { |
| case SIGHUP: sigdesc = &socat_sighup; break; |
| case SIGINT: sigdesc = &socat_sigint; break; |
| case SIGQUIT: sigdesc = &socat_sigquit; break; |
| default: sigdesc = NULL; break; |
| } |
| return sigdesc; |
| } |
| |
| /* a signal handler that possibly passes the signal to sub processes */ |
| void socatsignalpass(int sig) { |
| int i; |
| struct socat_sig_desc *sigdesc; |
| int _errno; |
| |
| _errno = errno; |
| diag_in_handler = 1; |
| Notice1("socatsignalpass(sig=%d)", sig); |
| if ((sigdesc = socat_get_sig_desc(sig)) == NULL) { /* is async-signal-safe */ |
| diag_in_handler = 0; |
| errno = _errno; |
| return; |
| } |
| |
| { /*debug*/ |
| int n = 0; |
| for (i=0; i<sigdesc->sig_use; ++i) { |
| if (sigdesc->sig_pids[i]) { |
| ++n; |
| if (Kill(sigdesc->sig_pids[i], sig) < 0) { |
| Warn2("kill("F_pid", %d): %m", |
| sigdesc->sig_pids[i], sig); |
| } |
| } |
| } |
| if (n >= 0) |
| Info1("socatsignalpass(): propagated signal to %d sub processes", n); |
| } |
| #if !HAVE_SIGACTION |
| Signal(sig, socatsignalpass); |
| #endif /* !HAVE_SIGACTION */ |
| Debug("socatsignalpass() ->"); |
| diag_in_handler = 0; |
| errno = _errno; |
| } |
| |
| |
| /* register the sub process pid for passing of signals of type signum. |
| Only for SIGHUP, SIGINT, and SIGQUIT! |
| returns 0 on success or <0 if an error occurred */ |
| int xio_opt_signal(pid_t pid, int signum) { |
| struct socat_sig_desc *sigdesc; |
| |
| if ((sigdesc = socat_get_sig_desc(signum)) == NULL) { |
| Error("sub process registered for unsupported signal"); |
| return -1; |
| } |
| |
| if (sigdesc->sig_use >= SOCAT_MAXPIDS) { |
| Error1("too many sub processes registered for signal %d", signum); |
| return -1; |
| } |
| if (sigdesc->sig_use == 0) { |
| /* the special signal handler has not been registered yet - do it now */ |
| #if HAVE_SIGACTION |
| struct sigaction act; |
| memset(&act, 0, sizeof(struct sigaction)); |
| act.sa_flags = 0/*|SA_RESTART*/; |
| act.sa_handler = socatsignalpass; |
| sigfillset(&act.sa_mask); |
| if (Sigaction(signum, &act, NULL) < 0) { |
| /*! man does not say that errno is defined */ |
| Warn3("sigaction(%d, %p, NULL): %s", signum, &act, strerror(errno)); |
| } |
| #else |
| Signal(signum, socatsignalpass); |
| #endif /* !HAVE_SIGACTION */ |
| } |
| sigdesc->sig_pids[sigdesc->sig_use++] = pid; |
| return 0; |
| } |
| |