Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/native/java/lang/UNIXProcess_md.c
32287 views
/*1* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#undef _LARGEFILE64_SOURCE26#define _LARGEFILE64_SOURCE 12728#include "jni.h"29#include "jvm.h"30#include "jvm_md.h"31#include "jni_util.h"32#include "io_util.h"3334/*35* Platform-specific support for java.lang.Process36*/37#include <assert.h>38#include <stddef.h>39#include <stdlib.h>40#include <sys/types.h>41#include <ctype.h>42#include <sys/wait.h>43#include <signal.h>44#include <string.h>4546#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX)47#include <spawn.h>48#endif4950#include "childproc.h"5152/*53* There are 4 possible strategies we might use to "fork":54*55* - fork(2). Very portable and reliable but subject to56* failure due to overcommit (see the documentation on57* /proc/sys/vm/overcommit_memory in Linux proc(5)).58* This is the ancient problem of spurious failure whenever a large59* process starts a small subprocess.60*61* - vfork(). Using this is scary because all relevant man pages62* contain dire warnings, e.g. Linux vfork(2). But at least it's63* documented in the glibc docs and is standardized by XPG4.64* http://www.opengroup.org/onlinepubs/000095399/functions/vfork.html65* On Linux, one might think that vfork() would be implemented using66* the clone system call with flag CLONE_VFORK, but in fact vfork is67* a separate system call (which is a good sign, suggesting that68* vfork will continue to be supported at least on Linux).69* Another good sign is that glibc implements posix_spawn using70* vfork whenever possible. Note that we cannot use posix_spawn71* ourselves because there's no reliable way to close all inherited72* file descriptors.73*74* - clone() with flags CLONE_VM but not CLONE_THREAD. clone() is75* Linux-specific, but this ought to work - at least the glibc76* sources contain code to handle different combinations of CLONE_VM77* and CLONE_THREAD. However, when this was implemented, it78* appeared to fail on 32-bit i386 (but not 64-bit x86_64) Linux with79* the simple program80* Runtime.getRuntime().exec("/bin/true").waitFor();81* with:82* # Internal Error (os_linux_x86.cpp:683), pid=19940, tid=293463953683* # Error: pthread_getattr_np failed with errno = 3 (ESRCH)84* We believe this is a glibc bug, reported here:85* http://sources.redhat.com/bugzilla/show_bug.cgi?id=1031186* but the glibc maintainers closed it as WONTFIX.87*88* - posix_spawn(). While posix_spawn() is a fairly elaborate and89* complicated system call, it can't quite do everything that the old90* fork()/exec() combination can do, so the only feasible way to do91* this, is to use posix_spawn to launch a new helper executable92* "jprochelper", which in turn execs the target (after cleaning93* up file-descriptors etc.) The end result is the same as before,94* a child process linked to the parent in the same way, but it95* avoids the problem of duplicating the parent (VM) process96* address space temporarily, before launching the target command.97*98* Based on the above analysis, we are currently using vfork() on99* Linux and spawn() on other Unix systems, but the code to use clone()100* and fork() remains.101*/102103104static void105setSIGCHLDHandler(JNIEnv *env)106{107/* There is a subtle difference between having the signal handler108* for SIGCHLD be SIG_DFL and SIG_IGN. We cannot obtain process109* termination information for child processes if the signal110* handler is SIG_IGN. It must be SIG_DFL.111*112* We used to set the SIGCHLD handler only on Linux, but it's113* safest to set it unconditionally.114*115* Consider what happens if java's parent process sets the SIGCHLD116* handler to SIG_IGN. Normally signal handlers are inherited by117* children, but SIGCHLD is a controversial case. Solaris appears118* to always reset it to SIG_DFL, but this behavior may be119* non-standard-compliant, and we shouldn't rely on it.120*121* References:122* http://www.opengroup.org/onlinepubs/7908799/xsh/exec.html123* http://www.pasc.org/interps/unofficial/db/p1003.1/pasc-1003.1-132.html124*/125struct sigaction sa;126sa.sa_handler = SIG_DFL;127sigemptyset(&sa.sa_mask);128sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;129if (sigaction(SIGCHLD, &sa, NULL) < 0)130JNU_ThrowInternalError(env, "Can't set SIGCHLD handler");131}132133static void*134xmalloc(JNIEnv *env, size_t size)135{136void *p = malloc(size);137if (p == NULL)138JNU_ThrowOutOfMemoryError(env, NULL);139return p;140}141142#define NEW(type, n) ((type *) xmalloc(env, (n) * sizeof(type)))143144/**145* If PATH is not defined, the OS provides some default value.146* Unfortunately, there's no portable way to get this value.147* Fortunately, it's only needed if the child has PATH while we do not.148*/149static const char*150defaultPath(void)151{152#ifdef __solaris__153/* These really are the Solaris defaults! */154return (geteuid() == 0 || getuid() == 0) ?155"/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin:/usr/sbin" :156"/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin:";157#else158return ":/bin:/usr/bin"; /* glibc */159#endif160}161162static const char*163effectivePath(void)164{165const char *s = getenv("PATH");166return (s != NULL) ? s : defaultPath();167}168169static int170countOccurrences(const char *s, char c)171{172int count;173for (count = 0; *s != '\0'; s++)174count += (*s == c);175return count;176}177178static const char * const *179effectivePathv(JNIEnv *env)180{181char *p;182int i;183const char *path = effectivePath();184int count = countOccurrences(path, ':') + 1;185size_t pathvsize = sizeof(const char *) * (count+1);186size_t pathsize = strlen(path) + 1;187const char **pathv = (const char **) xmalloc(env, pathvsize + pathsize);188189if (pathv == NULL)190return NULL;191p = (char *) pathv + pathvsize;192memcpy(p, path, pathsize);193/* split PATH by replacing ':' with NULs; empty components => "." */194for (i = 0; i < count; i++) {195char *q = p + strcspn(p, ":");196pathv[i] = (p == q) ? "." : p;197*q = '\0';198p = q + 1;199}200pathv[count] = NULL;201return pathv;202}203204JNIEXPORT void JNICALL205Java_java_lang_UNIXProcess_init(JNIEnv *env, jclass clazz)206{207parentPathv = effectivePathv(env);208CHECK_NULL(parentPathv);209setSIGCHLDHandler(env);210}211212213#ifndef WIFEXITED214#define WIFEXITED(status) (((status)&0xFF) == 0)215#endif216217#ifndef WEXITSTATUS218#define WEXITSTATUS(status) (((status)>>8)&0xFF)219#endif220221#ifndef WIFSIGNALED222#define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0)223#endif224225#ifndef WTERMSIG226#define WTERMSIG(status) ((status)&0x7F)227#endif228229/* Block until a child process exits and return its exit code.230Note, can only be called once for any given pid. */231JNIEXPORT jint JNICALL232Java_java_lang_UNIXProcess_waitForProcessExit(JNIEnv* env,233jobject junk,234jint pid)235{236/* We used to use waitid() on Solaris, waitpid() on Linux, but237* waitpid() is more standard, so use it on all POSIX platforms. */238int status;239/* Wait for the child process to exit. This returns immediately if240the child has already exited. */241while (waitpid(pid, &status, 0) < 0) {242switch (errno) {243case ECHILD: return 0;244case EINTR: break;245default: return -1;246}247}248249if (WIFEXITED(status)) {250/*251* The child exited normally; get its exit code.252*/253return WEXITSTATUS(status);254} else if (WIFSIGNALED(status)) {255/* The child exited because of a signal.256* The best value to return is 0x80 + signal number,257* because that is what all Unix shells do, and because258* it allows callers to distinguish between process exit and259* process death by signal.260* Unfortunately, the historical behavior on Solaris is to return261* the signal number, and we preserve this for compatibility. */262#ifdef __solaris__263return WTERMSIG(status);264#else265return 0x80 + WTERMSIG(status);266#endif267} else {268/*269* Unknown exit code; pass it through.270*/271return status;272}273}274275static const char *276getBytes(JNIEnv *env, jbyteArray arr)277{278return arr == NULL ? NULL :279(const char*) (*env)->GetByteArrayElements(env, arr, NULL);280}281282static void283releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr)284{285if (parr != NULL)286(*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT);287}288289static void290throwIOException(JNIEnv *env, int errnum, const char *defaultDetail)291{292static const char * const format = "error=%d, %s";293const char *detail = defaultDetail;294char *errmsg;295char tmpbuf[1024];296jstring s;297298if (errnum != 0) {299int ret = getErrorString(errnum, tmpbuf, sizeof(tmpbuf));300if (ret != EINVAL)301detail = tmpbuf;302}303/* ASCII Decimal representation uses 2.4 times as many bits as binary. */304errmsg = NEW(char, strlen(format) + strlen(detail) + 3 * sizeof(errnum));305if (errmsg == NULL)306return;307308sprintf(errmsg, format, errnum, detail);309s = JNU_NewStringPlatform(env, errmsg);310if (s != NULL) {311jobject x = JNU_NewObjectByName(env, "java/io/IOException",312"(Ljava/lang/String;)V", s);313if (x != NULL)314(*env)->Throw(env, x);315}316free(errmsg);317}318319#ifdef DEBUG_PROCESS320/* Debugging process code is difficult; where to write debug output? */321static void322debugPrint(char *format, ...)323{324FILE *tty = fopen("/dev/tty", "w");325va_list ap;326va_start(ap, format);327vfprintf(tty, format, ap);328va_end(ap);329fclose(tty);330}331#endif /* DEBUG_PROCESS */332333static void334copyPipe(int from[2], int to[2])335{336to[0] = from[0];337to[1] = from[1];338}339340/* arg is an array of pointers to 0 terminated strings. array is terminated341* 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 element346* But if arg is null, then *nelems set to 0, and *nbytes to 0347*/348static void arraysize(const char * const *arg, int *nelems, int *nbytes)349{350int i, bytes, count;351const char * const *a = arg;352char *p;353int *q;354if (arg == 0) {355*nelems = 0;356*nbytes = 0;357return;358}359/* count the array elements and number of bytes */360for (count=0, bytes=0; *a != 0; count++, a++) {361bytes += strlen(*a)+1;362}363*nbytes = bytes;364*nelems = count+1;365}366367/* copy the strings from arg[] into buf, starting at given offset368* return new offset to next free byte369*/370static int copystrings(char *buf, int offset, const char * const *arg) {371char *p;372const char * const *a;373int count=0;374375if (arg == 0) {376return offset;377}378for (p=buf+offset, a=arg; *a != 0; a++) {379int len = strlen(*a) +1;380memcpy(p, *a, len);381p += len;382count += len;383}384return offset+count;385}386387/**388* We are unusually paranoid; use of clone/vfork is389* especially likely to tickle gcc/glibc bugs.390*/391#ifdef __attribute_noinline__ /* See: sys/cdefs.h */392__attribute_noinline__393#endif394395#define START_CHILD_USE_CLONE 0 /* clone() currently disabled; see above. */396397#ifdef START_CHILD_USE_CLONE398static pid_t399cloneChild(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, just405* allocate twice as much and start the stack in the middle.406*/407if ((c->clone_stack = malloc(2 * START_CHILD_CLONE_STACK_SIZE)) == NULL)408/* errno will be set to ENOMEM */409return -1;410return clone(childProcess,411c->clone_stack + START_CHILD_CLONE_STACK_SIZE,412CLONE_VFORK | CLONE_VM | SIGCHLD, c);413#else414/* not available on Solaris / Mac */415assert(0);416return -1;417#endif418}419#endif420421static pid_t422vforkChild(ChildStuff *c) {423volatile pid_t resultPid;424425/*426* We separate the call to vfork into a separate function to make427* 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*/431resultPid = vfork();432433if (resultPid == 0) {434childProcess(c);435}436assert(resultPid != 0); /* childProcess never returns */437return resultPid;438}439440static pid_t441forkChild(ChildStuff *c) {442pid_t resultPid;443444/*445* From Solaris fork(2): In Solaris 10, a call to fork() is446* identical to a call to fork1(); only the calling thread is447* replicated in the child process. This is the POSIX-specified448* behavior for fork().449*/450resultPid = fork();451452if (resultPid == 0) {453childProcess(c);454}455assert(resultPid != 0); /* childProcess never returns */456return resultPid;457}458459#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX)460static pid_t461spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {462pid_t resultPid;463jboolean isCopy;464int i, offset, rval, bufsize, magic;465char *buf, buf1[16];466char *hlpargs[2];467SpawnInfo sp;468469/* need to tell helper which fd is for receiving the childstuff470* and which fd to send response back on471*/472snprintf(buf1, sizeof(buf1), "%d:%d", c->childenv[0], c->fail[1]);473/* put the fd string as argument to the helper cmd */474hlpargs[0] = buf1;475hlpargs[1] = 0;476477/* Following items are sent down the pipe to the helper478* after it is spawned.479* All strings are null terminated. All arrays of strings480* have an empty string for termination.481* - the ChildStuff struct482* - the SpawnInfo struct483* - the argv strings array484* - the envv strings array485* - the home directory string486* - the parentPath string487* - the parentPathv array488*/489/* First calculate the sizes */490arraysize(c->argv, &sp.nargv, &sp.argvBytes);491bufsize = sp.argvBytes;492arraysize(c->envv, &sp.nenvv, &sp.envvBytes);493bufsize += sp.envvBytes;494sp.dirlen = c->pdir == 0 ? 0 : strlen(c->pdir)+1;495bufsize += sp.dirlen;496arraysize(parentPathv, &sp.nparentPathv, &sp.parentPathvBytes);497bufsize += 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 */501for (i=0; i<3; i++) {502if (c->fds[i] != -1) {503int flags = fcntl(c->fds[i], F_GETFD);504if (flags & FD_CLOEXEC) {505fcntl(c->fds[i], F_SETFD, flags & (~1));506}507}508}509510rval = posix_spawn(&resultPid, helperpath, 0, 0, (char * const *) hlpargs, environ);511512if (rval != 0) {513return -1;514}515516/* now the lengths are known, copy the data */517buf = NEW(char, bufsize);518if (buf == 0) {519return -1;520}521offset = copystrings(buf, 0, &c->argv[0]);522offset = copystrings(buf, offset, &c->envv[0]);523memcpy(buf+offset, c->pdir, sp.dirlen);524offset += sp.dirlen;525offset = copystrings(buf, offset, parentPathv);526assert(offset == bufsize);527528magic = magicNumber();529530/* write the two structs and the data buffer */531write(c->childenv[1], (char *)&magic, sizeof(magic)); // magic number first532write(c->childenv[1], (char *)c, sizeof(*c));533write(c->childenv[1], (char *)&sp, sizeof(sp));534write(c->childenv[1], buf, bufsize);535free(buf);536537/* In this mode an external main() in invoked which calls back into538* childProcess() in this file, rather than directly539* via the statement below */540return resultPid;541}542#endif543544/*545* Start a child process running function childProcess.546* This function only returns in the parent.547*/548static pid_t549startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {550switch (c->mode) {551case MODE_VFORK:552return vforkChild(c);553case MODE_FORK:554return forkChild(c);555#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX)556case MODE_POSIX_SPAWN:557return spawnChild(env, process, c, helperpath);558#endif559default:560return -1;561}562}563564JNIEXPORT jint JNICALL565Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,566jobject process,567jint mode,568jbyteArray helperpath,569jbyteArray prog,570jbyteArray argBlock, jint argc,571jbyteArray envBlock, jint envc,572jbyteArray dir,573jintArray std_fds,574jboolean redirectErrorStream)575{576int errnum;577int resultPid = -1;578int in[2], out[2], err[2], fail[2], childenv[2];579jint *fds = NULL;580const char *phelperpath = NULL;581const char *pprog = NULL;582const char *pargBlock = NULL;583const char *penvBlock = NULL;584ChildStuff *c;585586in[0] = in[1] = out[0] = out[1] = err[0] = err[1] = fail[0] = fail[1] = -1;587childenv[0] = childenv[1] = -1;588589if ((c = NEW(ChildStuff, 1)) == NULL) return -1;590c->argv = NULL;591c->envv = NULL;592c->pdir = NULL;593c->clone_stack = NULL;594595/* Convert prog + argBlock into a char ** argv.596* Add one word room for expansion of argv for use by597* execve_as_traditional_shell_script.598* This word is also used when using spawn mode599*/600assert(prog != NULL && argBlock != NULL);601if ((phelperpath = getBytes(env, helperpath)) == NULL) goto Catch;602if ((pprog = getBytes(env, prog)) == NULL) goto Catch;603if ((pargBlock = getBytes(env, argBlock)) == NULL) goto Catch;604if ((c->argv = NEW(const char *, argc + 3)) == NULL) goto Catch;605c->argv[0] = pprog;606c->argc = argc + 2;607initVectorFromBlock(c->argv+1, pargBlock, argc);608609if (envBlock != NULL) {610/* Convert envBlock into a char ** envv */611if ((penvBlock = getBytes(env, envBlock)) == NULL) goto Catch;612if ((c->envv = NEW(const char *, envc + 1)) == NULL) goto Catch;613initVectorFromBlock(c->envv, penvBlock, envc);614}615616if (dir != NULL) {617if ((c->pdir = getBytes(env, dir)) == NULL) goto Catch;618}619620assert(std_fds != NULL);621fds = (*env)->GetIntArrayElements(env, std_fds, NULL);622if (fds == NULL) goto Catch;623624if ((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)) {629throwIOException(env, errno, "Bad file descriptor");630goto Catch;631}632c->fds[0] = fds[0];633c->fds[1] = fds[1];634c->fds[2] = fds[2];635636copyPipe(in, c->in);637copyPipe(out, c->out);638copyPipe(err, c->err);639copyPipe(fail, c->fail);640copyPipe(childenv, c->childenv);641642c->redirectErrorStream = redirectErrorStream;643c->mode = mode;644645resultPid = startChild(env, process, c, phelperpath);646assert(resultPid != 0);647648if (resultPid < 0) {649switch (c->mode) {650case MODE_VFORK:651throwIOException(env, errno, "vfork failed");652break;653case MODE_FORK:654throwIOException(env, errno, "fork failed");655break;656case MODE_POSIX_SPAWN:657throwIOException(env, errno, "spawn failed");658break;659}660goto Catch;661}662close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec (childproc.c) */663664switch (readFully(fail[0], &errnum, sizeof(errnum))) {665case 0: break; /* Exec succeeded */666case sizeof(errnum):667waitpid(resultPid, NULL, 0);668throwIOException(env, errnum, "Exec failed");669goto Catch;670default:671throwIOException(env, errno, "Read failed");672goto Catch;673}674675fds[0] = (in [1] != -1) ? in [1] : -1;676fds[1] = (out[0] != -1) ? out[0] : -1;677fds[2] = (err[0] != -1) ? err[0] : -1;678679Finally:680free(c->clone_stack);681682/* Always clean up the child's side of the pipes */683closeSafely(in [0]);684closeSafely(out[1]);685closeSafely(err[1]);686687/* Always clean up fail and childEnv descriptors */688closeSafely(fail[0]);689closeSafely(fail[1]);690closeSafely(childenv[0]);691closeSafely(childenv[1]);692693releaseBytes(env, helperpath, phelperpath);694releaseBytes(env, prog, pprog);695releaseBytes(env, argBlock, pargBlock);696releaseBytes(env, envBlock, penvBlock);697releaseBytes(env, dir, c->pdir);698699free(c->argv);700free(c->envv);701free(c);702703if (fds != NULL)704(*env)->ReleaseIntArrayElements(env, std_fds, fds, 0);705706return resultPid;707708Catch:709/* Clean up the parent's side of the pipes in case of failure only */710closeSafely(in [1]); in[1] = -1;711closeSafely(out[0]); out[0] = -1;712closeSafely(err[0]); err[0] = -1;713goto Finally;714}715716JNIEXPORT void JNICALL717Java_java_lang_UNIXProcess_destroyProcess(JNIEnv *env,718jobject junk,719jint pid,720jboolean force)721{722int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;723kill(pid, sig);724}725726727