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