mirror of
https://github.com/moparisthebest/socat
synced 2024-12-21 06:28:48 -05:00
Made code async-signal-safe
This commit is contained in:
parent
e4c6f3d934
commit
2af0495cc6
19
CHANGES
19
CHANGES
@ -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:
|
||||
|
16
DEVELOPMENT
16
DEVELOPMENT
@ -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
|
||||
|
@ -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)
|
||||
|
4
compat.h
4
compat.h
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
283
error.c
@ -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
34
error.h
@ -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) */
|
||||
|
20
hostan.c
20
hostan.c
@ -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);
|
||||
|
@ -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
85
snprinterr.c
Normal 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
10
snprinterr.h
Normal 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
58
socat.c
@ -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);
|
||||
}
|
||||
|
6
sslcls.c
6
sslcls.c
@ -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
67
sycls.c
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
569
vsnprintf_r.c
Normal file
569
vsnprintf_r.c
Normal 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
11
vsnprintf_r.h
Normal 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) */
|
31
xio-socket.c
31
xio-socket.c
@ -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));
|
||||
|
@ -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()");
|
||||
}
|
||||
|
@ -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 */
|
||||
|
22
xiosigchld.c
22
xiosigchld.c
@ -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));
|
||||
|
23
xiosignal.c
23
xiosignal.c
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user