natPosixProcess.cc (fail): Removed.

* java/lang/natPosixProcess.cc (fail): Removed.
	(startProcess): Simplified error-handling.  Preserve
	LD_LIBRARY_PATH across exec.

From-SVN: r50343
This commit is contained in:
Tom Tromey 2002-03-06 05:14:38 +00:00 committed by Tom Tromey
parent ab02e8446b
commit 2fadde235c
2 changed files with 157 additions and 124 deletions

View File

@ -1,3 +1,9 @@
2002-03-05 Tom Tromey <tromey@redhat.com>
* java/lang/natPosixProcess.cc (fail): Removed.
(startProcess): Simplified error-handling. Preserve
LD_LIBRARY_PATH across exec.
2002-03-05 Tom Tromey <tromey@redhat.com>
* jni.cc (_Jv_LookupJNIMethod): Throw UnsatisfiedLinkError, not

View File

@ -114,38 +114,6 @@ myclose (int &fd)
fd = -1;
}
static void
fail (int error_value, char **args, char **env,
int *one = NULL, int *two = NULL,
int *three = NULL, int *four = NULL,
java::lang::Throwable *t = NULL)
{
cleanup (args, env);
if (one != NULL)
{
myclose (one[0]);
myclose (one[1]);
}
if (two != NULL)
{
myclose (two[0]);
myclose (two[1]);
}
if (three != NULL)
{
myclose (three[0]);
myclose (three[1]);
}
if (four != NULL)
{
myclose (four[0]);
myclose (four[1]);
}
if (t == NULL)
t = new java::io::IOException (JvNewStringLatin1 (strerror (error_value)));
throw t;
}
void
java::lang::ConcreteProcess::startProcess (jstringArray progarray,
jstringArray envp)
@ -154,21 +122,34 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray,
hasExited = false;
if (! progarray)
throw new NullPointerException;
// Transform arrays to native form.
char **args = (char **) _Jv_Malloc ((progarray->length + 1)
* sizeof (char *));
// Initialize all locals here to make cleanup simpler.
char **args = NULL;
char **env = NULL;
// Initialize so we can gracefully recover.
jstring *elts = elements (progarray);
for (int i = 0; i <= progarray->length; ++i)
args[i] = 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;
@ -186,105 +167,151 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray,
env[i] = new_string (elts[i]);
env[envp->length] = NULL;
}
}
catch (java::lang::OutOfMemoryError *oome)
{
fail (0, args, env, NULL, NULL, NULL, NULL, oome);
throw oome;
}
// Create pipes for I/O. MSGP is for communicating exec() status.
int inp[2], outp[2], errp[2], msgp[2];
// 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)));
if (pipe (inp))
fail (errno, args, env);
if (pipe (outp))
fail (errno, args, env, inp);
if (pipe (errp))
fail (errno, args, env, inp, outp);
if (pipe (msgp))
fail (errno, args, env, inp, outp, errp);
if (fcntl (msgp[1], F_SETFD, FD_CLOEXEC))
fail (errno, args, env, inp, outp, errp, msgp);
// 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.
try
{
// 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]));
}
catch (java::lang::Throwable *t)
{
fail (0, args, env, inp, outp, errp, msgp, t);
}
// We don't use vfork() because that would cause the local
// environment to be set by the child.
if ((pid = (jlong) fork ()) == -1)
fail (errno, args, env, inp, outp, errp, msgp);
// 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 (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)
if (envp)
{
char *path_env = (char *) _Jv_Malloc (strlen (path_val) + 5 + 1);
strcpy (path_env, "PATH=");
strcat (path_env, path_val);
putenv (path_env);
// 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);
}
// 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]);
// Parent. Close extra file descriptors and mark ours as
// close-on-exec.
myclose (outp[0]);
myclose (inp[1]);
myclose (errp[1]);
myclose (msgp[1]);
execvp (args[0], args);
// Send the parent notification that the exec failed.
char c = errno;
write (msgp[1], &c, 1);
_exit (127);
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.
// Parent. Close extra file descriptors and mark ours as
// close-on-exec.
myclose (outp[0]);
myclose (inp[1]);
myclose (errp[1]);
myclose (msgp[1]);
try
{
if (inputStream != NULL)
inputStream->close ();
else
myclose (inp[0]);
}
catch (java::lang::Throwable *ignore)
{
}
char c;
int r = read (msgp[0], &c, 1);
if (r == -1)
fail (errno, args, env, inp, outp, errp, msgp);
else if (r != 0)
fail (c, args, env, inp, outp, errp, msgp);
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);
fcntl (outp[1], F_SETFD, FD_CLOEXEC);
fcntl (inp[0], F_SETFD, FD_CLOEXEC);
fcntl (errp[0], F_SETFD, FD_CLOEXEC);
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);
}
}