report child process exit status according to config parameter

Add new global setting 'reportChildProcessExits' with possible values
'none|errors|all' (default 'errors'), and new global function
'glblReportChildProcessExit' to report the exit status of a child
process according to the setting.

Invoke the report function whenever rsyslog reaps a child, namely in:
- rsyslogd.c (SIGCHLD signal handler)
- omprog
- mmexternal
- srutils.c (execProg function, invoked from stream.c and omshell)

Remove redundant "reaped by main loop" info log in omprog.

Promote debug message in mmexternal indicating that the child has
terminated prematurely to a warning log, like in omprog.

Closes #3281
This commit is contained in:
Joan Sala 2018-12-02 19:54:00 +01:00
parent 49eda256b9
commit 9315787c6d
10 changed files with 164 additions and 101 deletions

View File

@ -40,6 +40,7 @@
#include "msg.h"
#include "errmsg.h"
#include "cfsysline.h"
#include "glbl.h"
MODULE_TYPE_OUTPUT
@ -384,26 +385,15 @@ cleanup(wrkrInstanceData_t *pWrkrData)
{
int status;
int ret;
char errStr[1024];
DEFiRet;
assert(pWrkrData->bIsRunning == 1);
ret = waitpid(pWrkrData->pid, &status, 0);
if(ret != pWrkrData->pid) {
/* if waitpid() fails, we can not do much - try to ignore it... */
DBGPRINTF("mmexternal: waitpid() returned state %d[%s], future malfunction may happen\n", ret,
rs_strerror_r(errno, errStr, sizeof(errStr)));
} else {
/* check if we should print out some diagnostic information */
DBGPRINTF("mmexternal: waitpid status return for program '%s': %2.2x\n",
pWrkrData->pData->szBinary, status);
if(WIFEXITED(status)) {
LogError(0, NO_ERRCODE, "program '%s' exited normally, state %d",
pWrkrData->pData->szBinary, WEXITSTATUS(status));
} else if(WIFSIGNALED(status)) {
LogError(0, NO_ERRCODE, "program '%s' terminated by signal %d.",
pWrkrData->pData->szBinary, WTERMSIG(status));
}
/* waitpid will fail with errno == ECHILD if the child process has already
been reaped by the rsyslogd main loop (see rsyslogd.c) */
if(ret == pWrkrData->pid) {
glblReportChildProcessExit(pWrkrData->pData->szBinary, pWrkrData->pid, status);
}
if(pWrkrData->fdOutput != -1) {
@ -448,7 +438,6 @@ callExtProg(wrkrInstanceData_t *__restrict__ const pWrkrData, smsg_t *__restrict
int lenWrite;
int writeOffset;
int i_iov;
char errStr[1024];
struct iovec iov[2];
int bFreeInputstr = 1; /* we must only free if it does not point to msg-obj mem! */
const uchar *inputstr = NULL; /* string to be processed by external program */
@ -482,15 +471,15 @@ callExtProg(wrkrInstanceData_t *__restrict__ const pWrkrData, smsg_t *__restrict
if(lenWritten == -1) {
switch(errno) {
case EPIPE:
DBGPRINTF("mmexternal: program '%s' terminated, trying to restart\n",
pWrkrData->pData->szBinary);
LogMsg(0, RS_RET_ERR_WRITE_PIPE, LOG_WARNING,
"mmexternal: program '%s' (pid %d) terminated; will be restarted",
pWrkrData->pData->szBinary, pWrkrData->pid);
CHKiRet(cleanup(pWrkrData));
CHKiRet(tryRestart(pWrkrData));
writeOffset = 0;
break;
default:
DBGPRINTF("mmexternal: error %d writing to pipe: %s\n", errno,
rs_strerror_r(errno, errStr, sizeof(errStr)));
LogError(errno, RS_RET_ERR_WRITE_PIPE, "mmexternal: error sending message to program");
ABORT_FINALIZE(RS_RET_ERR_WRITE_PIPE);
break;
}

View File

@ -46,6 +46,7 @@
#include "module-template.h"
#include "errmsg.h"
#include "cfsysline.h"
#include "glbl.h"
MODULE_TYPE_OUTPUT
MODULE_TYPE_NOKEEP
@ -336,28 +337,14 @@ waitForChild(instanceData *pData, childProcessCtx_t *pChildCtx)
LogError(errno, RS_RET_SYS_ERR, "omprog: could not send SIGKILL to child process");
return;
}
ret = waitpid(pChildCtx->pid, &status, 0);
}
if (ret != pChildCtx->pid) {
if (errno == ECHILD) { /* child reaped by the rsyslogd main loop (see rsyslogd.c) */
LogMsg(0, NO_ERRCODE, LOG_INFO, "omprog: program '%s' (pid %d) exited; reaped by main loop",
pData->szBinary, pChildCtx->pid);
} else {
LogError(errno, RS_RET_SYS_ERR, "omprog: waitpid failed for program '%s' (pid %d)",
pData->szBinary, pChildCtx->pid);
}
} else {
/* check if we should print out some diagnostic information */
DBGPRINTF("omprog: waitpid status return for program '%s' (pid %d): %2.2x\n",
pData->szBinary, pChildCtx->pid, status);
if(WIFEXITED(status)) {
LogMsg(0, NO_ERRCODE, LOG_INFO, "omprog: program '%s' (pid %d) exited normally, status %d",
pData->szBinary, pChildCtx->pid, WEXITSTATUS(status));
} else if(WIFSIGNALED(status)) {
LogMsg(0, NO_ERRCODE, LOG_WARNING, "omprog: program '%s' (pid %d) terminated by signal %d",
pData->szBinary, pChildCtx->pid, WTERMSIG(status));
}
/* waitpid will fail with errno == ECHILD if the child process has already
been reaped by the rsyslogd main loop (see rsyslogd.c) */
if(ret == pChildCtx->pid) {
glblReportChildProcessExit(pData->szBinary, pChildCtx->pid, status);
}
}

View File

@ -31,6 +31,7 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
@ -56,6 +57,10 @@
#include "rsconf.h"
#include "queue.h"
#define REPORT_CHILD_PROCESS_EXITS_NONE 0
#define REPORT_CHILD_PROCESS_EXITS_ERRORS 1
#define REPORT_CHILD_PROCESS_EXITS_ALL 2
/* some defaults */
#ifndef DFLT_NETSTRM_DRVR
# define DFLT_NETSTRM_DRVR ((uchar*)"ptcp")
@ -90,6 +95,7 @@ static int iMaxLine = 8096; /* maximum length of a syslog message */
static uchar * oversizeMsgErrorFile = NULL; /* File where oversize messages are written to */
static int oversizeMsgInputMode = 0; /* Mode which oversize messages will be forwarded */
static int reportOversizeMsg = 1; /* shall error messages be generated for oversize messages? */
static int reportChildProcessExits = REPORT_CHILD_PROCESS_EXITS_ERRORS;
static int iGnuTLSLoglevel = 0;
static int iDefPFFamily = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */
static int bDropMalPTRMsgs = 0;/* Drop messages which have malicious PTR records during DNS lookup */
@ -168,6 +174,7 @@ static struct cnfparamdescr cnfparamdescr[] = {
{ "oversizemsg.errorfile", eCmdHdlrGetWord, 0 },
{ "oversizemsg.report", eCmdHdlrBinary, 0 },
{ "oversizemsg.input.mode", eCmdHdlrGetWord, 0 },
{ "reportchildprocessexits", eCmdHdlrGetWord, 0 },
{ "action.reportsuspension", eCmdHdlrBinary, 0 },
{ "action.reportsuspensioncontinuation", eCmdHdlrBinary, 0 },
{ "parser.controlcharacterescapeprefix", eCmdHdlrGetChar, 0 },
@ -480,6 +487,25 @@ setOversizeMsgInputMode(const uchar *const mode)
RETiRet;
}
static rsRetVal ATTR_NONNULL()
setReportChildProcessExits(const uchar *const mode)
{
DEFiRet;
if(!strcmp((char*)mode, "none")) {
reportChildProcessExits = REPORT_CHILD_PROCESS_EXITS_NONE;
} else if(!strcmp((char*)mode, "errors")) {
reportChildProcessExits = REPORT_CHILD_PROCESS_EXITS_ERRORS;
} else if(!strcmp((char*)mode, "all")) {
reportChildProcessExits = REPORT_CHILD_PROCESS_EXITS_ALL;
} else {
LogError(0, RS_RET_CONF_PARAM_INVLD,
"invalid value '%s' for global parameter reportChildProcessExits -- ignored",
mode);
iRet = RS_RET_CONF_PARAM_INVLD;
}
RETiRet;
}
static rsRetVal
setDisableDNS(int val)
{
@ -615,6 +641,42 @@ glblReportOversizeMessage(void)
return reportOversizeMsg;
}
/* logs a message indicating that a child process has terminated.
* If name != NULL, prints it as the program name.
*/
void
glblReportChildProcessExit(const uchar *name, pid_t pid, int status)
{
DBGPRINTF("waitpid for child %d returned status: %2.2x\n", pid, status);
if(reportChildProcessExits == REPORT_CHILD_PROCESS_EXITS_NONE
|| (reportChildProcessExits == REPORT_CHILD_PROCESS_EXITS_ERRORS
&& WIFEXITED(status) && WEXITSTATUS(status) == 0)) {
return;
}
if(WIFEXITED(status)) {
int severity = WEXITSTATUS(status) == 0 ? LOG_INFO : LOG_WARNING;
if(name != NULL) {
LogMsg(0, NO_ERRCODE, severity, "program '%s' (pid %d) exited with status %d",
name, pid, WEXITSTATUS(status));
} else {
LogMsg(0, NO_ERRCODE, severity, "child process (pid %d) exited with status %d",
pid, WEXITSTATUS(status));
}
} else if(WIFSIGNALED(status)) {
if(name != NULL) {
LogMsg(0, NO_ERRCODE, LOG_WARNING, "program '%s' (pid %d) terminated by signal %d",
name, pid, WTERMSIG(status));
} else {
LogMsg(0, NO_ERRCODE, LOG_WARNING, "child process (pid %d) terminated by signal %d",
pid, WTERMSIG(status));
}
}
}
/* set our local domain name. Free previous domain, if it was already set.
*/
static rsRetVal
@ -866,6 +928,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
free(oversizeMsgErrorFile);
oversizeMsgErrorFile = NULL;
oversizeMsgInputMode = glblOversizeMsgInputMode_Accept;
reportChildProcessExits = REPORT_CHILD_PROCESS_EXITS_ERRORS;
free(pszWorkDir);
pszWorkDir = NULL;
free((void*)operatingStateFile);
@ -1076,7 +1139,7 @@ glblProcessCnf(struct cnfobj *o)
if(!strcmp(paramblk.descr[i].name, "processinternalmessages")) {
bProcessInternalMessages = (int) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "internal.developeronly.options")) {
glblDevOptions = (uint64_t) cnfparamvals[i].val.d.n;
glblDevOptions = (uint64_t) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "stdlog.channelspec")) {
#ifndef ENABLE_LIBLOGGING_STDLOG
LogError(0, RS_RET_ERR, "rsyslog wasn't "
@ -1285,6 +1348,10 @@ glblDoneLoadCnf(void)
const char *const tmp = es_str2cstr(cnfparamvals[i].val.d.estr, NULL);
setOversizeMsgInputMode((uchar*) tmp);
free((void*)tmp);
} else if(!strcmp(paramblk.descr[i].name, "reportchildprocessexits")) {
const char *const tmp = es_str2cstr(cnfparamvals[i].val.d.estr, NULL);
setReportChildProcessExits((uchar*) tmp);
free((void*)tmp);
} else if(!strcmp(paramblk.descr[i].name, "debug.onshutdown")) {
glblDebugOnShutdown = (int) cnfparamvals[i].val.d.n;
LogError(0, RS_RET_OK, "debug: onShutdown set to %d", glblDebugOnShutdown);
@ -1342,40 +1409,39 @@ glblDoneLoadCnf(void)
}
free(proto);
} else if(!strcmp(paramblk.descr[i].name, "senders.reportnew")) {
glblReportNewSenders = (int) cnfparamvals[i].val.d.n;
glblReportNewSenders = (int) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "senders.reportgoneaway")) {
glblReportGoneAwaySenders = (int) cnfparamvals[i].val.d.n;
glblReportGoneAwaySenders = (int) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "senders.timeoutafter")) {
glblSenderStatsTimeout = (int) cnfparamvals[i].val.d.n;
glblSenderStatsTimeout = (int) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "senders.keeptrack")) {
glblSenderKeepTrack = (int) cnfparamvals[i].val.d.n;
glblSenderKeepTrack = (int) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "inputs.timeout.shutdown")) {
glblInputTimeoutShutdown = (int) cnfparamvals[i].val.d.n;
glblInputTimeoutShutdown = (int) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "privdrop.group.keepsupplemental")) {
loadConf->globals.gidDropPrivKeepSupplemental = (int) cnfparamvals[i].val.d.n;
loadConf->globals.gidDropPrivKeepSupplemental = (int) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "net.acladdhostnameonfail")) {
*(net.pACLAddHostnameOnFail) = (int) cnfparamvals[i].val.d.n;
*(net.pACLAddHostnameOnFail) = (int) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "net.aclresolvehostname")) {
*(net.pACLDontResolve) = !((int) cnfparamvals[i].val.d.n);
*(net.pACLDontResolve) = !((int) cnfparamvals[i].val.d.n);
} else if(!strcmp(paramblk.descr[i].name, "net.enabledns")) {
setDisableDNS(!((int) cnfparamvals[i].val.d.n));
setDisableDNS(!((int) cnfparamvals[i].val.d.n));
} else if(!strcmp(paramblk.descr[i].name, "net.permitwarning")) {
setOption_DisallowWarning(!((int) cnfparamvals[i].val.d.n));
setOption_DisallowWarning(!((int) cnfparamvals[i].val.d.n));
} else if(!strcmp(paramblk.descr[i].name, "abortonuncleanconfig")) {
loadConf->globals.bAbortOnUncleanConfig = cnfparamvals[i].val.d.n;
loadConf->globals.bAbortOnUncleanConfig = cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "internalmsg.ratelimit.burst")) {
glblIntMsgRateLimitBurst = (int) cnfparamvals[i].val.d.n;
glblIntMsgRateLimitBurst = (int) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "internalmsg.ratelimit.interval")) {
glblIntMsgRateLimitItv = (int) cnfparamvals[i].val.d.n;
glblIntMsgRateLimitItv = (int) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "environment")) {
for(int j = 0 ; j < cnfparamvals[i].val.d.ar->nmemb ; ++j) {
char *const var =
es_str2cstr(cnfparamvals[i].val.d.ar->arr[j], NULL);
char *const var = es_str2cstr(cnfparamvals[i].val.d.ar->arr[j], NULL);
do_setenv(var);
free(var);
}
} else if(!strcmp(paramblk.descr[i].name, "errormessagestostderr.maxnumber")) {
loadConf->globals.maxErrMsgToStderr = (int) cnfparamvals[i].val.d.n;
loadConf->globals.maxErrMsgToStderr = (int) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "debug.files")) {
free(glblDbgFiles); /* "fix" Coverity false positive */
glblDbgFilesNum = cnfparamvals[i].val.d.ar->nmemb;
@ -1385,11 +1451,11 @@ glblDoneLoadCnf(void)
}
qsort(glblDbgFiles, glblDbgFilesNum, sizeof(char*), qs_arrcmp_glblDbgFiles);
} else if(!strcmp(paramblk.descr[i].name, "debug.whitelist")) {
glblDbgWhitelist = (int) cnfparamvals[i].val.d.n;
glblDbgWhitelist = (int) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "umask")) {
loadConf->globals.umask = (int) cnfparamvals[i].val.d.n;
loadConf->globals.umask = (int) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "shutdown.enable.ctlc")) {
glblPermitCtlC = (int) cnfparamvals[i].val.d.n;
glblPermitCtlC = (int) cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "default.action.queue.timeoutshutdown")) {
actq_dflt_toQShutdown = cnfparamvals[i].val.d.n;
} else if(!strcmp(paramblk.descr[i].name, "default.action.queue.timeoutactioncompletion")) {
@ -1400,7 +1466,7 @@ glblDoneLoadCnf(void)
actq_dflt_toWrkShutdown = cnfparamvals[i].val.d.n;
} else {
dbgprintf("glblDoneLoadCnf: program error, non-handled "
"param '%s'\n", paramblk.descr[i].name);
"param '%s'\n", paramblk.descr[i].name);
}
}

