Made code async-signal-safe

This commit is contained in:
Gerhard Rieger 2015-01-12 21:46:16 +01:00
parent e4c6f3d934
commit 2af0495cc6
25 changed files with 1707 additions and 625 deletions

19
CHANGES
View File

@ -1,4 +1,23 @@
security:
(CVE Id pending)
Fixed problems with signal handling caused by use of not async signal
safe functions in signal handlers that could freeze socat, allowing
denial of service attacks.
Many changes in signal handling and the diagnostic messages system were
applied to make the code async signal safe but still provide detailled
logging from signal handlers:
Coded function vsnprintf_r() as async signal safe incomplete substitute
of libc vsnprintf()
Coded function snprinterr() to replace %m in strings with a system error
message
Instead of gettimeofday() use clock_gettime() when available
Pass Diagnostic messages from signal handler per unix socket to the main
program flow
Use sigaction() instead of signal() for better control
Turn off nested signal handler invocations
Thanks to Peter Lobsinger for reporting and explaining this issue.
####################### V 1.7.2.4:
corrections:

View File

@ -204,3 +204,19 @@ PH_PREFORK, PH_FORK, PH_PASTFORK # (all before/after?)
PH_LATE # chroot
PH_LATE2 # su, su-d.2
PH_PREEXEC, PH_EXEC # (all before)
===============================================================================
// Up to 1.7.2.4 socat used non async signal safe system and library calls in signal handlers, mostly for logging purposes. This problem was fixed in release 1.7.3.0 with the following concepts:
Signal handlers set on entry and unset on return the diag_in_handler global variable. The logging system, when this variable is set, queues the text message together with errno and exit info in a UNIX datagram socket. When invoked with unset diag_in_handler it first checks if there are messages in that queue and prints them first.
A async signal safe but minimal version of vsnprintf, named vsnprintf_r, was written so no value arguments need to be queued.
Because strerror is not async signal safe a new function snprinterr was written that replaces the (glibc compatible) %m format with strerror output. The original errno is passed in the message queue, snprinterr is called when dequeuing messages outside of signal handler.
// List of signal handlers in socat
socat.c:socat_signal (generic, just logs and maybe exits)
xioshutdown.c:signal_kill_pid (SIGALRM, kill child process)
xiosigchld.c:childdied (SIGCHLD: get info, log; possibly close channel)
xiosignal.c:socatsignalpass: cascades signal to channel child processes; w/ options sighup,sigint,sigquit
xio-socket.c:xiosigaction_hasread: SIGUSR1,SIGCHLD, tells parent that datagram has been consumed

View File

