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 <wait.h> 44 #include <signal.h> 45 #include <string.h> 46 #include <errno.h> 47 #include <dirent.h> 48 #include <unistd.h> 49 #include <fcntl.h> 50 #include <limits.h> 51 52 #ifndef STDIN_FILENO 53 #define STDIN_FILENO 0 54 #endif 55 56 #ifndef STDOUT_FILENO 57 #define STDOUT_FILENO 1 58 #endif 59 60 #ifndef STDERR_FILENO 61 #define STDERR_FILENO 2 62 #endif 63 64 #ifndef SA_NOCLDSTOP 65 #define SA_NOCLDSTOP 0 66 #endif 67 68 #ifndef SA_RESTART 69 #define SA_RESTART 0 70 #endif 71 72 #define FAIL_FILENO (STDERR_FILENO + 1) 73 74 static void 75 setSIGCHLDHandler(JNIEnv *env) 76 { 77 /* There is a subtle difference between having the signal handler 78 * for SIGCHLD be SIG_DFL and SIG_IGN. We cannot obtain process 79 * termination information for child processes if the signal 80 * handler is SIG_IGN. It must be SIG_DFL. 81 * 82 * We used to set the SIGCHLD handler only on Linux, but it's 83 * safest to set it unconditionally. 84 * 85 * Consider what happens if java's parent process sets the SIGCHLD 86 * handler to SIG_IGN. Normally signal handlers are inherited by 87 * children, but SIGCHLD is a controversial case. Solaris appears 88 * to always reset it to SIG_DFL, but this behavior may be 89 * non-standard-compliant, and we shouldn't rely on it. 90 * 91 * References: 92 * http://www.opengroup.org/onlinepubs/7908799/xsh/exec.html 93 * http://www.pasc.org/interps/unofficial/db/p1003.1/pasc-1003.1-132.html 94 */ 95 struct sigaction sa; 96 sa.sa_handler = SIG_DFL; 97 sigemptyset(&sa.sa_mask); 98 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; 99 if (sigaction(SIGCHLD, &sa, NULL) < 0) 100 JNU_ThrowInternalError(env, "Can't set SIGCHLD handler"); 101 } 102 103 static void* 104 xmalloc(JNIEnv *env, size_t size) 105 { 106 void *p = malloc(size); 107 if (p == NULL) 108 JNU_ThrowOutOfMemoryError(env, NULL); 109 return p; 110 } 111 112 #define NEW(type, n) ((type *) xmalloc(env, (n) * sizeof(type))) 113 114 /** 115 * If PATH is not defined, the OS provides some default value. 116 * Unfortunately, there's no portable way to get this value. 117 * Fortunately, it's only needed if the child has PATH while we do not. 118 */ 119 static const char* 120 defaultPath(void) 121 { 122 #ifdef __solaris__ 123 /* These really are the Solaris defaults! */ 124 return (geteuid() == 0 || getuid() == 0) ? 125 "/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin:/usr/sbin" : 126 "/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin:"; 127 #else 128 return ":/bin:/usr/bin"; /* glibc */ 129 #endif 130 } 131 132 static const char* 133 effectivePath(void) 134 { 135 const char *s = getenv("PATH"); 136 return (s != NULL) ? s : defaultPath(); 137 } 138 139 static int 140 countOccurrences(const char *s, char c) 141 { 142 int count; 143 for (count = 0; *s != '\0'; s++) 144 count += (*s == c); 145 return count; 146 } 147 148 static const char * const * 149 splitPath(JNIEnv *env, const char *path) 150 { 151 const char *p, *q; 152 char **pathv; 153 int i; 154 int count = countOccurrences(path, ':') + 1; 155 156 pathv = NEW(char*, count+1); 157 pathv[count] = NULL; 158 for (p = path, i = 0; i < count; i++, p = q + 1) { 159 for (q = p; (*q != ':') && (*q != '\0'); q++) 160 ; 161 if (q == p) /* empty PATH component => "." */ 162 pathv[i] = "./"; 163 else { 164 int addSlash = ((*(q - 1)) != '/'); 165 pathv[i] = NEW(char, q - p + addSlash + 1); 166 memcpy(pathv[i], p, q - p); 167 if (addSlash) 168 pathv[i][q - p] = '/'; 169 pathv[i][q - p + addSlash] = '\0'; 170 } 171 } 172 return (const char * const *) pathv; 173 } 174 175 /** 176 * Cached value of JVM's effective PATH. 177 * (We don't support putenv("PATH=...") in native code) 178 */ 179 static const char *parentPath; 180 181 /** 182 * Split, canonicalized version of parentPath 183 */ 184 static const char * const *parentPathv; 185 186 static jfieldID field_exitcode; 187 188 JNIEXPORT void JNICALL 189 Java_java_lang_UNIXProcess_initIDs(JNIEnv *env, jclass clazz) 190 { 191 field_exitcode = (*env)->GetFieldID(env, clazz, "exitcode", "I"); 192 193 parentPath = effectivePath(); 194 parentPathv = splitPath(env, parentPath); 195 196 setSIGCHLDHandler(env); 197 } 198 199 200 #ifndef WIFEXITED 201 #define WIFEXITED(status) (((status)&0xFF) == 0) 202 #endif 203 204 #ifndef WEXITSTATUS 205 #define WEXITSTATUS(status) (((status)>>8)&0xFF) 206 #endif 207 208 #ifndef WIFSIGNALED 209 #define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0) 210 #endif 211 212 #ifndef WTERMSIG 213 #define WTERMSIG(status) ((status)&0x7F) 214 #endif 242 /* The child exited because of a signal. 243 * The best value to return is 0x80 + signal number, 244 * because that is what all Unix shells do, and because 245 * it allows callers to distinguish between process exit and 246 * process death by signal. 247 * Unfortunately, the historical behavior on Solaris is to return 248 * the signal number, and we preserve this for compatibility. */ 249 #ifdef __solaris__ 250 return WTERMSIG(status); 251 #else 252 return 0x80 + WTERMSIG(status); 253 #endif 254 } else { 255 /* 256 * Unknown exit code; pass it through. 257 */ 258 return status; 259 } 260 } 261 262 static int 263 isAsciiDigit(char c) 264 { 265 return c >= '0' && c <= '9'; 266 } 267 268 static int 269 closeDescriptors(void) 270 { 271 DIR *dp; 272 struct dirent64 *dirp; 273 int from_fd = FAIL_FILENO + 1; 274 275 /* We're trying to close all file descriptors, but opendir() might 276 * itself be implemented using a file descriptor, and we certainly 277 * don't want to close that while it's in use. We assume that if 278 * opendir() is implemented using a file descriptor, then it uses 279 * the lowest numbered file descriptor, just like open(). So we 280 * close a couple explicitly. */ 281 282 close(from_fd); /* for possible use by opendir() */ 283 close(from_fd + 1); /* another one for good luck */ 284 285 if ((dp = opendir("/proc/self/fd")) == NULL) 286 return 0; 287 288 /* We use readdir64 instead of readdir to work around Solaris bug 289 * 6395699: /proc/self/fd fails to report file descriptors >= 1024 on Solaris 9 290 */ 291 while ((dirp = readdir64(dp)) != NULL) { 292 int fd; 293 if (isAsciiDigit(dirp->d_name[0]) && 294 (fd = strtol(dirp->d_name, NULL, 10)) >= from_fd + 2) 295 close(fd); 296 } 297 298 closedir(dp); 299 300 return 1; 301 } 302 303 static void 304 moveDescriptor(int fd_from, int fd_to) 305 { 306 if (fd_from != fd_to) { 307 dup2(fd_from, fd_to); 308 close(fd_from); 309 } 310 } 311 312 static const char * 313 getBytes(JNIEnv *env, jbyteArray arr) 314 { 315 return arr == NULL ? NULL : 316 (const char*) (*env)->GetByteArrayElements(env, arr, NULL); 317 } 318 319 static void 320 releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr) 321 { 322 if (parr != NULL) 323 (*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT); 324 } 325 326 static void 327 initVectorFromBlock(const char**vector, const char* block, int count) 328 { 329 int i; 330 const char *p; 331 for (i = 0, p = block; i < count; i++) { 332 /* Invariant: p always points to the start of a C string. */ 333 vector[i] = p; 334 while (*(p++)); 335 } 336 vector[count] = NULL; 337 } 338 339 static void 340 throwIOException(JNIEnv *env, int errnum, const char *defaultDetail) 341 { 342 static const char * const format = "error=%d, %s"; 343 const char *detail = defaultDetail; 344 char *errmsg; 345 jstring s; 346 347 if (errnum != 0) { 348 const char *s = strerror(errnum); 349 if (strcmp(s, "Unknown error") != 0) 350 detail = s; 351 } 352 /* ASCII Decimal representation uses 2.4 times as many bits as binary. */ 353 errmsg = NEW(char, strlen(format) + strlen(detail) + 3 * sizeof(errnum)); 354 sprintf(errmsg, format, errnum, detail); 355 s = JNU_NewStringPlatform(env, errmsg); 356 if (s != NULL) { 357 jobject x = JNU_NewObjectByName(env, "java/io/IOException", 358 "(Ljava/lang/String;)V", s); 359 if (x != NULL) 360 (*env)->Throw(env, x); 361 } 362 free(errmsg); 363 } 364 365 #ifdef DEBUG_PROCESS 366 /* Debugging process code is difficult; where to write debug output? */ 367 static void 368 debugPrint(char *format, ...) 369 { 370 FILE *tty = fopen("/dev/tty", "w"); 371 va_list ap; 372 va_start(ap, format); 373 vfprintf(tty, format, ap); 374 va_end(ap); 375 fclose(tty); 376 } 377 #endif /* DEBUG_PROCESS */ 378 379 /* Version of execvpe when child's PATH differs from parent's */ 380 static int 381 execvp_usingParentPath(const char *file, const char *const argv[]) 382 { 383 char expanded_file[PATH_MAX]; 384 int filelen = strlen(file); 385 int sticky_errno = 0; 386 const char * const * dirs; 387 /* Search parent's PATH */ 388 for (dirs = parentPathv; *dirs; dirs++) { 389 const char * dir = *dirs; 390 int dirlen = strlen(dir); 391 if (filelen + dirlen + 1 >= PATH_MAX) { 392 /* Resist the urge to remove this limit; 393 * calling malloc after fork is unsafe. */ 394 errno = ENAMETOOLONG; 395 continue; 396 } 397 strcpy(expanded_file, dir); 398 strcpy(expanded_file + dirlen, file); 399 execvp(expanded_file, (char **) argv); 400 /* There are 3 responses to various classes of errno: 401 * return immediately, continue (especially for ENOENT), 402 * or continue with "sticky" errno. 403 * 404 * From exec(3): 405 * 406 * If permission is denied for a file (the attempted 407 * execve returned EACCES), these functions will continue 408 * searching the rest of the search path. If no other 409 * file is found, however, they will return with the 410 * global variable errno set to EACCES. 411 */ 412 switch (errno) { 413 case EACCES: 414 sticky_errno = errno; 415 /* FALLTHRU */ 416 case ENOENT: 417 case ENOTDIR: 418 #ifdef ELOOP 419 case ELOOP: 420 #endif 421 #ifdef ESTALE 422 case ESTALE: 423 #endif 424 #ifdef ENODEV 425 case ENODEV: 426 #endif 427 #ifdef ETIMEDOUT 428 case ETIMEDOUT: 429 #endif 430 break; /* Try other directories in PATH */ 431 default: 432 return -1; 433 } 434 } 435 if (sticky_errno != 0) 436 errno = sticky_errno; 437 return -1; 438 } 439 440 /* execvpe should have been included in the Unix standards. */ 441 static int 442 execvpe(const char *file, const char *const argv[], const char *const envp[]) 443 { 444 /* This is one of the rare times it's more portable to declare an 445 * external symbol explicitly, rather than via a system header. 446 * The declaration is standardized as part of UNIX98, but there is 447 * no standard (not even de-facto) header file where the 448 * declaration is to be found. See: 449 * http://www.opengroup.org/onlinepubs/009695399/functions/environ.html 450 * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html 451 * 452 * "All identifiers in this volume of IEEE Std 1003.1-2001, except 453 * environ, are defined in at least one of the headers" (!) 454 */ 455 extern char **environ; 456 457 if (envp != NULL) 458 environ = (char **) envp; 459 460 if (/* Parent and child environment the same? Use child PATH. */ 461 (envp == NULL) 462 463 /* http://www.opengroup.org/onlinepubs/009695399/functions/exec.html 464 * "If the file argument contains a slash character, it is used as 465 * the pathname for this file. Otherwise, the path prefix for this 466 * file is obtained by a search of the directories passed in the 467 * PATH environment variable" */ 468 || (strchr(file, '/') != NULL) 469 470 /* Parent and child PATH the same? Use child PATH. */ 471 || (strcmp(parentPath, effectivePath()) == 0) 472 473 /* We want ENOENT, not EACCES, for zero-length program names. */ 474 || (*file == '\0')) 475 476 return execvp(file, (char **) argv); 477 else 478 return execvp_usingParentPath(file, argv); 479 } 480 481 static void 482 closeSafely(int fd) 483 { 484 if (fd != -1) 485 close(fd); 486 } 487 488 /* 489 * Reads nbyte bytes from file descriptor fd into buf, 490 * The read operation is retried in case of EINTR or partial reads. 491 * 492 * Returns number of bytes read (normally nbyte, but may be less in 493 * case of EOF). In case of read errors, returns -1 and sets errno. 494 */ 495 static ssize_t 496 readFully(int fd, void *buf, size_t nbyte) 497 { 498 ssize_t remaining = nbyte; 499 for (;;) { 500 ssize_t n = read(fd, buf, remaining); 501 if (n == 0) { 502 return nbyte - remaining; 503 } else if (n > 0) { 504 remaining -= n; 505 if (remaining <= 0) 506 return nbyte; 507 /* We were interrupted in the middle of reading the bytes. 508 * Unlikely, but possible. */ 509 buf = (void *) (((char *)buf) + n); 510 } else if (errno == EINTR) { 511 /* Strange signals like SIGJVM1 are possible at any time. 512 * See http://www.dreamsongs.com/WorseIsBetter.html */ 513 } else { 514 return -1; 515 } 516 } 517 } 518 519 #ifndef __solaris__ 520 #undef fork1 521 #define fork1() fork() 522 #endif 523 524 JNIEXPORT jint JNICALL 525 Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env, 526 jobject process, 527 jbyteArray prog, 528 jbyteArray argBlock, jint argc, 529 jbyteArray envBlock, jint envc, 530 jbyteArray dir, 531 jintArray std_fds, 532 jboolean redirectErrorStream) 533 { 534 int errnum; 535 int resultPid = -1; 536 int in[2], out[2], err[2], fail[2]; 537 const char **argv = NULL; 538 const char **envv = NULL; 539 const char *pprog = getBytes(env, prog); 540 const char *pargBlock = getBytes(env, argBlock); 541 const char *penvBlock = getBytes(env, envBlock); 542 const char *pdir = getBytes(env, dir); 543 jint *fds = NULL; 544 545 in[0] = in[1] = out[0] = out[1] = err[0] = err[1] = fail[0] = fail[1] = -1; 546 547 assert(prog != NULL && argBlock != NULL); 548 if (pprog == NULL) goto Catch; 549 if (pargBlock == NULL) goto Catch; 550 if (envBlock != NULL && penvBlock == NULL) goto Catch; 551 if (dir != NULL && pdir == NULL) goto Catch; 552 553 /* Convert pprog + pargBlock into a char ** argv */ 554 if ((argv = NEW(const char *, argc + 2)) == NULL) 555 goto Catch; 556 argv[0] = pprog; 557 initVectorFromBlock(argv+1, pargBlock, argc); 558 559 if (envBlock != NULL) { 560 /* Convert penvBlock into a char ** envv */ 561 if ((envv = NEW(const char *, envc + 1)) == NULL) 562 goto Catch; 563 initVectorFromBlock(envv, penvBlock, envc); 564 } 565 566 assert(std_fds != NULL); 567 fds = (*env)->GetIntArrayElements(env, std_fds, NULL); 568 if (fds == NULL) goto Catch; 569 570 if ((fds[0] == -1 && pipe(in) < 0) || 571 (fds[1] == -1 && pipe(out) < 0) || 572 (fds[2] == -1 && pipe(err) < 0) || 573 (pipe(fail) < 0)) { 574 throwIOException(env, errno, "Bad file descriptor"); 575 goto Catch; 576 } 577 578 resultPid = fork1(); 579 if (resultPid < 0) { 580 throwIOException(env, errno, "Fork failed"); 581 goto Catch; 582 } 583 584 if (resultPid == 0) { 585 /* Child process */ 586 587 /* Close the parent sides of the pipes. 588 Closing pipe fds here is redundant, since closeDescriptors() 589 would do it anyways, but a little paranoia is a good thing. */ 590 closeSafely(in[1]); 591 closeSafely(out[0]); 592 closeSafely(err[0]); 593 closeSafely(fail[0]); 594 595 /* Give the child sides of the pipes the right fileno's. */ 596 /* Note: it is possible for in[0] == 0 */ 597 moveDescriptor(in[0] != -1 ? in[0] : fds[0], STDIN_FILENO); 598 moveDescriptor(out[1]!= -1 ? out[1] : fds[1], STDOUT_FILENO); 599 600 if (redirectErrorStream) { 601 closeSafely(err[1]); 602 dup2(STDOUT_FILENO, STDERR_FILENO); 603 } else { 604 moveDescriptor(err[1] != -1 ? err[1] : fds[2], STDERR_FILENO); 605 } 606 607 moveDescriptor(fail[1], FAIL_FILENO); 608 609 /* close everything */ 610 if (closeDescriptors() == 0) { /* failed, close the old way */ 611 int max_fd = (int)sysconf(_SC_OPEN_MAX); 612 int i; 613 for (i = FAIL_FILENO + 1; i < max_fd; i++) 614 close(i); 615 } 616 617 /* change to the new working directory */ 618 if (pdir != NULL && chdir(pdir) < 0) 619 goto WhyCantJohnnyExec; 620 621 if (fcntl(FAIL_FILENO, F_SETFD, FD_CLOEXEC) == -1) 622 goto WhyCantJohnnyExec; 623 624 execvpe(argv[0], argv, envv); 625 626 WhyCantJohnnyExec: 627 /* We used to go to an awful lot of trouble to predict whether the 628 * child would fail, but there is no reliable way to predict the 629 * success of an operation without *trying* it, and there's no way 630 * to try a chdir or exec in the parent. Instead, all we need is a 631 * way to communicate any failure back to the parent. Easy; we just 632 * send the errno back to the parent over a pipe in case of failure. 633 * The tricky thing is, how do we communicate the *success* of exec? 634 * We use FD_CLOEXEC together with the fact that a read() on a pipe 635 * yields EOF when the write ends (we have two of them!) are closed. 636 */ 637 errnum = errno; 638 write(FAIL_FILENO, &errnum, sizeof(errnum)); 639 close(FAIL_FILENO); 640 _exit(-1); 641 } 642 643 /* parent process */ 644 645 close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec */ 646 647 switch (readFully(fail[0], &errnum, sizeof(errnum))) { 648 case 0: break; /* Exec succeeded */ 649 case sizeof(errnum): 650 waitpid(resultPid, NULL, 0); 651 throwIOException(env, errnum, "Exec failed"); 652 goto Catch; 653 default: 654 throwIOException(env, errno, "Read failed"); 655 goto Catch; 656 } 657 658 fds[0] = (in [1] != -1) ? in [1] : -1; 659 fds[1] = (out[0] != -1) ? out[0] : -1; 660 fds[2] = (err[0] != -1) ? err[0] : -1; 661 662 Finally: 663 /* Always clean up the child's side of the pipes */ 664 closeSafely(in [0]); 665 closeSafely(out[1]); 666 closeSafely(err[1]); 667 668 /* Always clean up fail descriptors */ 669 closeSafely(fail[0]); 670 closeSafely(fail[1]); 671 672 free(argv); 673 free(envv); 674 675 releaseBytes(env, prog, pprog); 676 releaseBytes(env, argBlock, pargBlock); 677 releaseBytes(env, envBlock, penvBlock); 678 releaseBytes(env, dir, pdir); 679 680 if (fds != NULL) 681 (*env)->ReleaseIntArrayElements(env, std_fds, fds, 0); 682 683 return resultPid; 684 685 Catch: 686 /* Clean up the parent's side of the pipes in case of failure only */ 687 closeSafely(in [1]); 688 closeSafely(out[0]); 689 closeSafely(err[0]); 690 goto Finally; 691 } 692 693 JNIEXPORT void JNICALL 694 Java_java_lang_UNIXProcess_destroyProcess(JNIEnv *env, jobject junk, jint pid) 695 { 696 kill(pid, SIGTERM); 697 } | 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 <wait.h> 44 #include <signal.h> 45 #include <string.h> 46 #include <errno.h> 47 #include <dirent.h> 48 #include <unistd.h> 49 #include <fcntl.h> 50 #include <limits.h> 51 #include "processutil_md.h" 52 53 #ifdef __solaris__ 54 55 #include <spawn.h> 56 #include <sys/stat.h> 57 58 #endif 59 60 #ifndef STDIN_FILENO 61 #define STDIN_FILENO 0 62 #endif 63 64 #ifndef STDOUT_FILENO 65 #define STDOUT_FILENO 1 66 #endif 67 68 #ifndef STDERR_FILENO 69 #define STDERR_FILENO 2 70 #endif 71 72 #ifndef SA_NOCLDSTOP 73 #define SA_NOCLDSTOP 0 74 #endif 75 76 #ifndef SA_RESTART 77 #define SA_RESTART 0 78 #endif 79 80 #define FAIL_FILENO (STDERR_FILENO + 1) 81 82 extern int jlup_isAsciiDigit(char c); 83 84 extern void jlup_moveDescriptor(int fd_from, int fd_to); 85 86 static void 87 setSIGCHLDHandler(JNIEnv *env) 88 { 89 /* There is a subtle difference between having the signal handler 90 * for SIGCHLD be SIG_DFL and SIG_IGN. We cannot obtain process 91 * termination information for child processes if the signal 92 * handler is SIG_IGN. It must be SIG_DFL. 93 * 94 * We used to set the SIGCHLD handler only on Linux, but it's 95 * safest to set it unconditionally. 96 * 97 * Consider what happens if java's parent process sets the SIGCHLD 98 * handler to SIG_IGN. Normally signal handlers are inherited by 99 * children, but SIGCHLD is a controversial case. Solaris appears 100 * to always reset it to SIG_DFL, but this behavior may be 101 * non-standard-compliant, and we shouldn't rely on it. 102 * 103 * References: 104 * http://www.opengroup.org/onlinepubs/7908799/xsh/exec.html 105 * http://www.pasc.org/interps/unofficial/db/p1003.1/pasc-1003.1-132.html 106 */ 107 struct sigaction sa; 108 sa.sa_handler = SIG_DFL; 109 sigemptyset(&sa.sa_mask); 110 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; 111 if (sigaction(SIGCHLD, &sa, NULL) < 0) 112 JNU_ThrowInternalError(env, "Can't set SIGCHLD handler"); 113 } 114 115 void* 116 jlup_xmalloc(void *env, int size) 117 { 118 void *p = malloc(size); 119 if (p == NULL) 120 JNU_ThrowOutOfMemoryError((JNIEnv *)env, NULL); 121 return p; 122 } 123 124 static jfieldID field_exitcode; 125 126 JNIEXPORT void JNICALL 127 Java_java_lang_UNIXProcess_initIDs(JNIEnv *env, jclass clazz) 128 { 129 field_exitcode = (*env)->GetFieldID(env, clazz, "exitcode", "I"); 130 131 jlup_initialize(env); 132 133 setSIGCHLDHandler(env); 134 } 135 136 137 #ifndef WIFEXITED 138 #define WIFEXITED(status) (((status)&0xFF) == 0) 139 #endif 140 141 #ifndef WEXITSTATUS 142 #define WEXITSTATUS(status) (((status)>>8)&0xFF) 143 #endif 144 145 #ifndef WIFSIGNALED 146 #define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0) 147 #endif 148 149 #ifndef WTERMSIG 150 #define WTERMSIG(status) ((status)&0x7F) 151 #endif 179 /* The child exited because of a signal. 180 * The best value to return is 0x80 + signal number, 181 * because that is what all Unix shells do, and because 182 * it allows callers to distinguish between process exit and 183 * process death by signal. 184 * Unfortunately, the historical behavior on Solaris is to return 185 * the signal number, and we preserve this for compatibility. */ 186 #ifdef __solaris__ 187 return WTERMSIG(status); 188 #else 189 return 0x80 + WTERMSIG(status); 190 #endif 191 } else { 192 /* 193 * Unknown exit code; pass it through. 194 */ 195 return status; 196 } 197 } 198 199 200 extern int 201 jlp_closeDescriptors(int from_fd); 202 203 static const char * 204 getBytes(JNIEnv *env, jbyteArray arr) 205 { 206 return arr == NULL ? NULL : 207 (const char*) (*env)->GetByteArrayElements(env, arr, NULL); 208 } 209 210 static const char * 211 getBytesWithLength(JNIEnv *env, jbyteArray arr, int*len) 212 { 213 if (len != 0) { 214 *len = (arr == NULL) ? 0 : (*env)->GetArrayLength (env, arr); 215 } 216 return arr == NULL ? NULL : 217 (const char*) (*env)->GetByteArrayElements(env, arr, NULL); 218 } 219 220 static void 221 releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr) 222 { 223 if (parr != NULL) 224 (*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT); 225 } 226 227 static void 228 throwIOException(JNIEnv *env, int errnum, const char *defaultDetail) 229 { 230 static const char * const format = "error=%d, %s"; 231 const char *detail = defaultDetail; 232 char *errmsg; 233 jstring s; 234 235 if (errnum != 0) { 236 const char *s = strerror(errnum); 237 if (strcmp(s, "Unknown error") != 0) 238 detail = s; 239 } 240 /* ASCII Decimal representation uses 2.4 times as many bits as binary. */ 241 errmsg = jlup_xmalloc(env, strlen(format) + strlen(detail) + 3 * sizeof(errnum)); 242 sprintf(errmsg, format, errnum, detail); 243 s = JNU_NewStringPlatform(env, errmsg); 244 if (s != NULL) { 245 jobject x = JNU_NewObjectByName(env, "java/io/IOException", 246 "(Ljava/lang/String;)V", s); 247 if (x != NULL) 248 (*env)->Throw(env, x); 249 } 250 free(errmsg); 251 } 252 253 #ifdef DEBUG_PROCESS 254 /* Debugging process code is difficult; where to write debug output? */ 255 static void 256 debugPrint(char *format, ...) 257 { 258 FILE *tty = fopen("/dev/tty", "w"); 259 va_list ap; 260 va_start(ap, format); 261 vfprintf(tty, format, ap); 262 va_end(ap); 263 fclose(tty); 264 } 265 #endif /* DEBUG_PROCESS */ 266 267 #ifndef __solaris__ 268 #undef fork1 269 #define fork1() fork() 270 #endif 271 272 #ifdef __solaris__ 273 274 /* solaris version uses posix_spawn() */ 275 276 JNIEXPORT jint JNICALL 277 Java_java_lang_UNIXProcess_forkAndExec (JNIEnv *env, 278 jobject process, 279 jbyteArray prog, 280 jbyteArray argBlock, jint argc, 281 jbyteArray envBlock, jint envc, 282 jbyteArray dir, 283 jintArray std_fds, 284 jobject helperstr, 285 jboolean redirectErrorStream) 286 { 287 int i, flags, errnum, n, rval, fd = -1; 288 int in[2], out[2], err[2], fail[2], op; 289 int envLength; 290 const char **argv = NULL; 291 const char *pprog = getBytes(env, prog); 292 const char *pargBlock = getBytes(env, argBlock); 293 const char *penvBlock = getBytesWithLength(env, envBlock, &envLength); 294 const char *pdir = getBytes(env, dir); 295 jint *fds = NULL; 296 pid_t targetpid; 297 int hlprcode [2]; /* first response from helper */ 298 extern char **environ; 299 char buf[256], buf1[2]; 300 char *ptr; 301 302 const char *helperpath = JNU_GetStringPlatformChars ( 303 env, helperstr, JNI_FALSE 304 ); 305 306 if (helperpath == NULL) { 307 throwIOException(env, errno, "Bad helper path"); 308 goto Catch; 309 } 310 311 in[0] = in[1] = out[0] = out[1] = err[0] = err[1] = fail[0] = fail[1] = -1; 312 313 assert(prog != NULL && argBlock != NULL); 314 if (pprog == NULL) goto Catch; 315 if (pargBlock == NULL) goto Catch; 316 if (envBlock != NULL && penvBlock == NULL) goto Catch; 317 if (dir != NULL && pdir == NULL) goto Catch; 318 319 /* Convert pprog + pargBlock into a char ** argv */ 320 if ((argv = jlup_xmalloc(env, sizeof(const char *)*( argc + 5))) == NULL) 321 goto Catch; 322 argv[0] = pprog; 323 jlup_initVectorFromBlock(&argv[4], pargBlock, argc); 324 /* new working directory (if any) passed as extra arg */ 325 argv[1] = (pdir == NULL) ? "": pdir; 326 /* fd numbers for streams that target will need */ 327 argv[2] = buf; 328 329 assert(std_fds != NULL); 330 fds = (*env)->GetIntArrayElements(env, std_fds, NULL); 331 if (fds == NULL) goto Catch; 332 333 if ((fds[0] == -1 && pipe(in) < 0) || 334 (fds[1] == -1 && pipe(out) < 0) || 335 (fds[2] == -1 && pipe(err) < 0) || 336 (pipe(fail) < 0)) { 337 throwIOException(env, errno, "Bad file descriptor"); 338 goto Catch; 339 } 340 341 342 /* Two flags passed to child */ 343 flags = (err[0] != -1) << 1 ; /* =1 if we created a pipe */ 344 flags += redirectErrorStream & 0x1; 345 buf1[0] = '0' + flags; 346 buf1[1] = 0; 347 argv[3] = buf1; 348 349 /* clear FD_CLOEXEC if set. */ 350 for (i=0; i<3; i++) { 351 if (fds[i] != -1) { 352 int flags = fcntl(fds[i], F_GETFD); 353 if (flags & FD_CLOEXEC) { 354 fcntl (fds[i], F_SETFD, flags & (~1)); 355 } 356 } 357 } 358 /* 359 * we can't move (or close) the descriptors in the parent. We could organise 360 * close and dup2 actions for posix_spawn, but that doesn't work so well 361 * in multi-threaded systems, where other threads could be opening 362 * or closing fds in parallel. 363 * So we pass the actual fd numbers to the helper, and it moves the 364 * them to the right location, and closes all others. 365 */ 366 sprintf (buf, "%d %d %d %d", (in[0]==-1) ? fds[0] : in[0], 367 (out[1]==-1) ? fds[1] : out[1], 368 (err[1]==-1) ? fds[2] : err[1], fail[1]); 369 370 rval = posix_spawn (&targetpid, helperpath, 0, 0, (char * const *) &argv[0], environ); 371 if (rval < 0) { 372 throwIOException(env, errno, "Spawn failed"); 373 goto Catch; 374 } 375 close(fail[1]); fail[1] = -1; 376 377 /* need to send the child environment down the pipe. First word 378 * is the number of bytes, followed by the number of entries 379 * in the envrionment, followed by the strings themselves. 380 * In the case where no there is no environment, both words will be -1 381 */ 382 if (envBlock == NULL) { 383 envLength = envc = -1; 384 } 385 write (fail[0], &envLength, sizeof(envLength)); 386 write (fail[0], &envc, sizeof(envc)); 387 if (envLength > 0) { 388 write (fail[0], penvBlock, envLength); 389 } 390 391 n = jlup_readFully(fail[0], &hlprcode[0],sizeof(hlprcode)); 392 393 if (n == sizeof(hlprcode)) { 394 /* error */ 395 waitpid(targetpid, NULL, 0); 396 if (hlprcode[0] == 1) { 397 throwIOException(env, hlprcode[1], "chdir() failed"); 398 } else { 399 throwIOException(env, hlprcode[1], "exec() failed"); 400 } 401 goto Catch; 402 } else if (n != 0) { 403 throwIOException(env, errno, "Read failed"); 404 goto Catch; 405 } 406 407 /* n==0 => pipe is closed, means successful exec of target */ 408 409 Finally: 410 /* If we created pipes, set the parent fds. These fds are returned 411 * to caller to be placed in the relevant FileDescriptor objects 412 */ 413 fds[0] = (in [1] != -1) ? in [1] : -1; 414 fds[1] = (out[0] != -1) ? out[0] : -1; 415 fds[2] = (err[0] != -1) ? err[0] : -1; 416 417 /* Always clean up the child's side of the pipes */ 418 jlup_closeSafely(in [0]); 419 jlup_closeSafely(out[1]); 420 jlup_closeSafely(err[1]); 421 422 /* Always clean up fail descriptors */ 423 jlup_closeSafely(fail[0]); 424 425 free(argv); 426 427 releaseBytes(env, prog, pprog); 428 releaseBytes(env, argBlock, pargBlock); 429 releaseBytes(env, envBlock, penvBlock); 430 releaseBytes(env, dir, pdir); 431 432 if (fds != NULL) 433 (*env)->ReleaseIntArrayElements(env, std_fds, fds, 0); 434 435 return targetpid; 436 437 Catch: 438 /* Clean up the parent's side of the pipes in case of failure only */ 439 jlup_closeSafely(in [1]); 440 jlup_closeSafely(out[0]); 441 jlup_closeSafely(err[0]); 442 goto Finally; 443 } 444 445 #else /* Linux version */ 446 447 JNIEXPORT jint JNICALL 448 Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env, 449 jobject process, 450 jbyteArray prog, 451 jbyteArray argBlock, jint argc, 452 jbyteArray envBlock, jint envc, 453 jbyteArray dir, 454 jintArray std_fds, 455 jboolean redirectErrorStream) 456 { 457 int errnum; 458 int resultPid = -1; 459 int in[2], out[2], err[2], fail[2]; 460 const char **argv = NULL; 461 const char **envv = NULL; 462 const char *pprog = getBytes(env, prog); 463 const char *pargBlock = getBytes(env, argBlock); 464 const char *penvBlock = getBytes(env, envBlock); 465 const char *pdir = getBytes(env, dir); 466 jint *fds = NULL; 467 468 in[0] = in[1] = out[0] = out[1] = err[0] = err[1] = fail[0] = fail[1] = -1; 469 470 assert(prog != NULL && argBlock != NULL); 471 if (pprog == NULL) goto Catch; 472 if (pargBlock == NULL) goto Catch; 473 if (envBlock != NULL && penvBlock == NULL) goto Catch; 474 if (dir != NULL && pdir == NULL) goto Catch; 475 476 /* Convert pprog + pargBlock into a char ** argv */ 477 if ((argv = (const char **)jlup_xmalloc(env, sizeof(const char *)*( argc + 2))) == NULL) 478 goto Catch; 479 argv[0] = pprog; 480 jlup_initVectorFromBlock(argv+1, pargBlock, argc); 481 482 if (envBlock != NULL) { 483 /* Convert penvBlock into a char ** envv */ 484 if ((envv = (const char **)jlup_xmalloc(env, sizeof(const char *)*( envc + 1))) == NULL) 485 goto Catch; 486 jlup_initVectorFromBlock(envv, penvBlock, envc); 487 } 488 489 assert(std_fds != NULL); 490 fds = (*env)->GetIntArrayElements(env, std_fds, NULL); 491 if (fds == NULL) goto Catch; 492 493 if ((fds[0] == -1 && pipe(in) < 0) || 494 (fds[1] == -1 && pipe(out) < 0) || 495 (fds[2] == -1 && pipe(err) < 0) || 496 (pipe(fail) < 0)) { 497 throwIOException(env, errno, "Bad file descriptor"); 498 goto Catch; 499 } 500 501 resultPid = fork1(); 502 if (resultPid < 0) { 503 throwIOException(env, errno, "Fork failed"); 504 goto Catch; 505 } 506 507 if (resultPid == 0) { 508 /* Child process */ 509 510 /* Close the parent sides of the pipes. 511 Closing pipe fds here is redundant, since closeDescriptors() 512 would do it anyways, but a little paranoia is a good thing. */ 513 jlup_closeSafely(in[1]); 514 jlup_closeSafely(out[0]); 515 jlup_closeSafely(err[0]); 516 jlup_closeSafely(fail[0]); 517 518 /* Give the child sides of the pipes the right fileno's. */ 519 /* Note: it is possible for in[0] == 0 */ 520 jlup_moveDescriptor(in[0] != -1 ? in[0] : fds[0], STDIN_FILENO); 521 jlup_moveDescriptor(out[1]!= -1 ? out[1] : fds[1], STDOUT_FILENO); 522 523 if (redirectErrorStream) { 524 jlup_closeSafely(err[1]); 525 dup2(STDOUT_FILENO, STDERR_FILENO); 526 } else { 527 jlup_moveDescriptor(err[1] != -1 ? err[1] : fds[2], STDERR_FILENO); 528 } 529 530 jlup_moveDescriptor(fail[1], FAIL_FILENO); 531 532 /* close everything */ 533 if (jlup_closeDescriptors(FAIL_FILENO + 1) == 0) { 534 /* failed, close the old way */ 535 int max_fd = (int)sysconf(_SC_OPEN_MAX); 536 int i; 537 for (i = FAIL_FILENO + 1; i < max_fd; i++) 538 close(i); 539 } 540 541 /* change to the new working directory */ 542 if (pdir != NULL && chdir(pdir) < 0) 543 goto WhyCantJohnnyExec; 544 545 if (fcntl(FAIL_FILENO, F_SETFD, FD_CLOEXEC) == -1) 546 goto WhyCantJohnnyExec; 547 548 jlup_execvpe(argv[0], argv, envv); 549 550 WhyCantJohnnyExec: 551 /* We used to go to an awful lot of trouble to predict whether the 552 * child would fail, but there is no reliable way to predict the 553 * success of an operation without *trying* it, and there's no way 554 * to try a chdir or exec in the parent. Instead, all we need is a 555 * way to communicate any failure back to the parent. Easy; we just 556 * send the errno back to the parent over a pipe in case of failure. 557 * The tricky thing is, how do we communicate the *success* of exec? 558 * We use FD_CLOEXEC together with the fact that a read() on a pipe 559 * yields EOF when the write ends (we have two of them!) are closed. 560 */ 561 errnum = errno; 562 write(FAIL_FILENO, &errnum, sizeof(errnum)); 563 close(FAIL_FILENO); 564 _exit(-1); 565 } 566 567 /* parent process */ 568 569 close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec */ 570 571 switch (jlup_readFully(fail[0], &errnum, sizeof(errnum))) { 572 case 0: break; /* Exec succeeded */ 573 case sizeof(errnum): 574 waitpid(resultPid, NULL, 0); 575 throwIOException(env, errnum, "Exec failed"); 576 goto Catch; 577 default: 578 throwIOException(env, errno, "Read failed"); 579 goto Catch; 580 } 581 582 fds[0] = (in [1] != -1) ? in [1] : -1; 583 fds[1] = (out[0] != -1) ? out[0] : -1; 584 fds[2] = (err[0] != -1) ? err[0] : -1; 585 586 Finally: 587 /* Always clean up the child's side of the pipes */ 588 jlup_closeSafely(in [0]); 589 jlup_closeSafely(out[1]); 590 jlup_closeSafely(err[1]); 591 592 /* Always clean up fail descriptors */ 593 jlup_closeSafely(fail[0]); 594 jlup_closeSafely(fail[1]); 595 596 free(argv); 597 free(envv); 598 599 releaseBytes(env, prog, pprog); 600 releaseBytes(env, argBlock, pargBlock); 601 releaseBytes(env, envBlock, penvBlock); 602 releaseBytes(env, dir, pdir); 603 604 if (fds != NULL) 605 (*env)->ReleaseIntArrayElements(env, std_fds, fds, 0); 606 607 return resultPid; 608 609 Catch: 610 /* Clean up the parent's side of the pipes in case of failure only */ 611 jlup_closeSafely(in [1]); 612 jlup_closeSafely(out[0]); 613 jlup_closeSafely(err[0]); 614 goto Finally; 615 } 616 #endif 617 618 JNIEXPORT void JNICALL 619 Java_java_lang_UNIXProcess_destroyProcess(JNIEnv *env, jobject junk, jint pid) 620 { 621 kill(pid, SIGTERM); 622 } |