View File

@ -42,7 +42,6 @@
#define glblOversizeMsgInputMode_Split 1
#define glblOversizeMsgInputMode_Accept 2
extern pid_t glbl_ourpid;
extern int bProcessInternalMessages;
extern int bPermitSlashInProgramname;
@ -156,5 +155,6 @@ uchar* glblGetOversizeMsgErrorFile(void);
const uchar* glblGetOperatingStateFile(void);
int glblGetOversizeMsgInputMode(void);
int glblReportOversizeMessage(void);
void glblReportChildProcessExit(const uchar *name, pid_t pid, int status);
#endif /* #ifndef GLBL_H_INCLUDED */

View File

@ -47,6 +47,7 @@
#include "srUtils.h"
#include "obj.h"
#include "errmsg.h"
#include "glbl.h"
#if _POSIX_TIMERS <= 0
#include <sys/time.h>
@ -286,17 +287,22 @@ int execProg(uchar *program, int bWait, uchar *arg)
}
if(pid) { /* Parent */
if(bWait)
if(waitpid(pid, NULL, 0) == -1)
if(errno != ECHILD) {
/* we do not use logerror(), because
* that might bring us into an endless
* loop. At some time, we may
* reconsider this behaviour.
*/
dbgprintf("could not wait on child after executing '%s'",
(char*)program);
}
if(bWait) {
/* waitpid will fail with errno == ECHILD if the child process has already
been reaped by the rsyslogd main loop (see rsyslogd.c) */
int status;
if(waitpid(pid, &status, 0) == pid) {
glblReportChildProcessExit(program, pid, status);
} else if(errno != ECHILD) {
/* we do not use logerror(), because
* that might bring us into an endless
* loop. At some time, we may
* reconsider this behaviour.
*/
dbgprintf("could not wait on child after executing '%s'",
(char*)program);
}
}
return pid;
}
/* Child */

