1 /* |
|
2 * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 #undef _LARGEFILE64_SOURCE |
|
27 #define _LARGEFILE64_SOURCE 1 |
|
28 |
|
29 #include "jni.h" |
|
30 #include "jvm.h" |
|
31 #include "jvm_md.h" |
|
32 #include "jni_util.h" |
|
33 #include "io_util.h" |
|
34 |
|
35 /* |
|
36 * Platform-specific support for java.lang.Process |
|
37 */ |
|
38 #include <assert.h> |
|
39 #include <stddef.h> |
|
40 #include <stdlib.h> |
|
41 #include <sys/types.h> |
|
42 #include <ctype.h> |
|
43 #include <sys/wait.h> |
|
44 #include <signal.h> |
|
45 #include <string.h> |
|
46 |
|
47 #if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX) |
|
48 #include <spawn.h> |
|
49 #endif |
|
50 |
|
51 #include "childproc.h" |
|
52 |
|
53 /* |
|
54 * There are 4 possible strategies we might use to "fork": |
|
55 * |
|
56 * - fork(2). Very portable and reliable but subject to |
|
57 * failure due to overcommit (see the documentation on |
|
58 * /proc/sys/vm/overcommit_memory in Linux proc(5)). |
|
59 * This is the ancient problem of spurious failure whenever a large |
|
60 * process starts a small subprocess. |
|
61 * |
|
62 * - vfork(). Using this is scary because all relevant man pages |
|
63 * contain dire warnings, e.g. Linux vfork(2). But at least it's |
|
64 * documented in the glibc docs and is standardized by XPG4. |
|
65 * http://www.opengroup.org/onlinepubs/000095399/functions/vfork.html |
|
66 * On Linux, one might think that vfork() would be implemented using |
|
67 * the clone system call with flag CLONE_VFORK, but in fact vfork is |
|
68 * a separate system call (which is a good sign, suggesting that |
|
69 * vfork will continue to be supported at least on Linux). |
|
70 * Another good sign is that glibc implements posix_spawn using |
|
71 * vfork whenever possible. Note that we cannot use posix_spawn |
|
72 * ourselves because there's no reliable way to close all inherited |
|
73 * file descriptors. |
|
74 * |
|
75 * - clone() with flags CLONE_VM but not CLONE_THREAD. clone() is |
|
76 * Linux-specific, but this ought to work - at least the glibc |
|
77 * sources contain code to handle different combinations of CLONE_VM |
|
78 * and CLONE_THREAD. However, when this was implemented, it |
|
79 * appeared to fail on 32-bit i386 (but not 64-bit x86_64) Linux with |
|
80 * the simple program |
|
81 * Runtime.getRuntime().exec("/bin/true").waitFor(); |
|
82 * with: |
|
83 * # Internal Error (os_linux_x86.cpp:683), pid=19940, tid=2934639536 |
|
84 * # Error: pthread_getattr_np failed with errno = 3 (ESRCH) |
|
85 * We believe this is a glibc bug, reported here: |
|
86 * http://sources.redhat.com/bugzilla/show_bug.cgi?id=10311 |
|
87 * but the glibc maintainers closed it as WONTFIX. |
|
88 * |
|
89 * - posix_spawn(). While posix_spawn() is a fairly elaborate and |
|
90 * complicated system call, it can't quite do everything that the old |
|
91 * fork()/exec() combination can do, so the only feasible way to do |
|
92 * this, is to use posix_spawn to launch a new helper executable |
|
93 * "jprochelper", which in turn execs the target (after cleaning |
|
94 * up file-descriptors etc.) The end result is the same as before, |
|
95 * a child process linked to the parent in the same way, but it |
|
96 * avoids the problem of duplicating the parent (VM) process |
|
97 * address space temporarily, before launching the target command. |
|
98 * |
|
99 * Based on the above analysis, we are currently using vfork() on |
|
100 * Linux and spawn() on other Unix systems, but the code to use clone() |
|
101 * and fork() remains. |
|
102 */ |
|
103 |
|
104 |
|
105 static void |
|
106 setSIGCHLDHandler(JNIEnv *env) |
|
107 { |
|
108 /* There is a subtle difference between having the signal handler |
|
109 * for SIGCHLD be SIG_DFL and SIG_IGN. We cannot obtain process |
|
110 * termination information for child processes if the signal |
|
111 * handler is SIG_IGN. It must be SIG_DFL. |
|
112 * |
|
113 * We used to set the SIGCHLD handler only on Linux, but it's |
|
114 * safest to set it unconditionally. |
|
115 * |
|
116 * Consider what happens if java's parent process sets the SIGCHLD |
|
117 * handler to SIG_IGN. Normally signal handlers are inherited by |
|
118 * children, but SIGCHLD is a controversial case. Solaris appears |
|
119 * to always reset it to SIG_DFL, but this behavior may be |
|
120 * non-standard-compliant, and we shouldn't rely on it. |
|
121 * |
|
122 * References: |
|
123 * http://www.opengroup.org/onlinepubs/7908799/xsh/exec.html |
|
124 * http://www.pasc.org/interps/unofficial/db/p1003.1/pasc-1003.1-132.html |
|
125 */ |
|
126 struct sigaction sa; |
|
127 sa.sa_handler = SIG_DFL; |
|
128 sigemptyset(&sa.sa_mask); |
|
129 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; |
|
130 if (sigaction(SIGCHLD, &sa, NULL) < 0) |
|
131 JNU_ThrowInternalError(env, "Can't set SIGCHLD handler"); |
|
132 } |
|
133 |
|
134 static void* |
|
135 xmalloc(JNIEnv *env, size_t size) |
|
136 { |
|
137 void *p = malloc(size); |
|
138 if (p == NULL) |
|
139 JNU_ThrowOutOfMemoryError(env, NULL); |
|
140 return p; |
|
141 } |
|
142 |
|
143 #define NEW(type, n) ((type *) xmalloc(env, (n) * sizeof(type))) |
|
144 |
|
145 /** |
|
146 * If PATH is not defined, the OS provides some default value. |
|
147 * Unfortunately, there's no portable way to get this value. |
|
148 * Fortunately, it's only needed if the child has PATH while we do not. |
|
149 */ |
|
150 static const char* |
|
151 defaultPath(void) |
|
152 { |
|
153 #ifdef __solaris__ |
|
154 /* These really are the Solaris defaults! */ |
|
155 return (geteuid() == 0 || getuid() == 0) ? |
|
156 "/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin:/usr/sbin" : |
|
157 "/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin:"; |
|
158 #else |
|
159 return ":/bin:/usr/bin"; /* glibc */ |
|
160 #endif |
|
161 } |
|
162 |
|
163 static const char* |
|
164 effectivePath(void) |
|
165 { |
|
166 const char *s = getenv("PATH"); |
|
167 return (s != NULL) ? s : defaultPath(); |
|
168 } |
|
169 |
|
170 static int |
|
171 countOccurrences(const char *s, char c) |
|
172 { |
|
173 int count; |
|
174 for (count = 0; *s != '\0'; s++) |
|
175 count += (*s == c); |
|
176 return count; |
|
177 } |
|
178 |
|
179 static const char * const * |
|
180 effectivePathv(JNIEnv *env) |
|
181 { |
|
182 char *p; |
|
183 int i; |
|
184 const char *path = effectivePath(); |
|
185 int count = countOccurrences(path, ':') + 1; |
|
186 size_t pathvsize = sizeof(const char *) * (count+1); |
|
187 size_t pathsize = strlen(path) + 1; |
|
188 const char **pathv = (const char **) xmalloc(env, pathvsize + pathsize); |
|
189 |
|
190 if (pathv == NULL) |
|
191 return NULL; |
|
192 p = (char *) pathv + pathvsize; |
|
193 memcpy(p, path, pathsize); |
|
194 /* split PATH by replacing ':' with NULs; empty components => "." */ |
|
195 for (i = 0; i < count; i++) { |
|
196 char *q = p + strcspn(p, ":"); |
|
197 pathv[i] = (p == q) ? "." : p; |
|
198 *q = '\0'; |
|
199 p = q + 1; |
|
200 } |
|
201 pathv[count] = NULL; |
|
202 return pathv; |
|
203 } |
|
204 |
|
205 JNIEXPORT void JNICALL |
|
206 Java_java_lang_UNIXProcess_init(JNIEnv *env, jclass clazz) |
|
207 { |
|
208 parentPathv = effectivePathv(env); |
|
209 CHECK_NULL(parentPathv); |
|
210 setSIGCHLDHandler(env); |
|
211 } |
|
212 |
|
213 |
|
214 #ifndef WIFEXITED |
|
215 #define WIFEXITED(status) (((status)&0xFF) == 0) |
|
216 #endif |
|
217 |
|
218 #ifndef WEXITSTATUS |
|
219 #define WEXITSTATUS(status) (((status)>>8)&0xFF) |
|
220 #endif |
|
221 |
|
222 #ifndef WIFSIGNALED |
|
223 #define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0) |
|
224 #endif |
|
225 |
|
226 #ifndef WTERMSIG |
|
227 #define WTERMSIG(status) ((status)&0x7F) |
|
228 #endif |
|
229 |
|
230 /* Block until a child process exits and return its exit code. |
|
231 Note, can only be called once for any given pid. */ |
|
232 JNIEXPORT jint JNICALL |
|
233 Java_java_lang_UNIXProcess_waitForProcessExit(JNIEnv* env, |
|
234 jobject junk, |
|
235 jint pid) |
|
236 { |
|
237 /* We used to use waitid() on Solaris, waitpid() on Linux, but |
|
238 * waitpid() is more standard, so use it on all POSIX platforms. */ |
|
239 int status; |
|
240 /* Wait for the child process to exit. This returns immediately if |
|
241 the child has already exited. */ |
|
242 while (waitpid(pid, &status, 0) < 0) { |
|
243 switch (errno) { |
|
244 case ECHILD: return 0; |
|
245 case EINTR: break; |
|
246 default: return -1; |
|
247 } |
|
248 } |
|
249 |
|
250 if (WIFEXITED(status)) { |
|
251 /* |
|
252 * The child exited normally; get its exit code. |
|
253 */ |
|
254 return WEXITSTATUS(status); |
|
255 } else if (WIFSIGNALED(status)) { |
|
256 /* The child exited because of a signal. |
|
257 * The best value to return is 0x80 + signal number, |
|
258 * because that is what all Unix shells do, and because |
|
259 * it allows callers to distinguish between process exit and |
|
260 * process death by signal. |
|
261 * Unfortunately, the historical behavior on Solaris is to return |
|
262 * the signal number, and we preserve this for compatibility. */ |
|
263 #ifdef __solaris__ |
|
264 return WTERMSIG(status); |
|
265 #else |
|
266 return 0x80 + WTERMSIG(status); |
|
267 #endif |
|
268 } else { |
|
269 /* |
|
270 * Unknown exit code; pass it through. |
|
271 */ |
|
272 return status; |
|
273 } |
|
274 } |
|
275 |
|
276 static const char * |
|
277 getBytes(JNIEnv *env, jbyteArray arr) |
|
278 { |
|
279 return arr == NULL ? NULL : |
|
280 (const char*) (*env)->GetByteArrayElements(env, arr, NULL); |
|
281 } |
|
282 |
|
283 static void |
|
284 releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr) |
|
285 { |
|
286 if (parr != NULL) |
|
287 (*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT); |
|
288 } |
|
289 |
|
290 static void |
|
291 throwIOException(JNIEnv *env, int errnum, const char *defaultDetail) |
|
292 { |
|
293 static const char * const format = "error=%d, %s"; |
|
294 const char *detail = defaultDetail; |
|
295 char *errmsg; |
|
296 jstring s; |
|
297 |
|
298 if (errnum != 0) { |
|
299 const char *s = strerror(errnum); |
|
300 if (strcmp(s, "Unknown error") != 0) |
|
301 detail = s; |
|
302 } |
|
303 /* ASCII Decimal representation uses 2.4 times as many bits as binary. */ |
|
304 errmsg = NEW(char, strlen(format) + strlen(detail) + 3 * sizeof(errnum)); |
|
305 if (errmsg == NULL) |
|
306 return; |
|
307 |
|
308 sprintf(errmsg, format, errnum, detail); |
|
309 s = JNU_NewStringPlatform(env, errmsg); |
|
310 if (s != NULL) { |
|
311 jobject x = JNU_NewObjectByName(env, "java/io/IOException", |
|
312 "(Ljava/lang/String;)V", s); |
|
313 if (x != NULL) |
|
314 (*env)->Throw(env, x); |
|
315 } |
|
316 free(errmsg); |
|
317 } |
|
318 |
|
319 #ifdef DEBUG_PROCESS |
|
320 /* Debugging process code is difficult; where to write debug output? */ |
|
321 static void |
|
322 debugPrint(char *format, ...) |
|
323 { |
|
324 FILE *tty = fopen("/dev/tty", "w"); |
|
325 va_list ap; |
|
326 va_start(ap, format); |
|
327 vfprintf(tty, format, ap); |
|
328 va_end(ap); |
|
329 fclose(tty); |
|
330 } |
|
331 #endif /* DEBUG_PROCESS */ |
|
332 |
|
333 static void |
|
334 copyPipe(int from[2], int to[2]) |
|
335 { |
|
336 to[0] = from[0]; |
|
337 to[1] = from[1]; |
|
338 } |
|
339 |
|
340 /* arg is an array of pointers to 0 terminated strings. array is terminated |
|
341 * by a null element. |
|
342 * |
|
343 * *nelems and *nbytes receive the number of elements of array (incl 0) |
|
344 * and total number of bytes (incl. 0) |
|
345 * Note. An empty array will have one null element |
|
346 * But if arg is null, then *nelems set to 0, and *nbytes to 0 |
|
347 */ |
|
348 static void arraysize(const char * const *arg, int *nelems, int *nbytes) |
|
349 { |
|
350 int i, bytes, count; |
|
351 const char * const *a = arg; |
|
352 char *p; |
|
353 int *q; |
|
354 if (arg == 0) { |
|
355 *nelems = 0; |
|
356 *nbytes = 0; |
|
357 return; |
|
358 } |
|
359 /* count the array elements and number of bytes */ |
|
360 for (count=0, bytes=0; *a != 0; count++, a++) { |
|
361 bytes += strlen(*a)+1; |
|
362 } |
|
363 *nbytes = bytes; |
|
364 *nelems = count+1; |
|
365 } |
|
366 |
|
367 /* copy the strings from arg[] into buf, starting at given offset |
|
368 * return new offset to next free byte |
|
369 */ |
|
370 static int copystrings(char *buf, int offset, const char * const *arg) { |
|
371 char *p; |
|
372 const char * const *a; |
|
373 int count=0; |
|
374 |
|
375 if (arg == 0) { |
|
376 return offset; |
|
377 } |
|
378 for (p=buf+offset, a=arg; *a != 0; a++) { |
|
379 int len = strlen(*a) +1; |
|
380 memcpy(p, *a, len); |
|
381 p += len; |
|
382 count += len; |
|
383 } |
|
384 return offset+count; |
|
385 } |
|
386 |
|
387 /** |
|
388 * We are unusually paranoid; use of clone/vfork is |
|
389 * especially likely to tickle gcc/glibc bugs. |
|
390 */ |
|
391 #ifdef __attribute_noinline__ /* See: sys/cdefs.h */ |
|
392 __attribute_noinline__ |
|
393 #endif |
|
394 |
|
395 #define START_CHILD_USE_CLONE 0 /* clone() currently disabled; see above. */ |
|
396 |
|
397 #ifdef START_CHILD_USE_CLONE |
|
398 static pid_t |
|
399 cloneChild(ChildStuff *c) { |
|
400 #ifdef __linux__ |
|
401 #define START_CHILD_CLONE_STACK_SIZE (64 * 1024) |
|
402 /* |
|
403 * See clone(2). |
|
404 * Instead of worrying about which direction the stack grows, just |
|
405 * allocate twice as much and start the stack in the middle. |
|
406 */ |
|
407 if ((c->clone_stack = malloc(2 * START_CHILD_CLONE_STACK_SIZE)) == NULL) |
|
408 /* errno will be set to ENOMEM */ |
|
409 return -1; |
|
410 return clone(childProcess, |
|
411 c->clone_stack + START_CHILD_CLONE_STACK_SIZE, |
|
412 CLONE_VFORK | CLONE_VM | SIGCHLD, c); |
|
413 #else |
|
414 /* not available on Solaris / Mac */ |
|
415 assert(0); |
|
416 return -1; |
|
417 #endif |
|
418 } |
|
419 #endif |
|
420 |
|
421 static pid_t |
|
422 vforkChild(ChildStuff *c) { |
|
423 volatile pid_t resultPid; |
|
424 |
|
425 /* |
|
426 * We separate the call to vfork into a separate function to make |
|
427 * very sure to keep stack of child from corrupting stack of parent, |
|
428 * as suggested by the scary gcc warning: |
|
429 * warning: variable 'foo' might be clobbered by 'longjmp' or 'vfork' |
|
430 */ |
|
431 resultPid = vfork(); |
|
432 |
|
433 if (resultPid == 0) { |
|
434 childProcess(c); |
|
435 } |
|
436 assert(resultPid != 0); /* childProcess never returns */ |
|
437 return resultPid; |
|
438 } |
|
439 |
|
440 static pid_t |
|
441 forkChild(ChildStuff *c) { |
|
442 pid_t resultPid; |
|
443 |
|
444 /* |
|
445 * From Solaris fork(2): In Solaris 10, a call to fork() is |
|
446 * identical to a call to fork1(); only the calling thread is |
|
447 * replicated in the child process. This is the POSIX-specified |
|
448 * behavior for fork(). |
|
449 */ |
|
450 resultPid = fork(); |
|
451 |
|
452 if (resultPid == 0) { |
|
453 childProcess(c); |
|
454 } |
|
455 assert(resultPid != 0); /* childProcess never returns */ |
|
456 return resultPid; |
|
457 } |
|
458 |
|
459 #if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX) |
|
460 static pid_t |
|
461 spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) { |
|
462 pid_t resultPid; |
|
463 jboolean isCopy; |
|
464 int i, offset, rval, bufsize, magic; |
|
465 char *buf, buf1[16]; |
|
466 char *hlpargs[2]; |
|
467 SpawnInfo sp; |
|
468 |
|
469 /* need to tell helper which fd is for receiving the childstuff |
|
470 * and which fd to send response back on |
|
471 */ |
|
472 snprintf(buf1, sizeof(buf1), "%d:%d", c->childenv[0], c->fail[1]); |
|
473 /* put the fd string as argument to the helper cmd */ |
|
474 hlpargs[0] = buf1; |
|
475 hlpargs[1] = 0; |
|
476 |
|
477 /* Following items are sent down the pipe to the helper |
|
478 * after it is spawned. |
|
479 * All strings are null terminated. All arrays of strings |
|
480 * have an empty string for termination. |
|
481 * - the ChildStuff struct |
|
482 * - the SpawnInfo struct |
|
483 * - the argv strings array |
|
484 * - the envv strings array |
|
485 * - the home directory string |
|
486 * - the parentPath string |
|
487 * - the parentPathv array |
|
488 */ |
|
489 /* First calculate the sizes */ |
|
490 arraysize(c->argv, &sp.nargv, &sp.argvBytes); |
|
491 bufsize = sp.argvBytes; |
|
492 arraysize(c->envv, &sp.nenvv, &sp.envvBytes); |
|
493 bufsize += sp.envvBytes; |
|
494 sp.dirlen = c->pdir == 0 ? 0 : strlen(c->pdir)+1; |
|
495 bufsize += sp.dirlen; |
|
496 arraysize(parentPathv, &sp.nparentPathv, &sp.parentPathvBytes); |
|
497 bufsize += sp.parentPathvBytes; |
|
498 /* We need to clear FD_CLOEXEC if set in the fds[]. |
|
499 * Files are created FD_CLOEXEC in Java. |
|
500 * Otherwise, they will be closed when the target gets exec'd */ |
|
501 for (i=0; i<3; i++) { |
|
502 if (c->fds[i] != -1) { |
|
503 int flags = fcntl(c->fds[i], F_GETFD); |
|
504 if (flags & FD_CLOEXEC) { |
|
505 fcntl(c->fds[i], F_SETFD, flags & (~1)); |
|
506 } |
|
507 } |
|
508 } |
|
509 |
|
510 rval = posix_spawn(&resultPid, helperpath, 0, 0, (char * const *) hlpargs, environ); |
|
511 |
|
512 if (rval != 0) { |
|
513 return -1; |
|
514 } |
|
515 |
|
516 /* now the lengths are known, copy the data */ |
|
517 buf = NEW(char, bufsize); |
|
518 if (buf == 0) { |
|
519 return -1; |
|
520 } |
|
521 offset = copystrings(buf, 0, &c->argv[0]); |
|
522 offset = copystrings(buf, offset, &c->envv[0]); |
|
523 memcpy(buf+offset, c->pdir, sp.dirlen); |
|
524 offset += sp.dirlen; |
|
525 offset = copystrings(buf, offset, parentPathv); |
|
526 assert(offset == bufsize); |
|
527 |
|
528 magic = magicNumber(); |
|
529 |
|
530 /* write the two structs and the data buffer */ |
|
531 write(c->childenv[1], (char *)&magic, sizeof(magic)); // magic number first |
|
532 write(c->childenv[1], (char *)c, sizeof(*c)); |
|
533 write(c->childenv[1], (char *)&sp, sizeof(sp)); |
|
534 write(c->childenv[1], buf, bufsize); |
|
535 free(buf); |
|
536 |
|
537 /* In this mode an external main() in invoked which calls back into |
|
538 * childProcess() in this file, rather than directly |
|
539 * via the statement below */ |
|
540 return resultPid; |
|
541 } |
|
542 #endif |
|
543 |
|
544 /* |
|
545 * Start a child process running function childProcess. |
|
546 * This function only returns in the parent. |
|
547 */ |
|
548 static pid_t |
|
549 startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) { |
|
550 switch (c->mode) { |
|
551 case MODE_VFORK: |
|
552 return vforkChild(c); |
|
553 case MODE_FORK: |
|
554 return forkChild(c); |
|
555 #if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX) |
|
556 case MODE_POSIX_SPAWN: |
|
557 return spawnChild(env, process, c, helperpath); |
|
558 #endif |
|
559 default: |
|
560 return -1; |
|
561 } |
|
562 } |
|
563 |
|
564 JNIEXPORT jint JNICALL |
|
565 Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env, |
|
566 jobject process, |
|
567 jint mode, |
|
568 jbyteArray helperpath, |
|
569 jbyteArray prog, |
|
570 jbyteArray argBlock, jint argc, |
|
571 jbyteArray envBlock, jint envc, |
|
572 jbyteArray dir, |
|
573 jintArray std_fds, |
|
574 jboolean redirectErrorStream) |
|
575 { |
|
576 int errnum; |
|
577 int resultPid = -1; |
|
578 int in[2], out[2], err[2], fail[2], childenv[2]; |
|
579 jint *fds = NULL; |
|
580 const char *phelperpath = NULL; |
|
581 const char *pprog = NULL; |
|
582 const char *pargBlock = NULL; |
|
583 const char *penvBlock = NULL; |
|
584 ChildStuff *c; |
|
585 |
|
586 in[0] = in[1] = out[0] = out[1] = err[0] = err[1] = fail[0] = fail[1] = -1; |
|
587 childenv[0] = childenv[1] = -1; |
|
588 |
|
589 if ((c = NEW(ChildStuff, 1)) == NULL) return -1; |
|
590 c->argv = NULL; |
|
591 c->envv = NULL; |
|
592 c->pdir = NULL; |
|
593 c->clone_stack = NULL; |
|
594 |
|
595 /* Convert prog + argBlock into a char ** argv. |
|
596 * Add one word room for expansion of argv for use by |
|
597 * execve_as_traditional_shell_script. |
|
598 * This word is also used when using spawn mode |
|
599 */ |
|
600 assert(prog != NULL && argBlock != NULL); |
|
601 if ((phelperpath = getBytes(env, helperpath)) == NULL) goto Catch; |
|
602 if ((pprog = getBytes(env, prog)) == NULL) goto Catch; |
|
603 if ((pargBlock = getBytes(env, argBlock)) == NULL) goto Catch; |
|
604 if ((c->argv = NEW(const char *, argc + 3)) == NULL) goto Catch; |
|
605 c->argv[0] = pprog; |
|
606 c->argc = argc + 2; |
|
607 initVectorFromBlock(c->argv+1, pargBlock, argc); |
|
608 |
|
609 if (envBlock != NULL) { |
|
610 /* Convert envBlock into a char ** envv */ |
|
611 if ((penvBlock = getBytes(env, envBlock)) == NULL) goto Catch; |
|
612 if ((c->envv = NEW(const char *, envc + 1)) == NULL) goto Catch; |
|
613 initVectorFromBlock(c->envv, penvBlock, envc); |
|
614 } |
|
615 |
|
616 if (dir != NULL) { |
|
617 if ((c->pdir = getBytes(env, dir)) == NULL) goto Catch; |
|
618 } |
|
619 |
|
620 assert(std_fds != NULL); |
|
621 fds = (*env)->GetIntArrayElements(env, std_fds, NULL); |
|
622 if (fds == NULL) goto Catch; |
|
623 |
|
624 if ((fds[0] == -1 && pipe(in) < 0) || |
|
625 (fds[1] == -1 && pipe(out) < 0) || |
|
626 (fds[2] == -1 && pipe(err) < 0) || |
|
627 (pipe(childenv) < 0) || |
|
628 (pipe(fail) < 0)) { |
|
629 throwIOException(env, errno, "Bad file descriptor"); |
|
630 goto Catch; |
|
631 } |
|
632 c->fds[0] = fds[0]; |
|
633 c->fds[1] = fds[1]; |
|
634 c->fds[2] = fds[2]; |
|
635 |
|
636 copyPipe(in, c->in); |
|
637 copyPipe(out, c->out); |
|
638 copyPipe(err, c->err); |
|
639 copyPipe(fail, c->fail); |
|
640 copyPipe(childenv, c->childenv); |
|
641 |
|
642 c->redirectErrorStream = redirectErrorStream; |
|
643 c->mode = mode; |
|
644 |
|
645 resultPid = startChild(env, process, c, phelperpath); |
|
646 assert(resultPid != 0); |
|
647 |
|
648 if (resultPid < 0) { |
|
649 switch (c->mode) { |
|
650 case MODE_VFORK: |
|
651 throwIOException(env, errno, "vfork failed"); |
|
652 break; |
|
653 case MODE_FORK: |
|
654 throwIOException(env, errno, "fork failed"); |
|
655 break; |
|
656 case MODE_POSIX_SPAWN: |
|
657 throwIOException(env, errno, "spawn failed"); |
|
658 break; |
|
659 } |
|
660 goto Catch; |
|
661 } |
|
662 close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec (childproc.c) */ |
|
663 |
|
664 switch (readFully(fail[0], &errnum, sizeof(errnum))) { |
|
665 case 0: break; /* Exec succeeded */ |
|
666 case sizeof(errnum): |
|
667 waitpid(resultPid, NULL, 0); |
|
668 throwIOException(env, errnum, "Exec failed"); |
|
669 goto Catch; |
|
670 default: |
|
671 throwIOException(env, errno, "Read failed"); |
|
672 goto Catch; |
|
673 } |
|
674 |
|
675 fds[0] = (in [1] != -1) ? in [1] : -1; |
|
676 fds[1] = (out[0] != -1) ? out[0] : -1; |
|
677 fds[2] = (err[0] != -1) ? err[0] : -1; |
|
678 |
|
679 Finally: |
|
680 free(c->clone_stack); |
|
681 |
|
682 /* Always clean up the child's side of the pipes */ |
|
683 closeSafely(in [0]); |
|
684 closeSafely(out[1]); |
|
685 closeSafely(err[1]); |
|
686 |
|
687 /* Always clean up fail and childEnv descriptors */ |
|
688 closeSafely(fail[0]); |
|
689 closeSafely(fail[1]); |
|
690 closeSafely(childenv[0]); |
|
691 closeSafely(childenv[1]); |
|
692 |
|
693 releaseBytes(env, helperpath, phelperpath); |
|
694 releaseBytes(env, prog, pprog); |
|
695 releaseBytes(env, argBlock, pargBlock); |
|
696 releaseBytes(env, envBlock, penvBlock); |
|
697 releaseBytes(env, dir, c->pdir); |
|
698 |
|
699 free(c->argv); |
|
700 free(c->envv); |
|
701 free(c); |
|
702 |
|
703 if (fds != NULL) |
|
704 (*env)->ReleaseIntArrayElements(env, std_fds, fds, 0); |
|
705 |
|
706 return resultPid; |
|
707 |
|
708 Catch: |
|
709 /* Clean up the parent's side of the pipes in case of failure only */ |
|
710 closeSafely(in [1]); in[1] = -1; |
|
711 closeSafely(out[0]); out[0] = -1; |
|
712 closeSafely(err[0]); err[0] = -1; |
|
713 goto Finally; |
|
714 } |
|
715 |
|
716 JNIEXPORT void JNICALL |
|
717 Java_java_lang_UNIXProcess_destroyProcess(JNIEnv *env, |
|
718 jobject junk, |
|
719 jint pid, |
|
720 jboolean force) |
|
721 { |
|
722 int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM; |
|
723 kill(pid, sig); |
|
724 } |
|