| 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 |