head 1.34;
access;
symbols
L2_0_9_13:1.34
FSL_1_7_0:1.34
L2_0_9_12:1.34
LMTP2NNTP_1_4_1:1.34
LMTP2NNTP_1_4_0:1.34
FSL_1_6_1:1.34
L2_0_9_11:1.34
FSL_1_6_0:1.33
FSL_1_6b2:1.33
L2_0_9_10:1.33
FSL_1_6b1:1.32
L2_0_9_9:1.32
LMTP2NNTP_1_3_0:1.31
LMTP2NNTP_1_3b2:1.31
LMTP2NNTP_1_3b1:1.31
LMTP2NNTP_1_3a3:1.31
FSL_1_5_0:1.31
LMTP2NNTP_1_3a2:1.31
FSL_1_5a3:1.31
LMTP2NNTP_1_3a1:1.31
FSL_1_5a2:1.31
L2_0_9_8:1.31
FSL_1_5a1:1.31
L2_0_9_7:1.31
L2_0_9_6:1.31
FSL_1_4_0:1.31
FSL_1_4b1:1.31
L2_0_9_5:1.31
FSL_1_4a1:1.31
FSL_1_3_0:1.31
FSL_1_3b1:1.31
L2_0_9_4:1.31
FSL_1_2_1:1.31
L2_0_9_3:1.31
FSL_1_2_0:1.31
L2_0_9_2:1.31
FSL_1_1_0:1.31
FSL_1_1b1:1.31
WORKOFF:1.31.0.2
WORKOFF_BP:1.31
FSL_1_0_8:1.31
LMTP2NNTP_1_2_0:1.31
LMTP2NNTP_1_2b4:1.31
LMTP2NNTP_1_2b3:1.31
LMTP2NNTP_1_2b2:1.31
LMTP2NNTP_1_2b1:1.31
LMTP2NNTP_1_2a8:1.31
LMTP2NNTP_1_2a7:1.31
FSL_1_0_7:1.31
FSL_1_0_6:1.30
FSL_1_0_5:1.30
FSL_1_0_4:1.30
L2_0_9_1:1.30
FSL_1_0_3:1.30
LMTP2NNTP_1_2a6:1.30
FSL_1_0_2:1.30
FSL_1_0_1:1.30
FSL_1_0_0:1.30
FSL_0_9_0:1.30
L2_0_9_0:1.30
FSL_0_1_12:1.29
FSL_0_1_11:1.29
FSL_0_1_10:1.29
FSL_0_1_9:1.29
FSL_0_1_8:1.29
FSL_0_1_7:1.29
FSL_0_1_6:1.29
FSL_0_1_5:1.29
FSL_0_1_1:1.29
LMTP2NNTP_1_2a5:1.29
LMTP2NNTP_1_2a4:1.29
LMTP2NNTP_1_2a3:1.29
LMTP2NNTP_1_2a1:1.28
LMTP2NNTP_1_1_1:1.25
LMTP2NNTP_1_1_0:1.25
LMTP2NNTP_1_1b4:1.25
LMTP2NNTP_1_1b3:1.25
L2_CHANNEL_ONLY_REVAMPING_BEFORE:1.26
LMTP2NNTP_1_1b2:1.25
LMTP2NNTP_1_1b1:1.25
L2_0_1_0:1.8
L2NGATE:1.4.0.2
START_MICHAEL:1.4
L2_INITIAL:1.1.1.1
OSSP:1.1.1;
locks; strict;
comment @ * @;
1.34
date 2005.10.03.08.08.11; author rse; state Exp;
branches;
next 1.33;
1.33
date 2005.02.03.09.41.38; author rse; state Exp;
branches;
next 1.32;
1.32
date 2005.01.24.15.03.17; author rse; state Exp;
branches;
next 1.31;
1.31
date 2003.01.06.11.41.51; author rse; state Exp;
branches;
next 1.30;
1.30
date 2002.07.30.19.08.24; author rse; state Exp;
branches;
next 1.29;
1.29
date 2002.01.02.17.07.38; author rse; state Exp;
branches;
next 1.28;
1.28
date 2001.11.07.13.05.20; author rse; state Exp;
branches;
next 1.27;
1.27
date 2001.11.07.11.37.18; author rse; state Exp;
branches;
next 1.26;
1.26
date 2001.10.30.18.56.13; author ms; state Exp;
branches;
next 1.25;
1.25
date 2001.10.04.12.53.54; author ms; state Exp;
branches;
next 1.24;
1.24
date 2001.10.04.12.34.41; author ms; state Exp;
branches;
next 1.23;
1.23
date 2001.10.02.15.51.32; author ms; state Exp;
branches;
next 1.22;
1.22
date 2001.10.01.16.26.14; author ms; state Exp;
branches;
next 1.21;
1.21
date 2001.10.01.16.14.10; author ms; state Exp;
branches;
next 1.20;
1.20
date 2001.09.26.14.31.22; author rse; state Exp;
branches;
next 1.19;
1.19
date 2001.09.26.14.29.03; author rse; state Exp;
branches;
next 1.18;
1.18
date 2001.09.26.12.10.31; author ms; state Exp;
branches;
next 1.17;
1.17
date 2001.09.26.09.13.27; author ms; state Exp;
branches;
next 1.16;
1.16
date 2001.09.25.15.22.21; author ms; state Exp;
branches;
next 1.15;
1.15
date 2001.09.24.14.36.34; author ms; state Exp;
branches;
next 1.14;
1.14
date 2001.09.21.17.32.08; author ms; state Exp;
branches;
next 1.13;
1.13
date 2001.09.20.16.26.56; author ms; state Exp;
branches;
next 1.12;
1.12
date 2001.09.19.16.39.44; author ms; state Exp;
branches;
next 1.11;
1.11
date 2001.09.18.14.38.51; author ms; state Exp;
branches;
next 1.10;
1.10
date 2001.09.14.15.40.04; author ms; state Exp;
branches;
next 1.9;
1.9
date 2001.09.14.11.13.32; author ms; state Exp;
branches;
next 1.8;
1.8
date 2001.09.12.09.42.34; author ms; state Exp;
branches;
next 1.7;
1.7
date 2001.09.05.07.47.12; author rse; state Exp;
branches;
next 1.6;
1.6
date 2001.09.04.19.18.49; author rse; state Exp;
branches;
next 1.5;
1.5
date 2001.09.04.15.41.17; author rse; state Exp;
branches;
next 1.4;
1.4
date 2001.08.15.10.36.03; author rse; state Exp;
branches;
next 1.3;
1.3
date 2001.05.26.08.02.55; author rse; state Exp;
branches;
next 1.2;
1.2
date 2001.05.11.17.07.52; author rse; state Exp;
branches;
next 1.1;
1.1
date 2001.05.10.19.46.01; author rse; state Exp;
branches
1.1.1.1;
next ;
1.1.1.1
date 2001.05.10.19.46.01; author rse; state Exp;
branches;
next ;
desc
@@
1.34
log
@Adjust copyright messages for new year 2005.
@
text
@/*
** OSSP l2 - Flexible Logging
** Copyright (c) 2001-2005 Cable & Wireless
** Copyright (c) 2001-2005 The OSSP Project
** Copyright (c) 2001-2005 Ralf S. Engelschall
**
** This file is part of OSSP l2, a flexible logging library which
** can be found at http://www.ossp.org/pkg/lib/l2/.
**
** Permission to use, copy, modify, and distribute this software for
** any purpose with or without fee is hereby granted, provided that
** the above copyright notice and this permission notice appear in all
** copies.
**
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
**
** l2_ch_pipe.c: pipe channel implementation
*/
#include "l2.h"
#include "l2_p.h" /* for TRACE() */
#include
#include
#include
#include
#define L2_PIPE_EXECMODE_DIRECT 1 /* direct command execution */
#define L2_PIPE_EXECMODE_SHELL 2 /* shell command execution */
#define L2_PIPE_RUNTIME_CONTINU 3 /* continuous pipe command processing */
#define L2_PIPE_RUNTIME_ONESHOT 4 /* oneshot pipe command processing */
#define L2_PIPE_WRITEFAIL 6 /* how long before failure occurs */
#define L2_PIPE_MAXARGS 256 /* how many args can piped command have */
/* declare private channel configuration */
typedef struct {
pid_t Pid; /* process id of child command */
int iWritefail; /* counter to failed write() operations */
int piFd[2]; /* pipe file descriptor */
int iNulldev; /* null device file descriptor */
int iMode; /* execution mode direct or shell */
int iRtme; /* runtime mode continuous or oneshot */
char *szCmdpath; /* path to command and arguments */
struct sigaction sigchld; /* initial state of chld signal handler */
struct sigaction sigpipe; /* initial state of pipe signal handler */
} l2_ch_pipe_t;
static void catchsignal(int sig, ...)
{
pid_t Pid; /* for wait() */
int iStatus = 0; /* for wait() */
if (sig == SIGCHLD) {
TRACE("SIGCHLD caught");
Pid = waitpid((pid_t)-1, &iStatus, WUNTRACED | WNOHANG);
if (WIFEXITED(iStatus))
TRACE("EXITED child"); /* child finished and returned */
else if (WIFSIGNALED(iStatus))
TRACE("SIGNALED child"); /* child finished due to a signal */
else if (WIFSTOPPED(iStatus))
TRACE("STOPPED child"); /* child stopped due to a signal */
else
TRACE("SIGNAL Unknown"); /* child stopped due to a signal */
}
else if (sig == SIGPIPE); /* noop for now */
}
/*
* The lifecycle of the command executed by the pipe channel handler
* depends on the runtime option selected during configuration. The
* option 'continuous' describes subsequent behavior which rebuilds an
* (un)intentionally severed child-controlled pipe. In this case, when
* the pipe handler encounters a failed write operation, it will attempt
* the reconnection a user-defined number of times until failure is assumed.
*
* The option 'oneshot' describes subsequent behavior which also rebuilds
* such a severed pipe. The difference is that the pipe handler will not
* spawn the child process until writing actually occurs. The channel will
* also block until the child process finishes and terminates on its own.
*
* The lifecycle of a pipe command process is illustrated in the
* following figure:
*
* -----BEGIN EMBEDDED OBJECT-----
* Content-editor: xfig %s
* Content-encoding: gzip:9 base64
* Content-type: application/fig
* Content-viewer: xfig %s
* Description: L2 Pipe Channel Command Lifecycle
* Filename: l2_ch_pipe.fig
* Last-modified: 2000-09-28/14:40
* Name: l2_ch_pipe
* Version: eo/1.0
* H4sIAIW5uTsCA61ZUW/cNgx+3v0KAX3YCjSBJEuy/VxsQ4EMG9bubS+Oo+SM+uyb
* 7WuWfz+Ssi352iTSrW3jir7jJ0qk+FHMm18+/Mqya7m7qbq7sa6OdvfedpMddr/Z
* aWjq3Y2dQGJsJzi/5nz3sekeWru7kjshOWdyx1km2Zua/uwMk0ZqprjmTPAi10yD
* vBMsY/ACfjjT+JDwADR6h//DmxweWpWcGYn/vCxzAyPN8xgYmJS7b884wQsYEpJU
* MUiZ2Rrk5cwkGKTVFsbLWiXAKL2F8bLSCTC53MJ4OZcJMIXYwni5EAkwJa1MqAXG
* yyU3ONJxMOUZzCqXZQKMybYwgZwtMJIgFPzkDuZqVmeLgNBy90MQvz5wQqct2KrU
* 4Qg/Be0wSlYrch2OZq/xcISfgnZulm/SaHYMD0f0aaH1ut9eu1Tr22AjF+35PKGZ
* VwbOe1nCIRcKDr2QGQwlYO6U32fUWIOYiQy+V9A55TjUoPFXdwcJpuuHQ9Wyuhnq
* 02Gcqq6247u/ORcvg0nhwRC3YjeS/dEcLXu/r7rOtuyxmfZssG1T3TZtMz3FYGYL
* puSwsOk0dPaO9R1gtS1YOrHOwoupZ1P12bKqew2UA5Is9QIq4Tt1Pwy2npovoA//
* ATjAHaqmm+CHNdPI6n3T3sVYm6/ACoZ1fzhALmfHoYctHK/Zz/9Wh2Nr2bjvH7tr
* AvSeUxK1pcFMDZH2iufyfNkYpeBD57nxaOvm/7lOGXh8F9fxYtkMhcn+zHWDtWDf
* bduMe9riI8wWAZrpBVQj/t1pABIEe+/b6hHQH4dmsqw/2qEiR96dLDgzAlcXywbo
* TGDs1m0/AiB5njXd8TSRic/7kEIpk3j6BCUcPH0uSQlWYJISzyUpzFFyyQ4zjopQ
* Fk4ZB+Ia0yZ+CiFE1UGIOVuEmQJB8S9UCh5VPmsSpRynTjnJLdVQjqFgx8JCFrDU
* 2MKCHkFhMT8MPkRCYYHf3hQW9MIVFjLPVDSVBwZ5mag81iCiJwijDV05GelKZCae
* ygNrvExUHmsNkVwA42WqlmJhiO2CRXmZqqXYRREZBtZ4mcqcWGuIFQNrvEz1Saw1
* RJ4hzCpTfUIwUYWFEEthMe+sD5zNaI6CzQg/Be3Qvd6KzYg+XaKbz6fPpSlT4MEE
* itegrvRr+d0s6c0g1XzaW3YagTAO1RNk4n9OzQBZs7NXkNSm2FQMs86Y5NNbu6++
* NP1wzT4Age4bYM1qtO9gaCGLEov8OEbASr7CYilTjWMPnDZhLp7pdKX+8Vg9dhGQ
* rlgiSExXt21ffx7ZqZuadjYPk/zM0gzuWIemgxmjrDWLteTE+6E/EJ0BN7C2f2jq
* bxLGKxynVnOxZnR2IrMh1d3ah6aDUuKT31ZcQ3dGRFg4urQt81wn8pCL6xnm+9CQ
* i2SxHJhUGqIj4dRxOC8Ua6wZGCsvWcrNORBmu7eQDhT8SI2PAgi/Hiy4+dwj52p4
* bCHUMyqpSa3v7puH0/CqJsyTgabKzKwJhUkXqURlCClRTROpZeSiRfVL5NIoJ1y0
* tLy8YGlFecnSynyZKnZpGqsUbhZv30HBOfRPwUHBQNAaq2lBd+VcRMePNvkl8ePU
* Lokf0kyNH1JK2WRyTbIWucYtLdk1pBa6JjLIk42kIE/WogA/03IsTMaXBZX7eJWH
* oojwihBPXOucFwEe0ZvBEdx+Aiue16Kajec4MHzhwG/rbazHykAInA5NY8MJWLk5
* fL3u4mvnoCYur8jATaDYAfG8pocHA3mL9ARsCBB0ylzknvO5Cq8nA72Cu9yvS+oI
* wWTLdfV3qGE+Yg1z09zb+qluzz2m+OIwzAmvTJJht4AmAXJf5/iTbsFA6Osc7CfX
* Mnkb4c41CPDMvBADz/iSMtklvpS5usiX0ohkX4qsfN6XL0Q4VrqbCPd+y0S5OA5P
* Y6z1dGkJrY9wTIbrSD6dWZFfdjopuVziUSWKlBOTcTUHM11WXormweIV4G2KMUSj
* oTGeYSmLOIYtNI9mWMpa6Qzr1C5hWNJMZVhSSq7QnJGpFdpFSyMCS10alQHJS6My
* IGlpvgwgta8rNKz9DV+vDhhKiXeZQhZ8wcm+02WGMGeLYJh6mTFlNt/vcbS01GBv
* 3J2eF1hOZHl8S43sCVpqbs3YUitkmdBSw29vWmr0wrXUikzE/64uMMjL1H2KNYia
* JwGMl6kzFwtD+T+A8TI1sWJhqMERwHiZmlixMNS0CmC8TE2saJjyDGaVqYkVC0MN
* iwDGy9RujIWhlhaFdND8dDI2P02pYltq6+/q5nDxHvdO24zcLPl8pECbxvOG8nDk
* jpzS4cid4jnOCzqH/wEp6AKCgx8AAA==
* -----END EMBEDDED OBJECT-----
*/
/* create channel */
static l2_result_t hook_create(l2_context_t *ctx, l2_channel_t *ch)
{
l2_ch_pipe_t *cfg;
/* allocate private channel configuration */
if ((cfg = (l2_ch_pipe_t *)malloc(sizeof(l2_ch_pipe_t))) == NULL)
return L2_ERR_ARG;
/* initialize configuration with reasonable defaults */
cfg->Pid = -1;
cfg->iWritefail = 0;
cfg->piFd[0] = -1;
cfg->piFd[1] = -1;
cfg->iNulldev = -1;
cfg->iMode = -1;
cfg->iRtme = -1;
cfg->szCmdpath = NULL;
memset(&cfg->sigchld, 0, sizeof(cfg->sigchld));
memset(&cfg->sigpipe, 0, sizeof(cfg->sigpipe));
/* link private channel configuration into channel context */
ctx->vp = cfg;
return L2_OK;
}
/* configure channel */
static l2_result_t hook_configure(l2_context_t *ctx, l2_channel_t *ch, const char *fmt, va_list ap)
{
l2_ch_pipe_t *cfg = (l2_ch_pipe_t *)ctx->vp;
l2_param_t pa[4];
l2_result_t rv;
char *szMode = NULL;
char *szRel = NULL;
l2_env_t *env;
/* feed and call generic parameter parsing engine */
L2_PARAM_SET(pa[0], execmode, STR, &szMode); /* mode direct or shell */
L2_PARAM_SET(pa[1], runtime, STR, &szRel); /* continuous or oneshot */
L2_PARAM_SET(pa[2], path, STR, &cfg->szCmdpath); /* path of cmd */
L2_PARAM_END(pa[3]);
l2_channel_env(ch, &env);
if ((rv = l2_util_setparams(env, pa, fmt, ap)) != L2_OK)
return rv;
if (szMode != NULL) {
if (strcmp(szMode, "direct") == 0)
cfg->iMode = L2_PIPE_EXECMODE_DIRECT;
else if (strcmp(szMode, "shell") == 0)
cfg->iMode = L2_PIPE_EXECMODE_SHELL;
else
return L2_ERR_ARG;
free(szMode);
}
if (szRel != NULL) {
if (strncmp(szRel, "continuous", strlen("cont")) == 0)
cfg->iRtme = L2_PIPE_RUNTIME_CONTINU;
else if (strncmp(szMode, "oneshot", strlen("one")) == 0)
cfg->iRtme = L2_PIPE_RUNTIME_ONESHOT;
else
return L2_ERR_ARG;
free(szRel);
}
return L2_OK;
}
/**********************************************************
* parse_cmdpath: Helper method to spawn_command *
* Parses szBuf into an argv-style string vector szArgs *
**********************************************************/
static l2_result_t parse_cmdpath(char *szBuf, char *szArgs[]) {
int iCnt = 0;
if (szBuf == NULL) /* check for bad input before we */
return L2_ERR_ARG; /* dereference and throw a SIGSEV */
while ((iCnt++ < L2_PIPE_MAXARGS) && (*szBuf != '\0')) {
while ((*szBuf == ' ') || (*szBuf == '\t'))
*szBuf++ = '\0'; /* overwrite whitespace with EOL */
*szArgs++ = szBuf; /* found the start of a new token */
while ((*szBuf != '\0') && (*szBuf != ' ') && (*szBuf != '\t'))
szBuf++;
}
*szArgs = '\0'; /* add a NULL to mark the end of the chain */
if (iCnt <= L2_PIPE_MAXARGS)
return L2_OK;
else
return L2_ERR_ARG;
}
/************************************************************
* spawn_command: Helper method to hook_open and hook_write *
* Forks a new process, and copies the command executable *
************************************************************/
static l2_result_t spawn_command(l2_ch_pipe_t *cfg)
{
char *pVec[L2_PIPE_MAXARGS];
char *sz = NULL;
l2_result_t rv;
/* initialize auto vars before using them */
memset(pVec, 0, sizeof(pVec));
/* spawn a child process to be later overwritten by the user command */
if ((cfg->Pid = fork()) > 0) { /* parent process */
free(sz); /* no exec() in parent */
close(cfg->piFd[0]); /* half-duplex (no reading) */
cfg->piFd[0] = -1;
return L2_OK;
}
else if (cfg->Pid == 0) { /* child process */
close(cfg->piFd[1]); /* close the writing end, */
cfg->piFd[1] = -1; /* because we don't use it */
dup2(cfg->piFd[0], fileno(stdin)); /* copy the reading end */
/* redirection of child's stdout and stdin */
cfg->iNulldev = open("/dev/null", O_RDWR);
dup2(cfg->iNulldev, fileno(stdout)); /* redirect stdout to null */
dup2(cfg->iNulldev, fileno(stderr)); /* redirect stderr to null */
/* the distinction between modes is necessary, because only executing */
/* commands in a shell environment allows usage of variables and such */
if (cfg->iMode == L2_PIPE_EXECMODE_SHELL) {
pVec[0] = "/bin/sh";
pVec[1] = "-c";
pVec[2] = cfg->szCmdpath;
pVec[3] = NULL; /* add a NULL to mark the end of the chain */
}
else { /* plain direct command execution */
sz = strdup(cfg->szCmdpath);
if ((rv = parse_cmdpath(sz, pVec)) != L2_OK) {
free(sz);
return rv;
}
}
if (execvp(*pVec, pVec) == -1) { /* launch */
TRACE("execvp in child returned -1");
free(sz); /* cleanup in case we fail */
close(cfg->piFd[0]);
cfg->piFd[0] = -1; /* if execvp() doesn't swap our context or */
return L2_ERR_SYS; /* if child returns, we have an error */
}
else
return L2_OK; /* NOTREACHED */
}
else /* fork failed */
return L2_ERR_SYS;
}
/* open channel */
static l2_result_t hook_open(l2_context_t *ctx, l2_channel_t *ch)
{
l2_ch_pipe_t *cfg = (l2_ch_pipe_t *)ctx->vp;
struct sigaction locact;
/* consistency check */
if (cfg->szCmdpath == NULL)
return L2_ERR_USE;
/* initialize auto vars before using them */
memset(&locact, 0, sizeof(locact));
locact.sa_handler = (void(*)(int))catchsignal;
sigemptyset(&locact.sa_mask);
locact.sa_flags = 0;
/* save old signal context before replacing with our own */
if (sigaction(SIGCHLD, &locact, &cfg->sigchld) < 0)
return L2_ERR_SYS;
if (sigaction(SIGPIPE, &locact, &cfg->sigpipe) < 0)
return L2_ERR_SYS;
if (pipe(cfg->piFd) == -1) /* open the pipe */
return L2_ERR_SYS;
/* short circuit hack, if in oneshot mode and not yet opened then return */
if ((cfg->iRtme == L2_PIPE_RUNTIME_ONESHOT) && (ch->state != L2_CHSTATE_OPENED))
return L2_OK;
else
return spawn_command(cfg); /* spawn the command process */
}
/* write to channel, possibly recursively */
static l2_result_t hook_write(l2_context_t *ctx, l2_channel_t *ch,
l2_level_t level, const char *buf, size_t buf_size)
{
l2_result_t rv = L2_OK;
l2_ch_pipe_t *cfg = (l2_ch_pipe_t *)ctx->vp;
/* spawn the child command process if we are in oneshot mode */
if ((cfg->iRtme == L2_PIPE_RUNTIME_ONESHOT) && (cfg->Pid == -1))
if (spawn_command(cfg) != L2_OK)
return L2_ERR_SYS; /* immediate return if we can't spawn command */
/* write message to channel pipe */
if (write(cfg->piFd[1], buf, buf_size) == -1) {
if ((errno == EPIPE) && (cfg->iWritefail++ < L2_PIPE_WRITEFAIL)) {
if ((rv = l2_channel_close(ch)) != L2_OK)
return rv;
if ((rv = l2_channel_open(ch)) != L2_OK)
return rv;
return hook_write(ctx, ch, level, buf, buf_size);
}
else { /* not broken pipe problem or over the fail limit, so panic */
cfg->iWritefail = 0; /* reset pipe failure counter */
rv = L2_ERR_SYS;
}
}
else /* write() to pipe succeeded */
cfg->iWritefail = 0; /* reset pipe failure counter */
/* block until child terminates if in oneshot execmode */
if ((cfg->iRtme == L2_PIPE_RUNTIME_ONESHOT) && (cfg->Pid != -1))
cfg->Pid = waitpid(cfg->Pid, NULL, WUNTRACED | WNOHANG);
return rv;
}
/* close channel */
static l2_result_t hook_close(l2_context_t *ctx, l2_channel_t *ch)
{
l2_result_t rv = L2_OK;
l2_ch_pipe_t *cfg = (l2_ch_pipe_t *)ctx->vp;
/* close null device */
if (cfg->iNulldev != -1) {
close(cfg->iNulldev);
cfg->iNulldev = -1;
}
/* close output pipe for parent */
if (cfg->piFd[1] != -1) {
close(cfg->piFd[1]);
cfg->piFd[1] = -1;
}
/* restore previous signal context, but only if it was saved and replaced */
if (&cfg->sigchld.sa_handler) {
if (sigaction(SIGCHLD, &cfg->sigchld, 0) < 0)
rv = L2_ERR_SYS;
if (sigaction(SIGPIPE, &cfg->sigpipe, 0) < 0)
rv = L2_ERR_SYS;
}
/* kill child process if still running */
if (cfg->Pid != -1) {
kill(cfg->Pid, SIGTERM);
cfg->Pid = waitpid(cfg->Pid, NULL, WUNTRACED | WNOHANG);
cfg->Pid = -1;
}
return rv;
}
/* destroy channel */
static l2_result_t hook_destroy(l2_context_t *ctx, l2_channel_t *ch)
{
l2_ch_pipe_t *cfg = (l2_ch_pipe_t *)ctx->vp;
/* destroy channel configuration */
free(cfg->szCmdpath);
cfg->szCmdpath = NULL;
free(cfg);
return L2_OK;
}
/* exported channel handler structure */
l2_handler_t l2_handler_pipe = {
"pipe",
L2_CHANNEL_OUTPUT,
hook_create,
hook_configure,
hook_open,
hook_write,
NULL,
hook_close,
hook_destroy
};
@
1.33
log
@Fix compile warnings related to sigaction()'s sa_handler.
@
text
@d3 3
a5 3
** Copyright (c) 2001-2004 Cable & Wireless
** Copyright (c) 2001-2004 The OSSP Project
** Copyright (c) 2001-2004 Ralf S. Engelschall
@
1.32
log
@Adjust copyright messages for new year 2005.
@
text
@d312 1
a312 1
locact.sa_handler = (void(*)())catchsignal;
@
1.31
log
@- remove trailing whitespaces
- adjust copyright messages
- consistently use "OSSP l2"
- consistently talk about "Flexible Logging"
- use standard OSSP ASCII-art
@
text
@d3 3
a5 3
** Copyright (c) 2001-2003 Cable & Wireless Deutschland GmbH
** Copyright (c) 2001-2003 The OSSP Project (http://www.ossp.org/)
** Copyright (c) 2001-2003 Ralf S. Engelschall
@
1.30
log
@polish for release
@
text
@d2 4
a5 3
** OSSP l2 - Logging Library
** Copyright (c) 2001-2002 The OSSP Project (http://www.ossp.org/)
** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/)
d7 1
a7 1
** This file is part of OSSP L2, a flexible logging library which
d79 1
a79 1
/*
d156 6
a161 6
cfg->iWritefail = 0;
cfg->piFd[0] = -1;
cfg->piFd[1] = -1;
cfg->iNulldev = -1;
cfg->iMode = -1;
cfg->iRtme = -1;
d176 1
a176 1
l2_param_t pa[4];
@
1.29
log
@bump copyright year
@
text
@d2 1
a2 1
** L2 - OSSP Logging Library
d7 1
a7 1
** can be found at http://www.ossp.org/pkg/l2/.
@
1.28
log
@Hell, I've seldom seen that it is needed to prepare and adjust such a
lot of subtle details of existing code in order to make a new feature
implementable in a straight-forward way. Anyway, here comes one more
preparation change for the forthcoming channel tree specification
parser:
- change l2_util_setparam() to take an l2_env_t parameter
which allows the function to report better error messages.
- completely rewrite l2_util_setparam() to support calls
l2_channel_configure(ch, "n1=v1,n2=v2,n3=v3")
and/or
l2_channel_configure(ch, "n1=%x,n2=%x,n3=%x", v1, v2, v3)
instead of
l2_channel_configure(ch, "n1,n2,n3", v1, v2, v3)
This is both a step forward to make the interface of
l2_channel_configure() more flexible (because one now can directly
inline values instead of having them to be passed explicitly) and
allows the spec parser not having to know the type (integer, floating
point or string) of a parameter (which is important if one wants the
parser to be independent of the implementing channel handlers).
@
text
@d3 2
a4 2
** Copyright (c) 2001 The OSSP Project (http://www.ossp.org/)
** Copyright (c) 2001 Cable & Wireless Deutschland (http://www.cw.com/de/)
@
1.27
log
@More preparations for forthcoming channel tree specification parser
(especially to allow the parser to determine the handler structure
from a handler name without introducing another and this way redundant
sub-API):
- add "char *name" to l2_handler_t in order to tag each
handler structure with the corresponding channel name
- add l2_env_handler() function to add handler to
l2_env_t objects. All l2_handler_xxxx are automatically
pre-configured there after l2_env_create().
- change l2_channel_create() to take a "const char *name"
(handler name) instead of the "l2_handler_t *h" (handler
pointer) to make the stuff consistent and more clear.
- adjust l2_test.c to reflect the changes.
@
text
@d179 1
d182 3
a184 3
L2_PARAM_SET(pa[0], execmode, CHARPTR, &szMode); /* mode direct or shell */
L2_PARAM_SET(pa[1], runtime, CHARPTR, &szRel); /* continuous or oneshot */
L2_PARAM_SET(pa[2], path, STRING, &cfg->szCmdpath); /* path of cmd */
d186 2
a187 1
if ((rv = l2_util_setparams(pa, fmt, ap)) != L2_OK)
d197 1
d207 1
@
1.26
log
@Cleanup the signal handler to avoid compiler warnings on some platforms.
@
text
@d414 1
@
1.25
log
@Pipe and socket channel configuration-time parameter improvements.
@
text
@d65 1
a65 1
Pid = waitpid(-1, &iStatus, WUNTRACED | WNOHANG);
@
1.24
log
@Bug fixes and new child process blocking with oneshot mode.
@
text
@d40 1
a40 1
#define L2_PIPE_RUNTIME_RELIABLE 3 /* reliable pipe command processing */
d52 1
a52 1
int iRtme; /* runtime mode reliable or oneshot */
d81 1
a81 1
* option 'reliable' describes subsequent behavior which rebuilds an
d181 3
a183 3
L2_PARAM_SET(pa[0], execmode, CHARPTR, &szMode); /* mode direct or shell */
L2_PARAM_SET(pa[1], runtime, CHARPTR, &szRel); /* reliable or oneshot */
L2_PARAM_SET(pa[2], path, STRING, &cfg->szCmdpath); /* path of cmd */
d198 3
a200 3
if (strcmp(szRel, "reliable") == 0)
cfg->iRtme = L2_PIPE_RUNTIME_RELIABLE;
else if (strcmp(szMode, "oneshot") == 0)
@
1.23
log
@Added new logic to accommodate one-shot behavior, and some changes to handle
a child process that writes when it should only read.
@
text
@d65 1
a65 1
Pid = waitpid(-1, &iStatus, WUNTRACED);
d317 1
a317 1
if (pipe(cfg->piFd) == -1) /* open the pipe */
d324 1
a324 3
spawn_command(cfg); /* spawn the command process */
return L2_OK;
d331 2
a332 2
l2_ch_pipe_t *cfg = (l2_ch_pipe_t *)ctx->vp;
l2_result_t rv;
d334 4
a337 3
/* we must still spawn the child command process if we are in oneshot mode */
if ((cfg->iRtme == L2_PIPE_RUNTIME_ONESHOT) && (cfg->Pid != -1))
spawn_command(cfg);
d348 3
a350 3
else { /* not broken pipe problem or over the fail limit */
cfg->iWritefail = 0; /* reset pipe failure counter */
return L2_ERR_SYS;
d353 1
a353 1
else { /* write() to pipe succeeded */
d355 6
a360 2
return L2_OK;
}
d366 2
a367 9
l2_ch_pipe_t *cfg = (l2_ch_pipe_t *)ctx->vp;
/* restore previous signal context, but only if it was saved and replaced */
if (&cfg->sigchld.sa_handler) {
if (sigaction(SIGCHLD, &cfg->sigchld, 0) < 0)
return L2_ERR_SYS;
if (sigaction(SIGPIPE, &cfg->sigpipe, 0) < 0)
return L2_ERR_SYS;
}
d381 9
a389 1
/* kill child process if already started */
d391 2
a392 2
if ((kill (cfg->Pid, SIGTERM)) && (errno != ESRCH))
return L2_ERR_SYS;
d396 1
a396 1
return L2_OK;
@
1.22
log
@Fixed incorrect comments.
@
text
@d36 1
d38 6
a43 4
#define L2_PIPE_MODEDIRECT 1 /* direct command execution */
#define L2_PIPE_MODESHELL 2 /* shell command execution */
#define L2_PIPE_WRITEFAIL 6 /* how long before real failure is indicated */
#define L2_PIPE_MAXARGS 256 /* how many args can our piped command have */
d50 1
d52 1
d88 2
a89 4
* spawn the child process until writing actually occurs. It will also
* terminate the child process after writing is finished, independant of
* whether the write operation succeeded or failed after the user-specified
* number of retries.
d104 37
a140 35
* H4sIALKVuDsCA61Z32/cNgx+3v0VAvqwDWgO+mnLz8U2FMiwYW3f9uL4lJ43n+9m
* +5rlvx9J2Sc5bRrp1qZxRdvfJ9KkSEp99fPbX5jays1t3e/Gpj65zRvXT27Y/Oqm
* oW02t24CibGN4HzL+eZd23/s3OZGboTknMkNZ0qyVw392RRM6tIwWcIjIQQOK2k2
* mnH4MXgRBRPwL1DBK5oBCdPwKw1erOWsGVw9uT85F1+Dwc1CG6YUTkGwY3/ffjwP
* LyJhHgVIrYoZeTy5PhFklJi1fBjaKXWqQi6opjuOqaYV1bWmldUVptnqGtOqcpkq
* 1TQjDdwrFm/v3DgNx0cC3hQYPwUghCzgwm0Fb5UV3wimkC0Qy5kV73l2Cjm6FBL/
* BlmWBV5EmUIDk3L/9swT3YAhMSmdwqTNWqEga5OhUKFQUmahiWSFH0kVSTRWrLUJ
* shUZ2sCUK5ogqyKDxui1UUE2OsOoUq61CXIpM7Sp+FqbIFc8Q5uqekJzkatqoZFE
* gSuk9DQ3M5wtAs4iNt9F8Ru+cRxCIQpWI3wK6Ni9QYvVyOfoOboBFFaf5mZZfcbY
* 9NVndLVafSTT6jOGZ6w+fHu1+uiGX33GSJ0cqJFCQaZATVWIAjOiCTIFaioNuSui
* CTLlglQaiu+IJsgU76k0FBIRTZApF6TS0DLRQq+WDcm0bLQw6csmprnItGxSaSj6
* I5pIVgtN0uqTcll9c7gEV61GxK0rE4/wKaDjKLloUZp4NHuNxyN8CmgoqfObNJod
* w+MRPbXGXL53QFf6cjf6kAt6Xk+oJq13IFNQj7XGmquU78PiCs7XBRxftrRQCWeg
* RfnQ76A/7I/Doe5Y0w7N+TBOdd+48fXTduBzMikCGfLW7Fay39uTY2/2dd+7jj20
* 054Nrmvru7Zrp8cUTrVwSg7dxnQeerdjxx64ug40nVjv4MZ0ZFP9t2N1/xIpByZZ
* mYVUGuzJhsE1U/sJ8PAPkAPdoW77CX5ZO42s2bfdLkXb8kKMrXNzPBygFWen4Qif
* cNyyn/6tD6fOsXF/fOi3oVHyGC0RLgtqTo15wXVluXwZreGhd914ck37/3ynC7h8
* E99xu3wNjen+ie8GB+1ifde1456+8QlmSyCFDzOTGuTfnQfYxIC+9139AOzU8GKv
* PNTkyd3ZgTcTeKE4Lry4Mah9E7zzrmdtfzpPpOLzTqR6W1gyGuutVWV6vbXSruot
* yVRvrawy6i2+vaq3dMPXW6tEer2NFAoy1dtUhSizRjRBpkKZSkNpN6IJMpXtVBqq
* IRFNJKsMGkruEU2QqWyn0lDmj2iCTGU7lYaKRUQTZCrbyTTVE5qLTGWbaNK6XbXU
* 2zlcgseD01ajooIEb6zxI6y3OJ6/RDBmNSIM1cYwwqeAXmLermpiYakm4tmEFdq8
* lAqLJRPQtv393rHzCLn1UD9C0vrn3A6QYHp3A+t/Ss1aMOvMSQFz5/b1p/Y4bNlb
* KDb7FipMPbrXMHSQcCjhfj8m0Ep+odVQHetxPEL6nzBtzaXnUibHU/3Qp+TXS1mh
* juXcT21HWRXT7J372PZQx96TnpgY59KWVWHIsfdtD5nfjQv3F/PqC9ari/UWHEWm
* Tm44tD18AvbXeZxYfY8HXtFnjdI1ln4MHSH89gwCwwe5YBaDXDzXVGKMI9hv62aa
* l7HCY3EgthjG+BRPX7a0zQuUi0Lck+KPkhGrfFYj2hF6OA4jQ5XUyxMDzUWmpX73
* t/B8G1N9DyuW5jzXVGqGPZy65WBqwdXyxCqZa6ovvAvPtzGVOGeNMDVlmuqzXDVn
* PrQ08QzWFOU1Z7Aeds0ZLCFzz2AJlHNQSceb2Sg63vSmZR9vEiw+3kw8KM5WkipO
* NooOibNQlxCx2EPlh4iHXRMihMwNEQJlH9N7JXOP6a8yjTyQaxrFcbZpFMdZpoU4
* JtjTOLYxUGxNyW00HfUYBY5gtxYp+TyKDo95iQP6ktSIfBm3Ms7gzk7gdKTmcIbW
* qD18bqD93EBEkn2Q7xHYQ0PxEg5XAJYQwgmoRdAl5cxFwfJ0LhtwMsJhScEDAVPR
* GRZMtmyvf4NG8h02krftvWsem87l+EWhNtl+Uba8zi+UYq7xC7Yc1/iFtgiZftHC
* 5vhFcT37hXYri1/+oJMO6EYvfmE/DA67/R9zHIRrNds/uIm5yj/0v3DX+Aeb32v8
* Q0cemf4RqsryD57YkX9g2/BV9/hjS++e/wBMybpdCx8AAA==
d158 1
d160 1
d175 1
a175 1
l2_param_t pa[3];
d177 2
a178 1
char *sz = NULL;
d181 4
a184 3
L2_PARAM_SET(pa[0], mode, CHARPTR, &sz);
L2_PARAM_SET(pa[1], path, STRING, &cfg->szCmdpath);
L2_PARAM_END(pa[2]);
d188 14
a201 5
if (sz != NULL) {
if (strcmp(sz, "direct") == 0)
cfg->iMode = L2_PIPE_MODEDIRECT;
else if (strcmp(sz, "shell") == 0)
cfg->iMode = L2_PIPE_MODESHELL;
d210 1
a210 1
* parse_cmdpath: Helper method to hook_open *
d213 1
a213 1
static l2_result_t parse_cmdpath (char *szBuf, char *szArgs[]) {
d234 5
a238 2
/* open channel */
static l2_result_t hook_open(l2_context_t *ctx, l2_channel_t *ch)
a239 1
l2_ch_pipe_t *cfg = (l2_ch_pipe_t *)ctx->vp;
d241 1
a241 1
struct sigaction locact;
a242 5
char *sz = NULL;
/* consistency check */
if (cfg->szCmdpath == NULL)
return L2_ERR_USE;
a245 14
memset(&locact, 0, sizeof(locact));
locact.sa_handler = (void(*)())catchsignal;
sigemptyset(&locact.sa_mask);
locact.sa_flags = 0;
/* save old signal context before replacing with our own */
if (sigaction(SIGCHLD, &locact, &cfg->sigchld) < 0)
return L2_ERR_SYS;
if (sigaction(SIGPIPE, &locact, &cfg->sigpipe) < 0)
return L2_ERR_SYS;
if (pipe(cfg->piFd) == -1) /* open the pipe */
return L2_ERR_SYS;
d247 1
d252 1
d259 5
d266 1
a266 1
if (cfg->iMode == L2_PIPE_MODESHELL) {
a271 1
d287 2
d292 33
d336 4
d365 19
a383 5
/* restore previous signal context */
if (sigaction(SIGCHLD, &cfg->sigchld, 0) < 0)
return L2_ERR_SYS;
if (sigaction(SIGPIPE, &cfg->sigpipe, 0) < 0)
return L2_ERR_SYS;
d385 6
a390 5
/* close channel pipe for parent process created in hook_open() */
close(cfg->piFd[1]);
cfg->piFd[1] = -1;
if ((kill (cfg->Pid, SIGTERM)) && (errno != ESRCH))
return L2_ERR_SYS;
a391 1
cfg->Pid = -1;
@
1.21
log
@Added graphical commentary describing new runtime reliability options.
@
text
@d74 15
a88 5
* A channel is the central object for a logging stream. It is
* implemented by a framework (the code implemented here) which provides
* the channel API and which is equal for all channels and a particular
* handler which implements the characteristics specific to a particular
* channel class. The lifecycle of a channel is illustrated in the
@
1.20
log
@Cleanup: always use the channel API and 1:1 pass through errors.
@
text
@d73 56
@
1.19
log
@bugfix pipe channel
@
text
@a41 3
static l2_result_t hook_close(l2_context_t *, l2_channel_t *); /* prototypes */
d226 1
d231 4
a234 4
if (hook_close(ctx, ch) != L2_OK)
return L2_ERR_SYS;
if (hook_open(ctx, ch) != L2_OK)
return L2_ERR_SYS;
@
1.18
log
@Fixed bugs, adjusted scope of command parse, corrected NULL assignments and
comparisons, removed inconsistent command check, added fail-safe exit code.
@
text
@d107 1
a107 1
char *sz;
d116 8
a123 6
if (strcmp(sz, "direct") == 0)
cfg->iMode = L2_PIPE_MODEDIRECT;
else if (strcmp(sz, "shell") == 0)
cfg->iMode = L2_PIPE_MODESHELL;
else
return L2_ERR_ARG;
d125 1
a125 1
return rv;
d161 4
@
1.17
log
@Removed magic number, corrected comment.
@
text
@d71 1
a71 1
TRACE("Unknown SIGNAL"); /* child stopped due to a signal */
d107 1
a107 3
FILE *File;
char *szTemp;
char *pbIndex;
d110 1
a110 1
L2_PARAM_SET(pa[0], mode, CHARPTR, &szTemp);
d116 1
a116 1
if (strcmp(szTemp, "direct") == NULL)
d118 1
a118 1
else if (strcmp(szTemp, "shell") == NULL)
a122 14
/* check to see if a file exists at the user specified path */
if (cfg->iMode != L2_PIPE_MODESHELL) {
szTemp = strdup(cfg->szCmdpath);
for (pbIndex = szTemp; (*pbIndex != ' ') && (*pbIndex != NULL); pbIndex++);
*pbIndex = NULL;
if (!(File = fopen(szTemp, "r")))
return L2_ERR_ARG; /* the command does not exist at the given path */
else
fclose(File);
free(szTemp);
szTemp = NULL;
pbIndex = NULL;
}
d136 1
a136 1
while ((iCnt++ < L2_PIPE_MAXARGS) && (*szBuf != NULL)) {
d143 1
a143 1
*szArgs = NULL; /* add a NULL to mark the end of the chain */
d158 1
a173 13
/* the distinction between modes is necessary, because only executing */
/* commands in a shell environment allows usage of variables and such */
if (cfg->iMode == L2_PIPE_MODESHELL) {
pVec[0] = "/bin/sh";
pVec[1] = "-c";
pVec[2] = cfg->szCmdpath;
pVec[3] = NULL; /* add a NULL to mark the end of the chain */
}
else /* plain direct command execution */
if ((rv = parse_cmdpath(cfg->szCmdpath, pVec)) != L2_OK)
return rv;
d178 1
d187 17
d205 3
a207 1
close(cfg->piFd[0]); /* cleanup in case we fail */
d227 4
a230 2
hook_close(ctx, ch);
hook_open(ctx, ch);
d250 1
a250 1
if (sigaction(SIGCHLD, &cfg->sigchld, NULL) < 0)
d252 1
a252 1
if (sigaction(SIGPIPE, &cfg->sigpipe, NULL) < 0)
@
1.16
log
@Got rid of compile warnings and made minor TRACE modifications. Sorry, but
there is no way to use a va_list in a TRACE call. TRACE is a macro that
expands anywhere in source, so a va_list declaraction will sometimes violate
ANSI c decl specs.
@
text
@d37 4
a40 3
#define L2_PIPE_MODEDIRECT 1 /* direct command execution */
#define L2_PIPE_MODESHELL 2 /* shell command execution */
#define L2_PIPE_MAXARGS 256 /* shell command execution */
d234 1
a234 1
if ((errno == EPIPE) && (cfg->iWritefail++ < 6)) {
@
1.15
log
@Debugged TRACE and added debug test code.
@
text
@d61 1
a61 1
TRACE("SIGCHLD caught\n");
d64 1
a64 1
TRACE("EXITED child\n"); /* child finished and returned */
d66 1
a66 1
TRACE("SIGNALED child\n"); /* child finished due to a signal */
d68 1
a68 1
TRACE("STOPPED child\n"); /* child stopped due to a signal */
d70 1
a70 1
TRACE("Unknown SIGNAL\n"); /* child stopped due to a signal */
@
1.14
log
@Yet another signal handler redesign and more reliability.
@
text
@d69 2
@
1.13
log
@Debugging of channel's behavior logic when facing problematic children.
@
text
@d31 1
d41 1
a41 2
static l2_result_t hook_open(l2_context_t *, l2_channel_t *); /* prototypes */
static l2_result_t hook_close(l2_context_t *, l2_channel_t *);
d46 7
a52 5
int piFd[2]; /* pipe file descriptor */
int iChild; /* exception status of child pipe process */
int iMode; /* execution mode direct or shell */
pid_t Pid; /* pid set during fork in hook_open() */
char *szCmdpath; /* path to command and arguments */
d57 12
a68 33
va_list ap = NULL;
static l2_context_t *ctx = NULL;
static l2_channel_t *chan = NULL;
if (sig == 0) {
va_start(ap, sig);
ctx = va_arg(ap, l2_context_t *);
chan = va_arg(ap, l2_channel_t *);
va_end(ap);
}
else if (sig == SIGCHLD) {
/* TRACE("SIGCHLD caught\n");*/
waitpid(((l2_ch_pipe_t *)ctx->vp)->Pid, &((l2_ch_pipe_t *)ctx->vp)->iChild, WUNTRACED);
if (WIFEXITED(((l2_ch_pipe_t *)ctx->vp)->iChild)) {
close(((l2_ch_pipe_t *)ctx->vp)->piFd[1]);
((l2_ch_pipe_t *)ctx->vp)->piFd[1] = -1;
((l2_ch_pipe_t *)ctx->vp)->Pid = -1;
/* check if process called exit() abnormally, then if so restarts */
if (WEXITSTATUS(((l2_ch_pipe_t *)ctx->vp)->iChild)) {
fprintf(stderr, "exit status is %d\n", WEXITSTATUS(((l2_ch_pipe_t *)ctx->vp)->iChild));
if (hook_open(ctx, chan) != L2_OK) { /* TODO: Fix infinit loop! */
close(((l2_ch_pipe_t *)ctx->vp)->piFd[1]);
((l2_ch_pipe_t *)ctx->vp)->piFd[1] = -1;
}
}
}
else if (WIFSTOPPED(((l2_ch_pipe_t *)ctx->vp)->iChild)) {
}
}
else if (sig == SIGPIPE) { /* thrown when we write to child's closed pipe */
/* TRACE("SIGPIPE caught\n");*/
close(((l2_ch_pipe_t *)ctx->vp)->piFd[1]);
((l2_ch_pipe_t *)ctx->vp)->piFd[1] = -1;
d70 1
d83 8
a90 6
cfg->piFd[0] = -1;
cfg->piFd[1] = -1;
cfg->iChild = 0;
cfg->iMode = -1;
cfg->Pid = -1;
cfg->szCmdpath = NULL;
d122 2
a123 2
/* check to see if a file exists at the user specified path */
if(cfg->iMode != L2_PIPE_MODESHELL) {
d125 1
a125 1
for (pbIndex = szTemp; *pbIndex != NULL; pbIndex++);
d136 1
a136 5
catchsignal(0, ctx, ch); /* initialize signal handler with context & ch */
signal(SIGCHLD, (void(*)())catchsignal); /* pipe changes descriptor */
signal(SIGPIPE, (void(*)())catchsignal); /* pipe closes reading fd */
return rv; /* all okay */
d146 3
d169 1
d172 3
a174 3
/* make sure a command path was set */
if (cfg->szCmdpath == NULL)
return L2_ERR_USE;
d176 9
a184 1
memset(pVec, 0, sizeof(pVec));
d195 1
a195 1
else /* plain command execution */
d212 2
a213 2
close(cfg->piFd[0]); /* cleanup */
cfg->piFd[0] = -1;
d223 1
a223 1
/* write to channel */
d229 3
a231 5
if (cfg->piFd[1] == -1)
return L2_ERR_IO;
if (WIFSTOPPED(cfg->iChild)) {
if (kill(cfg->Pid, SIGCONT)) {
d233 5
a237 1
cfg->iChild = 0;
d241 4
a244 5
/* write message to channel pipe */
else if (write(cfg->piFd[1], buf, buf_size) == -1)
return L2_ERR_SYS;
return L2_OK;
d252 6
d261 1
a261 1
if (kill(cfg->Pid, SIGTERM))
d263 1
a264 1
@
1.12
log
@New implementation of signal handler and process control logic, improved
reliability, some redesign, and test logic.
@
text
@d41 1
d46 5
a50 4
int piFd[2]; /* pipe file descriptor */
int iMode; /* execution mode direct or shell */
pid_t Pid; /* pid set during fork in hook_open() */
char *szCmdpath; /* path to command and arguments */
d55 3
a57 4
int iStatus = 0;
va_list ap = NULL;
static l2_context_t *ctx = NULL;
static l2_channel_t *chan = NULL;
d67 2
a68 4
waitpid(((l2_ch_pipe_t *)ctx->vp)->Pid, &iStatus, 0);
close(((l2_ch_pipe_t *)ctx->vp)->piFd[1]);
((l2_ch_pipe_t *)ctx->vp)->piFd[1] = -1;
if (hook_open(ctx, chan) != L2_OK) { /* TODO: Fix infinit loop! */
d71 11
d84 1
a84 1
else if (sig == SIGPIPE) {
d101 5
a105 3
cfg->piFd[0] = -1;
cfg->piFd[1] = -1;
cfg->iMode = -1;
d240 7
d262 3
@
1.11
log
@Pipe channel handler redesign, bugfixes, and cleanup.
@
text
@d34 1
d40 3
d45 4
a48 4
int piFd[2]; /* pipe file descriptor */
int iMode; /* execution mode direct or shell */
char *szCmdpath; /* path to command and arguments */
char *pVec[L2_PIPE_MAXARGS]; /* vector of command and params */
d53 11
a63 6
va_list ap;
static l2_ch_pipe_t *cfg = NULL;
va_start(ap, sig);
if (sig == 0)
cfg = va_arg(ap, l2_ch_pipe_t *);
d65 8
a72 3
fprintf(stderr, "Pipe: SIGCHLD caught\n");
close(cfg->piFd[1]);
cfg->piFd[1] = -1; /* TODO: Fill in with new pipe fd */
d75 3
a77 4
fprintf(stderr, "Pipe: SIGPIPE caught\n");
close(cfg->piFd[1]);
cfg->piFd[1] = -1; /* TODO: Fill in with new pipe fd */
/* ((l2_ch_pipe_t *)(int *)ctx->vp)->piFd[1] = -1; */
a78 1
va_end(ap);
a94 1
memset(cfg->pVec, 0, sizeof(cfg->pVec));
d108 3
a110 1
char szMode[16]; /* just eneough for double-byte "direct" and NULL */
d113 1
a113 1
L2_PARAM_SET(pa[0], mode, CHARPTR, szMode);
d116 2
a117 1
rv = l2_util_setparams(pa, fmt, ap);
d119 1
a119 1
if (strcmp(szMode, "direct") == NULL)
d121 1
a121 1
else if (strcmp(szMode, "shell") == NULL)
d126 15
a140 1
catchsignal(0, cfg); /* initialize signal handler with incoming context */
d144 1
a144 1
return rv;
d153 1
d156 2
a157 2
*szBuf++ = '\0';
*szArgs++ = szBuf;
d161 1
a161 1
*szArgs = NULL;
d169 2
a170 6
/**********************************************************
* child_exec: Helper method to hook_open *
* Redirect stdin to read from cfg->piFd. Exec a given *
* command or passes it to the sh shell for execution. *
**********************************************************/
static l2_result_t child_exec(l2_ch_pipe_t *cfg)
d172 4
d180 1
a180 3
close(cfg->piFd[1]); /* close the writing end, */
cfg->piFd[1] = -1; /* because we don't use it */
dup2(cfg->piFd[0], fileno(stdin)); /* copy the reading end */
d182 8
a189 2
return execvp(*cfg->pVec, cfg->pVec); /* launch */
}
d191 3
a193 6
/* open channel */
static l2_result_t hook_open(l2_context_t *ctx, l2_channel_t *ch)
{
l2_ch_pipe_t *cfg = (l2_ch_pipe_t *)ctx->vp;
l2_result_t rv;
pid_t Pid;
d195 1
a195 4
if ((rv = parse_cmdpath(cfg->szCmdpath, cfg->pVec)) != L2_OK)
return rv;
if (pipe(cfg->piFd) == -1) /* open the pipe */
d198 2
a199 2
if ((Pid = fork()) > 0) { /* parent process */
close(cfg->piFd[0]);
d202 7
a208 4
else if ((Pid = fork()) == 0) { /* child process */
/* if child returns, there was an error */
if (child_exec(cfg) == -1) {
close(cfg->piFd[0]);
d210 1
a210 1
return L2_ERR_SYS;
d225 2
a226 3
/* validate the pipe fd */
if (cfg->piFd[1] == -1) /* TODO: possibly remove this validation in */
return L2_ERR_ARG; /* lieu of incoming SIGPIPE signal */
d229 1
a229 1
if (write(cfg->piFd[1], buf, buf_size) == -1)
d253 1
a253 1
free(&cfg->szCmdpath);
@
1.10
log
@Added the Thomas signal handler to catch SIGCHLD and SIGPIPE, pipe handler is
now a filter not an output, new logic to test code, bugfixes.
@
text
@d35 4
d41 4
a44 1
int iPipe; /* pipe filedescriptor used for writing only */
d50 1
a50 1
static l2_context_t *ctx = NULL;
d54 1
a54 1
ctx = va_arg(ap, l2_context_t *);
d56 9
a64 1
((l2_ch_pipe_t *)(int *)ctx->vp)->iPipe = -1; /* TODO: Fill in with new pipe fd */
a65 2
else if (sig == SIGPIPE)
((l2_ch_pipe_t *)(int *)ctx->vp)->iPipe = -1;
d79 5
a83 1
cfg->iPipe = -1;
d95 1
a95 1
l2_param_t pa[2];
d97 1
d100 3
a102 2
L2_PARAM_SET(pa[0], pipe, INT, &cfg->iPipe);
L2_PARAM_END(pa[1]);
d105 5
a109 2
/* validate the pipe fd */
if (cfg->iPipe == -1)
d112 1
a112 1
catchsignal(0, ctx); /* initialize signal handler with incoming context */
d119 70
d194 1
a194 3
l2_channel_t *downstream = l2_channel_downstream(ch);
l2_result_t rv;
d196 2
a197 2
if (cfg->iPipe == -1)
return L2_ERR_ARG;
d200 1
a200 1
if (write(cfg->iPipe, buf, buf_size) == -1)
a202 4
/* write to downstream channel */
if ((rv = l2_channel_write(downstream, level, buf, buf_size)) != L2_OK)
return rv;
a209 6
l2_channel_t *downstream = l2_channel_downstream(ch);
l2_result_t rv;
/* close channel pipe */
close(cfg->iPipe);
cfg->iPipe = -1;
d211 3
a213 3
/* close downstream channel, too */
if ((rv = l2_channel_close(downstream)) != L2_OK)
return rv;
a221 2
l2_channel_t *downstream = l2_channel_downstream(ch);
l2_result_t rv;
d224 2
a227 4
/* destroy downstream channel, too */
if ((rv = l2_channel_destroy(downstream)) != L2_OK)
return rv;
d233 1
a233 1
L2_CHANNEL_FILTER,
d236 1
a236 1
NULL,
@
1.9
log
@First cut at pipe channel handler. Lacks logic to guarantee reliability.
@
text
@d33 1
d40 16
d90 4
d102 2
d105 4
d113 4
d124 3
a126 1
d131 4
d142 2
d148 4
d157 1
a157 1
L2_CHANNEL_OUTPUT,
@
1.8
log
@Upgraded both stream and channel-level APIs to include new L2_LEVEL parameter design.
@
text
@d27 1
a27 1
** l2_ch_pipe.c: program pipe channel implementation
d32 8
d42 12
d57 1
d60 12
a71 2
return L2_OK;
}
d73 1
a73 3
static l2_result_t hook_open(l2_context_t *ctx, l2_channel_t *ch)
{
return L2_OK;
d76 3
a78 1
static l2_result_t hook_write(l2_context_t *ctx, l2_channel_t *ch, l2_level_t level, const char *buf, size_t buf_size)
d80 5
a84 2
return L2_OK;
}
a85 2
static l2_result_t hook_flush(l2_context_t *ctx, l2_channel_t *ch)
{
d89 1
d92 6
d101 1
d104 5
d112 1
d117 1
a117 1
hook_open,
d119 1
a119 1
hook_flush,
@
1.7
log
@Be politically correct: channels are intended to be implemented also by
users, which have only access to the public API (l2.h), so do not even
try to use anything more in our own shipped channels.
@
text
@d47 1
a47 2
static l2_result_t hook_write(l2_context_t *ctx, l2_channel_t *ch,
const char *buf, size_t buf_size)
@
1.6
log
@Be pedantically correct: handler hooks return "l2_result_t"
and not "int", although currently it is just an int/enum.
@
text
@a30 1
#include "l2_p.h"
@
1.5
log
@Revamp channel handler API:
Instead of passing the downstream channel to all channels we instead
provide a l2_channel_downstream() function and provide the current
channel. This way the handler API is prototype-wise fully orthogonal
with the channel API (which it implements) and we no longer pass
information to 2/3 of our (output) channels which is of no use there.
Additionally add a channel type field to l2_handler_t which allows a
handler to say what type of channel it implements (filter or output).
This information is now used in l2_channel_stack() to make sure that
one can only stack a filter channel on top of another channel. For
convinience reasons there is also a new l2_channel_type() function which
allows one to query the type of a particular channel.
@
text
@d33 1
a33 1
static int hook_create(l2_context_t *ctx, l2_channel_t *ch)
d38 1
a38 1
static int hook_configure(l2_context_t *ctx, l2_channel_t *ch, const char *fmt, va_list ap)
d43 1
a43 1
static int hook_open(l2_context_t *ctx, l2_channel_t *ch)
d48 1
a48 1
static int hook_write(l2_context_t *ctx, l2_channel_t *ch,
d54 1
a54 1
static int hook_flush(l2_context_t *ctx, l2_channel_t *ch)
d59 1
a59 1
static int hook_close(l2_context_t *ctx, l2_channel_t *ch)
d64 1
a64 1
static int hook_destroy(l2_context_t *ctx, l2_channel_t *ch)
@
1.4
log
@Fix more ossp.com references by replacing with the
correct domain name ossp.org.
@
text
@d33 1
a33 1
static int hook_create(l2_context_t *ctx)
d38 1
a38 1
static int hook_configure(l2_context_t *ctx, const char *fmt, va_list ap)
d43 1
a43 1
static int hook_open(l2_context_t *ctx, l2_channel_t *downstream)
d48 1
a48 1
static int hook_write(l2_context_t *ctx, l2_channel_t *downstream,
d54 1
a54 1
static int hook_flush(l2_context_t *ctx, l2_channel_t *downstream)
d59 1
a59 1
static int hook_close(l2_context_t *ctx, l2_channel_t *downstream)
d64 1
a64 1
static int hook_destroy(l2_context_t *ctx)
d70 1
@
1.3
log
@change terminology: below -> downstream
@
text
@d7 1
a7 1
** can be found at http://www.ossp.com/pkg/l2/.
@
1.2
log
@Fill in channel handler template code.
@
text
@d43 1
a43 1
static int hook_open(l2_context_t *ctx, l2_channel_t *below)
d48 1
a48 1
static int hook_write(l2_context_t *ctx, l2_channel_t *below,
d54 1
a54 1
static int hook_flush(l2_context_t *ctx, l2_channel_t *below)
d59 1
a59 1
static int hook_close(l2_context_t *ctx, l2_channel_t *below)
@
1.1
log
@Initial revision
@
text
@d33 46
@
1.1.1.1
log
@L2 initial source tree
@
text
@@