--- l2_ch_pipe.c 2001/10/01 16:26:14 1.22
+++ l2_ch_pipe.c 2001/10/02 15:51:32 1.23
@@ -33,18 +33,23 @@
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
+#include <fcntl.h>
-#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 */
+#define L2_PIPE_EXECMODE_DIRECT 1 /* direct command execution */
+#define L2_PIPE_EXECMODE_SHELL 2 /* shell command execution */
+#define L2_PIPE_RUNTIME_RELIABLE 3 /* reliable 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 reliable 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 */
@@ -80,10 +85,8 @@
*
* 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. 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.
+ * 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:
@@ -98,41 +101,43 @@
* Last-modified: 2000-09-28/14:40
* Name: l2_ch_pipe
* Version: eo/1.0
- * 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==
+ * 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-----
*/
@@ -150,7 +155,9 @@
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));
@@ -165,22 +172,33 @@
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[3];
+ l2_param_t pa[4];
l2_result_t rv;
- char *sz = NULL;
+ char *szMode = NULL;
+ char *szRel = NULL;
/* feed and call generic parameter parsing engine */
- L2_PARAM_SET(pa[0], mode, CHARPTR, &sz);
- L2_PARAM_SET(pa[1], path, STRING, &cfg->szCmdpath);
- L2_PARAM_END(pa[2]);
+ 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 */
+ L2_PARAM_END(pa[3]);
if ((rv = l2_util_setparams(pa, fmt, ap)) != L2_OK)
return rv;
- if (sz != NULL) {
- if (strcmp(sz, "direct") == 0)
- cfg->iMode = L2_PIPE_MODEDIRECT;
- else if (strcmp(sz, "shell") == 0)
- cfg->iMode = L2_PIPE_MODESHELL;
+ 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;
+ }
+
+ if (szRel != NULL) {
+ if (strcmp(szRel, "reliable") == 0)
+ cfg->iRtme = L2_PIPE_RUNTIME_RELIABLE;
+ else if (strcmp(szMode, "oneshot") == 0)
+ cfg->iRtme = L2_PIPE_RUNTIME_ONESHOT;
else
return L2_ERR_ARG;
}
@@ -189,10 +207,10 @@
}
/**********************************************************
- * parse_cmdpath: Helper method to hook_open *
+ * 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[]) {
+static l2_result_t parse_cmdpath(char *szBuf, char *szArgs[]) {
int iCnt = 0;
if (szBuf == NULL) /* check for bad input before we */
@@ -213,55 +231,44 @@
return L2_ERR_ARG;
}
-/* open channel */
-static l2_result_t hook_open(l2_context_t *ctx, l2_channel_t *ch)
+/************************************************************
+ * 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)
{
- l2_ch_pipe_t *cfg = (l2_ch_pipe_t *)ctx->vp;
char *pVec[L2_PIPE_MAXARGS];
- struct sigaction locact;
- l2_result_t rv;
char *sz = NULL;
-
- /* consistency check */
- if (cfg->szCmdpath == NULL)
- return L2_ERR_USE;
+ l2_result_t rv;
/* initialize auto vars before using them */
memset(pVec, 0, sizeof(pVec));
- 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;
+ /* 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_MODESHELL) {
+ 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) {
@@ -277,9 +284,44 @@
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(*)())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
+ spawn_command(cfg); /* spawn the command process */
return L2_OK;
}
@@ -291,6 +333,10 @@
l2_ch_pipe_t *cfg = (l2_ch_pipe_t *)ctx->vp;
l2_result_t rv;
+ /* 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);
+
/* write message to channel pipe */
if (write(cfg->piFd[1], buf, buf_size) == -1) {
if ((errno == EPIPE) && (cfg->iWritefail++ < L2_PIPE_WRITEFAIL)) {
@@ -316,19 +362,33 @@
{
l2_ch_pipe_t *cfg = (l2_ch_pipe_t *)ctx->vp;
- /* 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;
+ /* 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;
+ }
- /* 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;
+ /* 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;
+ }
+
+ /* kill child process if already started */
+ if (cfg->Pid != -1) {
+ if ((kill (cfg->Pid, SIGTERM)) && (errno != ESRCH))
+ return L2_ERR_SYS;
+ cfg->Pid = -1;
+ }
- cfg->Pid = -1;
return L2_OK;
}
|