This commit was manufactured by cvs2svn to create branch
[official-gcc.git] / libjava / java / lang / natPosixProcess.cc
bloba6dfc1ada2883872cdd6c1859517126129a83005
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
9 details. */
11 #include <config.h>
13 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <signal.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stdio.h>
25 #include <gcj/cni.h>
26 #include <jvm.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;
42 void
43 java::lang::ConcreteProcess::destroy (void)
45 if (! hasExited)
47 // Really kill it.
48 kill ((pid_t) pid, SIGKILL);
52 jint
53 java::lang::ConcreteProcess::waitFor (void)
55 if (! hasExited)
57 int wstat;
58 int r = waitpid ((pid_t) pid, &wstat, 0);
60 if (r == -1)
62 if (java::lang::Thread::interrupted())
63 throw new InterruptedException (JvNewStringLatin1 (strerror
64 (errno)));
66 else
68 hasExited = true;
70 if (WIFEXITED (wstat))
71 status = WEXITSTATUS (wstat);
72 else
73 status = -1;
77 return status;
80 static char *
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);
86 buf[s] = '\0';
87 return buf;
90 static void
91 cleanup (char **args, char **env, char *path)
93 if (args != NULL)
95 for (int i = 0; args[i] != NULL; ++i)
96 _Jv_Free (args[i]);
97 _Jv_Free (args);
99 if (env != NULL)
101 for (int i = 0; env[i] != NULL; ++i)
102 _Jv_Free (env[i]);
103 _Jv_Free (env);
105 if (path != NULL)
106 _Jv_Free (path);
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
111 // a second time.
112 static void
113 myclose (int &fd)
115 if (fd != -1)
116 close (fd);
117 fd = -1;
120 void
121 java::lang::ConcreteProcess::startProcess (jstringArray progarray,
122 jstringArray envp,
123 java::io::File *dir)
125 using namespace java::io;
127 hasExited = false;
129 // Initialize all locals here to make cleanup simpler.
130 char **args = NULL;
131 char **env = NULL;
132 char *path = NULL;
133 int inp[2], outp[2], errp[2], msgp[2];
134 inp[0] = -1;
135 inp[1] = -1;
136 outp[0] = -1;
137 outp[1] = -1;
138 errp[0] = -1;
139 errp[1] = -1;
140 msgp[0] = -1;
141 msgp[1] = -1;
142 java::lang::Throwable *exc = NULL;
143 errorStream = NULL;
144 inputStream = NULL;
145 outputStream = NULL;
149 // Transform arrays to native form.
150 args = (char **) _Jv_Malloc ((progarray->length + 1)
151 * sizeof (char *));
153 // Initialize so we can gracefully recover.
154 jstring *elts = elements (progarray);
155 for (int i = 0; i <= progarray->length; ++i)
156 args[i] = NULL;
158 for (int i = 0; i < progarray->length; ++i)
159 args[i] = new_string (elts[i]);
160 args[progarray->length] = NULL;
162 if (envp)
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)
169 env[i] = NULL;
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
177 // the fork.
178 if (dir != NULL)
179 path = new_string (dir->getPath ());
181 // Create pipes for I/O. MSGP is for communicating exec()
182 // status.
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)));
199 if (pid == 0)
201 // Child process, so remap descriptors, chdir and exec.
203 if (envp)
205 // Preserve PATH and LD_LIBRARY_PATH unless specified
206 // explicitly.
207 char *path_val = getenv ("PATH");
208 char *ld_path_val = getenv ("LD_LIBRARY_PATH");
209 environ = env;
210 if (path_val && getenv ("PATH") == NULL)
212 char *path_env = (char *) _Jv_Malloc (strlen (path_val)
213 + 5 + 1);
214 strcpy (path_env, "PATH=");
215 strcat (path_env, path_val);
216 putenv (path_env);
218 if (ld_path_val && getenv ("LD_LIBRARY_PATH") == NULL)
220 char *ld_path_env
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.
229 dup2 (outp[0], 0);
230 dup2 (inp[1], 1);
231 dup2 (errp[1], 2);
233 // Use close and not myclose -- we're in the child, and we
234 // aren't worried about the possible race condition.
235 close (inp[0]);
236 close (inp[1]);
237 close (errp[0]);
238 close (errp[1]);
239 close (outp[0]);
240 close (outp[1]);
241 close (msgp[0]);
243 // Change directory.
244 if (path != NULL)
246 if (chdir (path) != 0)
248 char c = errno;
249 write (msgp[1], &c, 1);
250 _exit (127);
254 execvp (args[0], args);
256 // Send the parent notification that the exec failed.
257 char c = errno;
258 write (msgp[1], &c, 1);
259 _exit (127);
262 // Parent. Close extra file descriptors and mark ours as
263 // close-on-exec.
264 myclose (outp[0]);
265 myclose (inp[1]);
266 myclose (errp[1]);
267 myclose (msgp[1]);
269 char c;
270 int r = read (msgp[0], &c, 1);
271 if (r == -1)
272 throw new IOException (JvNewStringLatin1 (strerror (errno)));
273 else if (r != 0)
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 ();
288 else
289 myclose (inp[0]);
291 catch (java::lang::Throwable *ignore)
297 if (outputStream != NULL)
298 outputStream->close ();
299 else
300 myclose (outp[1]);
302 catch (java::lang::Throwable *ignore)
308 if (errorStream != NULL)
309 errorStream->close ();
310 else
311 myclose (errp[0]);
313 catch (java::lang::Throwable *ignore)
317 // These are potentially duplicate, but it doesn't matter due to
318 // the use of myclose.
319 myclose (outp[0]);
320 myclose (inp[1]);
321 myclose (errp[1]);
322 myclose (msgp[1]);
324 exc = thrown;
327 myclose (msgp[0]);
328 cleanup (args, env, path);
330 if (exc != NULL)
331 throw exc;
332 else
334 fcntl (outp[1], F_SETFD, FD_CLOEXEC);
335 fcntl (inp[0], F_SETFD, FD_CLOEXEC);
336 fcntl (errp[0], F_SETFD, FD_CLOEXEC);