// natPosixProcess.cc - Native side of POSIX process code. /* Copyright (C) 1998, 1999 Cygnus Solutions This file is part of libgcj. This software is copyrighted work licensed under the terms of the Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern char **environ; void java::lang::ConcreteProcess::destroy (void) { if (! hasExited) { // Really kill it. kill ((pid_t) pid, SIGKILL); } } jint java::lang::ConcreteProcess::exitValue (void) { if (! hasExited) { int wstat; pid_t r = waitpid ((pid_t) pid, &wstat, WNOHANG); if (r == -1) { jstring x = JvNewStringLatin1 (strerror (errno)); _Jv_Throw (new IllegalThreadStateException (x)); } hasExited = true; // Just use the raw status. FIXME: what is right? status = wstat; } return status; } jint java::lang::ConcreteProcess::waitFor (void) { if (! hasExited) { int wstat; int r = waitpid ((pid_t) pid, &wstat, 0); if (r != -1) { hasExited = true; // Just use the raw status. FIXME: what is right? status = wstat; } if (java::lang::Thread::interrupted()) _Jv_Throw (new InterruptedException (JvNewStringLatin1 ("wait interrupted"))); } return status; } static char * new_string (jstring string) { jsize s = _Jv_GetStringUTFLength (string); char *buf = (char *) _Jv_Malloc (s + 1); _Jv_GetStringUTFRegion (string, 0, s, buf); buf[s] = '\0'; return buf; } void java::lang::ConcreteProcess::startProcess (jstringArray progarray, jstringArray envp) { using namespace java::io; hasExited = false; if (! progarray) _Jv_Throw (new NullPointerException); // Transform arrays to native form. // FIXME: we use malloc here. We shouldn't. If an exception is // thrown we will leak memory. char **args = (char **) _Jv_Malloc ((progarray->length + 1) * sizeof (char *)); char **env = NULL; // FIXME: GC will fail here if _Jv_Malloc throws an exception. // That's because we have to manually free the contents, but we jstring *elts = elements (progarray); for (int i = 0; i < progarray->length; ++i) args[i] = new_string (elts[i]); args[progarray->length] = NULL; if (envp) { env = (char **) _Jv_Malloc ((envp->length + 1) * sizeof (char *)); elts = elements (envp); for (int i = 0; i < envp->length; ++i) env[i] = new_string (elts[i]); env[envp->length] = NULL; } // Create pipes for I/O. int inp[2], outp[2], errp[2]; if (pipe (inp) || pipe (outp) || pipe (errp)) { ioerror: // FIXME. _Jv_Free (args); if (env) _Jv_Free (env); _Jv_Throw (new IOException (JvNewStringLatin1 (strerror (errno)))); } // We create the streams before forking. Otherwise if we had an // error while creating the streams we would have run the child with // no way to communicate with it. errorStream = new FileInputStream (new FileDescriptor (errp[0])); inputStream = new FileInputStream (new FileDescriptor (inp[0])); outputStream = new FileOutputStream (new FileDescriptor (outp[1])); // We don't use vfork() because that would cause the local // environment to be set by the child. if ((pid = (jlong) fork ()) == -1) goto ioerror; if (pid == 0) { // Child process, so remap descriptors and exec. if (envp) { // preserve PATH unless specified explicitly char *path_val = getenv("PATH"); environ = env; if (getenv("PATH") == NULL) { char *path_env = (char *) _Jv_Malloc (strlen(path_val) + 5 + 1); sprintf (path_env, "PATH=%s", path_val); putenv (path_env); } } // We ignore errors from dup2 because they should never occur. dup2 (outp[0], 0); dup2 (inp[1], 1); dup2 (errp[1], 2); close (inp[0]); close (inp[1]); close (errp[0]); close (errp[1]); close (outp[0]); close (outp[1]); execvp (args[0], args); // FIXME: should throw an IOException if execvp() fails. Not trivial, // because _Jv_Throw won't work from child process _exit (127); } // Parent. Close extra file descriptors and mark ours as // close-on-exec. close (outp[0]); close (inp[1]); close (errp[1]); fcntl (outp[1], F_SETFD, 1); fcntl (inp[0], F_SETFD, 1); fcntl (errp[0], F_SETFD, 1); }