1 // natPosixProcess.cc - Native side of POSIX process code.
3 /* Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004 Free Software Foundation
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
18 #include <sys/types.h>
28 #include <java/lang/ConcreteProcess.h>
29 #include <java/lang/IllegalThreadStateException.h>
30 #include <java/lang/InterruptedException.h>
31 #include <java/lang/NullPointerException.h>
32 #include <java/lang/Thread.h>
33 #include <java/io/File.h>
34 #include <java/io/FileDescriptor.h>
35 #include <java/io/FileInputStream.h>
36 #include <java/io/FileOutputStream.h>
37 #include <java/io/IOException.h>
38 #include <java/lang/OutOfMemoryError.h>
40 extern char **environ
;
43 java::lang::ConcreteProcess::destroy (void)
48 kill ((pid_t
) pid
, SIGKILL
);
53 java::lang::ConcreteProcess::waitFor (void)
58 int r
= waitpid ((pid_t
) pid
, &wstat
, 0);
62 if (java::lang::Thread::interrupted())
63 throw new InterruptedException (JvNewStringLatin1 (strerror
70 if (WIFEXITED (wstat
))
71 status
= WEXITSTATUS (wstat
);
81 new_string (jstring string
)
83 jsize s
= _Jv_GetStringUTFLength (string
);
84 char *buf
= (char *) _Jv_Malloc (s
+ 1);
85 _Jv_GetStringUTFRegion (string
, 0, string
->length(), buf
);
91 cleanup (char **args
, char **env
, char *path
)
95 for (int i
= 0; args
[i
] != NULL
; ++i
)
101 for (int i
= 0; env
[i
] != NULL
; ++i
)
109 // This makes our error handling a bit simpler and it lets us avoid
110 // thread bugs where we close a possibly-reopened file descriptor for
121 java::lang::ConcreteProcess::startProcess (jstringArray progarray
,
125 using namespace java::io
;
129 // Initialize all locals here to make cleanup simpler.
133 int inp
[2], outp
[2], errp
[2], msgp
[2];
142 java::lang::Throwable
*exc
= NULL
;
149 // Transform arrays to native form.
150 args
= (char **) _Jv_Malloc ((progarray
->length
+ 1)
153 // Initialize so we can gracefully recover.
154 jstring
*elts
= elements (progarray
);
155 for (int i
= 0; i
<= progarray
->length
; ++i
)
158 for (int i
= 0; i
< progarray
->length
; ++i
)
159 args
[i
] = new_string (elts
[i
]);
160 args
[progarray
->length
] = NULL
;
164 env
= (char **) _Jv_Malloc ((envp
->length
+ 1) * sizeof (char *));
165 elts
= elements (envp
);
167 // Initialize so we can gracefully recover.
168 for (int i
= 0; i
<= envp
->length
; ++i
)
171 for (int i
= 0; i
< envp
->length
; ++i
)
172 env
[i
] = new_string (elts
[i
]);
173 env
[envp
->length
] = NULL
;
176 // We allocate this here because we can't call malloc() after
179 path
= new_string (dir
->getPath ());
181 // Create pipes for I/O. MSGP is for communicating exec()
183 if (pipe (inp
) || pipe (outp
) || pipe (errp
) || pipe (msgp
)
184 || fcntl (msgp
[1], F_SETFD
, FD_CLOEXEC
))
185 throw new IOException (JvNewStringLatin1 (strerror (errno
)));
187 // We create the streams before forking. Otherwise if we had an
188 // error while creating the streams we would have run the child
189 // with no way to communicate with it.
190 errorStream
= new FileInputStream (new FileDescriptor (errp
[0]));
191 inputStream
= new FileInputStream (new FileDescriptor (inp
[0]));
192 outputStream
= new FileOutputStream (new FileDescriptor (outp
[1]));
194 // We don't use vfork() because that would cause the local
195 // environment to be set by the child.
196 if ((pid
= (jlong
) fork ()) == -1)
197 throw new IOException (JvNewStringLatin1 (strerror (errno
)));
201 // Child process, so remap descriptors, chdir and exec.
205 // Preserve PATH and LD_LIBRARY_PATH unless specified
207 char *path_val
= getenv ("PATH");
208 char *ld_path_val
= getenv ("LD_LIBRARY_PATH");
210 if (path_val
&& getenv ("PATH") == NULL
)
212 char *path_env
= (char *) _Jv_Malloc (strlen (path_val
)
214 strcpy (path_env
, "PATH=");
215 strcat (path_env
, path_val
);
218 if (ld_path_val
&& getenv ("LD_LIBRARY_PATH") == NULL
)
221 = (char *) _Jv_Malloc (strlen (ld_path_val
) + 16 + 1);
222 strcpy (ld_path_env
, "LD_LIBRARY_PATH=");
223 strcat (ld_path_env
, ld_path_val
);
224 putenv (ld_path_env
);
228 // We ignore errors from dup2 because they should never occur.
233 // Use close and not myclose -- we're in the child, and we
234 // aren't worried about the possible race condition.
246 if (chdir (path
) != 0)
249 write (msgp
[1], &c
, 1);
254 execvp (args
[0], args
);
256 // Send the parent notification that the exec failed.
258 write (msgp
[1], &c
, 1);
262 // Parent. Close extra file descriptors and mark ours as
270 int r
= read (msgp
[0], &c
, 1);
272 throw new IOException (JvNewStringLatin1 (strerror (errno
)));
274 throw new IOException (JvNewStringLatin1 (strerror (c
)));
276 catch (java::lang::Throwable
*thrown
)
278 // Do some cleanup we only do on failure. If a stream object
279 // has been created, we must close the stream itself (to avoid
280 // duplicate closes when the stream object is collected).
281 // Otherwise we simply close the underlying file descriptor.
282 // We ignore errors here as they are uninteresting.
286 if (inputStream
!= NULL
)
287 inputStream
->close ();
291 catch (java::lang::Throwable
*ignore
)
297 if (outputStream
!= NULL
)
298 outputStream
->close ();
302 catch (java::lang::Throwable
*ignore
)
308 if (errorStream
!= NULL
)
309 errorStream
->close ();
313 catch (java::lang::Throwable
*ignore
)
317 // These are potentially duplicate, but it doesn't matter due to
318 // the use of myclose.
328 cleanup (args
, env
, path
);
334 fcntl (outp
[1], F_SETFD
, FD_CLOEXEC
);
335 fcntl (inp
[0], F_SETFD
, FD_CLOEXEC
);
336 fcntl (errp
[0], F_SETFD
, FD_CLOEXEC
);