summaryrefslogtreecommitdiff
path: root/pr/src/md/unix/uxproces.c
diff options
context:
space:
mode:
Diffstat (limited to 'pr/src/md/unix/uxproces.c')
-rw-r--r--pr/src/md/unix/uxproces.c108
1 files changed, 106 insertions, 2 deletions
diff --git a/pr/src/md/unix/uxproces.c b/pr/src/md/unix/uxproces.c
index 8c0a9b96..d6cacf6d 100644
--- a/pr/src/md/unix/uxproces.c
+++ b/pr/src/md/unix/uxproces.c
@@ -27,7 +27,11 @@
#include <dlfcn.h> /* For dlopen, dlsym, dlclose */
#endif
+#if defined(RHAPSODY)
+#include <crt_externs.h>
+#else
extern char **environ;
+#endif
/*
* HP-UX 9 doesn't have the SA_RESTART flag.
@@ -36,6 +40,10 @@ extern char **environ;
#define SA_RESTART 0
#endif
+#if defined(VMS)
+static PRLock *_pr_vms_fork_lock = NULL;
+#endif
+
/*
**********************************************************************
*
@@ -146,7 +154,10 @@ ForkAndExec(
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);
@@ -156,7 +167,11 @@ ForkAndExec(
childEnvp = envp;
if (attr && attr->fdInheritBuffer) {
if (NULL == childEnvp) {
+#ifdef RHAPSODY
+ childEnvp = *(_NSGetEnviron());
+#else
childEnvp = environ;
+#endif
}
for (nEnv = 0; childEnvp[nEnv]; nEnv++) {
}
@@ -173,6 +188,65 @@ ForkAndExec(
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)();
@@ -193,7 +267,9 @@ ForkAndExec(
* 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) {
@@ -234,6 +310,7 @@ ForkAndExec(
}
}
}
+#endif /* !VMS */
if (childEnvp) {
(void)execve(path, argv, childEnvp);
@@ -242,12 +319,35 @@ ForkAndExec(
(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);
@@ -655,6 +755,10 @@ static PRStatus _MD_InitProcesses()
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);