Bugszilla: 49161. OpenVMS NSPRPUB_CLIENT_BRANCH
authorlarryh%netscape.com
Thu, 02 Nov 2000 22:31:40 +0000
branchNSPRPUB_CLIENT_BRANCH
changeset 1618 e86ea485bfd0e27d5fd37e603a4362886d705bd2
parent 1611 d0ce125dfc418cc768a7d3886a9f74d4e7f45cfc
child 1619 022f99f809383d13b8a0a69c8e61d3c04f80a1ff
child 1621 a7f09642b925859f2da01707d2c8dcca080b10fa
push idunknown
push userunknown
push dateunknown
bugs49161
Bugszilla: 49161. OpenVMS
pr/src/md/unix/uxproces.c
--- a/pr/src/md/unix/uxproces.c
+++ b/pr/src/md/unix/uxproces.c
@@ -35,16 +35,20 @@ extern char **environ;
 
 /*
  * HP-UX 9 doesn't have the SA_RESTART flag.
  */
 #ifndef SA_RESTART
 #define SA_RESTART 0
 #endif
 
+#if defined(VMS)
+static PRLock *_pr_vms_fork_lock = NULL;
+#endif
+
 /*
  **********************************************************************
  *
  * The Unix process routines
  *
  **********************************************************************
  */
 
