| Index: third_party/psutil/psutil/arch/osx/process_info.c
|
| diff --git a/third_party/psutil/psutil/arch/osx/process_info.c b/third_party/psutil/psutil/arch/osx/process_info.c
|
| index 53b04098f67066104d784969d88af7cbd3a0d607..ae7d4071459cae959ba0b9947305d8b3c72b6042 100644
|
| --- a/third_party/psutil/psutil/arch/osx/process_info.c
|
| +++ b/third_party/psutil/psutil/arch/osx/process_info.c
|
| @@ -1,5 +1,9 @@
|
| /*
|
| - * $Id: process_info.c 772 2010-11-03 13:51:11Z g.rodola $
|
| + * $Id: process_info.c 1142 2011-10-05 18:45:49Z g.rodola $
|
| + *
|
| + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| *
|
| * Helper functions related to fetching process information. Used by _psutil_osx
|
| * module methods.
|
| @@ -12,11 +16,35 @@
|
| #include <stdbool.h>
|
| #include <stdlib.h>
|
| #include <stdio.h>
|
| +#include <signal.h>
|
| #include <sys/sysctl.h>
|
|
|
| #include "process_info.h"
|
| +#include "../../_psutil_common.h"
|
| +
|
|
|
| -#define ARGS_ACCESS_DENIED -2
|
| +/*
|
| + * Return 1 if PID exists in the current process list, else 0.
|
| + */
|
| +int
|
| +pid_exists(long pid)
|
| +{
|
| + int kill_ret;
|
| +
|
| + // save some time if it's an invalid PID
|
| + if (pid < 0) {
|
| + return 0;
|
| + }
|
| +
|
| + // if kill returns success of permission denied we know it's a valid PID
|
| + kill_ret = kill(pid , 0);
|
| + if ( (0 == kill_ret) || (EPERM == errno) ) {
|
| + return 1;
|
| + }
|
| +
|
| + // otherwise return 0 for PID not found
|
| + return 0;
|
| +}
|
|
|
|
|
|
|
| @@ -94,179 +122,105 @@ get_proc_list(kinfo_proc **procList, size_t *procCount)
|
| }
|
|
|
|
|
| -/*
|
| - * Modified from psi Python System Information project
|
| - *
|
| - * Get command path, arguments and environment variables.
|
| - *
|
| - * Based on code from ps.
|
| - *
|
| - * Returns:
|
| - * 0 for success
|
| - * 1 for sysctl error, errno exception raised
|
| - * -1 for failure, system or memory exception raised
|
| - * -2 rather ARGS_ACCESS_DENIED, for insufficient privileges
|
| - */
|
| +/* Read the maximum argument size for processes */
|
| int
|
| -getcmdargs(long pid, PyObject **exec_path, PyObject **envlist, PyObject **arglist)
|
| +get_argmax()
|
| {
|
| - int nargs, mib[3];
|
| - size_t size, argmax;
|
| - char *curr_arg, *start_args, *iter_args, *end_args;
|
| - char *procargs = NULL;
|
| - char *err = NULL;
|
| - PyObject *arg;
|
| -
|
| - *arglist = Py_BuildValue("[]"); /* empty list */
|
| - if (*arglist == NULL) {
|
| - err = "getcmdargs(): arglist exception";
|
| - goto ERROR_RETURN;
|
| + int argmax;
|
| + int mib[] = { CTL_KERN, KERN_ARGMAX };
|
| + size_t size = sizeof(argmax);
|
| +
|
| + if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0) {
|
| + return argmax;
|
| }
|
| + return 0;
|
| +}
|
|
|
| - /* Get the maximum process arguments size. */
|
| - mib[0] = CTL_KERN;
|
| - mib[1] = KERN_ARGMAX;
|
|
|
| - size = sizeof(argmax);
|
| - if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) {
|
| - PyErr_SetFromErrno(NULL);
|
| - return errno;
|
| +/* return process args as a python list */
|
| +PyObject*
|
| +get_arg_list(long pid)
|
| +{
|
| + int mib[3];
|
| + int nargs;
|
| + int len;
|
| + char *procargs;
|
| + char *arg_ptr;
|
| + char *arg_end;
|
| + char *curr_arg;
|
| + size_t argmax;
|
| + PyObject *arg = NULL;
|
| + PyObject *arglist = NULL;
|
| +
|
| + //special case for PID 0 (kernel_task) where cmdline cannot be fetched
|
| + if (pid == 0) {
|
| + return Py_BuildValue("[]");
|
| }
|
|
|
| - /* Allocate space for the arguments. */
|
| + /* read argmax and allocate memory for argument space. */
|
| + argmax = get_argmax();
|
| + if (! argmax) { return PyErr_SetFromErrno(PyExc_OSError); }
|
| +
|
| procargs = (char *)malloc(argmax);
|
| - if (procargs == NULL) {
|
| - PyErr_SetString(PyExc_MemoryError,
|
| - "getcmdargs(): insufficient memory for procargs");
|
| - return ENOMEM;
|
| + if (NULL == procargs) {
|
| + return PyErr_SetFromErrno(PyExc_OSError);
|
| }
|
|
|
| - /*
|
| - * Make a sysctl() call to get the raw argument space of the process.
|
| - */
|
| + /* read argument space */
|
| mib[0] = CTL_KERN;
|
| mib[1] = KERN_PROCARGS2;
|
| - mib[2] = (int)pid;
|
| -
|
| - size = argmax;
|
| - if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) {
|
| - if (EINVAL == errno) { // invalid == access denied for some reason
|
| - free(procargs);
|
| - return ARGS_ACCESS_DENIED; /* Insufficient privileges */
|
| + mib[2] = pid;
|
| + if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
|
| + if (EINVAL == errno) { // invalid == access denied OR nonexistent PID
|
| + if ( pid_exists(pid) ) {
|
| + AccessDenied();
|
| + } else {
|
| + NoSuchProcess();
|
| + }
|
| }
|
| -
|
| - PyErr_SetFromErrno(PyExc_OSError);
|
| free(procargs);
|
| - return errno;
|
| + return NULL;
|
| }
|
|
|
| - // copy the number of argument to nargs
|
| + arg_end = &procargs[argmax];
|
| + /* copy the number of arguments to nargs */
|
| memcpy(&nargs, procargs, sizeof(nargs));
|
| - iter_args = procargs + sizeof(nargs);
|
| - end_args = &procargs[size]; // end of the argument space
|
| - if (iter_args >= end_args) {
|
| - err = "getcmdargs(): argument length mismatch";
|
| - goto ERROR_RETURN;
|
| +
|
| + arg_ptr = procargs + sizeof(nargs);
|
| + len = strlen(arg_ptr);
|
| + arg_ptr += len + 1;
|
| +
|
| + if (arg_ptr == arg_end) {
|
| + free(procargs);
|
| + return Py_BuildValue("[]");
|
| }
|
|
|
| - // Save the path
|
| - if (NULL != exec_path) {
|
| - *exec_path = Py_BuildValue("s", iter_args);
|
| - if (*exec_path == NULL) {
|
| - err = "getcmdargs(): exec_path exception";
|
| - goto ERROR_RETURN;
|
| + // skip ahead to the first argument
|
| + for (; arg_ptr < arg_end; arg_ptr++) {
|
| + if (*arg_ptr != '\0') {
|
| + break;
|
| }
|
| }
|
|
|
| - //TODO: save the environment variables to envlist as well
|
| - // Skip over the exec_path and '\0' characters.
|
| - while (iter_args < end_args && *iter_args != '\0') { iter_args++; }
|
| - while (iter_args < end_args && *iter_args == '\0') { iter_args++; }
|
| -
|
| - /* Iterate through the '\0'-terminated strings and add each string
|
| - * to the Python List arglist as a Python string.
|
| - * Stop when nargs strings have been extracted. That should be all
|
| - * the arguments. The rest of the strings will be environment
|
| - * strings for the command.
|
| - */
|
| - curr_arg = iter_args;
|
| - start_args = iter_args; //reset start position to beginning of cmdline
|
| - while (iter_args < end_args && nargs > 0) {
|
| - if (*iter_args++ == '\0') {
|
| - /* Fetch next argument */
|
| + /* iterate through arguments */
|
| + curr_arg = arg_ptr;
|
| + arglist = Py_BuildValue("[]");
|
| + while (arg_ptr < arg_end && nargs > 0) {
|
| + if (*arg_ptr++ == '\0') {
|
| arg = Py_BuildValue("s", curr_arg);
|
| - if (arg == NULL) {
|
| - err = "getcmdargs(): exception building argument string";
|
| - goto ERROR_RETURN;
|
| + if (NULL == arg) {
|
| + return NULL;
|
| }
|
| - PyList_Append(*arglist, arg);
|
| + PyList_Append(arglist, arg);
|
| Py_DECREF(arg);
|
| -
|
| - curr_arg = iter_args;
|
| + // iterate to next arg and decrement # of args
|
| + curr_arg = arg_ptr;
|
| nargs--;
|
| }
|
| }
|
|
|
| - /*
|
| - * curr_arg position should be further than the start of the argspace
|
| - * and number of arguments should be 0 after iterating above. Otherwise
|
| - * we had an empty argument space or a missing terminating \0 etc.
|
| - */
|
| - if (curr_arg == start_args || nargs > 0) {
|
| - err = "getcmdargs(): argument parsing failed";
|
| - goto ERROR_RETURN;
|
| - }
|
| -
|
| -ERROR_RETURN:
|
| - // Clean up.
|
| - if (NULL != procargs) {
|
| - free(procargs);
|
| - }
|
| - if (NULL != err) {
|
| - PyErr_SetString(PyExc_SystemError, err);
|
| - return -1;
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -
|
| -/* return process args as a python list */
|
| -PyObject*
|
| -get_arg_list(long pid)
|
| -{
|
| - int r;
|
| - PyObject *argList;
|
| - PyObject *env = NULL;
|
| - PyObject *args = NULL;
|
| - PyObject *exec_path = NULL;
|
| -
|
| - //special case for PID 0 (kernel_task) where cmdline cannot be fetched
|
| - if (pid == 0) {
|
| - return Py_BuildValue("[]");
|
| - }
|
| -
|
| - /* Fetch the command-line arguments and environment variables */
|
| - //printf("pid: %ld\n", pid);
|
| - if (pid < 0 || pid > (long)INT_MAX) {
|
| - return Py_BuildValue("");
|
| - }
|
| -
|
| - r = getcmdargs(pid, &exec_path, &env, &args);
|
| - if (r == 0) {
|
| - //PySequence_Tuple(args);
|
| - argList = PySequence_List(args);
|
| - }
|
| - else if (r == ARGS_ACCESS_DENIED) { //-2
|
| - argList = Py_BuildValue("[]");
|
| - }
|
| - else {
|
| - argList = Py_BuildValue("");
|
| - }
|
| -
|
| - Py_XDECREF(args);
|
| - Py_XDECREF(exec_path);
|
| - Py_XDECREF(env);
|
| - return argList;
|
| + free(procargs);
|
| + return arglist;
|
| }
|
|
|
|
|
| @@ -293,8 +247,7 @@ get_kinfo_proc(pid_t pid, struct kinfo_proc *kp)
|
| * sysctl succeeds but len is zero, happens when process has gone away
|
| */
|
| if (len == 0) {
|
| - errno = ESRCH;
|
| - PyErr_SetFromErrno(PyExc_OSError);
|
| + NoSuchProcess();
|
| return -1;
|
| }
|
| return 0;
|
|
|