1 /* 2 * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "jni.h" 27 #include "jni_util.h" 28 #include "java_lang_ProcessHandleImpl.h" 29 #include "java_lang_ProcessHandleImpl_Info.h" 30 31 32 #include <stdio.h> 33 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <pwd.h> 37 #include <signal.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 #include <sys/wait.h> 43 44 #include <string.h> 45 #include <dirent.h> 46 #include <ctype.h> 47 48 /** 49 * Implementations of ProcessHandleImpl functions that are common to all 50 * Unix variants: 51 * - waitForProcessExit0(pid, reap) 52 * - getCurrentPid0() 53 * - destroy0(pid, force) 54 */ 55 56 #ifndef WIFEXITED 57 #define WIFEXITED(status) (((status)&0xFF) == 0) 58 #endif 59 60 #ifndef WEXITSTATUS 61 #define WEXITSTATUS(status) (((status)>>8)&0xFF) 62 #endif 63 64 #ifndef WIFSIGNALED 65 #define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0) 66 #endif 67 68 #ifndef WTERMSIG 69 #define WTERMSIG(status) ((status)&0x7F) 70 #endif 71 72 #define RESTARTABLE(_cmd, _result) do { \ 73 do { \ 74 _result = _cmd; \ 75 } while((_result == -1) && (errno == EINTR)); \ 76 } while(0) 77 78 #define RESTARTABLE_RETURN_PTR(_cmd, _result) do { \ 79 do { \ 80 _result = _cmd; \ 81 } while((_result == NULL) && (errno == EINTR)); \ 82 } while(0) 83 84 #ifdef __solaris__ 85 #define STAT_FILE "/proc/%d/status" 86 #else 87 #define STAT_FILE "/proc/%d/stat" 88 #endif 89 90 /* Block until a child process exits and return its exit code. 91 * Note, can only be called once for any given pid if reapStatus = true. 92 */ 93 JNIEXPORT jint JNICALL 94 Java_java_lang_ProcessHandleImpl_waitForProcessExit0(JNIEnv* env, 95 jclass junk, 96 jlong jpid, 97 jboolean reapStatus) 98 { 99 pid_t pid = (pid_t)jpid; 100 errno = 0; 101 102 if (reapStatus != JNI_FALSE) { 103 /* Wait for the child process to exit. 104 * waitpid() is standard, so use it on all POSIX platforms. 105 * It is known to work when blocking to wait for the pid 106 * This returns immediately if the child has already exited. 107 */ 108 int status; 109 while (waitpid(pid, &status, 0) < 0) { 110 switch (errno) { 111 case ECHILD: return 0; 112 case EINTR: break; 113 default: return -1; 114 } 115 } 116 117 if (WIFEXITED(status)) { 118 return WEXITSTATUS(status); 119 } else if (WIFSIGNALED(status)) { 120 /* The child exited because of a signal. 121 * The best value to return is 0x80 + signal number, 122 * because that is what all Unix shells do, and because 123 * it allows callers to distinguish between process exit and 124 * process death by signal. 125 * Unfortunately, the historical behavior on Solaris is to return 126 * the signal number, and we preserve this for compatibility. */ 127 #ifdef __solaris__ 128 return WTERMSIG(status); 129 #else 130 return 0x80 + WTERMSIG(status); 131 #endif 132 } else { 133 return status; 134 } 135 } else { 136 /* 137 * Wait for the child process to exit without reaping the exitValue. 138 * waitid() is standard on all POSIX platforms. 139 * Note: waitid on Mac OS X 10.7 seems to be broken; 140 * it does not return the exit status consistently. 141 */ 142 siginfo_t siginfo; 143 int options = WEXITED | WNOWAIT; 144 memset(&siginfo, 0, sizeof siginfo); 145 while (waitid(P_PID, pid, &siginfo, options) < 0) { 146 switch (errno) { 147 case ECHILD: return 0; 148 case EINTR: break; 149 default: return -1; 150 } 151 } 152 153 if (siginfo.si_code == CLD_EXITED) { 154 /* 155 * The child exited normally; get its exit code. 156 */ 157 return siginfo.si_status; 158 } else if (siginfo.si_code == CLD_KILLED || siginfo.si_code == CLD_DUMPED) { 159 /* The child exited because of a signal. 160 * The best value to return is 0x80 + signal number, 161 * because that is what all Unix shells do, and because 162 * it allows callers to distinguish between process exit and 163 * process death by signal. 164 * Unfortunately, the historical behavior on Solaris is to return 165 * the signal number, and we preserve this for compatibility. */ 166 #ifdef __solaris__ 167 return WTERMSIG(siginfo.si_status); 168 #else 169 return 0x80 + WTERMSIG(siginfo.si_status); 170 #endif 171 } else { 172 /* 173 * Unknown exit code; pass it through. 174 */ 175 return siginfo.si_status; 176 } 177 } 178 } 179 180 /* 181 * Class: java_lang_ProcessHandleImpl 182 * Method: getCurrentPid0 183 * Signature: ()J 184 */ 185 JNIEXPORT jlong JNICALL 186 Java_java_lang_ProcessHandleImpl_getCurrentPid0(JNIEnv *env, jclass clazz) { 187 pid_t pid = getpid(); 188 return (jlong) pid; 189 } 190 191 /* 192 * Class: java_lang_ProcessHandleImpl 193 * Method: destroy0 194 * Signature: (Z)Z 195 */ 196 JNIEXPORT jboolean JNICALL 197 Java_java_lang_ProcessHandleImpl_destroy0(JNIEnv *env, 198 jobject obj, 199 jlong jpid, 200 jlong startTime, 201 jboolean force) { 202 pid_t pid = (pid_t) jpid; 203 int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM; 204 jlong start = Java_java_lang_ProcessHandleImpl_isAlive0(env, obj, jpid); 205 206 if (start == startTime || start == 0 || startTime == 0) { 207 return (kill(pid, sig) < 0) ? JNI_FALSE : JNI_TRUE; 208 } else { 209 return JNI_FALSE; 210 } 211 } 212 213 /** 214 * Size of password or group entry when not available via sysconf 215 */ 216 #define ENT_BUF_SIZE 1024 217 218 /** 219 * Return a strong username for the uid_t or null. 220 */ 221 jstring uidToUser(JNIEnv* env, uid_t uid) { 222 int result = 0; 223 int buflen; 224 char* pwbuf; 225 jstring name = NULL; 226 227 /* allocate buffer for password record */ 228 buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); 229 if (buflen == -1) 230 buflen = ENT_BUF_SIZE; 231 pwbuf = (char*)malloc(buflen); 232 if (pwbuf == NULL) { 233 JNU_ThrowOutOfMemoryError(env, "Unable to open getpwent"); 234 } else { 235 struct passwd pwent; 236 struct passwd* p = NULL; 237 238 #ifdef __solaris__ 239 RESTARTABLE_RETURN_PTR(getpwuid_r(uid, &pwent, pwbuf, (size_t)buflen), p); 240 #else 241 RESTARTABLE(getpwuid_r(uid, &pwent, pwbuf, (size_t)buflen, &p), result); 242 #endif 243 244 // Return the Java String if a name was found 245 if (result == 0 && p != NULL && 246 p->pw_name != NULL && *(p->pw_name) != '\0') { 247 name = JNU_NewStringPlatform(env, p->pw_name); 248 } 249 free(pwbuf); 250 } 251 return name; 252 } 253 254 /** 255 * Implementations of ProcessHandleImpl functions that are common to 256 * (some) Unix variants: 257 * - getProcessPids0(pid, pidArray, parentArray) 258 */ 259 260 #if defined(__linux__) || defined(__AIX__) 261 262 /* 263 * Signatures for internal OS specific functions. 264 */ 265 static pid_t getStatInfo(JNIEnv *env, pid_t pid, 266 jlong *totalTime, jlong* startTime); 267 static void getCmdlineInfo(JNIEnv *env, pid_t pid, jobject jinfo); 268 static long long getBoottime(JNIEnv *env); 269 270 jstring uidToUser(JNIEnv* env, uid_t uid); 271 272 /* Field id for jString 'command' in java.lang.ProcessHandleImpl.Info */ 273 static jfieldID ProcessHandleImpl_Info_commandID; 274 275 /* Field id for jString[] 'arguments' in java.lang.ProcessHandleImpl.Info */ 276 static jfieldID ProcessHandleImpl_Info_argumentsID; 277 278 /* Field id for jlong 'totalTime' in java.lang.ProcessHandleImpl.Info */ 279 static jfieldID ProcessHandleImpl_Info_totalTimeID; 280 281 /* Field id for jlong 'startTime' in java.lang.ProcessHandleImpl.Info */ 282 static jfieldID ProcessHandleImpl_Info_startTimeID; 283 284 /* Field id for jString 'user' in java.lang.ProcessHandleImpl.Info */ 285 static jfieldID ProcessHandleImpl_Info_userID; 286 287 /* static value for clock ticks per second. */ 288 static long clock_ticks_per_second; 289 290 /* A static offset in milliseconds since boot. */ 291 static long long bootTime_ms; 292 293 /************************************************************** 294 * Static method to initialize field IDs and the ticks per second rate. 295 * 296 * Class: java_lang_ProcessHandleImpl_Info 297 * Method: initIDs 298 * Signature: ()V 299 */ 300 JNIEXPORT void JNICALL 301 Java_java_lang_ProcessHandleImpl_00024Info_initIDs(JNIEnv *env, jclass clazz) { 302 303 CHECK_NULL(ProcessHandleImpl_Info_commandID = (*env)->GetFieldID(env, 304 clazz, "command", "Ljava/lang/String;")); 305 CHECK_NULL(ProcessHandleImpl_Info_argumentsID = (*env)->GetFieldID(env, 306 clazz, "arguments", "[Ljava/lang/String;")); 307 CHECK_NULL(ProcessHandleImpl_Info_totalTimeID = (*env)->GetFieldID(env, 308 clazz, "totalTime", "J")); 309 CHECK_NULL(ProcessHandleImpl_Info_startTimeID = (*env)->GetFieldID(env, 310 clazz, "startTime", "J")); 311 CHECK_NULL(ProcessHandleImpl_Info_userID = (*env)->GetFieldID(env, 312 clazz, "user", "Ljava/lang/String;")); 313 } 314 315 /************************************************************** 316 * Static method to initialize the ticks per second rate. 317 * 318 * Class: java_lang_ProcessHandleImpl 319 * Method: initNative 320 * Signature: ()V 321 */ 322 JNIEXPORT void JNICALL 323 Java_java_lang_ProcessHandleImpl_initNative(JNIEnv *env, jclass clazz) { 324 clock_ticks_per_second = sysconf(_SC_CLK_TCK); 325 bootTime_ms = getBoottime(env); 326 } 327 328 /* 329 * Check if a process is alive. 330 * Return the start time (ms since 1970) if it is available. 331 * If the start time is not available return 0. 332 * If the pid is invalid, return -1. 333 * 334 * Class: java_lang_ProcessHandleImpl 335 * Method: isAlive0 336 * Signature: (J)J 337 */ 338 JNIEXPORT jlong JNICALL 339 Java_java_lang_ProcessHandleImpl_isAlive0(JNIEnv *env, jobject obj, jlong jpid) { 340 pid_t pid = (pid_t) jpid; 341 jlong startTime = 0L; 342 jlong totalTime = 0L; 343 pid_t ppid = getStatInfo(env, pid, &totalTime, &startTime); 344 return (ppid <= 0) ? -1 : startTime; 345 } 346 347 /* 348 * Returns the parent pid of the requested pid. 349 * The start time of the process must match (or be ANY). 350 * 351 * Class: java_lang_ProcessHandleImpl 352 * Method: parent0 353 * Signature: (J)J 354 */ 355 JNIEXPORT jlong JNICALL 356 Java_java_lang_ProcessHandleImpl_parent0(JNIEnv *env, 357 jobject obj, 358 jlong jpid, 359 jlong startTime) { 360 pid_t pid = (pid_t) jpid; 361 pid_t ppid; 362 363 pid_t mypid = getpid(); 364 if (pid == mypid) { 365 ppid = getppid(); 366 } else { 367 jlong start = 0L;; 368 jlong total = 0L; // unused 369 ppid = getStatInfo(env, pid, &total, &start); 370 if (start != startTime && start != 0 && startTime != 0) { 371 ppid = -1; 372 } 373 } 374 return (jlong) ppid; 375 } 376 377 /* 378 * Returns the children of the requested pid and optionally each parent. 379 * Reads /proc and accumulates any process who parent pid matches. 380 * The resulting pids are stored into the array of longs. 381 * The number of pids is returned if they all fit. 382 * If the array is too short, the negative of the desired length is returned. * 383 * Class: java_lang_ProcessHandleImpl 384 * Method: getChildPids 385 * Signature: (J[J[J)I 386 */ 387 JNIEXPORT jint JNICALL 388 Java_java_lang_ProcessHandleImpl_getProcessPids0(JNIEnv *env, 389 jclass clazz, 390 jlong jpid, 391 jlongArray jarray, 392 jlongArray jparentArray, 393 jlongArray jstimesArray) { 394 395 DIR* dir; 396 struct dirent* ptr; 397 pid_t pid = (pid_t) jpid; 398 jlong* pids = NULL; 399 jlong* ppids = NULL; 400 jlong* stimes = NULL; 401 jsize parentArraySize = 0; 402 jsize arraySize = 0; 403 jsize stimesSize = 0; 404 jsize count = 0; 405 406 arraySize = (*env)->GetArrayLength(env, jarray); 407 JNU_CHECK_EXCEPTION_RETURN(env, -1); 408 if (jparentArray != NULL) { 409 parentArraySize = (*env)->GetArrayLength(env, jparentArray); 410 JNU_CHECK_EXCEPTION_RETURN(env, -1); 411 412 if (arraySize != parentArraySize) { 413 JNU_ThrowIllegalArgumentException(env, "array sizes not equal"); 414 return 0; 415 } 416 } 417 if (jstimesArray != NULL) { 418 stimesSize = (*env)->GetArrayLength(env, jstimesArray); 419 JNU_CHECK_EXCEPTION_RETURN(env, -1); 420 421 if (arraySize != stimesSize) { 422 JNU_ThrowIllegalArgumentException(env, "array sizes not equal"); 423 return 0; 424 } 425 } 426 427 /* 428 * To locate the children we scan /proc looking for files that have a 429 * position integer as a filename. 430 */ 431 if ((dir = opendir("/proc")) == NULL) { 432 JNU_ThrowByNameWithLastError(env, 433 "java/lang/RuntimeException", "Unable to open /proc"); 434 return -1; 435 } 436 437 do { // Block to break out of on Exception 438 pids = (*env)->GetLongArrayElements(env, jarray, NULL); 439 if (pids == NULL) { 440 break; 441 } 442 if (jparentArray != NULL) { 443 ppids = (*env)->GetLongArrayElements(env, jparentArray, NULL); 444 if (ppids == NULL) { 445 break; 446 } 447 } 448 if (jstimesArray != NULL) { 449 stimes = (*env)->GetLongArrayElements(env, jstimesArray, NULL); 450 if (stimes == NULL) { 451 break; 452 } 453 } 454 455 while ((ptr = readdir(dir)) != NULL) { 456 pid_t ppid = 0; 457 jlong totalTime = 0L; 458 jlong startTime = 0L; 459 460 /* skip files that aren't numbers */ 461 pid_t childpid = (pid_t) atoi(ptr->d_name); 462 if ((int) childpid <= 0) { 463 continue; 464 } 465 // Read /proc/pid/stat and get the parent pid, and start time 466 ppid = getStatInfo(env, childpid, &totalTime, &startTime); 467 if (ppid > 0 && (pid == 0 || ppid == pid)) { 468 if (count < arraySize) { 469 // Only store if it fits 470 pids[count] = (jlong) childpid; 471 472 if (ppids != NULL) { 473 // Store the parentPid 474 ppids[count] = (jlong) ppid; 475 } 476 if (stimes != NULL) { 477 // Store the process start time 478 stimes[count] = startTime; 479 } 480 } 481 count++; // Count to tabulate size needed 482 } 483 } 484 } while (0); 485 486 if (pids != NULL) { 487 (*env)->ReleaseLongArrayElements(env, jarray, pids, 0); 488 } 489 if (ppids != NULL) { 490 (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0); 491 } 492 if (stimes != NULL) { 493 (*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0); 494 } 495 496 closedir(dir); 497 // If more pids than array had size for; count will be greater than array size 498 return count; 499 } 500 501 502 /************************************************************** 503 * Implementation of ProcessHandleImpl_Info native methods. 504 */ 505 506 /* 507 * Fill in the Info object from the OS information about the process. 508 * 509 * Class: java_lang_ProcessHandleImpl_Info 510 * Method: info0 511 * Signature: (JLjava/lang/ProcessHandle/Info;)I 512 */ 513 JNIEXPORT void JNICALL 514 Java_java_lang_ProcessHandleImpl_00024Info_info0(JNIEnv *env, 515 jobject jinfo, 516 jlong jpid) { 517 pid_t pid = (pid_t) jpid; 518 pid_t ppid; 519 jlong totalTime = 0L; 520 jlong startTime = -1L; 521 522 ppid = getStatInfo(env, pid, &totalTime, &startTime); 523 if (ppid > 0) { 524 (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, totalTime); 525 JNU_CHECK_EXCEPTION(env); 526 527 (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime); 528 JNU_CHECK_EXCEPTION(env); 529 530 getCmdlineInfo(env, pid, jinfo); 531 } 532 } 533 534 /** 535 * Read /proc/<pid>/stat and return the ppid, total cputime and start time. 536 * -1 is fail; zero is unknown; > 0 is parent pid 537 */ 538 static pid_t getStatInfo(JNIEnv *env, pid_t pid, 539 jlong *totalTime, jlong* startTime) { 540 FILE* fp; 541 char buffer[2048]; 542 int statlen; 543 char fn[32]; 544 char* s; 545 int parentPid; 546 long unsigned int utime = 0; // clock tics 547 long unsigned int stime = 0; // clock tics 548 long long unsigned int start = 0; // microseconds 549 550 /* 551 * Try to stat and then open /proc/%d/stat 552 */ 553 snprintf(fn, sizeof fn, STAT_FILE, pid); 554 555 fp = fopen(fn, "r"); 556 if (fp == NULL) { 557 return -1; // fail, no such /proc/pid/stat 558 } 559 560 /* 561 * The format is: pid (command) state ppid ... 562 * As the command could be anything we must find the right most 563 * ")" and then skip the white spaces that follow it. 564 */ 565 statlen = fread(buffer, 1, (sizeof buffer - 1), fp); 566 fclose(fp); 567 if (statlen < 0) { 568 return 0; // parent pid is not available 569 } 570 571 buffer[statlen] = '\0'; 572 s = strchr(buffer, '('); 573 if (s == NULL) { 574 return 0; // parent pid is not available 575 } 576 // Found start of command, skip to end 577 s++; 578 s = strrchr(s, ')'); 579 if (s == NULL) { 580 return 0; // parent pid is not available 581 } 582 s++; 583 584 // Scan the needed fields from status, retaining only ppid(4), 585 // utime (14), stime(15), starttime(22) 586 if (4 != sscanf(s, " %*c %d %*d %*d %*d %*d %*d %*u %*u %*u %*u %lu %lu %*d %*d %*d %*d %*d %*d %llu", 587 &parentPid, &utime, &stime, &start)) { 588 return 0; // not all values parsed; return error 589 } 590 591 *totalTime = (utime + stime) * (jlong)(1000000000 / clock_ticks_per_second); 592 593 *startTime = bootTime_ms + ((start * 1000) / clock_ticks_per_second); 594 595 return parentPid; 596 } 597 598 /** 599 * Construct the argument array by parsing the arguments from the sequence 600 * of arguments. The zero'th arg is the command executable 601 */ 602 static int fillArgArray(JNIEnv *env, jobject jinfo, 603 int nargs, char *cp, char *argsEnd, jstring cmdexe) { 604 jobject argsArray; 605 int i; 606 607 if (nargs < 1) { 608 return 0; 609 } 610 611 if (cmdexe == NULL) { 612 // Create a string from arg[0] 613 CHECK_NULL_RETURN((cmdexe = JNU_NewStringPlatform(env, cp)), -1); 614 } 615 (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_commandID, cmdexe); 616 JNU_CHECK_EXCEPTION_RETURN(env, -3); 617 618 // Create a String array for nargs-1 elements 619 argsArray = (*env)->NewObjectArray(env, nargs - 1, JNU_ClassString(env), NULL); 620 CHECK_NULL_RETURN(argsArray, -1); 621 622 for (i = 0; i < nargs - 1; i++) { 623 jstring str = NULL; 624 625 cp += strnlen(cp, (argsEnd - cp)) + 1; 626 if (cp > argsEnd || *cp == '\0') { 627 return -2; // Off the end pointer or an empty argument is an error 628 } 629 630 CHECK_NULL_RETURN((str = JNU_NewStringPlatform(env, cp)), -1); 631 632 (*env)->SetObjectArrayElement(env, argsArray, i, str); 633 JNU_CHECK_EXCEPTION_RETURN(env, -3); 634 } 635 (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_argumentsID, argsArray); 636 JNU_CHECK_EXCEPTION_RETURN(env, -4); 637 return 0; 638 } 639 640 641 static void getCmdlineInfo(JNIEnv *env, pid_t pid, jobject jinfo) { 642 int fd; 643 int cmdlen = 0; 644 char *cmdline = NULL, *cmdEnd; // used for command line args and exe 645 jstring cmdexe = NULL; 646 char fn[32]; 647 struct stat stat_buf; 648 649 /* 650 * Try to open /proc/%d/cmdline 651 */ 652 snprintf(fn, sizeof fn, "/proc/%d/cmdline", pid); 653 if ((fd = open(fn, O_RDONLY)) < 0) { 654 return; 655 } 656 657 do { // Block to break out of on errors 658 int i; 659 char *s; 660 661 cmdline = (char*)malloc(PATH_MAX); 662 if (cmdline == NULL) { 663 break; 664 } 665 666 /* 667 * The path to the executable command is the link in /proc/<pid>/exe. 668 */ 669 snprintf(fn, sizeof fn, "/proc/%d/exe", pid); 670 if ((cmdlen = readlink(fn, cmdline, PATH_MAX - 1)) > 0) { 671 // null terminate and create String to store for command 672 cmdline[cmdlen] = '\0'; 673 cmdexe = JNU_NewStringPlatform(env, cmdline); 674 (*env)->ExceptionClear(env); // unconditionally clear any exception 675 } 676 677 /* 678 * The buffer format is the arguments nul terminated with an extra nul. 679 */ 680 cmdlen = read(fd, cmdline, PATH_MAX-1); 681 if (cmdlen < 0) { 682 break; 683 } 684 685 // Terminate the buffer and count the arguments 686 cmdline[cmdlen] = '\0'; 687 cmdEnd = &cmdline[cmdlen + 1]; 688 for (s = cmdline,i = 0; *s != '\0' && (s < cmdEnd); i++) { 689 s += strnlen(s, (cmdEnd - s)) + 1; 690 } 691 692 if (fillArgArray(env, jinfo, i, cmdline, cmdEnd, cmdexe) < 0) { 693 break; 694 } 695 696 // Get and store the user name 697 if (fstat(fd, &stat_buf) == 0) { 698 jstring name = uidToUser(env, stat_buf.st_uid); 699 if (name != NULL) { 700 (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, name); 701 } 702 } 703 } while (0); 704 705 if (cmdline != NULL) { 706 free(cmdline); 707 } 708 if (fd >= 0) { 709 close(fd); 710 } 711 } 712 713 /** 714 * Read the boottime from /proc/stat. 715 */ 716 static long long getBoottime(JNIEnv *env) { 717 FILE *fp; 718 char *line = NULL; 719 size_t len = 0; 720 long long bootTime = 0; 721 722 fp = fopen("/proc/stat", "r"); 723 if (fp == NULL) { 724 return -1; 725 } 726 727 while (getline(&line, &len, fp) != -1) { 728 if (sscanf(line, "btime %llu", &bootTime) == 1) { 729 break; 730 } 731 } 732 free(line); 733 734 if (fp != 0) { 735 fclose(fp); 736 } 737 738 return bootTime * 1000; 739 } 740 741 #endif // defined(__linux__) || defined(__AIX__) 742 743 744 /* Block until a child process exits and return its exit code. 745 Note, can only be called once for any given pid. */ 746 JNIEXPORT jint JNICALL 747 Java_java_lang_ProcessImpl_waitForProcessExit(JNIEnv* env, 748 jobject junk, 749 jint pid) 750 { 751 /* We used to use waitid() on Solaris, waitpid() on Linux, but 752 * waitpid() is more standard, so use it on all POSIX platforms. */ 753 int status; 754 /* Wait for the child process to exit. This returns immediately if 755 the child has already exited. */ 756 while (waitpid(pid, &status, 0) < 0) { 757 switch (errno) { 758 case ECHILD: return 0; 759 case EINTR: break; 760 default: return -1; 761 } 762 } 763 764 if (WIFEXITED(status)) { 765 /* 766 * The child exited normally; get its exit code. 767 */ 768 return WEXITSTATUS(status); 769 } else if (WIFSIGNALED(status)) { 770 /* The child exited because of a signal. 771 * The best value to return is 0x80 + signal number, 772 * because that is what all Unix shells do, and because 773 * it allows callers to distinguish between process exit and 774 * process death by signal. 775 * Unfortunately, the historical behavior on Solaris is to return 776 * the signal number, and we preserve this for compatibility. */ 777 #ifdef __solaris__ 778 return WTERMSIG(status); 779 #else 780 return 0x80 + WTERMSIG(status); 781 #endif 782 } else { 783 /* 784 * Unknown exit code; pass it through. 785 */ 786 return status; 787 } 788 } 789 790