View File

@ -71,7 +71,7 @@ injectmsg 6 1
injectmsg 7 1
wait_queueempty
kill -s USR1 $(get_child_pid)
kill -s KILL $(get_child_pid)
./msleep 100
injectmsg 8 1
@ -98,9 +98,6 @@ Starting
Received msgnum:00000005:
Received msgnum:00000006:
Received msgnum:00000007:
Received SIGUSR1, will terminate after the next message
Received msgnum:00000008:
Terminating without confirming the last message
Starting
Received msgnum:00000008:
Received msgnum:00000009:
@ -123,9 +120,6 @@ export EXPECTED="[stderr] Starting
[stderr] Received msgnum:00000005:
[stderr] Received msgnum:00000006:
[stderr] Received msgnum:00000007:
[stderr] Received SIGUSR1, will terminate after the next message
[stderr] Received msgnum:00000008:
[stderr] Terminating without confirming the last message
[stderr] Starting
[stderr] Received msgnum:00000008:
[stderr] Received msgnum:00000009:

View File

@ -63,7 +63,7 @@ injectmsg 6 1
injectmsg 7 1
wait_queueempty
kill -s USR1 $(get_child_pid)
kill -s KILL $(get_child_pid)
./msleep 100
injectmsg 8 1

View File

@ -7,6 +7,7 @@
# omprog is going to write to the pipe (to send a message to the
# program), and when omprog is going to read from the pipe (when it
# is expecting the program to confirm the last message).
. ${srcdir:=.}/diag.sh init
check_command_available lsof
@ -30,6 +31,10 @@ template(name="outfmt" type="string" string="%msg%\n")
signalOnClose="off"
)
}
syslog.* {
action(type="omfile" template="outfmt" file=`echo $RSYSLOG2_OUT_LOG`)
}
'
# We need a test-specific program name, as the test needs to signal the child process
@ -58,14 +63,16 @@ injectmsg 1 1
injectmsg 2 1
wait_queueempty
kill -s USR1 $(get_child_pid)
child_pid_1=$(get_child_pid)
kill -s USR1 $child_pid_1
./msleep 100
injectmsg 3 1
injectmsg 4 1
wait_queueempty
kill -s TERM $(get_child_pid)
child_pid_2=$(get_child_pid)
kill -s TERM $child_pid_2
./msleep 100
injectmsg 5 1
@ -73,7 +80,8 @@ injectmsg 6 1
injectmsg 7 1
wait_queueempty
kill -s USR1 $(get_child_pid)
child_pid_3=$(get_child_pid)
kill -s KILL $child_pid_3
./msleep 100
injectmsg 8 1
@ -81,7 +89,8 @@ injectmsg 9 1
wait_queueempty
end_fd_count=$(lsof -p $pid | wc -l)
child_lsof=$(lsof -a -d 0-65535 -p $(get_child_pid) | awk '$4 != "255r" { print $4 " " $9 }')
child_pid_4=$(get_child_pid)
child_lsof=$(lsof -a -d 0-65535 -p $child_pid_4 | awk '$4 != "255r" { print $4 " " $9 }')
shutdown_when_empty
wait_shutdown
@ -101,14 +110,10 @@ Starting
Received msgnum:00000005:
Received msgnum:00000006:
Received msgnum:00000007:
Received SIGUSR1, will terminate after the next message
Received msgnum:00000008:
Terminating without confirming the last message
Starting
Received msgnum:00000008:
Received msgnum:00000009:
Terminating normally"
cmp_exact $RSYSLOG_OUT_LOG
if [[ "$start_fd_count" != "$end_fd_count" ]]; then
@ -137,4 +142,14 @@ if [[ "$child_lsof" != "$EXPECTED_CHILD_LSOF" && "$child_lsof" != "$EXPECTED_CHI
error_exit 1
fi
# Check also that child process terminations are reported correctly.
# When the reportChildProcessExits global parameter is "errors" (the default),
# only non-zero exit codes are reported.
content_check "(pid $child_pid_1) terminated; will be restarted" $RSYSLOG2_OUT_LOG
custom_assert_content_missing "(pid $child_pid_1) exited with status" $RSYSLOG2_OUT_LOG
content_check "(pid $child_pid_2) terminated; will be restarted" $RSYSLOG2_OUT_LOG
content_check "(pid $child_pid_2) exited with status 1" $RSYSLOG2_OUT_LOG
content_check "(pid $child_pid_3) terminated; will be restarted" $RSYSLOG2_OUT_LOG
content_check "(pid $child_pid_3) terminated by signal 9" $RSYSLOG2_OUT_LOG
exit_test

View File

@ -34,7 +34,7 @@ while [[ -n "$log_line" ]]; do
# Terminate prematurely by closing pipe, without confirming the message
echo "Terminating without confirming the last message" >> $outfile
>&2 echo "[stderr] Terminating without confirming the last message"
exit 1
exit 0
fi
# Tell rsyslog we are ready to process the next message

View File

@ -1908,6 +1908,21 @@ wait_timeout(void)
#endif /* AIXPORT : SRC end */
}
static void
reapChild(void)
{
pid_t child;
do {
int status;
child = waitpid(-1, &status, WNOHANG);
if(child != -1 && child != 0) {
glblReportChildProcessExit(NULL, child, status);
}
} while(child > 0);
}
/* This is the main processing loop. It is called after successful initialization.
* When it returns, the syslogd terminates.
* Its sole function is to provide some housekeeping things. The real work is done
@ -1918,21 +1933,12 @@ mainloop(void)
{
time_t tTime;
do {
processImInternal();
wait_timeout();
if(bChildDied) {
pid_t child;
do {
child = waitpid(-1, NULL, WNOHANG);
DBGPRINTF("rsyslogd: mainloop waitpid (with-no-hang) returned %u\n",
(unsigned) child);
if (child != -1 && child != 0) {
LogMsg(0, RS_RET_OK, LOG_INFO, "Child %d has terminated, reaped "
"by main-loop.", (unsigned) child);
}
} while(child > 0);
reapChild();
bChildDied = 0;
}