From 747965f6dbffe0a664a2ae7816f6d9b9a0f83fb5 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 20 Apr 2023 20:19:12 +0200 Subject: OSX / refact: get rid of process_info.c (#2243) --- MANIFEST.in | 2 - docs/index.rst | 2 +- psutil/_psutil_osx.c | 1 - psutil/arch/osx/proc.c | 399 +++++++++++++++++++++++++++++++++++++++- psutil/arch/osx/proc.h | 2 + psutil/arch/osx/process_info.c | 408 ----------------------------------------- psutil/arch/osx/process_info.h | 18 -- setup.py | 1 - 8 files changed, 397 insertions(+), 436 deletions(-) delete mode 100644 psutil/arch/osx/process_info.c delete mode 100644 psutil/arch/osx/process_info.h diff --git a/MANIFEST.in b/MANIFEST.in index 82d0e9a7..8defe717 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -101,8 +101,6 @@ include psutil/arch/osx/net.c include psutil/arch/osx/net.h include psutil/arch/osx/proc.c include psutil/arch/osx/proc.h -include psutil/arch/osx/process_info.c -include psutil/arch/osx/process_info.h include psutil/arch/osx/sensors.c include psutil/arch/osx/sensors.h include psutil/arch/osx/sys.c diff --git a/docs/index.rst b/docs/index.rst index 344aecdf..2bf050a1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2602,7 +2602,7 @@ On Windows: :: set PSUTIL_DEBUG=1 python.exe script.py - psutil-debug [psutil/arch/windows/process_info.c:90]> NtWow64ReadVirtualMemory64(pbi64.PebBaseAddress) -> 998 (Unknown error) (ignored) + psutil-debug [psutil/arch/windows/proc.c:90]> NtWow64ReadVirtualMemory64(pbi64.PebBaseAddress) -> 998 (Unknown error) (ignored) Security diff --git a/psutil/_psutil_osx.c b/psutil/_psutil_osx.c index 59fe5b68..dd7168eb 100644 --- a/psutil/_psutil_osx.c +++ b/psutil/_psutil_osx.c @@ -16,7 +16,6 @@ #include "arch/osx/mem.h" #include "arch/osx/net.h" #include "arch/osx/proc.h" -#include "arch/osx/process_info.h" #include "arch/osx/sensors.h" #include "arch/osx/sys.h" diff --git a/psutil/arch/osx/proc.c b/psutil/arch/osx/proc.c index 948d080b..6f66c861 100644 --- a/psutil/arch/osx/proc.c +++ b/psutil/arch/osx/proc.c @@ -5,9 +5,10 @@ */ // Process related functions. Original code was moved in here from -// psutil/_psutil_osx.c in 2023. For reference, here's the GIT blame -// history before the move: +// psutil/_psutil_osx.c and psutil/arc/osx/process_info.c in 2023. +// For reference, here's the GIT blame history before the move: // https://github.com/giampaolo/psutil/blame/59504a5/psutil/_psutil_osx.c +// https://github.com/giampaolo/psutil/blame/efd7ed3/psutil/arch/osx/process_info.c #include #include @@ -30,10 +31,196 @@ #include "../../_psutil_common.h" #include "../../_psutil_posix.h" -#include "process_info.h" #define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) +typedef struct kinfo_proc kinfo_proc; + + +// ==================================================================== +// --- utils +// ==================================================================== + +/* + * Returns a list of all BSD processes on the system. This routine + * allocates the list and puts it in *procList and a count of the + * number of entries in *procCount. You are responsible for freeing + * this list (use "free" from System framework). + * On success, the function returns 0. + * On error, the function returns a BSD errno value. + */ +static int +psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) { + int mib[3]; + size_t size, size2; + void *ptr; + int err; + int lim = 8; // some limit + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_ALL; + *procCount = 0; + + /* + * We start by calling sysctl with ptr == NULL and size == 0. + * That will succeed, and set size to the appropriate length. + * We then allocate a buffer of at least that size and call + * sysctl with that buffer. If that succeeds, we're done. + * If that call fails with ENOMEM, we throw the buffer away + * and try again. + * Note that the loop calls sysctl with NULL again. This is + * is necessary because the ENOMEM failure case sets size to + * the amount of data returned, not the amount of data that + * could have been returned. + */ + while (lim-- > 0) { + size = 0; + if (sysctl((int *)mib, 3, NULL, &size, NULL, 0) == -1) { + PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_PROC_ALL)"); + return 1; + } + size2 = size + (size >> 3); // add some + if (size2 > size) { + ptr = malloc(size2); + if (ptr == NULL) + ptr = malloc(size); + else + size = size2; + } + else { + ptr = malloc(size); + } + if (ptr == NULL) { + PyErr_NoMemory(); + return 1; + } + + if (sysctl((int *)mib, 3, ptr, &size, NULL, 0) == -1) { + err = errno; + free(ptr); + if (err != ENOMEM) { + PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_PROC_ALL)"); + return 1; + } + } + else { + *procList = (kinfo_proc *)ptr; + *procCount = size / sizeof(kinfo_proc); + if (procCount <= 0) { + PyErr_Format(PyExc_RuntimeError, "no PIDs found"); + return 1; + } + return 0; // success + } + } + + PyErr_Format(PyExc_RuntimeError, "couldn't collect PIDs list"); + return 1; +} + + +// Read the maximum argument size for processes +static int +psutil_sysctl_argmax() { + int argmax; + int mib[2]; + size_t size = sizeof(argmax); + + mib[0] = CTL_KERN; + mib[1] = KERN_ARGMAX; + + if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0) + return argmax; + PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_ARGMAX)"); + return 0; +} + + +// Read process argument space. +static int +psutil_sysctl_procargs(pid_t pid, char *procargs, size_t *argmax) { + int mib[3]; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROCARGS2; + mib[2] = pid; + + if (sysctl(mib, 3, procargs, argmax, NULL, 0) < 0) { + if (psutil_pid_exists(pid) == 0) { + NoSuchProcess("psutil_pid_exists -> 0"); + return 1; + } + // In case of zombie process we'll get EINVAL. We translate it + // to NSP and _psosx.py will translate it to ZP. + if (errno == EINVAL) { + psutil_debug("sysctl(KERN_PROCARGS2) -> EINVAL translated to NSP"); + NoSuchProcess("sysctl(KERN_PROCARGS2) -> EINVAL"); + return 1; + } + // There's nothing we can do other than raising AD. + if (errno == EIO) { + psutil_debug("sysctl(KERN_PROCARGS2) -> EIO translated to AD"); + AccessDenied("sysctl(KERN_PROCARGS2) -> EIO"); + return 1; + } + PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_PROCARGS2)"); + return 1; + } + return 0; +} + + +static int +psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp) { + int mib[4]; + size_t len; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = pid; + + // fetch the info with sysctl() + len = sizeof(struct kinfo_proc); + + // now read the data from sysctl + if (sysctl(mib, 4, kp, &len, NULL, 0) == -1) { + // raise an exception and throw errno as the error + PyErr_SetFromOSErrnoWithSyscall("sysctl"); + return -1; + } + + // sysctl succeeds but len is zero, happens when process has gone away + if (len == 0) { + NoSuchProcess("sysctl(kinfo_proc), len == 0"); + return -1; + } + return 0; +} + + +/* + * A wrapper around proc_pidinfo(). + * https://opensource.apple.com/source/xnu/xnu-2050.7.9/bsd/kern/proc_info.c + * Returns 0 on failure. + */ +static int +psutil_proc_pidinfo(pid_t pid, int flavor, uint64_t arg, void *pti, int size) { + errno = 0; + int ret; + + ret = proc_pidinfo(pid, flavor, arg, pti, size); + if (ret <= 0) { + psutil_raise_for_pid(pid, "proc_pidinfo()"); + return 0; + } + if ((unsigned long)ret < sizeof(pti)) { + psutil_raise_for_pid( + pid, "proc_pidinfo() return size < sizeof(struct_pointer)"); + return 0; + } + return ret; +} /* @@ -50,7 +237,7 @@ * https://github.com/giampaolo/psutil/issues/1209 * https://github.com/giampaolo/psutil/issues/1291#issuecomment-396062519 */ -int +static int psutil_task_for_pid(pid_t pid, mach_port_t *task) { // See: https://github.com/giampaolo/psutil/issues/1181 @@ -68,7 +255,7 @@ psutil_task_for_pid(pid_t pid, mach_port_t *task) psutil_debug( "task_for_pid() failed (pid=%ld, err=%i, errno=%i, msg='%s'); " "setting AccessDenied()", - pid, err, errno, mach_error_string(err)); + (long)pid, err, errno, mach_error_string(err)); AccessDenied("task_for_pid"); } return 1; @@ -143,6 +330,11 @@ error: } +// ==================================================================== +// --- Python APIs +// ==================================================================== + + /* * Return a Python list of all the PIDs running on the system. */ @@ -876,3 +1068,200 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) { free(fds_pointer); return Py_BuildValue("i", num_fds); } + + +// return process args as a python list +PyObject * +psutil_proc_cmdline(PyObject *self, PyObject *args) { + pid_t pid; + int nargs; + size_t len; + char *procargs = NULL; + char *arg_ptr; + char *arg_end; + char *curr_arg; + size_t argmax; + PyObject *py_retlist = PyList_New(0); + PyObject *py_arg = NULL; + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid)) + goto error; + + // special case for PID 0 (kernel_task) where cmdline cannot be fetched + if (pid == 0) + return py_retlist; + + // read argmax and allocate memory for argument space. + argmax = psutil_sysctl_argmax(); + if (! argmax) + goto error; + + procargs = (char *)malloc(argmax); + if (NULL == procargs) { + PyErr_NoMemory(); + goto error; + } + + if (psutil_sysctl_procargs(pid, procargs, &argmax) != 0) + goto error; + + arg_end = &procargs[argmax]; + // copy the number of arguments to nargs + memcpy(&nargs, procargs, sizeof(nargs)); + + arg_ptr = procargs + sizeof(nargs); + len = strlen(arg_ptr); + arg_ptr += len + 1; + + if (arg_ptr == arg_end) { + free(procargs); + return py_retlist; + } + + // skip ahead to the first argument + for (; arg_ptr < arg_end; arg_ptr++) { + if (*arg_ptr != '\0') + break; + } + + // iterate through arguments + curr_arg = arg_ptr; + while (arg_ptr < arg_end && nargs > 0) { + if (*arg_ptr++ == '\0') { + py_arg = PyUnicode_DecodeFSDefault(curr_arg); + if (! py_arg) + goto error; + if (PyList_Append(py_retlist, py_arg)) + goto error; + Py_DECREF(py_arg); + // iterate to next arg and decrement # of args + curr_arg = arg_ptr; + nargs--; + } + } + + free(procargs); + return py_retlist; + +error: + Py_XDECREF(py_arg); + Py_XDECREF(py_retlist); + if (procargs != NULL) + free(procargs); + return NULL; +} + + +// Return process environment as a python string. +// On Big Sur this function returns an empty string unless: +// * kernel is DEVELOPMENT || DEBUG +// * target process is same as current_proc() +// * target process is not cs_restricted +// * SIP is off +// * caller has an entitlement +// See: https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/kern/kern_sysctl.c#L1315-L1321 +PyObject * +psutil_proc_environ(PyObject *self, PyObject *args) { + pid_t pid; + int nargs; + char *procargs = NULL; + char *procenv = NULL; + char *arg_ptr; + char *arg_end; + char *env_start; + size_t argmax; + PyObject *py_ret = NULL; + + if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid)) + return NULL; + + // special case for PID 0 (kernel_task) where cmdline cannot be fetched + if (pid == 0) + goto empty; + + // read argmax and allocate memory for argument space. + argmax = psutil_sysctl_argmax(); + if (! argmax) + goto error; + + procargs = (char *)malloc(argmax); + if (NULL == procargs) { + PyErr_NoMemory(); + goto error; + } + + if (psutil_sysctl_procargs(pid, procargs, &argmax) != 0) + goto error; + + arg_end = &procargs[argmax]; + // copy the number of arguments to nargs + memcpy(&nargs, procargs, sizeof(nargs)); + + // skip executable path + arg_ptr = procargs + sizeof(nargs); + arg_ptr = memchr(arg_ptr, '\0', arg_end - arg_ptr); + + if (arg_ptr == NULL || arg_ptr == arg_end) { + psutil_debug( + "(arg_ptr == NULL || arg_ptr == arg_end); set environ to empty"); + goto empty; + } + + // skip ahead to the first argument + for (; arg_ptr < arg_end; arg_ptr++) { + if (*arg_ptr != '\0') + break; + } + + // iterate through arguments + while (arg_ptr < arg_end && nargs > 0) { + if (*arg_ptr++ == '\0') + nargs--; + } + + // build an environment variable block + env_start = arg_ptr; + + procenv = calloc(1, arg_end - arg_ptr); + if (procenv == NULL) { + PyErr_NoMemory(); + goto error; + } + + while (*arg_ptr != '\0' && arg_ptr < arg_end) { + char *s = memchr(arg_ptr + 1, '\0', arg_end - arg_ptr); + if (s == NULL) + break; + memcpy(procenv + (arg_ptr - env_start), arg_ptr, s - arg_ptr); + arg_ptr = s + 1; + } + + py_ret = PyUnicode_DecodeFSDefaultAndSize( + procenv, arg_ptr - env_start + 1); + if (!py_ret) { + // XXX: don't want to free() this as per: + // https://github.com/giampaolo/psutil/issues/926 + // It sucks but not sure what else to do. + procargs = NULL; + goto error; + } + + free(procargs); + free(procenv); + return py_ret; + +empty: + if (procargs != NULL) + free(procargs); + return Py_BuildValue("s", ""); + +error: + Py_XDECREF(py_ret); + if (procargs != NULL) + free(procargs); + if (procenv != NULL) + free(procargs); + return NULL; +} diff --git a/psutil/arch/osx/proc.h b/psutil/arch/osx/proc.h index 621f0cad..63f16ccd 100644 --- a/psutil/arch/osx/proc.h +++ b/psutil/arch/osx/proc.h @@ -7,8 +7,10 @@ #include PyObject *psutil_pids(PyObject *self, PyObject *args); +PyObject *psutil_proc_cmdline(PyObject *self, PyObject *args); PyObject *psutil_proc_connections(PyObject *self, PyObject *args); PyObject *psutil_proc_cwd(PyObject *self, PyObject *args); +PyObject *psutil_proc_environ(PyObject *self, PyObject *args); PyObject *psutil_proc_exe(PyObject *self, PyObject *args); PyObject *psutil_proc_kinfo_oneshot(PyObject *self, PyObject *args); PyObject *psutil_proc_memory_uss(PyObject *self, PyObject *args); diff --git a/psutil/arch/osx/process_info.c b/psutil/arch/osx/process_info.c deleted file mode 100644 index 4b98d92a..00000000 --- a/psutil/arch/osx/process_info.c +++ /dev/null @@ -1,408 +0,0 @@ -/* - * 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. - */ - - -#include -#include -#include -#include - -#include "../../_psutil_common.h" -#include "../../_psutil_posix.h" -#include "process_info.h" - - -/* - * Returns a list of all BSD processes on the system. This routine - * allocates the list and puts it in *procList and a count of the - * number of entries in *procCount. You are responsible for freeing - * this list (use "free" from System framework). - * On success, the function returns 0. - * On error, the function returns a BSD errno value. - */ -int -psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) { - int mib[3]; - size_t size, size2; - void *ptr; - int err; - int lim = 8; // some limit - - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_ALL; - *procCount = 0; - - /* - * We start by calling sysctl with ptr == NULL and size == 0. - * That will succeed, and set size to the appropriate length. - * We then allocate a buffer of at least that size and call - * sysctl with that buffer. If that succeeds, we're done. - * If that call fails with ENOMEM, we throw the buffer away - * and try again. - * Note that the loop calls sysctl with NULL again. This is - * is necessary because the ENOMEM failure case sets size to - * the amount of data returned, not the amount of data that - * could have been returned. - */ - while (lim-- > 0) { - size = 0; - if (sysctl((int *)mib, 3, NULL, &size, NULL, 0) == -1) { - PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_PROC_ALL)"); - return 1; - } - size2 = size + (size >> 3); // add some - if (size2 > size) { - ptr = malloc(size2); - if (ptr == NULL) - ptr = malloc(size); - else - size = size2; - } - else { - ptr = malloc(size); - } - if (ptr == NULL) { - PyErr_NoMemory(); - return 1; - } - - if (sysctl((int *)mib, 3, ptr, &size, NULL, 0) == -1) { - err = errno; - free(ptr); - if (err != ENOMEM) { - PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_PROC_ALL)"); - return 1; - } - } - else { - *procList = (kinfo_proc *)ptr; - *procCount = size / sizeof(kinfo_proc); - if (procCount <= 0) { - PyErr_Format(PyExc_RuntimeError, "no PIDs found"); - return 1; - } - return 0; // success - } - } - - PyErr_Format(PyExc_RuntimeError, "couldn't collect PIDs list"); - return 1; -} - - -// Read the maximum argument size for processes -static int -psutil_sysctl_argmax() { - int argmax; - int mib[2]; - size_t size = sizeof(argmax); - - mib[0] = CTL_KERN; - mib[1] = KERN_ARGMAX; - - if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0) - return argmax; - PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_ARGMAX)"); - return 0; -} - - -// Read process argument space. -static int -psutil_sysctl_procargs(pid_t pid, char *procargs, size_t *argmax) { - int mib[3]; - - mib[0] = CTL_KERN; - mib[1] = KERN_PROCARGS2; - mib[2] = pid; - - if (sysctl(mib, 3, procargs, argmax, NULL, 0) < 0) { - if (psutil_pid_exists(pid) == 0) { - NoSuchProcess("psutil_pid_exists -> 0"); - return 1; - } - // In case of zombie process we'll get EINVAL. We translate it - // to NSP and _psosx.py will translate it to ZP. - if (errno == EINVAL) { - psutil_debug("sysctl(KERN_PROCARGS2) -> EINVAL translated to NSP"); - NoSuchProcess("sysctl(KERN_PROCARGS2) -> EINVAL"); - return 1; - } - // There's nothing we can do other than raising AD. - if (errno == EIO) { - psutil_debug("sysctl(KERN_PROCARGS2) -> EIO translated to AD"); - AccessDenied("sysctl(KERN_PROCARGS2) -> EIO"); - return 1; - } - PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_PROCARGS2)"); - return 1; - } - return 0; -} - - -// Return 1 if pid refers to a zombie process else 0. -int -psutil_is_zombie(pid_t pid) { - struct kinfo_proc kp; - - if (psutil_get_kinfo_proc(pid, &kp) == -1) - return 0; - return (kp.kp_proc.p_stat == SZOMB) ? 1 : 0; -} - - -// return process args as a python list -PyObject * -psutil_proc_cmdline(PyObject *self, PyObject *args) { - pid_t pid; - int nargs; - size_t len; - char *procargs = NULL; - char *arg_ptr; - char *arg_end; - char *curr_arg; - size_t argmax; - PyObject *py_retlist = PyList_New(0); - PyObject *py_arg = NULL; - - if (py_retlist == NULL) - return NULL; - if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid)) - goto error; - - // special case for PID 0 (kernel_task) where cmdline cannot be fetched - if (pid == 0) - return py_retlist; - - // read argmax and allocate memory for argument space. - argmax = psutil_sysctl_argmax(); - if (! argmax) - goto error; - - procargs = (char *)malloc(argmax); - if (NULL == procargs) { - PyErr_NoMemory(); - goto error; - } - - if (psutil_sysctl_procargs(pid, procargs, &argmax) != 0) - goto error; - - arg_end = &procargs[argmax]; - // copy the number of arguments to nargs - memcpy(&nargs, procargs, sizeof(nargs)); - - arg_ptr = procargs + sizeof(nargs); - len = strlen(arg_ptr); - arg_ptr += len + 1; - - if (arg_ptr == arg_end) { - free(procargs); - return py_retlist; - } - - // skip ahead to the first argument - for (; arg_ptr < arg_end; arg_ptr++) { - if (*arg_ptr != '\0') - break; - } - - // iterate through arguments - curr_arg = arg_ptr; - while (arg_ptr < arg_end && nargs > 0) { - if (*arg_ptr++ == '\0') { - py_arg = PyUnicode_DecodeFSDefault(curr_arg); - if (! py_arg) - goto error; - if (PyList_Append(py_retlist, py_arg)) - goto error; - Py_DECREF(py_arg); - // iterate to next arg and decrement # of args - curr_arg = arg_ptr; - nargs--; - } - } - - free(procargs); - return py_retlist; - -error: - Py_XDECREF(py_arg); - Py_XDECREF(py_retlist); - if (procargs != NULL) - free(procargs); - return NULL; -} - - -// Return process environment as a python string. -// On Big Sur this function returns an empty string unless: -// * kernel is DEVELOPMENT || DEBUG -// * target process is same as current_proc() -// * target process is not cs_restricted -// * SIP is off -// * caller has an entitlement -// See: https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/kern/kern_sysctl.c#L1315-L1321 -PyObject * -psutil_proc_environ(PyObject *self, PyObject *args) { - pid_t pid; - int nargs; - char *procargs = NULL; - char *procenv = NULL; - char *arg_ptr; - char *arg_end; - char *env_start; - size_t argmax; - PyObject *py_ret = NULL; - - if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid)) - return NULL; - - // special case for PID 0 (kernel_task) where cmdline cannot be fetched - if (pid == 0) - goto empty; - - // read argmax and allocate memory for argument space. - argmax = psutil_sysctl_argmax(); - if (! argmax) - goto error; - - procargs = (char *)malloc(argmax); - if (NULL == procargs) { - PyErr_NoMemory(); - goto error; - } - - if (psutil_sysctl_procargs(pid, procargs, &argmax) != 0) - goto error; - - arg_end = &procargs[argmax]; - // copy the number of arguments to nargs - memcpy(&nargs, procargs, sizeof(nargs)); - - // skip executable path - arg_ptr = procargs + sizeof(nargs); - arg_ptr = memchr(arg_ptr, '\0', arg_end - arg_ptr); - - if (arg_ptr == NULL || arg_ptr == arg_end) { - psutil_debug( - "(arg_ptr == NULL || arg_ptr == arg_end); set environ to empty"); - goto empty; - } - - // skip ahead to the first argument - for (; arg_ptr < arg_end; arg_ptr++) { - if (*arg_ptr != '\0') - break; - } - - // iterate through arguments - while (arg_ptr < arg_end && nargs > 0) { - if (*arg_ptr++ == '\0') - nargs--; - } - - // build an environment variable block - env_start = arg_ptr; - - procenv = calloc(1, arg_end - arg_ptr); - if (procenv == NULL) { - PyErr_NoMemory(); - goto error; - } - - while (*arg_ptr != '\0' && arg_ptr < arg_end) { - char *s = memchr(arg_ptr + 1, '\0', arg_end - arg_ptr); - if (s == NULL) - break; - memcpy(procenv + (arg_ptr - env_start), arg_ptr, s - arg_ptr); - arg_ptr = s + 1; - } - - py_ret = PyUnicode_DecodeFSDefaultAndSize( - procenv, arg_ptr - env_start + 1); - if (!py_ret) { - // XXX: don't want to free() this as per: - // https://github.com/giampaolo/psutil/issues/926 - // It sucks but not sure what else to do. - procargs = NULL; - goto error; - } - - free(procargs); - free(procenv); - return py_ret; - -empty: - if (procargs != NULL) - free(procargs); - return Py_BuildValue("s", ""); - -error: - Py_XDECREF(py_ret); - if (procargs != NULL) - free(procargs); - if (procenv != NULL) - free(procargs); - return NULL; -} - - -int -psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp) { - int mib[4]; - size_t len; - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = pid; - - // fetch the info with sysctl() - len = sizeof(struct kinfo_proc); - - // now read the data from sysctl - if (sysctl(mib, 4, kp, &len, NULL, 0) == -1) { - // raise an exception and throw errno as the error - PyErr_SetFromOSErrnoWithSyscall("sysctl"); - return -1; - } - - // sysctl succeeds but len is zero, happens when process has gone away - if (len == 0) { - NoSuchProcess("sysctl(kinfo_proc), len == 0"); - return -1; - } - return 0; -} - - -/* - * A wrapper around proc_pidinfo(). - * https://opensource.apple.com/source/xnu/xnu-2050.7.9/bsd/kern/proc_info.c - * Returns 0 on failure. - */ -int -psutil_proc_pidinfo(pid_t pid, int flavor, uint64_t arg, void *pti, int size) { - errno = 0; - int ret; - - ret = proc_pidinfo(pid, flavor, arg, pti, size); - if (ret <= 0) { - psutil_raise_for_pid(pid, "proc_pidinfo()"); - return 0; - } - if ((unsigned long)ret < sizeof(pti)) { - psutil_raise_for_pid( - pid, "proc_pidinfo() return size < sizeof(struct_pointer)"); - return 0; - } - return ret; -} diff --git a/psutil/arch/osx/process_info.h b/psutil/arch/osx/process_info.h deleted file mode 100644 index 08046bcb..00000000 --- a/psutil/arch/osx/process_info.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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. - */ - -#include - -typedef struct kinfo_proc kinfo_proc; - -int psutil_is_zombie(pid_t pid); -int psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp); -int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount); -int psutil_proc_pidinfo( - pid_t pid, int flavor, uint64_t arg, void *pti, int size); - -PyObject *psutil_proc_cmdline(PyObject *self, PyObject *args); -PyObject *psutil_proc_environ(PyObject *self, PyObject *args); diff --git a/setup.py b/setup.py index 91b1ab14..54652aae 100755 --- a/setup.py +++ b/setup.py @@ -246,7 +246,6 @@ elif MACOS: 'psutil/arch/osx/mem.c', 'psutil/arch/osx/net.c', 'psutil/arch/osx/proc.c', - 'psutil/arch/osx/process_info.c', 'psutil/arch/osx/sensors.c', 'psutil/arch/osx/sys.c', ], -- cgit v1.2.1