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