mirror of
https://github.com/rsyslog/rsyslog.git
synced 2025-12-16 02:50:40 +01:00
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:
parent
49eda256b9
commit
9315787c6d
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
108
runtime/glbl.c
108
runtime/glbl.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user