+++ /dev/null
-// natPosixProcess.cc - Native side of POSIX process code.
-
-/* Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation
-
- 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 <config.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <gcj/cni.h>
-#include <jvm.h>
-
-#include <java/lang/ConcreteProcess.h>
-#include <java/lang/IllegalThreadStateException.h>
-#include <java/lang/InterruptedException.h>
-#include <java/lang/NullPointerException.h>
-#include <java/lang/Thread.h>
-#include <java/io/FileDescriptor.h>
-#include <java/io/FileInputStream.h>
-#include <java/io/FileOutputStream.h>
-#include <java/io/IOException.h>
-#include <java/lang/OutOfMemoryError.h>
-
-extern char **environ;
-
-void
-java::lang::ConcreteProcess::destroy (void)
-{
- if (! hasExited)
- {
- // Really kill it.
- kill ((pid_t) pid, SIGKILL);
- }
-}
-
-jint
-java::lang::ConcreteProcess::waitFor (void)
-{
- if (! hasExited)
- {
- int wstat;
- int r = waitpid ((pid_t) pid, &wstat, 0);
-
- if (r == -1)
- {
- if (java::lang::Thread::interrupted())
- throw new InterruptedException (JvNewStringLatin1 (strerror
- (errno)));
- }
- else
- {
- hasExited = true;
-
- if (WIFEXITED (wstat))
- status = WEXITSTATUS (wstat);
- else
- status = -1;
- }
- }
-
- 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;
-}
-
-static void
-cleanup (char **args, char **env)
-{
- if (args != NULL)
- {
- for (int i = 0; args[i] != NULL; ++i)
- _Jv_Free (args[i]);
- _Jv_Free (args);
- }
- if (env != NULL)
- {
- for (int i = 0; env[i] != NULL; ++i)
- _Jv_Free (env[i]);
- _Jv_Free (env);
- }
-}
-
-// This makes our error handling a bit simpler and it lets us avoid
-// thread bugs where we close a possibly-reopened file descriptor for
-// a second time.
-static void
-myclose (int &fd)
-{
- if (fd != -1)
- close (fd);
- fd = -1;
-}
-
-void
-java::lang::ConcreteProcess::startProcess (jstringArray progarray,
- jstringArray envp)
-{
- using namespace java::io;
-
- hasExited = false;
-
- // Initialize all locals here to make cleanup simpler.
- char **args = NULL;
- char **env = NULL;
- int inp[2], outp[2], errp[2], msgp[2];
- inp[0] = -1;
- inp[1] = -1;
- outp[0] = -1;
- outp[1] = -1;
- errp[0] = -1;
- errp[1] = -1;
- msgp[0] = -1;
- msgp[1] = -1;
- java::lang::Throwable *exc = NULL;
- errorStream = NULL;
- inputStream = NULL;
- outputStream = NULL;
-
- try
- {
- // Transform arrays to native form.
- args = (char **) _Jv_Malloc ((progarray->length + 1)
- * sizeof (char *));
-
- // Initialize so we can gracefully recover.
- jstring *elts = elements (progarray);
- for (int i = 0; i <= progarray->length; ++i)
- args[i] = NULL;
-
- 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);
-
- // Initialize so we can gracefully recover.
- for (int i = 0; i <= envp->length; ++i)
- env[i] = NULL;
-
- for (int i = 0; i < envp->length; ++i)
- env[i] = new_string (elts[i]);
- env[envp->length] = NULL;
- }
-
- // Create pipes for I/O. MSGP is for communicating exec()
- // status.
- if (pipe (inp) || pipe (outp) || pipe (errp) || pipe (msgp)
- || fcntl (msgp[1], F_SETFD, FD_CLOEXEC))
- 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)
- throw new IOException (JvNewStringLatin1 (strerror (errno)));
-
- if (pid == 0)
- {
- // Child process, so remap descriptors and exec.
-
- if (envp)
- {
- // Preserve PATH and LD_LIBRARY_PATH unless specified
- // explicitly.
- char *path_val = getenv ("PATH");
- char *ld_path_val = getenv ("LD_LIBRARY_PATH");
- environ = env;
- if (getenv ("PATH") == NULL)
- {
- char *path_env = (char *) _Jv_Malloc (strlen (path_val)
- + 5 + 1);
- strcpy (path_env, "PATH=");
- strcat (path_env, path_val);
- putenv (path_env);
- }
- if (getenv ("LD_LIBRARY_PATH") == NULL)
- {
- char *ld_path_env
- = (char *) _Jv_Malloc (strlen (ld_path_val) + 16 + 1);
- strcpy (ld_path_env, "LD_LIBRARY_PATH=");
- strcat (ld_path_env, ld_path_val);
- putenv (ld_path_env);
- }
- }
-
- // We ignore errors from dup2 because they should never occur.
- dup2 (outp[0], 0);
- dup2 (inp[1], 1);
- dup2 (errp[1], 2);
-
- // Use close and not myclose -- we're in the child, and we
- // aren't worried about the possible race condition.
- close (inp[0]);
- close (inp[1]);
- close (errp[0]);
- close (errp[1]);
- close (outp[0]);
- close (outp[1]);
- close (msgp[0]);
-
- execvp (args[0], args);
-
- // Send the parent notification that the exec failed.
- char c = errno;
- write (msgp[1], &c, 1);
- _exit (127);
- }
-
- // Parent. Close extra file descriptors and mark ours as
- // close-on-exec.
- myclose (outp[0]);
- myclose (inp[1]);
- myclose (errp[1]);
- myclose (msgp[1]);
-
- char c;
- int r = read (msgp[0], &c, 1);
- if (r == -1)
- throw new IOException (JvNewStringLatin1 (strerror (errno)));
- else if (r != 0)
- throw new IOException (JvNewStringLatin1 (strerror (c)));
- }
- catch (java::lang::Throwable *thrown)
- {
- // Do some cleanup we only do on failure. If a stream object
- // has been created, we must close the stream itself (to avoid
- // duplicate closes when the stream object is collected).
- // Otherwise we simply close the underlying file descriptor.
- // We ignore errors here as they are uninteresting.
-
- try
- {
- if (inputStream != NULL)
- inputStream->close ();
- else
- myclose (inp[0]);
- }
- catch (java::lang::Throwable *ignore)
- {
- }
-
- try
- {
- if (outputStream != NULL)
- outputStream->close ();
- else
- myclose (outp[1]);
- }
- catch (java::lang::Throwable *ignore)
- {
- }
-
- try
- {
- if (errorStream != NULL)
- errorStream->close ();
- else
- myclose (errp[0]);
- }
- catch (java::lang::Throwable *ignore)
- {
- }
-
- // These are potentially duplicate, but it doesn't matter due to
- // the use of myclose.
- myclose (outp[0]);
- myclose (inp[1]);
- myclose (errp[1]);
- myclose (msgp[1]);
-
- exc = thrown;
- }
-
- myclose (msgp[0]);
- cleanup (args, env);
-
- if (exc != NULL)
- throw exc;
- else
- {
- fcntl (outp[1], F_SETFD, FD_CLOEXEC);
- fcntl (inp[0], F_SETFD, FD_CLOEXEC);
- fcntl (errp[0], F_SETFD, FD_CLOEXEC);
- }
-}