]> granicus.if.org Git - python/commitdiff
OS/2 specific fixes related to SF bug # 1003471.
authorAndrew MacIntyre <andymac@bullseye.apana.org.au>
Sun, 12 Dec 2004 08:30:51 +0000 (08:30 +0000)
committerAndrew MacIntyre <andymac@bullseye.apana.org.au>
Sun, 12 Dec 2004 08:30:51 +0000 (08:30 +0000)
Also revise a related function to minimise file handle/pipe leakage
and improve reliability.

Modules/posixmodule.c

index 31d7c6181723d4b1c1aae2dbf444cb153fbacd4e..f605cca4a3665bb6e7dbf78c78fbc3124e619c0c 100644 (file)
@@ -3248,86 +3248,85 @@ Open a pipe to/from a command returning a file object.");
 static int
 async_system(const char *command)
 {
-    char        *p, errormsg[256], args[1024];
-    RESULTCODES  rcodes;
-    APIRET       rc;
-    char        *shell = getenv("COMSPEC");
-    if (!shell)
-        shell = "cmd";
-
-    strcpy(args, shell);
-    p = &args[ strlen(args)+1 ];
-    strcpy(p, "/c ");
-    strcat(p, command);
-    p += strlen(p) + 1;
-    *p = '\0';
-
-    rc = DosExecPgm(errormsg, sizeof(errormsg),
-                    EXEC_ASYNC, /* Execute Async w/o Wait for Results */
-                    args,
-                    NULL,       /* Inherit Parent's Environment */
-                    &rcodes, shell);
-    return rc;
+       char errormsg[256], args[1024];
+       RESULTCODES rcodes;
+       APIRET rc;
+
+       char *shell = getenv("COMSPEC");
+       if (!shell)
+               shell = "cmd";
+
+       /* avoid overflowing the argument buffer */
+       if (strlen(shell) + 3 + strlen(command) >= 1024)
+               return ERROR_NOT_ENOUGH_MEMORY
+
+       args[0] = '\0';
+       strcat(args, shell);
+       strcat(args, "/c ");
+       strcat(args, command);
+
+       /* execute asynchronously, inheriting the environment */
+       rc = DosExecPgm(errormsg,
+                       sizeof(errormsg),
+                       EXEC_ASYNC,
+                       args,
+                       NULL,
+                       &rcodes,
+                       shell);
+       return rc;
 }
 
 static FILE *
 popen(const char *command, const char *mode, int pipesize, int *err)
 {
-    HFILE    rhan, whan;
-    FILE    *retfd = NULL;
-    APIRET   rc = DosCreatePipe(&rhan, &whan, pipesize);
-
-    if (rc != NO_ERROR) {
-       *err = rc;
-        return NULL; /* ERROR - Unable to Create Anon Pipe */
-    }
-
-    if (strchr(mode, 'r') != NULL) { /* Treat Command as a Data Source */
-        int oldfd = dup(1);      /* Save STDOUT Handle in Another Handle */
-
-        DosEnterCritSec();      /* Stop Other Threads While Changing Handles */
-        close(1);                /* Make STDOUT Available for Reallocation */
-
-        if (dup2(whan, 1) == 0) {      /* Connect STDOUT to Pipe Write Side */
-            DosClose(whan);            /* Close Now-Unused Pipe Write Handle */
-
-            rc = async_system(command);
-        }
-
-        dup2(oldfd, 1);          /* Reconnect STDOUT to Original Handle */
-        DosExitCritSec();        /* Now Allow Other Threads to Run */
-
-        if (rc == NO_ERROR)
-            retfd = fdopen(rhan, mode); /* And Return Pipe Read Handle */
-
-        close(oldfd);            /* And Close Saved STDOUT Handle */
-        return retfd;            /* Return fd of Pipe or NULL if Error */
-
-    } else if (strchr(mode, 'w')) { /* Treat Command as a Data Sink */
-        int oldfd = dup(0);      /* Save STDIN Handle in Another Handle */
+       int oldfd, tgtfd;
+       HFILE pipeh[2];
+       APIRET rc;
 
-        DosEnterCritSec();      /* Stop Other Threads While Changing Handles */
-        close(0);                /* Make STDIN Available for Reallocation */
+       /* mode determines which of stdin or stdout is reconnected to
+        * the pipe to the child
+        */
+       if (strchr(mode, 'r') != NULL) {
+               tgt_fd = 1;     /* stdout */
+       } else if (strchr(mode, 'w')) {
+               tgt_fd = 0;     /* stdin */
+       } else {
+               *err = ERROR_INVALID_ACCESS;
+               return NULL;
+       }
 
-        if (dup2(rhan, 0) == 0)     { /* Connect STDIN to Pipe Read Side */
-            DosClose(rhan);           /* Close Now-Unused Pipe Read Handle */
+       /* setup the pipe
+       if ((rc = DosCreatePipe(&pipeh[0], &pipeh[1], pipesize)) != NO_ERROR) {
+               *err = rc;
+               return NULL;
+       }
 
-            rc = async_system(command);
-        }
+       /* prevent other threads accessing stdio */
+       DosEnterCritSec();
 
-        dup2(oldfd, 0);          /* Reconnect STDIN to Original Handle */
-        DosExitCritSec();        /* Now Allow Other Threads to Run */
+       /* reconnect stdio and execute child */
+       oldfd = dup(tgtfd);
+       close(tgtfd);
+       if (dup2(pipeh[tgtfd], tgtfd) == 0) {
+               DosClose(pipeh[tgtfd]);
+               rc = async_system(command);
+       }
 
-        if (rc == NO_ERROR)
-            retfd = fdopen(whan, mode); /* And Return Pipe Write Handle */
+       /* restore stdio */
+       dup2(oldfd, tgtfd);
+       close(oldfd);
 
-        close(oldfd);            /* And Close Saved STDIN Handle */
-        return retfd;            /* Return fd of Pipe or NULL if Error */
+       /* allow other threads access to stdio */
+       DosExitCritSec();
 
-    } else {
-       *err = ERROR_INVALID_ACCESS;
-        return NULL; /* ERROR - Invalid Mode (Neither Read nor Write) */
-    }
+       /* if execution of child was successful return file stream */
+       if (rc == NO_ERROR)
+               return fdopen(pipeh[1 - tgtfd], mode);
+       else {
+               DosClose(pipeh[1 - tgtfd]);
+               *err = rc;
+               return NULL;
+       }
 }
 
 static PyObject *