@@ -145,17 +149,20 @@ ForkAndExec(
     char *const *envp,
     const PRProcessAttr *attr)
 {
     PRProcess *process;
     int nEnv, idx;
     char *const *childEnvp;
     char **newEnvp = NULL;
     int flags;
-	
+#ifdef VMS
+    char VMScurdir[FILENAME_MAX+1] = { '\0' } ;
+#endif	
+
     process = PR_NEW(PRProcess);
     if (!process) {
         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
         return NULL;
     }
 
     childEnvp = envp;
     if (attr && attr->fdInheritBuffer) {
@@ -176,16 +183,75 @@ ForkAndExec(
         }
         for (idx = 0; idx < nEnv; idx++) {
             newEnvp[idx] = childEnvp[idx];
         }
         newEnvp[idx++] = attr->fdInheritBuffer;
         newEnvp[idx] = NULL;
         childEnvp = newEnvp;
     }
+#ifdef VMS
+/*
+** Since vfork/exec is implemented VERY differently on OpenVMS, we have to
+** handle the setting up of the standard streams very differently. And since
+** none of this code can ever execute in the context of the child, we have
+** to perform the chdir in the parent so the child is born into the correct
+** directory (and then switch the parent back again).
+*/
+{
+    int decc$set_child_standard_streams(int,int,int);
+    int n, fd_stdin=0, fd_stdout=1, fd_stderr=2;
+
+    /* Set up any standard streams we are given, assuming defaults */
+    if (attr) {
+       if (attr->stdinFd)
+           fd_stdin = attr->stdinFd->secret->md.osfd;
+       if (attr->stdoutFd)
+           fd_stdout = attr->stdoutFd->secret->md.osfd;
+       if (attr->stderrFd)
+           fd_stderr = attr->stderrFd->secret->md.osfd;
+    }
+
+    /*
+    ** Put a lock around anything that isn't going to be thread-safe.
+    */
+    PR_Lock(_pr_vms_fork_lock);
+
+    /*
+    ** Prepare the child's streams. We always do this in case a previous fork
+    ** has left the stream assignments in some non-standard way.
+    */
+    n = decc$set_child_standard_streams(fd_stdin,fd_stdout,fd_stderr);
+    if (n == -1) {
+       PR_SetError(PR_BAD_DESCRIPTOR_ERROR, errno);
+       PR_DELETE(process);
+       if (newEnvp) {
+           PR_DELETE(newEnvp);
+       }
+       PR_Unlock(_pr_vms_fork_lock);
+       return NULL;
+    }
+
+    /* Switch directory if we have to */
+    if (attr) {
+       if (attr->currentDirectory) {
+           if ( (getcwd(VMScurdir,sizeof(VMScurdir)) == NULL) ||
+                (chdir(attr->currentDirectory) < 0) ) {
+               PR_SetError(PR_DIRECTORY_OPEN_ERROR, errno);
+               PR_DELETE(process);
+               if (newEnvp) {
+                   PR_DELETE(newEnvp);
+               }
+               PR_Unlock(_pr_vms_fork_lock);
+               return NULL;
+           }
+       }
+    }
+}
+#endif /* VMS */
 
 #ifdef AIX
     process->md.pid = (*pr_wp.forkptr)();
 #else
     process->md.pid = fork();
 #endif
     if ((pid_t) -1 == process->md.pid) {
         PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno);
@@ -196,17 +262,19 @@ ForkAndExec(
         return NULL;
     } else if (0 == process->md.pid) {  /* the child process */
         /*
          * If the child process needs to exit, it must call _exit().
          * Do not call exit(), because exit() will flush and close
          * the standard I/O file descriptors, and hence corrupt
          * the parent process's standard I/O data structures.
          */
-
+#ifdef VMS
+       /* OpenVMS has already handled all this above */
+#else
         if (attr) {
             if (attr->stdinFd
                     && attr->stdinFd->secret->md.osfd != 0) {
                 if (dup2(attr->stdinFd->secret->md.osfd, 0) != 0) {
                     _exit(1);  /* failed */
                 }
                 close(attr->stdinFd->secret->md.osfd);
                 flags = fcntl(0, F_GETFL, 0);
@@ -237,30 +305,54 @@ ForkAndExec(
                 }
             }
             if (attr->currentDirectory) {
                 if (chdir(attr->currentDirectory) < 0) {
                     _exit(1);  /* failed */
                 }
             }
         }
+#endif /* !VMS */
 
         if (childEnvp) {
             (void)execve(path, argv, childEnvp);
         } else {
             /* Inherit the environment of the parent. */
             (void)execv(path, argv);
         }
         /* Whoops! It returned. That's a bad sign. */
+#ifdef VMS
+       /*
+       ** On OpenVMS we are still in the context of the parent, and so we
+       ** can (and should!) perform normal error handling.
+       */
+       PR_SetError(PR_UNKNOWN_ERROR, errno);
+       PR_DELETE(process);
+       if (newEnvp) {
+           PR_DELETE(newEnvp);
+       }
+       if (VMScurdir[0] != '\0')
+           chdir(VMScurdir);
+       PR_Unlock(_pr_vms_fork_lock);
+       return NULL;
+#else
         _exit(1);
+#endif /* VMS */
     }
 
     if (newEnvp) {
         PR_DELETE(newEnvp);
     }
+#ifdef VMS
+    /* If we switched directories, then remember to switch back */
+    if (VMScurdir[0] != '\0') {
+       chdir(VMScurdir); /* can't do much if it fails */
+    }
+    PR_Unlock(_pr_vms_fork_lock);
+#endif /* VMS */
 
 #if defined(_PR_NATIVE_THREADS)
     PR_Lock(pr_wp.ml);
     if (0 == pr_wp.numProcs++) {
         PR_NotifyCondVar(pr_wp.cv);
     }
     PR_Unlock(pr_wp.ml);
 #endif
@@ -658,16 +750,20 @@ static PRStatus _MD_InitProcesses()
         }
         dlclose(handle);
     }
 #endif /* AIX */
 
     pr_wp.ml = PR_NewLock();
     PR_ASSERT(NULL != pr_wp.ml);
 
+#if defined(VMS)
+    _pr_vms_fork_lock = PR_NewLock();
+    PR_ASSERT(NULL != _pr_vms_fork_lock);
+#endif
 #if defined(_PR_NATIVE_THREADS)
     pr_wp.numProcs = 0;
     pr_wp.cv = PR_NewCondVar(pr_wp.ml);
     PR_ASSERT(NULL != pr_wp.cv);
 #else
     rv = pipe(pr_wp.pipefd);
     PR_ASSERT(0 == rv);
     flags = fcntl(pr_wp.pipefd[0], F_GETFL, 0);