OLD | NEW |
| (Empty) |
1 /* | |
2 * $Id: process_info.c 1142 2011-10-05 18:45:49Z g.rodola $ | |
3 * | |
4 * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. | |
5 * Use of this source code is governed by a BSD-style license that can be | |
6 * found in the LICENSE file. | |
7 * | |
8 * Helper functions related to fetching process information. Used by _psutil_osx | |
9 * module methods. | |
10 */ | |
11 | |
12 #include <Python.h> | |
13 #include <assert.h> | |
14 #include <errno.h> | |
15 #include <limits.h> /* for INT_MAX */ | |
16 #include <stdbool.h> | |
17 #include <stdlib.h> | |
18 #include <stdio.h> | |
19 #include <signal.h> | |
20 #include <sys/sysctl.h> | |
21 | |
22 #include "process_info.h" | |
23 #include "../../_psutil_common.h" | |
24 | |
25 | |
26 /* | |
27 * Return 1 if PID exists in the current process list, else 0. | |
28 */ | |
29 int | |
30 pid_exists(long pid) | |
31 { | |
32 int kill_ret; | |
33 | |
34 // save some time if it's an invalid PID | |
35 if (pid < 0) { | |
36 return 0; | |
37 } | |
38 | |
39 // if kill returns success of permission denied we know it's a valid PID | |
40 kill_ret = kill(pid , 0); | |
41 if ( (0 == kill_ret) || (EPERM == errno) ) { | |
42 return 1; | |
43 } | |
44 | |
45 // otherwise return 0 for PID not found | |
46 return 0; | |
47 } | |
48 | |
49 | |
50 | |
51 /* | |
52 * Returns a list of all BSD processes on the system. This routine | |
53 * allocates the list and puts it in *procList and a count of the | |
54 * number of entries in *procCount. You are responsible for freeing | |
55 * this list (use "free" from System framework). | |
56 * On success, the function returns 0. | |
57 * On error, the function returns a BSD errno value. | |
58 */ | |
59 int | |
60 get_proc_list(kinfo_proc **procList, size_t *procCount) | |
61 { | |
62 /* Declaring mib as const requires use of a cast since the | |
63 * sysctl prototype doesn't include the const modifier. */ | |
64 static const int mib3[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL }; | |
65 size_t size, size2; | |
66 void *ptr; | |
67 int err, lim = 8; /* some limit */ | |
68 | |
69 assert( procList != NULL); | |
70 assert(*procList == NULL); | |
71 assert(procCount != NULL); | |
72 | |
73 *procCount = 0; | |
74 | |
75 /* We start by calling sysctl with ptr == NULL and size == 0. | |
76 * That will succeed, and set size to the appropriate length. | |
77 * We then allocate a buffer of at least that size and call | |
78 * sysctl with that buffer. If that succeeds, we're done. | |
79 * If that call fails with ENOMEM, we throw the buffer away | |
80 * and try again. | |
81 * Note that the loop calls sysctl with NULL again. This is | |
82 * is necessary because the ENOMEM failure case sets size to | |
83 * the amount of data returned, not the amount of data that | |
84 * could have been returned. | |
85 */ | |
86 while (lim-- > 0) { | |
87 size = 0; | |
88 if (sysctl((int *)mib3, 3, NULL, &size, NULL, 0) == -1) { | |
89 return errno; | |
90 } | |
91 | |
92 size2 = size + (size >> 3); /* add some */ | |
93 if (size2 > size) { | |
94 ptr = malloc(size2); | |
95 if (ptr == NULL) { | |
96 ptr = malloc(size); | |
97 } else { | |
98 size = size2; | |
99 } | |
100 } | |
101 else { | |
102 ptr = malloc(size); | |
103 } | |
104 if (ptr == NULL) { | |
105 return ENOMEM; | |
106 } | |
107 | |
108 if (sysctl((int *)mib3, 3, ptr, &size, NULL, 0) == -1) { | |
109 err = errno; | |
110 free(ptr); | |
111 if (err != ENOMEM) { | |
112 return err; | |
113 } | |
114 | |
115 } else { | |
116 *procList = (kinfo_proc *)ptr; | |
117 *procCount = size / sizeof(kinfo_proc); | |
118 return 0; | |
119 } | |
120 } | |
121 return ENOMEM; | |
122 } | |
123 | |
124 | |
125 /* Read the maximum argument size for processes */ | |
126 int | |
127 get_argmax() | |
128 { | |
129 int argmax; | |
130 int mib[] = { CTL_KERN, KERN_ARGMAX }; | |
131 size_t size = sizeof(argmax); | |
132 | |
133 if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0) { | |
134 return argmax; | |
135 } | |
136 return 0; | |
137 } | |
138 | |
139 | |
140 /* return process args as a python list */ | |
141 PyObject* | |
142 get_arg_list(long pid) | |
143 { | |
144 int mib[3]; | |
145 int nargs; | |
146 int len; | |
147 char *procargs; | |
148 char *arg_ptr; | |
149 char *arg_end; | |
150 char *curr_arg; | |
151 size_t argmax; | |
152 PyObject *arg = NULL; | |
153 PyObject *arglist = NULL; | |
154 | |
155 //special case for PID 0 (kernel_task) where cmdline cannot be fetched | |
156 if (pid == 0) { | |
157 return Py_BuildValue("[]"); | |
158 } | |
159 | |
160 /* read argmax and allocate memory for argument space. */ | |
161 argmax = get_argmax(); | |
162 if (! argmax) { return PyErr_SetFromErrno(PyExc_OSError); } | |
163 | |
164 procargs = (char *)malloc(argmax); | |
165 if (NULL == procargs) { | |
166 return PyErr_SetFromErrno(PyExc_OSError); | |
167 } | |
168 | |
169 /* read argument space */ | |
170 mib[0] = CTL_KERN; | |
171 mib[1] = KERN_PROCARGS2; | |
172 mib[2] = pid; | |
173 if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) { | |
174 if (EINVAL == errno) { // invalid == access denied OR nonexistent PID | |
175 if ( pid_exists(pid) ) { | |
176 AccessDenied(); | |
177 } else { | |
178 NoSuchProcess(); | |
179 } | |
180 } | |
181 free(procargs); | |
182 return NULL; | |
183 } | |
184 | |
185 arg_end = &procargs[argmax]; | |
186 /* copy the number of arguments to nargs */ | |
187 memcpy(&nargs, procargs, sizeof(nargs)); | |
188 | |
189 arg_ptr = procargs + sizeof(nargs); | |
190 len = strlen(arg_ptr); | |
191 arg_ptr += len + 1; | |
192 | |
193 if (arg_ptr == arg_end) { | |
194 free(procargs); | |
195 return Py_BuildValue("[]"); | |
196 } | |
197 | |
198 // skip ahead to the first argument | |
199 for (; arg_ptr < arg_end; arg_ptr++) { | |
200 if (*arg_ptr != '\0') { | |
201 break; | |
202 } | |
203 } | |
204 | |
205 /* iterate through arguments */ | |
206 curr_arg = arg_ptr; | |
207 arglist = Py_BuildValue("[]"); | |
208 while (arg_ptr < arg_end && nargs > 0) { | |
209 if (*arg_ptr++ == '\0') { | |
210 arg = Py_BuildValue("s", curr_arg); | |
211 if (NULL == arg) { | |
212 return NULL; | |
213 } | |
214 PyList_Append(arglist, arg); | |
215 Py_DECREF(arg); | |
216 // iterate to next arg and decrement # of args | |
217 curr_arg = arg_ptr; | |
218 nargs--; | |
219 } | |
220 } | |
221 | |
222 free(procargs); | |
223 return arglist; | |
224 } | |
225 | |
226 | |
227 int | |
228 get_kinfo_proc(pid_t pid, struct kinfo_proc *kp) | |
229 { | |
230 int mib[4]; | |
231 size_t len; | |
232 mib[0] = CTL_KERN; | |
233 mib[1] = KERN_PROC; | |
234 mib[2] = KERN_PROC_PID; | |
235 mib[3] = pid; | |
236 | |
237 // fetch the info with sysctl() | |
238 len = sizeof(struct kinfo_proc); | |
239 | |
240 // now read the data from sysctl | |
241 if (sysctl(mib, 4, kp, &len, NULL, 0) == -1) { | |
242 // raise an exception and throw errno as the error | |
243 PyErr_SetFromErrno(PyExc_OSError); | |
244 } | |
245 | |
246 /* | |
247 * sysctl succeeds but len is zero, happens when process has gone away | |
248 */ | |
249 if (len == 0) { | |
250 NoSuchProcess(); | |
251 return -1; | |
252 } | |
253 return 0; | |
254 } | |
OLD | NEW |