OSSP CVS Repository

ossp - Check-in [1058]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 1058
Date: 2001-Oct-02 17:51:32 (local)
2001-Oct-02 15:51:32 (UTC)
User:ms
Branch:
Comment: Added new logic to accommodate one-shot behavior, and some changes to handle a child process that writes when it should only read.
Tickets:
Inspections:
Files:
ossp-pkg/l2/l2_ch_pipe.c      1.22 -> 1.23     151 inserted, 91 deleted

ossp-pkg/l2/l2_ch_pipe.c 1.22 -> 1.23

--- 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;
 }
 

CVSTrac 2.0.1