@ -54,13 +54,13 @@ XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \
xio-pty.c xio-openssl.c xio-streams.c\
xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c xio-tun.c
XIOOBJS = $(XIOSRCS:.c=.o)
UTLSRCS = error.c dalan.c procan.c procan-cdefs.c hostan.c fdname.c sysutils.c utils.c nestlex.c @FILAN@ @SYCLS@ @SSLCLS@
UTLSRCS = error.c dalan.c procan.c procan-cdefs.c hostan.c fdname.c sysutils.c utils.c nestlex.c vsnprintf_r.c snprinterr.c @FILAN@ @SYCLS@ @SSLCLS@
UTLOBJS = $(UTLSRCS:.c=.o)
CFILES = $(XIOSRCS) $(UTLSRCS) socat.c procan_main.c filan_main.c
OFILES = $(CFILES:.c=.o)
PROGS = socat procan filan
HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes.h xio.h xioopen.h sysutils.h utils.h nestlex.h compat.h \
HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes.h xio.h xioopen.h sysutils.h utils.h nestlex.h vsnprintf_r.h snprinterr.h compat.h \
xioconfig.h mytypes.h xioopts.h xiodiag.h xiohelp.h xiosysincludes.h \
xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \
xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h \
@ -114,12 +114,12 @@ depend: $(CFILES) $(HFILES)
socat: socat.o libxio.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ socat.o libxio.a $(CLIBS)
PROCAN_OBJS=procan_main.o procan.o procan-cdefs.o hostan.o error.o sycls.o sysutils.o utils.o
PROCAN_OBJS=procan_main.o procan.o procan-cdefs.o hostan.o error.o sycls.o sysutils.o utils.o vsnprintf_r.o snprinterr.o
procan: $(PROCAN_OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(PROCAN_OBJS) $(CLIBS)
filan: filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o $(CLIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ filan_main.o filan.o fdname.o error.o sycls.o sysutils.o utils.o vsnprintf_r.o snprinterr.o $(CLIBS)
libxio.a: $(XIOOBJS) $(UTLOBJS)
$(AR) r $@ $(XIOOBJS) $(UTLOBJS)

View File

@ -1 +1 @@
"1.7.2.4"
"1.7.2.4+sigfix"

View File

@ -31,6 +31,10 @@
/* substitute some features that might be missing on some platforms */
#if !HAVE_TYPE_SIG_ATOMIC_T
typedef int sig_atomic_t;
#endif
#ifndef SHUT_RD
# define SHUT_RD 0
#endif

View File

@ -131,6 +131,9 @@
/* Define if you have the ftruncate64 function */
#undef HAVE_FTRUNCATE64
/* Define if you have the clock_gettime function */
#undef HAVE_CLOCK_GETTIME
/* Define if you have the strtoll function */
#undef HAVE_STRTOLL
@ -418,6 +421,9 @@
/* Define if you have the long long type */
#undef HAVE_TYPE_LONGLONG
/* is sig_atomic_t declared */
#undef HAVE_TYPE_SIG_ATOMIC_T
/* is socklen_t already typedef'd? */
#undef HAVE_TYPE_SOCKLEN

View File

@ -764,6 +764,8 @@ if test $sc_cv_type_longlong = yes; then
fi
AC_MSG_RESULT($sc_cv_type_longlong)
AC_CHECK_TYPE(sig_atomic_t,AC_DEFINE(HAVE_TYPE_SIG_ATOMIC_T),,[#include "sysincludes.h"])
# following builtin macro does not check unistd.h and sys/socket.h where
# socklen_t might be defined
#AC_CHECK_TYPE(socklen_t, int)
@ -1316,6 +1318,9 @@ AC_CHECK_LIB(bsd, openpty,
AC_CHECK_LIB(util, openpty,
[LIBS="-lutil $LIBS"; AC_DEFINE(HAVE_OPENPTY)])
AC_CHECK_LIB(rt, clock_gettime,
[LIBS="-lrt $LIBS"; AC_DEFINE(HAVE_CLOCK_GETTIME)])
dnl Search for flock()
# with Linux it's in libc, with AIX in libbsd
AC_CHECK_FUNC(flock, AC_DEFINE(HAVE_FLOCK),

283
error.c
View File

@ -1,30 +1,21 @@
/* source: error.c */
/* Copyright Gerhard Rieger 2001-2011 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
/* the logging subsystem */
#include "config.h"
#include "sysincludes.h"
#include <stdarg.h>
#include <stdlib.h>
#include <errno.h>
#if HAVE_SYSLOG_H
#include <syslog.h>
#endif
#include <sys/utsname.h>
#include <time.h> /* time_t, strftime() */
#include <sys/time.h> /* gettimeofday() */
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "mytypes.h"
#include "compat.h"
#include "utils.h"
#include "vsnprintf_r.h"
#include "snprinterr.h"
#include "error.h"
#include "sysincludes.h"
#include "sycls.h"
/* translate MSG level to SYSLOG level */
int syslevel[] = {
@ -49,11 +40,27 @@ struct diag_opts {
} ;
static void _diag_exit(int status);
struct diag_opts diagopts =
{ NULL, E_ERROR, E_ERROR, 0, NULL, LOG_DAEMON, false, 0 } ;
static void msg2(
#if HAVE_CLOCK_GETTIME
struct timespec *now,
#elif HAVE_GETTIMEOFDAY
struct timeval *now,
#else
time_t *now,
#endif
int level, int exitcode, int handler, const char *text);
static void _msg(int level, const char *buff, const char *syslp);
sig_atomic_t diag_in_handler; /* !=0 indicates to msg() that in signal handler */
sig_atomic_t diag_immediate_msg; /* !=0 prints messages even from within signal handler instead of deferring them */
sig_atomic_t diag_immediate_exit; /* !=0 calls exit() from diag_exit() even when in signal handler. For system() */
static struct wordent facilitynames[] = {
{"auth", (void *)LOG_AUTH},
#ifdef LOG_AUTHPRIV
@ -87,15 +94,38 @@ static struct wordent facilitynames[] = {
{"uucp", (void *)LOG_UUCP}
} ;
/* serialize message for sending from signal handlers */
struct sermsg {
int severity;
#if HAVE_CLOCK_GETTIME
struct timespec ts;
#else
struct timeval tv;
#endif
} ;
static int diaginitialized;
static int diag_sock_send = -1;
static int diag_sock_recv = -1;
static int diag_msg_avail = 0; /* !=0: messages from within signal handler may be waiting */
static int diag_init(void) {
int handlersocks[2];
if (diaginitialized) {
return 0;
}
diaginitialized = 1;
/* gcc with GNU libc refuses to set this in the initializer */
diagopts.logfile = stderr;
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, handlersocks) < 0) {
diag_sock_send = -1;
diag_sock_recv = -1;
return -1;
}
diag_sock_send = handlersocks[1];
diag_sock_recv = handlersocks[0];
return 0;
}
#define DIAG_INIT ((void)(diaginitialized || diag_init()))
@ -180,67 +210,104 @@ const char *diag_get_string(char what) {
return NULL;
}
/* Linux and AIX syslog format:
Oct 4 17:10:37 hostname socat[52798]: D signal(13, 1)
*/
void msg(int level, const char *format, ...) {
#if HAVE_GETTIMEOFDAY || 1
struct timeval now;
int result;
time_t nowt;
#else /* !HAVE_GETTIMEOFDAY */
time_t now;
#endif /* !HAVE_GETTIMEOFDAY */
struct diag_dgram diag_dgram;
va_list ap;
/* does not perform a system call if nothing todo, thanks diag_msg_avail */
diag_dgram._errno = errno; /* keep for passing from signal handler to sock.
reason is that strerror is definitely not
async-signal-safe */
DIAG_INIT;
/* in normal program flow (not in signal handler) */
/* first flush the queue of datagrams from the socket */
if (diag_msg_avail && !diag_in_handler) {
diag_msg_avail = 0; /* _before_ flush to prevent inconsistent state when signal occurs inbetween */
diag_flush();
}
if (level < diagopts.msglevel) { va_end(ap); return; }
va_start(ap, format);
/* we do only a minimum in the outer parts which may run in a signal handler
these are: get actual time, level, serialized message and write them to socket
*/
diag_dgram.op = DIAG_OP_MSG;
#if HAVE_CLOCK_GETTIME
clock_gettime(CLOCK_REALTIME, &diag_dgram.now);
#elif HAVE_GETTIMEOFDAY
gettimeofday(&diag_dgram.now, NULL);
#else
diag_dgram.now = time(NULL);
#endif
diag_dgram.level = level;
diag_dgram.exitcode = diagopts.exitstatus;
vsnprintf_r(diag_dgram.text, sizeof(diag_dgram.text), format, ap);
if (diag_in_handler && !diag_immediate_msg) {
send(diag_sock_send, &diag_dgram, sizeof(diag_dgram)-TEXTLEN + strlen(diag_dgram.text)+1, MSG_DONTWAIT|MSG_NOSIGNAL);
diag_msg_avail = 1;
va_end(ap);
return;
}
msg2(&diag_dgram.now, diag_dgram.level, diagopts.exitstatus, 0, diag_dgram.text);
va_end(ap); return;
}
void msg2(
#if HAVE_CLOCK_GETTIME
struct timespec *now,
#elif HAVE_GETTIMEOFDAY
struct timeval *now,
#else
time_t *now,
#endif
int level, /* E_INFO... */
int exitcode, /* on exit use this exit code */
int handler, /* message comes from signal handler */
const char *text) {
time_t epoch;
unsigned long micros;
#if HAVE_STRFTIME
struct tm struct_tm;
#endif
#define BUFLEN 512
char buff[BUFLEN], *bufp, *syslp;
size_t bytes;
va_list ap;
DIAG_INIT;
if (level < diagopts.msglevel) return;
va_start(ap, format);
#if HAVE_GETTIMEOFDAY || 1
result = gettimeofday(&now, NULL);
if (result < 0) {
/* invoking msg() might create endless recursion; by hand instead */
sprintf(buff, "cannot read time: %s["F_pid"] E %s",
diagopts.progname, getpid(), strerror(errno));
_msg(LOG_ERR, buff, strstr(buff, " E "+1));
strcpy(buff, "unknown time "); bytes = 20;
} else {
nowt = now.tv_sec;
#if HAVE_STRFTIME
if (diagopts.micros) {
bytes = strftime(buff, 20, "%Y/%m/%d %H:%M:%S", localtime_r(&nowt, &struct_tm));
bytes += sprintf(buff+19, "."F_tv_usec" ", now.tv_usec);
} else {
bytes =
strftime(buff, 21, "%Y/%m/%d %H:%M:%S ", localtime_r(&nowt, &struct_tm));
}
#if HAVE_CLOCK_GETTIME
epoch = now->tv_sec;
#elif HAVE_GETTIMEOFDAY
epoch = now->tv_sec;
#else
strcpy(buff, ctime(&nowt));
bytes = strlen(buff);
epoch = *now;
#endif
}
#else /* !HAVE_GETTIMEOFDAY */
now = time(NULL); if (now == (time_t)-1) {
/* invoking msg() might create endless recursion; by hand instead */
sprintf(buff, "cannot read time: %s["F_pid"] E %s",
diagopts.progname, getpid(), strerror(errno));
_msg(LOG_ERR, buff, strstr(buff, " E "+1));
strcpy(buff, "unknown time "); bytes = 20;
} else {
#if HAVE_STRFTIME
bytes = strftime(buff, 21, "%Y/%m/%d %H:%M:%S ", localtime_r(&now, &struct_tm));
bytes = strftime(buff, 20, "%Y/%m/%d %H:%M:%S", localtime_r(&epoch, &struct_tm));
buff[bytes] = '\0';
#else
strcpy(buff, ctime(&now));
bytes = strlen(buff);
bytes = snprintf(buff, 11, F_time, epoch);
#endif
if (diagopts.micros) {
#if HAVE_CLOCK_GETTIME
micros = now->tv_nsec/1000;
#elif HAVE_GETTIMEOFDAY
micros = now->tv_usec;
#else
micros = 0;
#endif
bytes += sprintf(buff+19, ".%06lu ", micros);
} else {
buff[19] = ' '; buff[20] = '\0';
}
#endif /* !HAVE_GETTIMEOFDAY */
bytes = strlen(buff);
bufp = buff + bytes;
if (diagopts.withhostname) {
bytes = sprintf(bufp, "%s ", diagopts.hostname), bufp+=bytes;
@ -249,19 +316,20 @@ void msg(int level, const char *format, ...) {
bufp += bytes;
syslp = bufp;
*bufp++ = "DINWEF"[level];
#if 0 /* only for debugging socat */
if (handler) bufp[-1] = tolower(bufp[-1]); /* for debugging, low chars indicate messages from signal handlers */
#endif
*bufp++ = ' ';
vsnprintf(bufp, BUFLEN-(bufp-buff)-1, format, ap);
strncpy(bufp, text, BUFLEN-(bufp-buff)-1);
strcat(bufp, "\n");
_msg(level, buff, syslp);
if (level >= diagopts.exitlevel) {
va_end(ap);
if (E_NOTICE >= diagopts.msglevel) {
sprintf(syslp, "N exit(1)\n");
snprintf_r(syslp, 16, "N exit(%d)\n", exitcode?exitcode:(diagopts.exitstatus?diagopts.exitstatus:1));
_msg(E_NOTICE, buff, syslp);
}
exit(diagopts.exitstatus ? diagopts.exitstatus : 1);
exit(exitcode?exitcode:(diagopts.exitstatus?diagopts.exitstatus:1));
}
va_end(ap);
}
@ -276,6 +344,44 @@ static void _msg(int level, const char *buff, const char *syslp) {
}
/* handle the messages in the queue */
void diag_flush(void) {
struct diag_dgram recv_dgram;
char exitmsg[20];
while (recv(diag_sock_recv, &recv_dgram, sizeof(recv_dgram)-1, MSG_DONTWAIT) > 0) {
recv_dgram.text[TEXTLEN-1] = '\0';
switch (recv_dgram.op) {
case DIAG_OP_EXIT:
/* we want the actual time, not when this dgram was sent */
#if HAVE_CLOCK_GETTIME
clock_gettime(CLOCK_REALTIME, &recv_dgram.now);
#elif HAVE_GETTIMEOFDAY
gettimeofday(&recv_dgram.now, NULL);
#else
recv_dgram.now = time(NULL);
#endif
if (E_NOTICE >= diagopts.msglevel) {
snprintf_r(exitmsg, sizeof(exitmsg), "exit(%d)", recv_dgram.exitcode?recv_dgram.exitcode:1);
msg2(&recv_dgram.now, E_NOTICE, recv_dgram.exitcode?recv_dgram.exitcode:1, 1, exitmsg);
}
exit(recv_dgram.exitcode?recv_dgram.exitcode:1);
case DIAG_OP_MSG:
if (recv_dgram._errno) {
/* there might be a %m control in the string (glibc compatible,
replace with strerror(...errno) ) */
char text[TEXTLEN];
errno = recv_dgram._errno;
snprinterr(text, TEXTLEN, recv_dgram.text);
msg2(&recv_dgram.now, recv_dgram.level, recv_dgram.exitcode, 1, text);
} else {
msg2(&recv_dgram.now, recv_dgram.level, recv_dgram.exitcode, 1, recv_dgram.text);
}
break;
}
}
}
/* use a new log output file descriptor that is dup'ed from the current one.
this is useful when socat logs to stderr but fd 2 should be redirected to
serve other purposes */
@ -295,3 +401,52 @@ int diag_dup(void) {
}
return newfd;
}
/* this function is kind of async-signal-safe exit(). When invoked from signal
handler it defers exit. */
void diag_exit(int status) {
struct diag_dgram diag_dgram;
if (diag_in_handler && !diag_immediate_exit) {
diag_dgram.op = DIAG_OP_EXIT;
diag_dgram.exitcode = status;
send(diag_sock_send, &diag_dgram, sizeof(diag_dgram)-TEXTLEN, MSG_DONTWAIT|MSG_NOSIGNAL);
return;
}
_diag_exit(status);
}
static void _diag_exit(int status) {
Exit(status);
}
/* a function that appears to the application like select() but that also
monitors the diag socket diag_sock_recv and processes its messages.
Do not call from within a signal handler. */
int diag_select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout) {
int result;
fd_set save_readfds, save_writefds, save_exceptfds;
if (readfds) { memcpy(&save_readfds, readfds, sizeof(*readfds)); }
if (writefds) { memcpy(&save_writefds, writefds, sizeof(*writefds)); }
if (exceptfds) { memcpy(&save_exceptfds, exceptfds, sizeof(*exceptfds)); }
while (1) {
FD_SET(diag_sock_recv, readfds);
result = Select(nfds, readfds, writefds,
exceptfds, timeout);
if (!FD_ISSET(diag_sock_recv, readfds)) {
/* select terminated not due to diag_sock_recv, normalt continuation */
break;
}
diag_flush();
if (readfds) { memcpy(readfds, &save_readfds, sizeof(*readfds)); }
if (writefds) { memcpy(writefds, &save_writefds, sizeof(*writefds)); }
if (exceptfds) { memcpy(exceptfds, &save_exceptfds, sizeof(*exceptfds)); }
}
return result;
}

34
error.h
View File

@ -1,5 +1,5 @@
/* source: error.h */
/* Copyright Gerhard Rieger 2001-2008 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __error_h_included
@ -13,6 +13,7 @@
#define E_ERROR 4 /* errors */
#define E_FATAL 5 /* emergency abort */
#define F_strerror "%m" /* a pseudo format, replaced by strerror(errno) */
/* here are the macros for diag invocation; use WITH_MSGLEVEL to specify the
lowest priority that is compiled into your program */
@ -204,6 +205,33 @@
#endif /* !(WITH_MSGLEVEL <= E_FATAL) */
enum diag_op {
DIAG_OP_MSG, /* a diagnostic message */
DIAG_OP_EXIT, /* exit the program */
} ;
/* datagram for communication between outer msg() call from signal handler to
inner msg() call in normal flow */
# define TEXTLEN 480
struct diag_dgram {
enum diag_op op;
#if HAVE_CLOCK_GETTIME
struct timespec now;
#elif HAVE_GETTIMEOFDAY
struct timeval now;
#else
time_t now;
#endif
int level; /* E_FATAL, ... E_DEBUG */
int _errno; /* for glibc %m format */
int exitcode; /* if exiting take this num */
char text[TEXTLEN];
} ;
extern sig_atomic_t diag_in_handler;
extern int diag_immediate_msg;
extern int diag_immediate_exit;
extern void diag_set(char what, const char *arg);
extern void diag_set_int(char what, int arg);
extern int diag_get_int(char what);
@ -211,5 +239,9 @@ extern const char *diag_get_string(char what);
extern int diag_dup(void);
extern int diag_dup2(int newfd);
extern void msg(int level, const char *format, ...);
extern void diag_flush(void);
extern void diag_exit(int status);
extern int diag_select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
#endif /* !defined(__error_h_included) */

View File

@ -1,5 +1,5 @@
/* source: hostan.c */
/* Copyright Gerhard Rieger 2006-2011 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
/* the subroutine hostan makes a "HOST ANalysis". It gathers information
@ -17,9 +17,27 @@
#include "hostan.h"
#include "error.h"
static int iffan(FILE *outfile);
int hostan(FILE *outfile) {
fprintf(outfile, "\nC TYPE SIZES\n");
fprintf(outfile, "sizeof(char) = %u\n", (unsigned int)sizeof(char));
fprintf(outfile, "sizeof(short) = %u\n", (unsigned int)sizeof(short));
fprintf(outfile, "sizeof(int) = %u\n", (unsigned int)sizeof(int));
fprintf(outfile, "sizeof(long) = %u\n", (unsigned int)sizeof(long));
#if HAVE_TYPE_LONGLONG
fprintf(outfile, "sizeof(long long) = %u\n", (unsigned int)sizeof(long long));
#endif
fprintf(outfile, "sizeof(size_t) = %u\n", (unsigned int)sizeof(size_t));
#include <sys/time.h> /* select(); OpenBSD: struct timespec */
fprintf(outfile, "sizeof(struct timespec) = %u\n", (unsigned int)sizeof(struct timespec));
fprintf(outfile, "sizeof(struct diag_dgram) = %u\n", (unsigned int)sizeof(struct diag_dgram));
fprintf(outfile, "((struct diag_dgram *)0)->op-((struct diag_dgram *)0) = %u\n", (unsigned int)((char *)(&((struct diag_dgram *)0)->op)-(char *)((struct diag_dgram *)0)));
fprintf(outfile, "((struct diag_dgram *)0)->now-((struct diag_dgram *)0) = %u\n", (unsigned int)((char *)(&((struct diag_dgram *)0)->now)-(char *)((struct diag_dgram *)0)));
fprintf(outfile, "((struct diag_dgram *)0)->exitcode-((struct diag_dgram *)0) = %u\n", (unsigned int)((char *)(&((struct diag_dgram *)0)->exitcode)-(char *)((struct diag_dgram *)0)));
fprintf(outfile, "((struct diag_dgram *)0)->text-((struct diag_dgram *)0) = %u\n", (unsigned int)((((struct diag_dgram *)0)->text)-(char *)((struct diag_dgram *)0)));
#if _WITH_SOCKET
fprintf(outfile, "\nIP INTERFACES\n");
iffan(outfile);

View File

@ -1,12 +1,18 @@
/* source: procan_main.c */
/* Copyright Gerhard Rieger 2001-2008 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
const char copyright[] = "procan by Gerhard Rieger - send bug reports to socat@dest-unreach.org";
#include <signal.h> /* sig_atomic_t for error.h */
#include <time.h> /* struct timespec for error.h */
#include <stdlib.h> /* strtoul() */
#include <string.h>
#include <stdio.h>
#include "config.h"
#if HAVE_SYS_SELECT_H
#include <sys/select.h> /* select(), fdset on FreeBSD */
#endif
#include "mytypes.h"
#include "error.h"
#include "procan.h"

85
snprinterr.c Normal file
View File

@ -0,0 +1,85 @@
/* snprinterr.c */
/* Copyright Gerhard Rieger */
/* a function similar to vsnprintf() but it just handles %m */
#include "config.h"
#include <stddef.h> /* ptrdiff_t */
#include <ctype.h> /* isdigit() */
#include <stdarg.h>
#include <stdlib.h>
#include <errno.h>
#if HAVE_SYSLOG_H
#include <syslog.h>
#endif
#include <sys/utsname.h>
#include <time.h> /* time_t, strftime() */
#include <sys/time.h> /* gettimeofday() */
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "snprinterr.h"
#define HAVE_STRERROR_R 0
/* replace %m in format with actual strerror() message, write result to *str.
keep other % formats unchanged!
writes at most size chars including the terminating \0 to *str
returns the number of bytes in the output without terminating \0
result is always \0 terminated except when size==0
*/
int snprinterr(char *str, size_t size, const char *format) {
char c;
int full = 0; /* 1 means: there is no space left in * str for more data or \0 */
int count = 0;
if (size == 0) return 0;
if (count >= size) full = 1;
while (c = *format++) {
if (c == '%') {
c = *format++;
switch (c) {
case '\0':
++count; if (!full) { (*str++ = '%'); if (count+1 >= size) full = 1; }
break;
default:
++count; if (!full) { (*str++ = '%'); if (count+1 >= size) full = 1; }
++count; if (!full) { (*str++ = c); if (count+1 >= size) full = 1; }
break;
case 'm':
{
#if HAVE_STRERROR_R
# define BUFLEN 64
char buf[BUFLEN] = "";
#endif /* HAVE_STRERROR_R */
char *bufp;
#if !HAVE_STRERROR_R
bufp = strerror(errno);
#else
/* there are two versions floating around... */
# if 1 /* GNU version */
bufp = strerror_r(errno, buf, BUFLEN);
# else /* standard version */
strerror_r(errno, buf, BUFLEN);
bufp = buf;
# endif
#endif /* HAVE_STRERROR_R */
while ((c = *bufp++) != '\0') {
++count; if (!full) { (*str++ = c); if (count+1 >= size) full = 1; }
}
}
c = ' '; /* not \0 ! */
break;
}
if (c == '\0') break;
} else {
++count; if (!full) { (*str++ = c); if (count+1 >= size) full = 1; }
}
}
*str++ = '\0'; /* always write terminating \0 */
return count;
#undef BUFLEN
}

10
snprinterr.h Normal file
View File

@ -0,0 +1,10 @@
/* source: snprinterr.h */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __snprinterr_h_included
#define __snprinterr_h_included 1
int snprinterr(char *str, size_t size, const char *format);
#endif /* !defined(__snprinterr_h_included) */

58
socat.c
View File

@ -1,5 +1,5 @@
/* source: socat.c */
/* Copyright Gerhard Rieger 2001-2010 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this is the main source, including command line option parsing, general
@ -285,18 +285,23 @@ int main(int argc, const char *argv[]) {
}
#endif /* WITH_MSGLEVEL <= E_DEBUG */
/* not sure what signal should print a message */
Signal(SIGHUP, socat_signal);
Signal(SIGINT, socat_signal);
Signal(SIGQUIT, socat_signal);
Signal(SIGILL, socat_signal);
/* SIGABRT for assert; catching caused endless recursion on assert in libc
(tzfile.c:498: __tzfile_compute: Assertion 'num_types == 1' failed.) */
/*Signal(SIGABRT, socat_signal);*/
Signal(SIGBUS, socat_signal);
Signal(SIGFPE, socat_signal);
Signal(SIGSEGV, socat_signal);
Signal(SIGTERM, socat_signal);
{
struct sigaction act;
sigfillset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = socat_signal;
/* not sure which signals should be cauhgt and print a message */
Sigaction(SIGHUP, &act, NULL);
Sigaction(SIGINT, &act, NULL);
Sigaction(SIGQUIT, &act, NULL);
Sigaction(SIGILL, &act, NULL);
Sigaction(SIGABRT, &act, NULL);
Sigaction(SIGBUS, &act, NULL);
Sigaction(SIGFPE, &act, NULL);
Sigaction(SIGSEGV, &act, NULL);
Sigaction(SIGTERM, &act, NULL);
}
Signal(SIGPIPE, SIG_IGN);
/* set xio hooks */
xiohook_newchild = &socat_newchild;
@ -546,12 +551,6 @@ int closing = 0; /* 0..no eof yet, 1..first eof just occurred,
int socat(const char *address1, const char *address2) {
int mayexec;
#if 1
if (Signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
Warn1("signal(SIGPIPE, SIG_IGN): %s", strerror(errno));
}
#endif
if (socat_opts.lefttoright) {
if ((sock1 = xioopen(address1, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
return -1;
@ -680,7 +679,9 @@ int childleftdata(xiofile_t *xfd) {
in.revents = 0;
}
do {
int _errno;
retval = xiopoll(&in, 1, &timeout);
_errno = errno; diag_flush(); errno = _errno; /* just in case it's not debug level and Msg() not been called */
} while (retval < 0 && errno == EINTR);
if (retval < 0) {
@ -1405,6 +1406,10 @@ int cv_newline(unsigned char **buff, ssize_t *bufsiz,
}
void socat_signal(int signum) {
int _errno;
_errno = errno;
diag_in_handler = 1;
Notice1("socat_signal(): handling signal %d", signum);
switch (signum) {
case SIGQUIT:
case SIGILL:
@ -1423,7 +1428,11 @@ void socat_signal(int signum) {
case SIGINT:
Notice1("exiting on signal %d", signum); break;
}
Exit(128+signum);
//Exit(128+signum);
Notice1("socat_signal(): finishing signal %d", signum);
diag_exit(128+signum); /*!!! internal cleanup + _exit() */
diag_in_handler = 0;
errno = _errno;
}
/* this is the callback when the child of an address died */
@ -1478,8 +1487,13 @@ static void socat_unlock(void) {
if (!havelock) return;
if (socat_opts.lock.lockfile) {
if (Unlink(socat_opts.lock.lockfile) < 0) {
Warn2("unlink(\"%s\"): %s",
socat_opts.lock.lockfile, strerror(errno));
if (!diag_in_handler) {
Warn2("unlink(\"%s\"): %s",
socat_opts.lock.lockfile, strerror(errno));
} else {
Warn1("unlink(\"%s\"): "F_strerror,
socat_opts.lock.lockfile);
}
} else {
Info1("released lock \"%s\"", socat_opts.lock.lockfile);
}

View File

@ -1,5 +1,5 @@
/* source: sslcls.c */
/* Copyright Gerhard Rieger 2001-2011 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
/* explicit system call and C library trace function, for those who miss strace
@ -123,8 +123,8 @@ int sycSSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
const char *CApath) {
int result;
Debug7("SSL_CTX_load_verify_locations(%p, %s%s%s, %s%s%s)", ctx,
CAfile?"\"":"", CAfile?CAfile:NULL, CAfile?"\"":"",
CApath?"\"":"", CApath?CApath:NULL, CApath?"\"":"");
CAfile?"\"":"", CAfile?CAfile:"", CAfile?"\"":"",
CApath?"\"":"", CApath?CApath:"", CApath?"\"":"");
result = SSL_CTX_load_verify_locations(ctx, CAfile, CApath);
Debug1("SSL_CTX_load_verify_locations() -> %d", result);
return result;

67
sycls.c
View File

@ -36,9 +36,11 @@ mode_t Umask(mode_t mask) {
int Open(const char *pathname, int flags, mode_t mode) {
int result, _errno;
if (!diag_in_handler) diag_flush();
Debug3("open(\"%s\", 0%o, 0%03o)", pathname, flags, mode);
result = open(pathname, flags, mode);
_errno = errno;
if (!diag_in_handler) diag_flush();
Info4("open(\"%s\", 0%o, 0%03o) -> %d", pathname, flags, mode, result);
errno = _errno;
return result;
@ -516,9 +518,11 @@ int Pipe(int filedes[2]) {
ssize_t Read(int fd, void *buf, size_t count) {
ssize_t result;
int _errno;
if (!diag_in_handler) diag_flush();
Debug3("read(%d, %p, "F_Zu")", fd, buf, count);
result = read(fd, buf, count);
_errno = errno;
if (!diag_in_handler) diag_flush();
Debug1("read -> "F_Zd, result);
errno = _errno;
return result;
@ -527,9 +531,11 @@ ssize_t Read(int fd, void *buf, size_t count) {
ssize_t Write(int fd, const void *buf, size_t count) {
ssize_t result;
int _errno;
if (!diag_in_handler) diag_flush();
Debug3("write(%d, %p, "F_Zu")", fd, buf, count);
result = write(fd, buf, count);
_errno = errno;
if (!diag_in_handler) diag_flush();
Debug1("write -> "F_Zd, result);
errno = _errno;
return result;
@ -537,8 +543,10 @@ ssize_t Write(int fd, const void *buf, size_t count) {
int Fcntl(int fd, int cmd) {
int result, _errno;
if (!diag_in_handler) diag_flush();
Debug2("fcntl(%d, %d)", fd, cmd);
result = fcntl(fd, cmd);
if (!diag_in_handler) diag_flush();
_errno = errno;
Debug1("fcntl() -> %d", result);
errno = _errno;
@ -547,9 +555,11 @@ int Fcntl(int fd, int cmd) {
int Fcntl_l(int fd, int cmd, long arg) {
int result, _errno;
if (!diag_in_handler) diag_flush();
Debug3("fcntl(%d, %d, %ld)", fd, cmd, arg);
result = fcntl(fd, cmd, arg);
_errno = errno;
if (!diag_in_handler) diag_flush();
Debug1("fcntl() -> %d", result);
errno = _errno;
return result;
@ -557,10 +567,12 @@ int Fcntl_l(int fd, int cmd, long arg) {
int Fcntl_lock(int fd, int cmd, struct flock *l) {
int result, _errno;
if (!diag_in_handler) diag_flush();
Debug7("fcntl(%d, %d, {type=%hd,whence=%hd,start="F_off",len="F_off",pid="F_pid"})",
fd, cmd, l->l_type, l->l_whence, l->l_start, l->l_len, l->l_pid);
result = fcntl(fd, cmd, l);
_errno = errno;
if (!diag_in_handler) diag_flush();
Debug1("fcntl() -> %d", result);
errno = _errno;
return result;
@ -591,9 +603,11 @@ int Ftruncate64(int fd, off64_t length) {
#if HAVE_FLOCK
int Flock(int fd, int operation) {
int retval, _errno;
if (!diag_in_handler) diag_flush();
Debug2("flock(%d, %d)", fd, operation);
retval = flock(fd, operation);
_errno = errno;
if (!diag_in_handler) diag_flush();
Debug1("flock() -> %d", retval);
errno = _errno;
return retval;
@ -602,6 +616,7 @@ int Flock(int fd, int operation) {
int Ioctl(int d, int request, void *argp) {
int retval, _errno;
if (!diag_in_handler) diag_flush();
if (argp > (void *)0x10000) { /* fuzzy...*/
Debug4("ioctl(%d, 0x%x, %p{%lu})", d, request, argp, *(unsigned long *)argp);
} else {
@ -609,6 +624,7 @@ int Ioctl(int d, int request, void *argp) {
}
retval = ioctl(d, request, argp);
_errno = errno;
if (!diag_in_handler) diag_flush();
Debug1("ioctl() -> %d", retval);
errno = _errno;
return retval;
@ -707,7 +723,8 @@ int Chmod(const char *path, mode_t mode) {
#if HAVE_POLL
/* we only show the first struct pollfd; hope this is enough for most cases. */
int Poll(struct pollfd *ufds, unsigned int nfds, int timeout) {
int result;
int _errno, result;
if (!diag_in_handler) diag_flush();
if (nfds == 4) {
Debug10("poll({%d,0x%02hx,}{%d,0x%02hx,}{%d,0x%02hx,}{%d,0x%02hx,}, %u, %d)",
ufds[0].fd, ufds[0].events, ufds[1].fd, ufds[1].events,
@ -717,12 +734,15 @@ int Poll(struct pollfd *ufds, unsigned int nfds, int timeout) {
Debug4("poll({%d,0x%02hx,}, , %u, %d)", ufds[0].fd, ufds[0].events, nfds, timeout);
}
result = poll(ufds, nfds, timeout);
_errno = errno;
if (!diag_in_handler) diag_flush();
if (nfds == 4) {
Debug5("poll(, {,,0x%02hx}{,,0x%02hx}{,,0x%02hx}{,,0x%02hx}) -> %d",
ufds[0].revents, ufds[1].revents, ufds[2].revents, ufds[3].revents, result);
} else {
Debug2("poll(, {,,0x%02hx}) -> %d", ufds[0].revents, result);
}
errno = _errno;
return result;
}
#endif /* HAVE_POLL */
@ -732,34 +752,38 @@ int Poll(struct pollfd *ufds, unsigned int nfds, int timeout) {
int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout) {
int result, _errno;
if (!diag_in_handler) diag_flush();
#if HAVE_FDS_BITS
Debug7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu."F_tv_usec")",
n, readfds->fds_bits[0], writefds->fds_bits[0],
exceptfds->fds_bits[0],
n, readfds?readfds->fds_bits[0]:0, writefds?writefds->fds_bits[0]:0,
exceptfds?exceptfds->fds_bits[0]:0,
timeout?"&":"NULL/", timeout?timeout->tv_sec:0,
timeout?timeout->tv_usec:0);
#else
Debug7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu.%06u)",
n, readfds->__fds_bits[0], writefds->__fds_bits[0],
exceptfds->__fds_bits[0],
n, readfds?readfds->__fds_bits[0]:0, writefds?writefds->__fds_bits[0]:0,
exceptfds?exceptfds->__fds_bits[0]:0,
timeout?"&":"NULL/", timeout?timeout->tv_sec:0,
timeout?timeout->tv_usec:0);
#endif
result = select(n, readfds, writefds, exceptfds, timeout);
_errno = errno;
if (!diag_in_handler) diag_flush();
#if HAVE_FDS_BITS
Debug7("select -> (, 0x%lx, 0x%lx, 0x%lx, %s%lu."F_tv_usec"), %d",
readfds->fds_bits[0], writefds->fds_bits[0], exceptfds->fds_bits[0],
readfds?readfds->fds_bits[0]:0, writefds?writefds->fds_bits[0]:0,
exceptfds?exceptfds->fds_bits[0]:0,
timeout?"&":"NULL/", timeout?timeout->tv_sec:0,
timeout?timeout->tv_usec:0, result);
#else
Debug7("select -> (, 0x%lx, 0x%lx, 0x%lx, %s%lu.%06u), %d",
readfds->__fds_bits[0], writefds->__fds_bits[0],
exceptfds->__fds_bits[0],
readfds?readfds->__fds_bits[0]:0, writefds?writefds->__fds_bits[0]:0,
exceptfds?exceptfds->__fds_bits[0]:0,
timeout?"&":"NULL/", timeout?timeout->tv_sec:0,
timeout?timeout->tv_usec:0, result);
#endif
errno = _errno;
return result;
}
@ -777,9 +801,11 @@ pid_t Fork(void) {
pid_t Waitpid(pid_t pid, int *status, int options) {
int _errno;
pid_t retval;
if (!diag_in_handler) diag_flush();
Debug3("waitpid("F_pid", %p, %d)", pid, status, options);
retval = waitpid(pid, status, options);
_errno = errno;
if (!diag_in_handler) diag_flush();
Debug2("waitpid(, {%d}, ) -> "F_pid, *status, retval);
errno = _errno;
return retval;
@ -868,7 +894,9 @@ int Execvp(const char *file, char *const argv[]) {
int System(const char *string) {
int result, _errno;
Debug1("system(\"%s\")", string);
diag_immediate_exit = 1;
result = system(string);
diag_immediate_exit = 0;
_errno = errno;
Debug1("system() -> %d", result);
errno = _errno;
@ -917,6 +945,7 @@ int Connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) {
int result, _errno;
char infobuff[256];
if (!diag_in_handler) diag_flush();
/*sockaddr_info(serv_addr, infobuff, sizeof(infobuff));
Debug3("connect(%d, %s, "F_Zd")", sockfd, infobuff, addrlen);*/
#if 0
@ -939,6 +968,7 @@ int Connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) {
#endif
result = connect(sockfd, serv_addr, addrlen);
_errno = errno;
if (!diag_in_handler) diag_flush();
Debug1("connect() -> %d", result);
errno = _errno;
return result;
@ -961,10 +991,17 @@ int Listen(int s, int backlog) {
/* don't forget to handle EINTR when using Accept() ! */
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
int result, _errno;
fd_set accept_s;
if (!diag_in_handler) diag_flush();
FD_ZERO(&accept_s);
FD_SET(s, &accept_s);
if (diag_select(s+1, &accept_s, NULL, NULL, NULL) < 0) {
return -1;
}
Debug3("accept(%d, %p, %p)", s, addr, addrlen);
result = accept(s, addr, addrlen);
_errno = errno;
if (!diag_in_handler) diag_flush();
if (result >= 0) {
char infobuff[256];
sockaddr_info(addr, *addrlen, infobuff, sizeof(infobuff));
@ -1051,9 +1088,11 @@ int Setsockopt(int s, int level, int optname, const void *optval, int optlen) {
#if _WITH_SOCKET
int Recv(int s, void *buf, size_t len, int flags) {
int retval, _errno;
if (!diag_in_handler) diag_flush();
Debug4("recv(%d, %p, "F_Zu", %d)", s, buf, len, flags);
retval = recv(s, buf, len, flags);
_errno = errno;
if (!diag_in_handler) diag_flush();
Debug1("recv() -> %d", retval);
errno = _errno;
return retval;
@ -1065,10 +1104,12 @@ int Recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from,
socklen_t *fromlen) {
int retval, _errno;
char infobuff[256];
if (!diag_in_handler) diag_flush();
Debug6("recvfrom(%d, %p, "F_Zu", %d, %p, "F_socklen")",
s, buf, len, flags, from, *fromlen);
retval = recvfrom(s, buf, len, flags, from, fromlen);
_errno = errno;
if (!diag_in_handler) diag_flush();
if (from) {
Debug4("recvfrom(,,,, {%d,%s}, "F_socklen") -> %d",
from->sa_family,
@ -1085,6 +1126,7 @@ int Recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from,
#if _WITH_SOCKET
int Recvmsg(int s, struct msghdr *msgh, int flags) {
int retval, _errno;
if (!diag_in_handler) diag_flush();
char infobuff[256];
#if defined(HAVE_STRUCT_MSGHDR_MSGCONTROL) && defined(HAVE_STRUCT_MSGHDR_MSGCONTROLLEN) && defined(HAVE_STRUCT_MSGHDR_MSGFLAGS)
Debug10("recvmsg(%d, %p{%p,%u,%p,"F_Zu",%p,"F_Zu",%d}, %d)", s, msgh,
@ -1097,6 +1139,7 @@ int Recvmsg(int s, struct msghdr *msgh, int flags) {
#endif
retval = recvmsg(s, msgh, flags);
_errno = errno;
if (!diag_in_handler) diag_flush();
#if defined(HAVE_STRUCT_MSGHDR_MSGCONTROLLEN)
Debug5("recvmsg(, {%s,%u,,"F_Zu",,"F_Zu",}, ) -> %d",
msgh->msg_name?sockaddr_info(msgh->msg_name, msgh->msg_namelen, infobuff, sizeof(infobuff)):"NULL",
@ -1116,10 +1159,12 @@ int Recvmsg(int s, struct msghdr *msgh, int flags) {
#if _WITH_SOCKET
int Send(int s, const void *mesg, size_t len, int flags) {
int retval, _errno;
if (!diag_in_handler) diag_flush();
Debug5("send(%d, %p[%08x...], "F_Zu", %d)",
s, mesg, ntohl(*(unsigned long *)mesg), len, flags);
retval = send(s, mesg, len, flags);
_errno = errno;
if (!diag_in_handler) diag_flush();
Debug1("send() -> %d", retval);
errno = _errno;
return retval;
@ -1132,11 +1177,13 @@ int Sendto(int s, const void *mesg, size_t len, int flags,
int retval, _errno;
char infobuff[256];
if (!diag_in_handler) diag_flush();
sockaddr_info(to, tolen, infobuff, sizeof(infobuff));
Debug7("sendto(%d, %p[%08x...], "F_Zu", %d, {%s}, %d)",
s, mesg, htonl(*(unsigned long *)mesg), len, flags, infobuff, tolen);
retval = sendto(s, mesg, len, flags, to, tolen);
_errno = errno;
if (!diag_in_handler) diag_flush();
Debug1("sendto() -> %d", retval);
errno = _errno;
return retval;
@ -1163,6 +1210,7 @@ unsigned int Sleep(unsigned int seconds) {
return retval;
}
/* obsolete by POSIX.1-2001 */
void Usleep(unsigned long usec) {
Debug1("usleep(%lu)", usec);
usleep(usec);
@ -1451,6 +1499,7 @@ int Atexit(void (*func)(void)) {
void Exit(int status) {
if (!diag_in_handler) diag_flush();
Debug1("exit(%d)", status);
exit(status);
}

View File

@ -1,5 +1,5 @@
/* source: sysincludes.h */
/* Copyright Gerhard Rieger 2001-2011 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __sysincludes_h_included
@ -26,7 +26,7 @@
#include <syslog.h> /* openlog(), syslog(), closelog() */
#endif
#include <signal.h> /* signal(), SIGPIPE, SIG_IGN */
#include <time.h> /* struct timeval, strftime() */
#include <time.h> /* struct timeval, strftime(), clock_gettime() */
#if 0
#include <sys/timeb.h> /* struct timeb */
#endif

1022
test.sh

File diff suppressed because it is too large Load Diff

569
vsnprintf_r.c Normal file
View File

@ -0,0 +1,569 @@
/* vsnprintf_r.c */
/* Copyright Gerhard Rieger */
/* a reduced but async-signal-safe and thread-safe version of vsnprintf */
#include "config.h"
#include <stddef.h> /* ptrdiff_t */
#include <ctype.h> /* isdigit() */
#include <stdarg.h>
#include <stdlib.h>
#include <errno.h>
#if HAVE_SYSLOG_H
#include <syslog.h>
#endif
#include <sys/utsname.h>
#include <time.h> /* time_t, strftime() */
#include <sys/time.h> /* gettimeofday() */
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "vsnprintf_r.h"
/* helper functions for vsnprintf_r():
e.g. convert an unsigned long to decimal string.
in: field (must be long enough for all digits and \0
n: length of field in bytes
ulo: the value
returns: the pointer to the result string (need not be ==field)
*/
/* this function converts an unsigned long number to decimal ASCII
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it terminates result with \0
*/
static char *_diag_ulong_to_dec(char *field, size_t n, unsigned long ulo) {
char *np = field+n; /* point to the end */
if (n == 0) return NULL;
*--np = '\0'; /* \0 in last char of string */
/* this is not optimal - uses much CPU, but simple to implement */
/* calculate the result from right to left */
do { if (np==field) return NULL; *--np = '0'+(ulo%10); } while (ulo/=10);
return np;
}
/* this function converts an unsigned long number to decimal ASCII
and pads it with space or '0' when size and leading0 are set appropriately
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it reduces size to n-1 if it is greater or equal
it terminates result with \0
*/
static char *diag_ulong_to_dec(char *field, size_t n, unsigned long ulo, int leading0, int size) {
char *np;
char c;
int i;
if (n == 0) return NULL;
np = _diag_ulong_to_dec(field, n, ulo);
if (np == NULL) return np;
if (size) {
if (size >= n) size = n-1;
if (leading0) {
c = '0';
} else {
c = ' ';
}
i = size - strlen(np);
while (--i >= 0) {
*--np = c;
}
}
return np;
}
/* this function converts a signed long number to decimal ASCII
and pads it with space or '0' when size and leading0 are set appropriately
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it reduces size to n-1 if it is greater or equal
it terminates result with \0
*/
/* like diag_ulong_to_dec but signed; fields need also space for '-' */
static char *diag_long_to_dec(char *field, size_t n, long lo, int leading0, int size) {
char *np;
int minus;
unsigned long ulo;
int i;
if ((minus = (lo < 0))) {
ulo = (~lo)+1;
} else {
ulo = lo;
}
np = _diag_ulong_to_dec(field, n, ulo);
if (np == NULL) return np;
if (size) {
if (size >= n) size = n-1;
i = size - strlen(np);
if (leading0) {
if (minus) --i;
while (--i >= 0) {
*--np = '0';
}
if (minus) *--np = '-';
} else {
if (minus) { *--np = '-'; --i; }
while (--i >= 0) {
*--np = ' ';
}
}
} else {
if (minus) *--np = '-';
}
return np;
}
/* this function converts an unsigned long number to hexadecimal ASCII
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it terminates result with \0
*/
static char *diag_ulong_to_hex(char *field, size_t n, unsigned long ulo, int leading0, size_t size) {
char *np = field+n; /* point to the end */
int i;
char c;
if (n == 0) return NULL;
*--np = '\0'; /* \0 in last char of string */
/* calculate the result from right to left */
do { if (np==field) return NULL; i = (ulo&0x0f);
*--np = (i<10?'0':('a'-10))+i; }
while (ulo>>=4);
if (size) {
if (size >= n) size = n-1;
if (leading0) {
c = '0';
} else {
c = ' ';
}
i = size - strlen(np);
while (--i >= 0) {
*--np = c;
}
}
return np;
}
/* this function converts an unsigned long number to octal ASCII
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it terminates result with \0
*/
static char *diag_ulong_to_oct(char *field, size_t n, unsigned long ulo, int leading0, size_t size) {
char *np = field+n; /* point to the end */
int i;
char c;
if (n == 0) return NULL;
*--np = '\0'; /* \0 in last char of string */
/* calculate the result from right to left */
do { if (np==field) return NULL; i = (ulo&0x07); *--np = '0'+i; }
while (ulo>>=3);
if (size) {
if (size >= n) size = n-1;
if (leading0) {
c = '0';
} else {
c = ' ';
}
i = size - strlen(np);
while (--i >= 0) {
*--np = c;
}
}
return np;
}
#if HAVE_TYPE_LONGLONG
/* this function converts an unsigned long long number to decimal ASCII
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it terminates result with \0
*/
static char *_diag_ulonglong_to_dec(char *field, size_t n, unsigned long long ull) {
char *np = field+n; /* point to the end */
if (n == 0) return NULL;
*--np = '\0'; /* \0 in last char of string */
/* this is not optimal - uses much CPU, but simple to implement */
/* calculate the result from right to left */
do { if (np==field) return NULL; *--np = '0'+(ull%10); } while (ull/=10);
return np;
}
/* this function converts an unsigned long long number to decimal ASCII
and pads it with space or '0' when size and leading0 are set appropriately
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it reduces size to n-1 if it is greater or equal
it terminates result with \0
*/
static char *diag_ulonglong_to_dec(char *field, size_t n, unsigned long long ull, int leading0, int size) {
char *np;
char c;
int i;
if (n == 0) return NULL;
np = _diag_ulonglong_to_dec(field, n, ull);
if (size) {
if (size >= n) size = n-1;
if (leading0) {
c = '0';
} else {
c = ' ';
}
i = size - strlen(np);
while (i-- > 0) {
*--np = c;
}
}
return np;
}
/* this function converts a signed long long number to decimal ASCII
and pads it with space or '0' when size and leading0 are set appropriately
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it reduces size to n-1 if it is greater or equal
it terminates result with \0
*/
/* like diag_ulonglong_to_dec but signed; fields need also space for '-' */
static char *diag_longlong_to_dec(char *field, size_t n, long long ll, int leading0, int size) {
char *np;
int minus;
unsigned long ull;
int i;
if ((minus = (ll < 0))) {
ull = (~ll)+1;
} else {
ull = ll;
}
np = _diag_ulonglong_to_dec(field, n, ull);
if (np == NULL) return np;
if (size) {
if (size >= n) size = n-1;
i = size - strlen(np);
if (leading0) {
if (minus) --i;
while (--i >= 0) {
*--np = '0';
}
if (minus) *--np = '-';
} else {
if (minus) { *--np = '-'; --i; }
while (--i >= 0) {
*--np = ' ';
}
}
}
return np;
}
/* this function converts an unsigned long long number to hexadecimal ASCII
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it terminates result with \0
*/
static char *diag_ulonglong_to_hex(char *field, size_t n, unsigned long long ull, int leading0, size_t size) {
char *np = field+n; /* point to the end */
unsigned int i;
char c;
if (n == 0) return NULL;
*--np = '\0'; /* \0 in last char of string */
/* calculate the result from right to left */
do { if (np==field) return NULL; i = (ull&0x0f);
*--np = (i<10?'0':('a'-10))+i; }
while (ull>>=4);
if (size) {
if (size >= n) size = n-1;
if (leading0) {
c = '0';
} else {
c = ' ';
}
i = size - strlen(np);
while (--i >= 0) {
*--np = c;
}
}
return np;
}
/* this function converts an unsigned long long number to octal ASCII
it is async signal safe and thread safe
it returns NULL if n==0
it returns NULL if field is too short to hold the result
it returns a pointer to the result string (somewhere within field)
it terminates result with \0
*/
static char *diag_ulonglong_to_oct(char *field, size_t n, unsigned long long ull, int leading0, size_t size) {
char *np = field+n; /* point to the end */
int i;
char c;
if (n == 0) return NULL;
*--np = '\0'; /* \0 in last char of string */
/* calculate the result from right to left */
do { if (np==field) return NULL; i = (ull&0x07); *--np = '0'+i; }
while (ull>>=3);
if (size) {
if (size >= n) size = n-1;
if (leading0) {
c = '0';
} else {
c = ' ';
}
i = size - strlen(np);
while (--i >= 0) {
*--np = c;
}
}
return np;
}
#endif /* HAVE_TYPE_LONGLONG */
/* this function is designed as a variant of vsnprintf(3) but async signal safe
and thread safe
it currently only implements a subset of the format directives
returns <0 if an error occurred (no scenario know yet)
returns >=size if output is truncated (conforming to C99 standard)
*/
int vsnprintf_r(char *str, size_t size, const char *format, va_list ap) {
size_t i = 0;
char c;
int full = 0; /* indicate if output buffer full */
--size; /* without trailing \0 */
while (c = *format++) {
if (c == '\\') {
} else if (c == '%') {
#if HAVE_TYPE_LONGLONG
# define num_buff_len ((sizeof(unsigned long long)*8+2)/3+1) /* hold up to u long long in octal w/ \0 */
#else
# define num_buff_len ((sizeof(unsigned long)*8+2)/3+1)]; /* hold up to u long in octal w/ \0 */
#endif
char lengthmod = '\0'; /* 'h' 'l' 'L' 'z' */
int leading0 = 0; /* or 1 */
size_t fsize = 0; /* size of field */
const char *st; /* string */
long lo; unsigned long ulo;
#if HAVE_TYPE_LONGLONG
long long ll; unsigned long long ull;
#endif
char field[num_buff_len]; /* result of number conversion */
char *np; /* num pointer */
c = *format++;
if (c == '\0') { break; }
/* flag characters */
switch (c) {
case '0': leading0 = 1; c = *format++; break;
/* not handled: '#' '-' ' ' '+' '\'' */
}
if (c == '\0') { break; }
/* field width */
switch (c) {
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
do {
fsize = 10*fsize+(c-'0');
c = *format++;
} while (c && isdigit(c));
break;
}
if (c == '\0') { break; }
/* precision - not handles */
/* length modifier */
switch (c) {
/* not handled: 'q' 'j' 't' */
/* handled: 'h' 'hh'->'H' 'z' 'Z'->'z' 'l' 'll'->'L' 'L' */
case 'Z': c = 'z'; /* fall through */
#if HAVE_TYPE_LONGLONG
case 'L':
#endif
case 'z': lengthmod = c; c = *format++; break;
case 'h':
lengthmod = c;
if ((c = *format++) == 'h') {
lengthmod = 'H'; c = *format++;
}
break;
case 'l':
lengthmod = c;
if ((c = *format++) == 'l') {
lengthmod = 'L'; c = *format++;
}
break;
}
if (c == '\0') { break; }
/* conversion specifier */
switch (c) {
case 'c': c = va_arg(ap, int); /* fall through */
case '%': *str++ = c; if (++i == size) { full = 1; } break;
case 's': st = va_arg(ap, const char *);
/* no modifier handled! */
while (c = *st++) {
*str++ = c;
if (++i == size) { full = 1; break; }
}
break;
case 'd':
#if HAVE_TYPE_LONGLONG
if (lengthmod == 'L') {
ll = va_arg(ap, long long);
np = diag_longlong_to_dec(field, num_buff_len, ll, leading0, fsize);
while (c = *np++) {
*str++ = c;
if (++i == size) { full = 1; break; }
}
} else
#endif
{
switch (lengthmod) {
case 'l': lo = va_arg(ap, long); break;
case 'z': lo = va_arg(ap, ptrdiff_t); break;
default: lo = va_arg(ap, int); break;
}
np = diag_long_to_dec(field, num_buff_len, lo, leading0, fsize);
while (c = *np++) { *str++ = c;
if (++i == size) { full = 1; break; }
}
}
break;
case 'u':
#if HAVE_TYPE_LONGLONG
if (lengthmod == 'L') {
ull = va_arg(ap, unsigned long long);
np = diag_ulonglong_to_dec(field, num_buff_len, ull, leading0, fsize);
while (c = *np++) { *str++ = c;
if (++i == size) { full = 1; break; }
}
} else
#endif
{
switch (lengthmod) {
case 'l': ulo = va_arg(ap, unsigned long); break;
case 'z': ulo = va_arg(ap, size_t); break;
default: ulo = va_arg(ap, unsigned int); break;
}
np = diag_ulong_to_dec(field, num_buff_len, ulo, leading0, fsize);
while (c = *np++) { *str++ = c;
if (++i == size) { full = 1; break; }
}
}
break;
case 'p':
ulo = va_arg(ap, size_t);
np = diag_ulong_to_hex(field, num_buff_len, ulo, leading0, fsize);
*str++ = '0'; if (++i == size) { full = 1; break; }
*str++ = 'x'; if (++i == size) { full = 1; break; }
while (c = *np++) { *str++ = c;
if (++i == size) { full = 1; break; }
}
break;
case 'x':
#if HAVE_TYPE_LONGLONG
if (lengthmod == 'L') {
ull = va_arg(ap, unsigned long long);
np = diag_ulonglong_to_hex(field, num_buff_len, ull, leading0, fsize);
while (c = *np++) { *str++ = c;
if (++i == size) { full = 1; break; }
}
} else
#endif
{
switch (lengthmod) {
case 'l': ulo = va_arg(ap, unsigned long); break;
case 'z': ulo = va_arg(ap, size_t); break;
default: ulo = va_arg(ap, unsigned int); break;
}
np = diag_ulong_to_hex(field, num_buff_len, ulo, leading0, fsize);
while (c = *np++) { *str++ = c;
if (++i == size) { full = 1; break; }
}
}
break;
case 'o':
#if HAVE_TYPE_LONGLONG
if (lengthmod == 'L') {
ull = va_arg(ap, unsigned long long);
np = diag_ulonglong_to_oct(field, num_buff_len, ull, leading0, fsize);
while (c = *np++) { *str++ = c;
if (++i == size) break;
}
} else
#endif
{
switch (lengthmod) {
case 'l': ulo = va_arg(ap, unsigned long); break;
case 'z': ulo = va_arg(ap, size_t); break;
default: ulo = va_arg(ap, unsigned int); break;
}
np = diag_ulong_to_oct(field, num_buff_len, ulo, leading0, fsize);
while (c = *np++) { *str++ = c;
if (++i == size) { full = 1; break; }
}
}
break;
default:
*str++ = c; if (++i == size) { full = 1; break; }
}
if (full) break;
} else {
*str++ = c;
if (++i == size) break;
}
}
*str = '\0';
return i;
}
int snprintf_r(char *str, size_t size, const char *format, ...) {
int result;
va_list ap;
va_start(ap, format);
result = vsnprintf_r(str, size, format, ap);
va_end(ap);
return result;
}

11
vsnprintf_r.h Normal file
View File

@ -0,0 +1,11 @@
/* source: vsnprintf_r.h */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __vsnprintf_r_h_included
#define __vsnprintf_r_h_included 1
int vsnprintf_r(char *str, size_t size, const char *format, va_list ap);
int snprintf_r(char *str, size_t size, const char *format, ...);
#endif /* !defined(__vsnprintf_r_h_included) */

View File

@ -1099,7 +1099,7 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
handler sets xio_hashappened if the pid matched.
*/
static pid_t xio_waitingfor; /* info from recv loop to signal handler:
indicates the pid that of the child process
indicates the pid of the child process
that should send us the USR1 signal */
static bool xio_hashappened; /* info from signal handler to loop: child
process has read ("consumed") the packet */
@ -1113,6 +1113,9 @@ void xiosigaction_hasread(int signum
int _errno;
int status = 0;
bool wassig = false;
_errno = errno;
diag_in_handler = 1;
#if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
Debug5("xiosigaction_hasread(%d, {%d,%d,%d,"F_pid"}, )",
signum, siginfo->si_signo, siginfo->si_errno, siginfo->si_code,
@ -1121,35 +1124,39 @@ void xiosigaction_hasread(int signum
Debug1("xiosigaction_hasread(%d)", signum);
#endif
if (signum == SIGCHLD) {
_errno = errno;
do {
pid = Waitpid(-1, &status, WNOHANG);
if (pid == 0) {
Msg(wassig?E_INFO:E_WARN,
"waitpid(-1, {}, WNOHANG): no child has exited");
Info("xiosigaction_hasread() finished");
errno = _errno;
Debug("xiosigaction_hasread() ->");
diag_in_handler = 0;
errno = _errno;
return;
} else if (pid < 0 && errno == ECHILD) {
Msg1(wassig?E_INFO:E_WARN,
"waitpid(-1, {}, WNOHANG): %s", strerror(errno));
Msg(wassig?E_INFO:E_WARN,
"waitpid(-1, {}, WNOHANG): "F_strerror);
Info("xiosigaction_hasread() finished");
errno = _errno;
Debug("xiosigaction_hasread() ->");
diag_in_handler = 0;
errno = _errno;
return;
}
wassig = true;
if (pid < 0) {
Warn2("waitpid(-1, {%d}, WNOHANG): %s", status, strerror(errno));
Warn1("waitpid(-1, {%d}, WNOHANG): "F_strerror, status);
Info("xiosigaction_hasread() finished");
errno = _errno;
Debug("xiosigaction_hasread() ->");
diag_in_handler = 0;
errno = _errno;
return;
}
if (pid == xio_waitingfor) {
xio_hashappened = true;
Debug("xiosigaction_hasread() ->");
diag_in_handler = 0;
errno = _errno;
return;
}
} while (1);
@ -1161,7 +1168,12 @@ void xiosigaction_hasread(int signum
#else
xio_hashappened = true;
#endif
#if !HAVE_SIGACTION
Signal(sig, xiosigaction_hasread);
#endif /* !HAVE_SIGACTION */
Debug("xiosigaction_hasread() ->");
diag_in_handler = 0;
errno = _errno;
return;
}
@ -1265,7 +1277,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
{
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_NOCLDSTOP|SA_RESTART
act.sa_flags = SA_NOCLDSTOP/*|SA_RESTART*/
#ifdef SA_SIGINFO /* not on Linux 2.0(.33) */
|SA_SIGINFO
#endif
@ -1278,6 +1290,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
#else /* Linux 2.0(.33) does not have sigaction.sa_sigaction */
act.sa_handler = xiosigaction_hasread;
#endif
sigfillset(&act.sa_mask);
if (Sigaction(SIGUSR1, &act, NULL) < 0) {
/*! Linux man does not explicitely say that errno is defined */
Warn1("sigaction(SIGUSR1, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno));

View File

@ -7,6 +7,7 @@
#include "xiosysincludes.h"
#include "compat.h"
#include "xio.h"
#include "error.h"
/* this function closes all open xio sockets on exit, if they are still open.
@ -14,9 +15,12 @@
void xioexit(void) {
int i;
diag_in_handler = 0;
Debug("starting xioexit()");
for (i = 0; i < XIO_MAXSOCK; ++i) {
if (sock[i] != NULL && sock[i]->tag != XIO_TAG_INVALID) {
xioclose(sock[i]);
}
}
Debug("finished xioexit()");
}

View File

@ -11,8 +11,13 @@
static pid_t socat_kill_pid; /* here we pass the pid to be killed in sighandler */
static void signal_kill_pid(int dummy) {
Notice("SIGALRM while waiting for w/o child process to die, killing it now");
int _errno;
_errno = errno;
diag_in_handler = 1;
Notice("SIGALRM while waiting for wo child process to die, killing it now");
Kill(socat_kill_pid, SIGTERM);
diag_in_handler = 0;
errno = _errno;
}
int xioshutdown(xiofile_t *sock, int how) {
@ -114,7 +119,13 @@ int xioshutdown(xiofile_t *sock, int how) {
we raise an alarm after some time.
NOTE: the alarm does not terminate waitpid() on Linux/glibc (BUG?),
therefore we have to do the kill in the signal handler */
Signal(SIGALRM, signal_kill_pid);
{
struct sigaction act;
sigfillset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = signal_kill_pid;
Sigaction(SIGALRM, &act, NULL);
}
socat_kill_pid = sock->stream.para.exec.pid;
#if HAVE_SETITIMER
/*! with next feature release, we get usec resolution and an option */

View File

@ -27,6 +27,7 @@ int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *)) {
}
/* exec'd child has died, perform appropriate changes to descriptor */
/* is async-signal-safe */
static int sigchld_stream(struct single *file) {
/*!! call back to application */
file->para.exec.pid = 0;
@ -47,7 +48,7 @@ static int xio_checkchild(xiofile_t *socket, int socknum, pid_t deadchild) {
socket->stream.para.exec.pid == deadchild) {
Info2("exec'd process %d on socket %d terminated",
socket->stream.para.exec.pid, socknum);
sigchld_stream(&socket->stream);
sigchld_stream(&socket->stream); /* is async-signal-safe */
return 1;
}
} else {
@ -78,8 +79,8 @@ void childdied(int signum) {
to set it to EINTR _before_ handling the signal, and
then passes the value left by the signal handler to
the caller of select(), accept() etc. */
/* is not thread/signal save, but confused messages in rare cases are better
than no messages at all */
diag_in_handler = 1;
Notice1("childdied(): handling signal %d", signum);
Info1("childdied(signum=%d)", signum);
do {
pid = Waitpid(-1, &status, WNOHANG);
@ -87,19 +88,22 @@ void childdied(int signum) {
Msg(wassig?E_INFO:E_WARN,
"waitpid(-1, {}, WNOHANG): no child has exited");
Info("childdied() finished");
diag_in_handler = 0;
errno = _errno;
return;
} else if (pid < 0 && errno == ECHILD) {
Msg1(wassig?E_INFO:E_WARN,
"waitpid(-1, {}, WNOHANG): %s", strerror(errno));
Msg(wassig?E_INFO:E_WARN,
"waitpid(-1, {}, WNOHANG): "F_strerror);
Info("childdied() finished");
diag_in_handler = 0;
errno = _errno;
return;
}
wassig = true;
if (pid < 0) {
Warn2("waitpid(-1, {%d}, WNOHANG): %s", status, strerror(errno));
Warn1("waitpid(-1, {%d}, WNOHANG): "F_strerror, status);
Info("childdied() finished");
diag_in_handler = 0;
errno = _errno;
return;
}
@ -142,11 +146,12 @@ void childdied(int signum) {
#if !HAVE_SIGACTION
/* we might need to re-register our handler */
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
Warn("signal(SIGCHLD, childdied): "F_strerror);
}
#endif /* !HAVE_SIGACTION */
} while (1);
Info("childdied() finished");
diag_in_handler = 0;
errno = _errno;
}
@ -155,12 +160,13 @@ int xiosetchilddied(void) {
#if HAVE_SIGACTION
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_NOCLDSTOP|SA_RESTART
act.sa_flags = SA_NOCLDSTOP/*|SA_RESTART*/
#ifdef SA_NOMASK
|SA_NOMASK
#endif
;
act.sa_handler = childdied;
sigfillset(&act.sa_mask);
if (Sigaction(SIGCHLD, &act, NULL) < 0) {
/*! man does not say that errno is defined */
Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied, strerror(errno));

View File

@ -1,5 +1,5 @@
/* source: xiosignal.c */
/* Copyright Gerhard Rieger 2001-2003 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains code for handling signals (except SIGCHLD) */
@ -35,6 +35,7 @@ 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) {
@ -46,21 +47,26 @@ static struct socat_sig_desc *socat_get_sig_desc(int signum) {
return sigdesc;
}
/* a signal handler that eventually passes the signal to sub processes */
/* a signal handler that possibly passes the signal to sub processes */
void socatsignalpass(int sig) {
int i;
struct socat_sig_desc *sigdesc;
int _errno;
Debug1("socatsignalpass(%d)", sig);
if ((sigdesc = socat_get_sig_desc(sig)) == NULL) {
_errno = errno;
diag_in_handler = 1;
Notice1("socatsignalpass(%d)", sig);
if ((sigdesc = socat_get_sig_desc(sig)) == NULL) { /* is async-signal-safe */
diag_in_handler = 0;
errno = _errno;
return;
}
for (i=0; i<sigdesc->sig_use; ++i) {
if (sigdesc->sig_pids[i]) {
if (Kill(sigdesc->sig_pids[i], sig) < 0) {
Warn3("kill("F_pid", %d): %s",
sigdesc->sig_pids[i], sig, strerror(errno));
Warn2("kill("F_pid", %d): %m",
sigdesc->sig_pids[i], sig);
}
}
}
@ -68,6 +74,8 @@ void socatsignalpass(int sig) {
Signal(sig, socatsignalpass);
#endif /* !HAVE_SIGACTION */
Debug("socatsignalpass() ->");
diag_in_handler = 0;
errno = _errno;
}
@ -91,8 +99,9 @@ int xio_opt_signal(pid_t pid, int signum) {
#if HAVE_SIGACTION
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_RESTART;
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));