ProcessImpl_md.c revision 15674:2acdea04aa37
1139825Simp/*
21541Srgrimes * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
31541Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
41541Srgrimes *
51541Srgrimes * This code is free software; you can redistribute it and/or modify it
61541Srgrimes * under the terms of the GNU General Public License version 2 only, as
71541Srgrimes * published by the Free Software Foundation.  Oracle designates this
81541Srgrimes * particular file as subject to the "Classpath" exception as provided
91541Srgrimes * by Oracle in the LICENSE file that accompanied this code.
101541Srgrimes *
111541Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT
121541Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131541Srgrimes * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
141541Srgrimes * version 2 for more details (a copy is included in the LICENSE file that
151541Srgrimes * accompanied this code).
161541Srgrimes *
171541Srgrimes * You should have received a copy of the GNU General Public License version
181541Srgrimes * 2 along with this work; if not, write to the Free Software Foundation,
191541Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
201541Srgrimes *
211541Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
221541Srgrimes * or visit www.oracle.com if you need additional information or have any
231541Srgrimes * questions.
241541Srgrimes */
251541Srgrimes
261541Srgrimes#undef  _LARGEFILE64_SOURCE
271541Srgrimes#define _LARGEFILE64_SOURCE 1
281541Srgrimes
2922521Sdyson#include "jni.h"
301541Srgrimes#include "jvm.h"
311541Srgrimes#include "jvm_md.h"
32116192Sobrien#include "jni_util.h"
33116192Sobrien#include "io_util.h"
34116192Sobrien
3513260Swollman/*
3674433Srwatson * Platform-specific support for java.lang.Process
37136969Sphk */
38183072Skib#include <assert.h>
3913260Swollman#include <stddef.h>
401541Srgrimes#include <stdlib.h>
411541Srgrimes#include <sys/types.h>
421541Srgrimes#include <ctype.h>
43164033Srwatson#include <sys/wait.h>
441541Srgrimes#include <signal.h>
451541Srgrimes#include <string.h>
461541Srgrimes
471541Srgrimes#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
4860041Sphk#include <spawn.h>
491541Srgrimes#endif
5029888Skato
5124131Sbde#include "childproc.h"
52243245Strasz
531541Srgrimes/*
5471576Sjasone * There are 4 possible strategies we might use to "fork":
55251171Sjeff *
561541Srgrimes * - fork(2).  Very portable and reliable but subject to
57163606Srwatson *   failure due to overcommit (see the documentation on
58163606Srwatson *   /proc/sys/vm/overcommit_memory in Linux proc(5)).
5959241Srwatson *   This is the ancient problem of spurious failure whenever a large
60163841Spjd *   process starts a small subprocess.
611541Srgrimes *
621541Srgrimes * - vfork().  Using this is scary because all relevant man pages
631541Srgrimes *   contain dire warnings, e.g. Linux vfork(2).  But at least it's
641541Srgrimes *   documented in the glibc docs and is standardized by XPG4.
651541Srgrimes *   http://www.opengroup.org/onlinepubs/000095399/functions/vfork.html
661541Srgrimes *   On Linux, one might think that vfork() would be implemented using
671541Srgrimes *   the clone system call with flag CLONE_VFORK, but in fact vfork is
681541Srgrimes *   a separate system call (which is a good sign, suggesting that
697695Sdg *   vfork will continue to be supported at least on Linux).
70108316Sphk *   Another good sign is that glibc implements posix_spawn using
717695Sdg *   vfork whenever possible.  Note that we cannot use posix_spawn
727695Sdg *   ourselves because there's no reliable way to close all inherited
73137035Sphk *   file descriptors.
74137035Sphk *
75137035Sphk * - clone() with flags CLONE_VM but not CLONE_THREAD.  clone() is
76183072Skib *   Linux-specific, but this ought to work - at least the glibc
77183072Skib *   sources contain code to handle different combinations of CLONE_VM
78141631Sphk *   and CLONE_THREAD.  However, when this was implemented, it
7930309Sphk *   appeared to fail on 32-bit i386 (but not 64-bit x86_64) Linux with
80108313Sphk *   the simple program
8198542Smckusick *     Runtime.getRuntime().exec("/bin/true").waitFor();
8298542Smckusick *   with:
83108313Sphk *     #  Internal Error (os_linux_x86.cpp:683), pid=19940, tid=2934639536
84233609Skib *     #  Error: pthread_getattr_np failed with errno = 3 (ESRCH)
85233609Skib *   We believe this is a glibc bug, reported here:
86101777Sphk *     http://sources.redhat.com/bugzilla/show_bug.cgi?id=10311
87101777Sphk *   but the glibc maintainers closed it as WONTFIX.
88101780Sphk *
89138509Sphk * - posix_spawn(). While posix_spawn() is a fairly elaborate and
90141631Sphk *   complicated system call, it can't quite do everything that the old
91138509Sphk *   fork()/exec() combination can do, so the only feasible way to do
92141631Sphk *   this, is to use posix_spawn to launch a new helper executable
93141631Sphk *   "jprochelper", which in turn execs the target (after cleaning
94141631Sphk *   up file-descriptors etc.) The end result is the same as before,
953425Sphk *   a child process linked to the parent in the same way, but it
9633181Seivind *   avoids the problem of duplicating the parent (VM) process
97116271Sphk *   address space temporarily, before launching the target command.
98116271Sphk *
99116271Sphk * Based on the above analysis, we are currently using vfork() on
100138509Sphk * Linux and posix_spawn() on other Unix systems.
101138509Sphk */
102116271Sphk
103116271Sphk
104116271Sphkstatic void
105116271SphksetSIGCHLDHandler(JNIEnv *env)
106116271Sphk{
107116271Sphk    /* There is a subtle difference between having the signal handler
108116271Sphk     * for SIGCHLD be SIG_DFL and SIG_IGN.  We cannot obtain process
109183073Skib     * termination information for child processes if the signal
1101541Srgrimes     * handler is SIG_IGN.  It must be SIG_DFL.
1111541Srgrimes     *
11238909Sbde     * We used to set the SIGCHLD handler only on Linux, but it's
113160205Spjd     * safest to set it unconditionally.
1142946Swollman     *
115136969Sphk     * Consider what happens if java's parent process sets the SIGCHLD
116141539Sphk     * handler to SIG_IGN.  Normally signal handlers are inherited by
117136969Sphk     * children, but SIGCHLD is a controversial case.  Solaris appears
118136969Sphk     * to always reset it to SIG_DFL, but this behavior may be
119136981Sphk     * non-standard-compliant, and we shouldn't rely on it.
120141539Sphk     *
121136981Sphk     * References:
122140056Sphk     * http://www.opengroup.org/onlinepubs/7908799/xsh/exec.html
123166193Skib     * http://www.pasc.org/interps/unofficial/db/p1003.1/pasc-1003.1-132.html
124166193Skib     */
125166193Skib    struct sigaction sa;
126166193Skib    sa.sa_handler = SIG_DFL;
127166193Skib    sigemptyset(&sa.sa_mask);
128136969Sphk    sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
129136969Sphk    if (sigaction(SIGCHLD, &sa, NULL) < 0)
130208293Savg        JNU_ThrowInternalError(env, "Can't set SIGCHLD handler");
131208293Savg}
132208293Savg
133208293Savgstatic void*
134208293Savgxmalloc(JNIEnv *env, size_t size)
135208293Savg{
136177645Sjhb    void *p = malloc(size);
137208293Savg    if (p == NULL)
138224061Smckusick        JNU_ThrowOutOfMemoryError(env, NULL);
139224061Smckusick    return p;
140138509Sphk}
141132902Sphk
142191990Sattilio#define NEW(type, n) ((type *) xmalloc(env, (n) * sizeof(type)))
1431541Srgrimes
144138509Sphk/**
145191990Sattilio * If PATH is not defined, the OS provides some default value.
146238697Skevlo * Unfortunately, there's no portable way to get this value.
14796506Sphk * Fortunately, it's only needed if the child has PATH while we do not.
148224061Smckusick */
14962976Smckusickstatic const char*
150230249SmckusickdefaultPath(void)
151184413Strasz{
152132902Sphk#ifdef __solaris__
153138509Sphk    /* These really are the Solaris defaults! */
1548876Srgrimes    return (geteuid() == 0 || getuid() == 0) ?
155191990Sattilio        "/usr/xpg4/bin:/usr/bin:/opt/SUNWspro/bin:/usr/sbin" :
156138509Sphk        "/usr/xpg4/bin:/usr/bin:/opt/SUNWspro/bin:";
157138509Sphk#else
158108316Sphk    return ":/bin:/usr/bin";    /* glibc */
159108316Sphk#endif
160108316Sphk}
161108316Sphk
162108316Sphkstatic const char*
163108316SphkeffectivePath(void)
164108316Sphk{
165108316Sphk    const char *s = getenv("PATH");
166108316Sphk    return (s != NULL) ? s : defaultPath();
167108316Sphk}
168108316Sphk
169136144Spjdstatic int
170208293SavgcountOccurrences(const char *s, char c)
171208293Savg{
172208293Savg    int count;
173138509Sphk    for (count = 0; *s != '\0'; s++)
174138509Sphk        count += (*s == c);
175138509Sphk    return count;
1761541Srgrimes}
177162647Stegge
178152567Srodrigcstatic const char * const *
179162647SteggeeffectivePathv(JNIEnv *env)
180152567Srodrigc{
181179270Srodrigc    char *p;
182162647Stegge    int i;
183179270Srodrigc    const char *path = effectivePath();
184179270Srodrigc    int count = countOccurrences(path, ':') + 1;
185179270Srodrigc    size_t pathvsize = sizeof(const char *) * (count+1);
186179270Srodrigc    size_t pathsize = strlen(path) + 1;
187179270Srodrigc    const char **pathv = (const char **) xmalloc(env, pathvsize + pathsize);
188181528Skib
189179270Srodrigc    if (pathv == NULL)
190152567Srodrigc        return NULL;
191224061Smckusick    p = (char *) pathv + pathvsize;
192224061Smckusick    memcpy(p, path, pathsize);
193224061Smckusick    /* split PATH by replacing ':' with NULs; empty components => "." */
194224061Smckusick    for (i = 0; i < count; i++) {
195224061Smckusick        char *q = p + strcspn(p, ":");
196224061Smckusick        pathv[i] = (p == q) ? "." : p;
197224061Smckusick        *q = '\0';
198224061Smckusick        p = q + 1;
199224061Smckusick    }
200224061Smckusick    pathv[count] = NULL;
201224061Smckusick    return pathv;
202230101Smckusick}
203230101Smckusick
204224061SmckusickJNIEXPORT void JNICALL
205224061SmckusickJava_java_lang_ProcessImpl_init(JNIEnv *env, jclass clazz)
206224061Smckusick{
207230101Smckusick    parentPathv = effectivePathv(env);
208230101Smckusick    CHECK_NULL(parentPathv);
209224061Smckusick    setSIGCHLDHandler(env);
210224061Smckusick}
211224061Smckusick
212224061Smckusick
213224061Smckusick#ifndef WIFEXITED
214224061Smckusick#define WIFEXITED(status) (((status)&0xFF) == 0)
215224061Smckusick#endif
216200796Strasz
217200796Strasz#ifndef WEXITSTATUS
218230101Smckusick#define WEXITSTATUS(status) (((status)>>8)&0xFF)
219230101Smckusick#endif
220230101Smckusick
221200796Strasz#ifndef WIFSIGNALED
222200796Strasz#define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0)
223200796Strasz#endif
224200796Strasz
225200796Strasz#ifndef WTERMSIG
226162647Stegge#define WTERMSIG(status) ((status)&0x7F)
227203761Strasz#endif
228162647Stegge
22910358Sjulianstatic const char *
2301541SrgrimesgetBytes(JNIEnv *env, jbyteArray arr)
2311541Srgrimes{
2321541Srgrimes    return arr == NULL ? NULL :
2331541Srgrimes        (const char*) (*env)->GetByteArrayElements(env, arr, NULL);
2341541Srgrimes}
2351541Srgrimes
23634913Speterstatic void
237224061SmckusickreleaseBytes(JNIEnv *env, jbyteArray arr, const char* parr)
238224061Smckusick{
239224061Smckusick    if (parr != NULL)
240224061Smckusick        (*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT);
241224061Smckusick}
242224061Smckusick
243224061Smckusick#define IOE_FORMAT "error=%d, %s"
244224061Smckusick
245224061Smckusickstatic void
246224061SmckusickthrowIOException(JNIEnv *env, int errnum, const char *defaultDetail)
247224061Smckusick{
248224061Smckusick    const char *detail = defaultDetail;
249224061Smckusick    char *errmsg;
250224061Smckusick    size_t fmtsize;
251138509Sphk    char tmpbuf[1024];
252138509Sphk    jstring s;
253183074Skib
254183074Skib    if (errnum != 0) {
255183074Skib        int ret = getErrorString(errnum, tmpbuf, sizeof(tmpbuf));
25662976Smckusick        if (ret != EINVAL)
25762976Smckusick            detail = tmpbuf;
258269171Skib    }
259269171Skib    /* ASCII Decimal representation uses 2.4 times as many bits as binary. */
260269171Skib    fmtsize = sizeof(IOE_FORMAT) + strlen(detail) + 3 * sizeof(errnum);
26189384Smckusick    errmsg = NEW(char, fmtsize);
26289384Smckusick    if (errmsg == NULL)
26389384Smckusick        return;
26489384Smckusick
2651541Srgrimes    snprintf(errmsg, fmtsize, IOE_FORMAT, errnum, detail);
2661541Srgrimes    s = JNU_NewStringPlatform(env, errmsg);
2671541Srgrimes    if (s != NULL) {
268224503Smckusick        jobject x = JNU_NewObjectByName(env, "java/io/IOException",
26983366Sjulian                                        "(Ljava/lang/String;)V", s);
27034266Sjulian        if (x != NULL)
27183366Sjulian            (*env)->Throw(env, x);
27234266Sjulian    }
27362976Smckusick    free(errmsg);
274245286Skib}
27562976Smckusick
27662976Smckusick#ifdef DEBUG_PROCESS
27776357Smckusick/* Debugging process code is difficult; where to write debug output? */
27876357Smckusickstatic void
279230101SmckusickdebugPrint(char *format, ...)
280230101Smckusick{
28198542Smckusick    FILE *tty = fopen("/dev/tty", "w");
28276357Smckusick    va_list ap;
28376357Smckusick    va_start(ap, format);
28476357Smckusick    vfprintf(tty, format, ap);
28576357Smckusick    va_end(ap);
28675503Smckusick    fclose(tty);
28762976Smckusick}
288156451Stegge#endif /* DEBUG_PROCESS */
28962976Smckusick
29062976Smckusickstatic void
291245286SkibcopyPipe(int from[2], int to[2])
29262976Smckusick{
29362976Smckusick    to[0] = from[0];
294224503Smckusick    to[1] = from[1];
295223018Smckusick}
296137035Sphk
297137035Sphk/* arg is an array of pointers to 0 terminated strings. array is terminated
298223900Smckusick * by a null element.
299223900Smckusick *
300223900Smckusick * *nelems and *nbytes receive the number of elements of array (incl 0)
301223900Smckusick * and total number of bytes (incl. 0)
302137035Sphk * Note. An empty array will have one null element
303137035Sphk * But if arg is null, then *nelems set to 0, and *nbytes to 0
304138509Sphk */
305162647Steggestatic void arraysize(const char * const *arg, int *nelems, int *nbytes)
306138509Sphk{
307162647Stegge    int i, bytes, count;
308183074Skib    const char * const *a = arg;
309183074Skib    char *p;
310183074Skib    int *q;
311183074Skib    if (arg == 0) {
312245286Skib        *nelems = 0;
3131541Srgrimes        *nbytes = 0;
31462976Smckusick        return;
315243245Strasz    }
31662976Smckusick    /* count the array elements and number of bytes */
317138509Sphk    for (count=0, bytes=0; *a != 0; count++, a++) {
318138509Sphk        bytes += strlen(*a)+1;
31933820Sbde    }
320224061Smckusick    *nbytes = bytes;
321224061Smckusick    *nelems = count+1;
322224061Smckusick}
323230101Smckusick
324230101Smckusick/* copy the strings from arg[] into buf, starting at given offset
325224061Smckusick * return new offset to next free byte
326224061Smckusick */
327224061Smckusickstatic int copystrings(char *buf, int offset, const char * const *arg) {
32833820Sbde    char *p;
32933820Sbde    const char * const *a;
33033820Sbde    int count=0;
331175202Sattilio
332164033Srwatson    if (arg == 0) {
333164033Srwatson        return offset;
334164033Srwatson    }
335164033Srwatson    for (p=buf+offset, a=arg; *a != 0; a++) {
336164033Srwatson        int len = strlen(*a) +1;
337175294Sattilio        memcpy(p, *a, len);
338164033Srwatson        p += len;
33933820Sbde        count += len;
340175294Sattilio    }
34155029Sbde    return offset+count;
34239669Sbde}
34355029Sbde
34474548Smckusick/**
345207141Sjeff * We are unusually paranoid; use of vfork is
346207141Sjeff * especially likely to tickle gcc/glibc bugs.
34775503Smckusick */
348230101Smckusick#ifdef __attribute_noinline__  /* See: sys/cdefs.h */
349230101Smckusick__attribute_noinline__
35039669Sbde#endif
351230101Smckusick
352230101Smckusick/* vfork(2) is deprecated on Solaris */
353230101Smckusick#ifndef __solaris__
354230101Smckusickstatic pid_t
355230101SmckusickvforkChild(ChildStuff *c) {
356230101Smckusick    volatile pid_t resultPid;
357230101Smckusick
35862976Smckusick    /*
35939669Sbde     * We separate the call to vfork into a separate function to make
36039669Sbde     * very sure to keep stack of child from corrupting stack of parent,
361137194Sphk     * as suggested by the scary gcc warning:
362137194Sphk     *  warning: variable 'foo' might be clobbered by 'longjmp' or 'vfork'
363137194Sphk     */
364223900Smckusick    resultPid = vfork();
365137194Sphk
366223900Smckusick    if (resultPid == 0) {
367137194Sphk        childProcess(c);
368137194Sphk    }
369137194Sphk    assert(resultPid != 0);  /* childProcess never returns */
370137194Sphk    return resultPid;
37162976Smckusick}
37262976Smckusick#endif
37362976Smckusick
374162647Steggestatic pid_t
375138509SphkforkChild(ChildStuff *c) {
376162647Stegge    pid_t resultPid;
377207141Sjeff
37834913Speter    /*
37962976Smckusick     * From Solaris fork(2): In Solaris 10, a call to fork() is
38091406Sjhb     * identical to a call to fork1(); only the calling thread is
38162976Smckusick     * replicated in the child process. This is the POSIX-specified
38262976Smckusick     * behavior for fork().
38334913Speter     */
384207141Sjeff    resultPid = fork();
385207141Sjeff
386207141Sjeff    if (resultPid == 0) {
387207141Sjeff        childProcess(c);
388207141Sjeff    }
38962976Smckusick    assert(resultPid != 0);  /* childProcess never returns */
39062976Smckusick    return resultPid;
39162976Smckusick}
3928530Sdg
39336147Sjulian#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
39436147Sjulianstatic pid_t
39536147SjulianspawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {
39636147Sjulian    pid_t resultPid;
397212788Sobrien    jboolean isCopy;
39836147Sjulian    int i, offset, rval, bufsize, magic;
39936147Sjulian    char *buf, buf1[16];
400224503Smckusick    char *hlpargs[2];
401162647Stegge    SpawnInfo sp;
402162647Stegge
40336147Sjulian    /* need to tell helper which fd is for receiving the childstuff
404162647Stegge     * and which fd to send response back on
405162647Stegge     */
40662976Smckusick    snprintf(buf1, sizeof(buf1), "%d:%d", c->childenv[0], c->fail[1]);
407140306Spjd    /* put the fd string as argument to the helper cmd */
408140306Spjd    hlpargs[0] = buf1;
409162647Stegge    hlpargs[1] = 0;
410162647Stegge
411162647Stegge    /* Following items are sent down the pipe to the helper
412140306Spjd     * after it is spawned.
413162647Stegge     * All strings are null terminated. All arrays of strings
414162647Stegge     * have an empty string for termination.
415152639Srodrigc     * - the ChildStuff struct
416200796Strasz     * - the SpawnInfo struct
417200796Strasz     * - the argv strings array
418200796Strasz     * - the envv strings array
419200796Strasz     * - the home directory string
420200796Strasz     * - the parentPath string
421200796Strasz     * - the parentPathv array
422224061Smckusick     */
423224061Smckusick    /* First calculate the sizes */
424224061Smckusick    arraysize(c->argv, &sp.nargv, &sp.argvBytes);
425224061Smckusick    bufsize = sp.argvBytes;
426224061Smckusick    arraysize(c->envv, &sp.nenvv, &sp.envvBytes);
427224061Smckusick    bufsize += sp.envvBytes;
428230101Smckusick    sp.dirlen = c->pdir == 0 ? 0 : strlen(c->pdir)+1;
429230101Smckusick    bufsize += sp.dirlen;
430224061Smckusick    arraysize(parentPathv, &sp.nparentPathv, &sp.parentPathvBytes);
431224061Smckusick    bufsize += sp.parentPathvBytes;
432224061Smckusick    /* We need to clear FD_CLOEXEC if set in the fds[].
433224503Smckusick     * Files are created FD_CLOEXEC in Java.
434224061Smckusick     * Otherwise, they will be closed when the target gets exec'd */
435224061Smckusick    for (i=0; i<3; i++) {
436224061Smckusick        if (c->fds[i] != -1) {
437224061Smckusick            int flags = fcntl(c->fds[i], F_GETFD);
438224061Smckusick            if (flags & FD_CLOEXEC) {
439224061Smckusick                fcntl(c->fds[i], F_SETFD, flags & (~1));
440224061Smckusick            }
441224061Smckusick        }
442224061Smckusick    }
443224061Smckusick
444230101Smckusick    rval = posix_spawn(&resultPid, helperpath, 0, 0, (char * const *) hlpargs, environ);
445230101Smckusick
446224061Smckusick    if (rval != 0) {
447224061Smckusick        return -1;
448224061Smckusick    }
449224061Smckusick
450224061Smckusick    /* now the lengths are known, copy the data */
451224061Smckusick    buf = NEW(char, bufsize);
452224061Smckusick    if (buf == 0) {
453224061Smckusick        return -1;
454224061Smckusick    }
455224061Smckusick    offset = copystrings(buf, 0, &c->argv[0]);
456224061Smckusick    offset = copystrings(buf, offset, &c->envv[0]);
457212788Sobrien    memcpy(buf+offset, c->pdir, sp.dirlen);
45862976Smckusick    offset += sp.dirlen;
45962976Smckusick    offset = copystrings(buf, offset, parentPathv);
46062976Smckusick    assert(offset == bufsize);
46162976Smckusick
462138509Sphk    magic = magicNumber();
4631541Srgrimes
46410358Sjulian    /* write the two structs and the data buffer */
4651541Srgrimes    write(c->childenv[1], (char *)&magic, sizeof(magic)); // magic number first
4661541Srgrimes    write(c->childenv[1], (char *)c, sizeof(*c));
467125796Sbde    write(c->childenv[1], (char *)&sp, sizeof(sp));
4681541Srgrimes    write(c->childenv[1], buf, bufsize);
469149713Sssouhlal    free(buf);
470132902Sphk
47162976Smckusick    /* In this mode an external main() in invoked which calls back into
472132902Sphk     * childProcess() in this file, rather than directly
473132902Sphk     * via the statement below */
47462976Smckusick    return resultPid;
475149713Sssouhlal}
47662976Smckusick#endif
47762976Smckusick
4781541Srgrimes/*
47933820Sbde * Start a child process running function childProcess.
48033820Sbde * This function only returns in the parent.
48133820Sbde */
48233820Sbdestatic pid_t
483184413StraszstartChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {
484164033Srwatson    switch (c->mode) {
485184413Strasz/* vfork(2) is deprecated on Solaris */
486184413Strasz#ifndef __solaris__
487164033Srwatson      case MODE_VFORK:
488164033Srwatson        return vforkChild(c);
489164033Srwatson#endif
490164033Srwatson      case MODE_FORK:
491164033Srwatson        return forkChild(c);
49233820Sbde#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
49333820Sbde      case MODE_POSIX_SPAWN:
49410358Sjulian        return spawnChild(env, process, c, helperpath);
49510358Sjulian#endif
49662976Smckusick      default:
49762976Smckusick        return -1;
49835319Sjulian    }
49935319Sjulian}
50010358Sjulian
50110358SjulianJNIEXPORT jint JNICALL
502137035SphkJava_java_lang_ProcessImpl_forkAndExec(JNIEnv *env,
50362976Smckusick                                       jobject process,
504149713Sssouhlal                                       jint mode,
50562976Smckusick                                       jbyteArray helperpath,
50662976Smckusick                                       jbyteArray prog,
50710358Sjulian                                       jbyteArray argBlock, jint argc,
50810358Sjulian                                       jbyteArray envBlock, jint envc,
50962976Smckusick                                       jbyteArray dir,
51062976Smckusick                                       jintArray std_fds,
51162976Smckusick                                       jboolean redirectErrorStream)
51262976Smckusick{
51362976Smckusick    int errnum;
51473286Sadrian    int resultPid = -1;
51510358Sjulian    int in[2], out[2], err[2], fail[2], childenv[2];
516108313Sphk    jint *fds = NULL;
51762976Smckusick    const char *phelperpath = NULL;
51862976Smckusick    const char *pprog = NULL;
51962976Smckusick    const char *pargBlock = NULL;
520224061Smckusick    const char *penvBlock = NULL;
521224503Smckusick    ChildStuff *c;
522224061Smckusick
523224061Smckusick    in[0] = in[1] = out[0] = out[1] = err[0] = err[1] = fail[0] = fail[1] = -1;
524224061Smckusick    childenv[0] = childenv[1] = -1;
525224061Smckusick
526224061Smckusick    if ((c = NEW(ChildStuff, 1)) == NULL) return -1;
527224061Smckusick    c->argv = NULL;
528224061Smckusick    c->envv = NULL;
529224061Smckusick    c->pdir = NULL;
530224061Smckusick
531224061Smckusick    /* Convert prog + argBlock into a char ** argv.
532224061Smckusick     * Add one word room for expansion of argv for use by
533224061Smckusick     * execve_as_traditional_shell_script.
534230101Smckusick     * This word is also used when using posix_spawn mode
535230101Smckusick     */
536224061Smckusick    assert(prog != NULL && argBlock != NULL);
537224061Smckusick    if ((phelperpath = getBytes(env, helperpath))   == NULL) goto Catch;
538224061Smckusick    if ((pprog       = getBytes(env, prog))         == NULL) goto Catch;
539224061Smckusick    if ((pargBlock   = getBytes(env, argBlock))     == NULL) goto Catch;
540224061Smckusick    if ((c->argv     = NEW(const char *, argc + 3)) == NULL) goto Catch;
541224061Smckusick    c->argv[0] = pprog;
542224061Smckusick    c->argc = argc + 2;
543224061Smckusick    initVectorFromBlock(c->argv+1, pargBlock, argc);
544224061Smckusick
5451541Srgrimes    if (envBlock != NULL) {
546138509Sphk        /* Convert envBlock into a char ** envv */
54762976Smckusick        if ((penvBlock = getBytes(env, envBlock))   == NULL) goto Catch;
5481541Srgrimes        if ((c->envv = NEW(const char *, envc + 1)) == NULL) goto Catch;
5491541Srgrimes        initVectorFromBlock(c->envv, penvBlock, envc);
5501541Srgrimes    }
551138509Sphk
552138509Sphk    if (dir != NULL) {
553138509Sphk        if ((c->pdir = getBytes(env, dir)) == NULL) goto Catch;
554138509Sphk    }
555230249Smckusick
556138509Sphk    assert(std_fds != NULL);
557138509Sphk    fds = (*env)->GetIntArrayElements(env, std_fds, NULL);
558213664Skib    if (fds == NULL) goto Catch;
559138509Sphk
560138509Sphk    if ((fds[0] == -1 && pipe(in)  < 0) ||
561138509Sphk        (fds[1] == -1 && pipe(out) < 0) ||
562138509Sphk        (fds[2] == -1 && pipe(err) < 0) ||
563138509Sphk        (pipe(childenv) < 0) ||
564138509Sphk        (pipe(fail) < 0)) {
565138509Sphk        throwIOException(env, errno, "Bad file descriptor");
566213664Skib        goto Catch;
567138509Sphk    }
568138509Sphk    c->fds[0] = fds[0];
569213664Skib    c->fds[1] = fds[1];
570138509Sphk    c->fds[2] = fds[2];
571138509Sphk
572138509Sphk    copyPipe(in,   c->in);
573138509Sphk    copyPipe(out,  c->out);
574138509Sphk    copyPipe(err,  c->err);
575138509Sphk    copyPipe(fail, c->fail);
5761541Srgrimes    copyPipe(childenv, c->childenv);
577243245Strasz
578243245Strasz    c->redirectErrorStream = redirectErrorStream;
5791541Srgrimes    c->mode = mode;
5801541Srgrimes
5811541Srgrimes    resultPid = startChild(env, process, c, phelperpath);
5821541Srgrimes    assert(resultPid != 0);
5831541Srgrimes
5841541Srgrimes    if (resultPid < 0) {
5851541Srgrimes        switch (c->mode) {
5861541Srgrimes          case MODE_VFORK:
5871541Srgrimes            throwIOException(env, errno, "vfork failed");
588243245Strasz            break;
589243245Strasz          case MODE_FORK:
5901541Srgrimes            throwIOException(env, errno, "fork failed");
591154152Stegge            break;
5921541Srgrimes          case MODE_POSIX_SPAWN:
59371073Siedowse            throwIOException(env, errno, "posix_spawn failed");
5941541Srgrimes            break;
59522521Sdyson        }
596140708Sjeff        goto Catch;
59798542Smckusick    }
5981541Srgrimes    close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec  (childproc.c)  */
59922521Sdyson
6001541Srgrimes    switch (readFully(fail[0], &errnum, sizeof(errnum))) {
601243245Strasz    case 0: break; /* Exec succeeded */
602243245Strasz    case sizeof(errnum):
603243245Strasz        waitpid(resultPid, NULL, 0);
604243245Strasz        throwIOException(env, errnum, "Exec failed");
605243245Strasz        goto Catch;
6061541Srgrimes    default:
607243245Strasz        throwIOException(env, errno, "Read failed");
608243245Strasz        goto Catch;
609243245Strasz    }
6101541Srgrimes
6111541Srgrimes    fds[0] = (in [1] != -1) ? in [1] : -1;
6121541Srgrimes    fds[1] = (out[0] != -1) ? out[0] : -1;
61310358Sjulian    fds[2] = (err[0] != -1) ? err[0] : -1;
614175202Sattilio
615183754Sattilio Finally:
6161541Srgrimes    /* Always clean up the child's side of the pipes */
617175294Sattilio    closeSafely(in [0]);
61832286Sdyson    closeSafely(out[1]);
61932286Sdyson    closeSafely(err[1]);
6201541Srgrimes
6211541Srgrimes    /* Always clean up fail and childEnv descriptors */
62298542Smckusick    closeSafely(fail[0]);
623107294Smckusick    closeSafely(fail[1]);
62498542Smckusick    closeSafely(childenv[0]);
6251541Srgrimes    closeSafely(childenv[1]);
62622521Sdyson
62798542Smckusick    releaseBytes(env, helperpath, phelperpath);
62898542Smckusick    releaseBytes(env, prog,       pprog);
62998542Smckusick    releaseBytes(env, argBlock,   pargBlock);
63098542Smckusick    releaseBytes(env, envBlock,   penvBlock);
63122521Sdyson    releaseBytes(env, dir,        c->pdir);
63222521Sdyson
6331541Srgrimes    free(c->argv);
63422521Sdyson    free(c->envv);
63522521Sdyson    free(c);
63622521Sdyson
63722521Sdyson    if (fds != NULL)
63822521Sdyson        (*env)->ReleaseIntArrayElements(env, std_fds, fds, 0);
63971073Siedowse
64022521Sdyson    return resultPid;
64175892Siedowse
64288026Siedowse Catch:
643243245Strasz    /* Clean up the parent's side of the pipes in case of failure only */
64498542Smckusick    closeSafely(in [1]); in[1] = -1;
64522521Sdyson    closeSafely(out[0]); out[0] = -1;
6461541Srgrimes    closeSafely(err[0]); err[0] = -1;
64722521Sdyson    goto Finally;
64898542Smckusick}
649140708Sjeff
65076357Smckusick