blob: 6fe1e3bda17e52f554367dff91a1b3300d6a5067 [file] [log] [blame] [edit]
/* 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;
}