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 #include <ctype.h>
34 #include <dirent.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <procfs.h>
38 #include <signal.h>
39 #include <stdlib.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <unistd.h>
43 #include <limits.h>
44
45 /**
46 * Implementations of ProcessHandleImpl functions that are
47 * NOT common to all Unix variants:
48 * - getProcessPids0(pid, pidArray)
49 *
50 * Implementations of ProcessHandleImpl_Info
51 * - totalTime, startTime
52 * - Command
53 * - Arguments
54 */
55
56 /*
57 * Signatures for internal OS specific functions.
58 */
59 static pid_t getStatInfo(JNIEnv *env, pid_t pid,
60 jlong *totalTime, jlong* startTime,
61 uid_t *uid);
62 static void getCmdlineInfo(JNIEnv *env, jobject jinfo, pid_t pid);
63
64 extern jstring uidToUser(JNIEnv* env, uid_t uid);
65
66 /* Field id for jString 'command' in java.lang.ProcessHandle.Info */
67 static jfieldID ProcessHandleImpl_Info_commandID;
68
69 /* Field id for jString[] 'arguments' in java.lang.ProcessHandle.Info */
70 static jfieldID ProcessHandleImpl_Info_argumentsID;
71
72 /* Field id for jlong 'totalTime' in java.lang.ProcessHandle.Info */
73 static jfieldID ProcessHandleImpl_Info_totalTimeID;
74
75 /* Field id for jlong 'startTime' in java.lang.ProcessHandle.Info */
76 static jfieldID ProcessHandleImpl_Info_startTimeID;
77
78 /* Field id for jString 'user' in java.lang.ProcessHandleImpl.Info */
79 static jfieldID ProcessHandleImpl_Info_userID;
80
81 /* static value for clock ticks per second. */
82 static long clock_ticks_per_second;
83
84 /**************************************************************
85 * Static method to initialize field IDs and the ticks per second rate.
86 *
87 * Class: java_lang_ProcessHandleImpl_Info
88 * Method: initIDs
89 * Signature: ()V
90 */
91 JNIEXPORT void JNICALL
92 Java_java_lang_ProcessHandleImpl_00024Info_initIDs(JNIEnv *env, jclass clazz) {
93 CHECK_NULL(ProcessHandleImpl_Info_commandID = (*env)->GetFieldID(env,
94 clazz, "command", "Ljava/lang/String;"));
95 CHECK_NULL(ProcessHandleImpl_Info_argumentsID = (*env)->GetFieldID(env,
96 clazz, "arguments", "[Ljava/lang/String;"));
97 CHECK_NULL(ProcessHandleImpl_Info_totalTimeID = (*env)->GetFieldID(env,
98 clazz, "totalTime", "J"));
99 CHECK_NULL(ProcessHandleImpl_Info_startTimeID = (*env)->GetFieldID(env,
100 clazz, "startTime", "J"));
101 CHECK_NULL(ProcessHandleImpl_Info_userID = (*env)->GetFieldID(env,
102 clazz, "user", "Ljava/lang/String;"));
103 }
104
105 /**************************************************************
106 * Static method to initialize the ticks per second rate.
107 *
108 * Class: java_lang_ProcessHandleImpl
109 * Method: initNative
110 * Signature: ()V
111 */
112 JNIEXPORT void JNICALL
113 Java_java_lang_ProcessHandleImpl_initNative(JNIEnv *env, jclass clazz) {
114 clock_ticks_per_second = sysconf(_SC_CLK_TCK);
115 }
116
117 /*
118 * Check if a process is alive.
119 * Return the start time (ms since 1970) if it is available.
120 * If the start time is not available return 0.
121 * If the pid is invalid, return -1.
122 *
123 * Class: java_lang_ProcessHandleImpl
124 * Method: isAlive0
125 * Signature: (J)J
126 */
127 JNIEXPORT jlong JNICALL
128 Java_java_lang_ProcessHandleImpl_isAlive0(JNIEnv *env, jobject obj, jlong jpid) {
129 pid_t pid = (pid_t) jpid;
130 jlong startTime = 0L;
131 jlong totalTime = 0L;
132 uid_t uid = -1;
133 pid_t ppid = getStatInfo(env, pid, &totalTime, &startTime, &uid);
134 return (ppid < 0) ? -1 : startTime;
135 }
136
137 /*
138 * Returns the parent pid of the requested pid.
139 *
140 * Class: java_lang_ProcessHandleImpl
141 * Method: parent0
142 * Signature: (J)J
143 */
144 JNIEXPORT jlong JNICALL
145 Java_java_lang_ProcessHandleImpl_parent0(JNIEnv *env,
146 jobject obj,
147 jlong jpid,
148 jlong startTime) {
149 pid_t pid = (pid_t) jpid;
150 pid_t ppid = -1;
151
152 if (pid == getpid()) {
153 ppid = getppid();
154 } else {
155 jlong start = 0L;
156 jlong total = 0L;
157 uid_t uid = -1;
158
159 pid_t ppid = getStatInfo(env, pid, &total, &start, &uid);
160 if (start != startTime
161 && start != 0
162 && startTime != 0) {
163 ppid = -1;
164 }
165 }
166 return (jlong) ppid;
167 }
168
169 /*
170 * Returns the children of the requested pid and optionally each parent.
171 *
172 * Class: java_lang_ProcessHandleImpl
173 * Method: getChildPids
174 * Signature: (J[J)I
175 *
176 * Reads /proc and accumulates any process who parent pid matches.
177 * The resulting pids are stored into the array of longs.
178 * The number of pids is returned if they all fit.
179 * If the array is too short, the desired length is returned.
180 */
181 JNIEXPORT jint JNICALL
182 Java_java_lang_ProcessHandleImpl_getProcessPids0(JNIEnv *env,
183 jclass clazz,
184 jlong jpid,
185 jlongArray jarray,
186 jlongArray jparentArray,
187 jlongArray jstimesArray) {
188 DIR* dir;
189 struct dirent* ptr;
190 pid_t pid = (pid_t) jpid;
191 jlong* pids = NULL;
192 jlong* ppids = NULL;
193 jlong* stimes = NULL;
194 jsize parentArraySize = 0;
195 jsize arraySize = 0;
196 jsize stimesSize = 0;
197 jsize count = 0;
198 char procname[32];
199
200 arraySize = (*env)->GetArrayLength(env, jarray);
201 JNU_CHECK_EXCEPTION_RETURN(env, 0);
202 if (jparentArray != NULL) {
203 parentArraySize = (*env)->GetArrayLength(env, jparentArray);
204 JNU_CHECK_EXCEPTION_RETURN(env, 0);
205
206 if (arraySize != parentArraySize) {
207 JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
208 return 0;
209 }
210 }
211 if (jstimesArray != NULL) {
212 stimesSize = (*env)->GetArrayLength(env, jstimesArray);
213 JNU_CHECK_EXCEPTION_RETURN(env, -1);
214
215 if (arraySize != stimesSize) {
216 JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
217 return 0;
218 }
219 }
220
221 /*
222 * To locate the children we scan /proc looking for files that have a
223 * positive integer as a filename.
224 */
225 if ((dir = opendir("/proc")) == NULL) {
226 JNU_ThrowByNameWithLastError(env,
227 "java/lang/Runtime", "Unable to open /proc");
228 return 0;
229 }
230
231 do { // Block to break out of on Exception
232 pids = (*env)->GetLongArrayElements(env, jarray, NULL);
233 if (pids == NULL) {
234 break;
235 }
236 if (jparentArray != NULL) {
237 ppids = (*env)->GetLongArrayElements(env, jparentArray, NULL);
238 if (ppids == NULL) {
239 break;
240 }
241 }
242 if (jstimesArray != NULL) {
243 stimes = (*env)->GetLongArrayElements(env, jstimesArray, NULL);
244 if (stimes == NULL) {
245 break;
246 }
247 }
248
249 while ((ptr = readdir(dir)) != NULL) {
250 pid_t ppid = 0;
251 jlong totalTime = 0L;
252 jlong startTime = 0L;
253 uid_t uid; // value unused
254
255 /* skip files that aren't numbers */
256 pid_t childpid = (pid_t) atoi(ptr->d_name);
257 if ((int) childpid <= 0) {
258 continue;
259 }
260
261 // Read /proc/pid/stat and get the parent pid, and start time
262 ppid = getStatInfo(env, childpid, &totalTime, &startTime, &uid);
263 if (ppid >= 0 && (pid == 0 || ppid == pid)) {
264 if (count < arraySize) {
265 // Only store if it fits
266 pids[count] = (jlong) childpid;
267
268 if (ppids != NULL) {
269 // Store the parent Pid
270 ppids[count] = (jlong) ppid;
271 }
272 if (stimes != NULL) {
273 // Store the process start time
274 stimes[count] = startTime;
275 }
276 }
277 count++; // Count to tabulate size needed
278 }
279 }
280 } while (0);
281
282 if (pids != NULL) {
283 (*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
284 }
285 if (ppids != NULL) {
286 (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
287 }
288 if (stimes != NULL) {
289 (*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0);
290 }
291
292 closedir(dir);
293 // If more pids than array had size for; count will be greater than array size
294 return count;
295 }
296
297 /**************************************************************
298 * Implementation of ProcessHandleImpl_Info native methods.
299 */
300
301 /*
302 * Fill in the Info object from the OS information about the process.
303 *
304 * Class: java_lang_ProcessHandleImpl_Info
305 * Method: info0
306 * Signature: (J)V
307 */
308 JNIEXPORT void JNICALL
309 Java_java_lang_ProcessHandleImpl_00024Info_info0(JNIEnv *env,
310 jobject jinfo,
311 jlong jpid) {
312 pid_t pid = (pid_t) jpid;
313 jlong startTime = 0L;
314 jlong totalTime = 0L;
315 uid_t uid = -1;
316 pid_t ppid = getStatInfo(env, pid, &totalTime, &startTime, &uid);
317
318 getCmdlineInfo(env, jinfo, pid);
319
320 if (ppid > 0) {
321 jstring str;
322 (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
323 JNU_CHECK_EXCEPTION(env);
324
325 (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, totalTime);
326 JNU_CHECK_EXCEPTION(env);
327
328 CHECK_NULL((str = uidToUser(env, uid)));
329 (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, str);
330 JNU_CHECK_EXCEPTION(env);
331 }
332 }
333
334 /**
335 * Read /proc/<pid>/status and return the ppid, total cputime and start time.
336 * Return: -1 is fail; zero is unknown; > 0 is parent pid
337 */
338 static pid_t getStatInfo(JNIEnv *env, pid_t pid,
339 jlong *totalTime, jlong* startTime,
340 uid_t* uid) {
341 FILE* fp;
342 psinfo_t psinfo;
343 char fn[32];
344 int ret;
345
346 /*
347 * Try to open /proc/%d/status
348 */
349 snprintf(fn, sizeof fn, "/proc/%d/psinfo", pid);
350 fp = fopen(fn, "r");
351 if (fp == NULL) {
352 return -1;
353 }
354
355 ret = fread(&psinfo, 1, (sizeof psinfo), fp);
356 fclose(fp);
357 if (ret < (sizeof psinfo)) {
358 return -1;
359 }
360
361 *totalTime = psinfo.pr_time.tv_sec * 1000000000L + psinfo.pr_time.tv_nsec;
362
363 *startTime = psinfo.pr_start.tv_sec * (jlong)1000 +
364 psinfo.pr_start.tv_nsec / 1000000;
365
366 *uid = psinfo.pr_uid;
367
368 return (pid_t) psinfo.pr_ppid;
369 }
370
371 static void getCmdlineInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
372 char fn[32];
373 char exePath[PATH_MAX];
374 jstring str = NULL;
375 int ret;
376
377 /*
378 * The path to the executable command is the link in /proc/<pid>/paths/a.out.
379 */
380 snprintf(fn, sizeof fn, "/proc/%d/path/a.out", pid);
381 if ((ret = readlink(fn, exePath, PATH_MAX - 1)) < 0) {
382 return;
383 }
384
385 // null terminate and create String to store for command
386 exePath[ret] = '\0';
387 CHECK_NULL(str = JNU_NewStringPlatform(env, exePath));
388 (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_commandID, str);
389 JNU_CHECK_EXCEPTION(env);
390 }
391
|
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 #include "ProcessHandleImpl_unix.h"
32
33
34 #include <stdio.h>
35 #include <procfs.h>
36
37 /*
38 * Implementation of native ProcessHandleImpl functions for Solaris.
39 * See ProcessHandleImpl_unix.c for more details.
40 */
41
42 void os_initNative(JNIEnv *env, jclass clazz) {}
43
44 uid_t os_getUID(pid_t pid) {
45 return unix_getUID(pid);
46 }
47
48 jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray,
49 jlongArray jparentArray, jlongArray jstimesArray) {
50 return unix_getChildren(env, jpid, jarray, jparentArray, jstimesArray);
51 }
52
53 pid_t os_getParentPid(JNIEnv *env, pid_t pid, jlong *total, jlong *start) {
54 return unix_getParentPid(env, pid, total, start);
55 }
56
57 void os_getCmdlineInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
58 unix_getCmdlineInfo(env, jinfo, pid);
59 }
60
|