source: trunk/gcc/libjava/java/lang/natPosixProcess.cc

Last change on this file was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 7.8 KB
Line 
1// natPosixProcess.cc - Native side of POSIX process code.
2
3/* Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation
4
5 This file is part of libgcj.
6
7This software is copyrighted work licensed under the terms of the
8Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9details. */
10
11#include <config.h>
12
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>
24
25#include <gcj/cni.h>
26#include <jvm.h>
27
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>
39
40extern char **environ;
41
42void
43java::lang::ConcreteProcess::destroy (void)
44{
45 if (! hasExited)
46 {
47 // Really kill it.
48 kill ((pid_t) pid, SIGKILL);
49 }
50}
51
52jint
53java::lang::ConcreteProcess::waitFor (void)
54{
55 if (! hasExited)
56 {
57 int wstat;
58 int r = waitpid ((pid_t) pid, &wstat, 0);
59
60 if (r == -1)
61 {
62 if (java::lang::Thread::interrupted())
63 throw new InterruptedException (JvNewStringLatin1 (strerror
64 (errno)));
65 }
66 else
67 {
68 hasExited = true;
69
70 if (WIFEXITED (wstat))
71 status = WEXITSTATUS (wstat);
72 else
73 status = -1;
74 }
75 }
76
77 return status;
78}
79
80static char *
81new_string (jstring string)
82{
83 jsize s = _Jv_GetStringUTFLength (string);
84 char *buf = (char *) _Jv_Malloc (s + 1);
85 _Jv_GetStringUTFRegion (string, 0, s, buf);
86 buf[s] = '\0';
87 return buf;
88}
89
90static void
91cleanup (char **args, char **env, char *path)
92{
93 if (args != NULL)
94 {
95 for (int i = 0; args[i] != NULL; ++i)
96 _Jv_Free (args[i]);
97 _Jv_Free (args);
98 }
99 if (env != NULL)
100 {
101 for (int i = 0; env[i] != NULL; ++i)
102 _Jv_Free (env[i]);
103 _Jv_Free (env);
104 }
105 if (path != NULL)
106 _Jv_Free (path);
107}
108
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.
112static void
113myclose (int &fd)
114{
115 if (fd != -1)
116 close (fd);
117 fd = -1;
118}
119
120void
121java::lang::ConcreteProcess::startProcess (jstringArray progarray,
122 jstringArray envp,
123 java::io::File *dir)
124{
125 using namespace java::io;
126
127 hasExited = false;
128
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;
146
147 try
148 {
149 // Transform arrays to native form.
150 args = (char **) _Jv_Malloc ((progarray->length + 1)
151 * sizeof (char *));
152
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;
157
158 for (int i = 0; i < progarray->length; ++i)
159 args[i] = new_string (elts[i]);
160 args[progarray->length] = NULL;
161
162 if (envp)
163 {
164 env = (char **) _Jv_Malloc ((envp->length + 1) * sizeof (char *));
165 elts = elements (envp);
166
167 // Initialize so we can gracefully recover.
168 for (int i = 0; i <= envp->length; ++i)
169 env[i] = NULL;
170
171 for (int i = 0; i < envp->length; ++i)
172 env[i] = new_string (elts[i]);
173 env[envp->length] = NULL;
174 }
175
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 ());
180
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)));
186
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]));
193
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)));
198
199 if (pid == 0)
200 {
201 // Child process, so remap descriptors, chdir and exec.
202
203 if (envp)
204 {
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 (getenv ("PATH") == NULL)
211 {
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);
217 }
218 if (getenv ("LD_LIBRARY_PATH") == NULL)
219 {
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);
225 }
226 }
227
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);
232
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]);
242
243 // Change directory.
244 if (path != NULL)
245 {
246 if (chdir (path) != 0)
247 {
248 char c = errno;
249 write (msgp[1], &c, 1);
250 _exit (127);
251 }
252 }
253
254 execvp (args[0], args);
255
256 // Send the parent notification that the exec failed.
257 char c = errno;
258 write (msgp[1], &c, 1);
259 _exit (127);
260 }
261
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]);
268
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)));
275 }
276 catch (java::lang::Throwable *thrown)
277 {
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.
283
284 try
285 {
286 if (inputStream != NULL)
287 inputStream->close ();
288 else
289 myclose (inp[0]);
290 }
291 catch (java::lang::Throwable *ignore)
292 {
293 }
294
295 try
296 {
297 if (outputStream != NULL)
298 outputStream->close ();
299 else
300 myclose (outp[1]);
301 }
302 catch (java::lang::Throwable *ignore)
303 {
304 }
305
306 try
307 {
308 if (errorStream != NULL)
309 errorStream->close ();
310 else
311 myclose (errp[0]);
312 }
313 catch (java::lang::Throwable *ignore)
314 {
315 }
316
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]);
323
324 exc = thrown;
325 }
326
327 myclose (msgp[0]);
328 cleanup (args, env, path);
329
330 if (exc != NULL)
331 throw exc;
332 else
333 {
334 fcntl (outp[1], F_SETFD, FD_CLOEXEC);
335 fcntl (inp[0], F_SETFD, FD_CLOEXEC);
336 fcntl (errp[0], F_SETFD, FD_CLOEXEC);
337 }
338}
Note: See TracBrowser for help on using the repository browser.