From 0e63add84ecdb202c9af3ee65b568a8756dfcca9 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Fri, 26 Dec 2014 21:18:01 +0100 Subject: [PATCH 01/74] Build changes to try to support OpenBSD. Two new C files copied from the FreeBSD ones. --- psutil/__init__.py | 3 + psutil/_psutil_openbsd.c | 2212 ++++++++++++++++++++++++ psutil/arch/bsd/process_info_openbsd.c | 285 +++ setup.py | 13 + 4 files changed, 2513 insertions(+) create mode 100644 psutil/_psutil_openbsd.c create mode 100644 psutil/arch/bsd/process_info_openbsd.c diff --git a/psutil/__init__.py b/psutil/__init__.py index 91c23ce58..44d3c72fd 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -151,6 +151,9 @@ elif sys.platform.startswith("freebsd"): import psutil._psbsd as _psplatform +elif sys.platform.startswith("openbsd"): + import psutil._psbsd as _psplatform + elif sys.platform.startswith("sunos"): import psutil._pssunos as _psplatform from psutil._pssunos import (CONN_IDLE, # NOQA diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c new file mode 100644 index 000000000..5a9f9c08b --- /dev/null +++ b/psutil/_psutil_openbsd.c @@ -0,0 +1,2212 @@ +/* + * Copyright (c) 2009, 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. + * + * FreeBSD platform-specific module methods for _psutil_bsd + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include // for struct xsocket +#include +#include +// for xinpcb struct +#include +#include +#include +#include +#include // for struct xtcpcb +#include // for TCP connection states +#include // for inet_ntop() + +#if __FreeBSD_version < 900000 +#include // system users +#else +#include +#endif +#include // get io counters +#include // needed for vmtotal struct +#include // process open files, shared libs (kinfo_getvmmap) +#include + +#include // net io counters +#include +#include + +#include // process open files/connections +#include + +#include "_psutil_bsd.h" +#include "_psutil_common.h" +#include "arch/bsd/process_info.h" + + +// convert a timeval struct to a double +#define TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) + + +/* + * Utility function which fills a kinfo_proc struct based on process pid + */ +static int +psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) +{ + int mib[4]; + size_t size; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = pid; + + size = sizeof(struct kinfo_proc); + + if (sysctl((int *)mib, 4, proc, &size, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + + // sysctl stores 0 in the size if we can't find the process information. + if (size == 0) { + NoSuchProcess(); + return -1; + } + return 0; +} + + +/* + * Return a Python list of all the PIDs running on the system. + */ +static PyObject * +psutil_pids(PyObject *self, PyObject *args) +{ + kinfo_proc *proclist = NULL; + kinfo_proc *orig_address = NULL; + size_t num_processes; + size_t idx; + PyObject *retlist = PyList_New(0); + PyObject *pid = NULL; + + if (retlist == NULL) { + return NULL; + } + if (psutil_get_proc_list(&proclist, &num_processes) != 0) { + PyErr_SetString(PyExc_RuntimeError, + "failed to retrieve process list."); + goto error; + } + + if (num_processes > 0) { + orig_address = proclist; // save so we can free it after we're done + for (idx = 0; idx < num_processes; idx++) { + pid = Py_BuildValue("i", proclist->ki_pid); + if (!pid) + goto error; + if (PyList_Append(retlist, pid)) + goto error; + Py_DECREF(pid); + proclist++; + } + free(orig_address); + } + + return retlist; + +error: + Py_XDECREF(pid); + Py_DECREF(retlist); + if (orig_address != NULL) { + free(orig_address); + } + return NULL; +} + + +/* + * Return a Python float indicating the system boot time expressed in + * seconds since the epoch. + */ +static PyObject * +psutil_boot_time(PyObject *self, PyObject *args) +{ + // fetch sysctl "kern.boottime" + static int request[2] = { CTL_KERN, KERN_BOOTTIME }; + struct timeval boottime; + size_t len = sizeof(boottime); + + if (sysctl(request, 2, &boottime, &len, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + return Py_BuildValue("d", (double)boottime.tv_sec); +} + + +/* + * Return process name from kinfo_proc as a Python string. + */ +static PyObject * +psutil_proc_name(PyObject *self, PyObject *args) +{ + long pid; + struct kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) { + return NULL; + } + if (psutil_kinfo_proc(pid, &kp) == -1) { + return NULL; + } + return Py_BuildValue("s", kp.ki_comm); +} + + +/* + * Return process pathname executable. + * Thanks to Robert N. M. Watson: + * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_bin.c?v=8-CURRENT + */ +static PyObject * +psutil_proc_exe(PyObject *self, PyObject *args) +{ + long pid; + char pathname[PATH_MAX]; + int error; + int mib[4]; + size_t size; + + if (! PyArg_ParseTuple(args, "l", &pid)) { + return NULL; + } + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = pid; + + size = sizeof(pathname); + error = sysctl(mib, 4, pathname, &size, NULL, 0); + if (error == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + if (size == 0 || strlen(pathname) == 0) { + if (psutil_pid_exists(pid) == 0) { + return NoSuchProcess(); + } + else { + strcpy(pathname, ""); + } + } + return Py_BuildValue("s", pathname); +} + + +/* + * Return process cmdline as a Python list of cmdline arguments. + */ +static PyObject * +psutil_proc_cmdline(PyObject *self, PyObject *args) +{ + long pid; + PyObject *arglist = NULL; + + if (! PyArg_ParseTuple(args, "l", &pid)) { + return NULL; + } + + // get the commandline, defined in arch/bsd/process_info.c + arglist = psutil_get_arg_list(pid); + + // psutil_get_arg_list() returns NULL only if psutil_cmd_args + // failed with ESRCH (no process with that PID) + if (NULL == arglist) { + return PyErr_SetFromErrno(PyExc_OSError); + } + return Py_BuildValue("N", arglist); +} + + +/* + * Return process parent pid from kinfo_proc as a Python integer. + */ +static PyObject * +psutil_proc_ppid(PyObject *self, PyObject *args) +{ + long pid; + struct kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) { + return NULL; + } + if (psutil_kinfo_proc(pid, &kp) == -1) { + return NULL; + } + return Py_BuildValue("l", (long)kp.ki_ppid); +} + + +/* + * Return process status as a Python integer. + */ +static PyObject * +psutil_proc_status(PyObject *self, PyObject *args) +{ + long pid; + struct kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) { + return NULL; + } + if (psutil_kinfo_proc(pid, &kp) == -1) { + return NULL; + } + return Py_BuildValue("i", (int)kp.ki_stat); +} + + +/* + * Return process real, effective and saved user ids from kinfo_proc + * as a Python tuple. + */ +static PyObject * +psutil_proc_uids(PyObject *self, PyObject *args) +{ + long pid; + struct kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) { + return NULL; + } + if (psutil_kinfo_proc(pid, &kp) == -1) { + return NULL; + } + return Py_BuildValue("lll", + (long)kp.ki_ruid, + (long)kp.ki_uid, + (long)kp.ki_svuid); +} + + +/* + * Return process real, effective and saved group ids from kinfo_proc + * as a Python tuple. + */ +static PyObject * +psutil_proc_gids(PyObject *self, PyObject *args) +{ + long pid; + struct kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) { + return NULL; + } + if (psutil_kinfo_proc(pid, &kp) == -1) { + return NULL; + } + return Py_BuildValue("lll", + (long)kp.ki_rgid, + (long)kp.ki_groups[0], + (long)kp.ki_svuid); +} + + +/* + * Return process real, effective and saved group ids from kinfo_proc + * as a Python tuple. + */ +static PyObject * +psutil_proc_tty_nr(PyObject *self, PyObject *args) +{ + long pid; + struct kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) { + return NULL; + } + if (psutil_kinfo_proc(pid, &kp) == -1) { + return NULL; + } + return Py_BuildValue("i", kp.ki_tdev); +} + + +/* + * Return the number of context switches performed by process as a tuple. + */ +static PyObject * +psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) +{ + long pid; + struct kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) { + return NULL; + } + if (psutil_kinfo_proc(pid, &kp) == -1) { + return NULL; + } + return Py_BuildValue("(ll)", + kp.ki_rusage.ru_nvcsw, + kp.ki_rusage.ru_nivcsw); +} + + +/* + * Return number of threads used by process as a Python integer. + */ +static PyObject * +psutil_proc_num_threads(PyObject *self, PyObject *args) +{ + long pid; + struct kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) { + return NULL; + } + if (psutil_kinfo_proc(pid, &kp) == -1) { + return NULL; + } + return Py_BuildValue("l", (long)kp.ki_numthreads); +} + + +/* + * Retrieves all threads used by process returning a list of tuples + * including thread id, user time and system time. + * Thanks to Robert N. M. Watson: + * http://fxr.googlebit.com/source/usr.bin/procstat/ + * procstat_threads.c?v=8-CURRENT + */ +static PyObject * +psutil_proc_threads(PyObject *self, PyObject *args) +{ + long pid; + int mib[4]; + struct kinfo_proc *kip = NULL; + struct kinfo_proc *kipp = NULL; + int error; + unsigned int i; + size_t size; + PyObject *retList = PyList_New(0); + PyObject *pyTuple = NULL; + + if (retList == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + + // we need to re-query for thread information, so don't use *kipp + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD; + mib[3] = pid; + + size = 0; + error = sysctl(mib, 4, NULL, &size, NULL, 0); + if (error == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + if (size == 0) { + NoSuchProcess(); + goto error; + } + + kip = malloc(size); + if (kip == NULL) { + PyErr_NoMemory(); + goto error; + } + + error = sysctl(mib, 4, kip, &size, NULL, 0); + if (error == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + if (size == 0) { + NoSuchProcess(); + goto error; + } + + for (i = 0; i < size / sizeof(*kipp); i++) { + kipp = &kip[i]; + pyTuple = Py_BuildValue("Idd", + kipp->ki_tid, + TV2DOUBLE(kipp->ki_rusage.ru_utime), + TV2DOUBLE(kipp->ki_rusage.ru_stime)); + if (pyTuple == NULL) + goto error; + if (PyList_Append(retList, pyTuple)) + goto error; + Py_DECREF(pyTuple); + } + free(kip); + return retList; + +error: + Py_XDECREF(pyTuple); + Py_DECREF(retList); + if (kip != NULL) { + free(kip); + } + return NULL; +} + + +/* + * Return a Python tuple (user_time, kernel_time) + */ +static PyObject * +psutil_proc_cpu_times(PyObject *self, PyObject *args) +{ + long pid; + double user_t, sys_t; + struct kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) { + return NULL; + } + if (psutil_kinfo_proc(pid, &kp) == -1) { + return NULL; + } + // convert from microseconds to seconds + user_t = TV2DOUBLE(kp.ki_rusage.ru_utime); + sys_t = TV2DOUBLE(kp.ki_rusage.ru_stime); + return Py_BuildValue("(dd)", user_t, sys_t); +} + + +/* + * Return the number of logical CPUs in the system. + * XXX this could be shared with OSX + */ +static PyObject * +psutil_cpu_count_logical(PyObject *self, PyObject *args) +{ + int mib[2]; + int ncpu; + size_t len; + + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + len = sizeof(ncpu); + + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) { + // mimic os.cpu_count() + Py_INCREF(Py_None); + return Py_None; + } + else { + return Py_BuildValue("i", ncpu); + } +} + + +/* + * Return an XML string from which we'll determine the number of + * physical CPU cores in the system. + */ +static PyObject * +psutil_cpu_count_phys(PyObject *self, PyObject *args) +{ + void *topology = NULL; + size_t size = 0; + + if (sysctlbyname("kern.sched.topology_spec", NULL, &size, NULL, 0)) + goto error; + + topology = malloc(size); + if (!topology) { + PyErr_NoMemory(); + return NULL; + } + + if (sysctlbyname("kern.sched.topology_spec", topology, &size, NULL, 0)) + goto error; + + return Py_BuildValue("s", topology); + +error: + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * Return a Python float indicating the process create time expressed in + * seconds since the epoch. + */ +static PyObject * +psutil_proc_create_time(PyObject *self, PyObject *args) +{ + long pid; + struct kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) { + return NULL; + } + if (psutil_kinfo_proc(pid, &kp) == -1) { + return NULL; + } + return Py_BuildValue("d", TV2DOUBLE(kp.ki_start)); +} + + +/* + * Return a Python float indicating the process create time expressed in + * seconds since the epoch. + */ +static PyObject * +psutil_proc_io_counters(PyObject *self, PyObject *args) +{ + long pid; + struct kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) { + return NULL; + } + if (psutil_kinfo_proc(pid, &kp) == -1) { + return NULL; + } + // there's apparently no way to determine bytes count, hence return -1. + return Py_BuildValue("(llll)", + kp.ki_rusage.ru_inblock, + kp.ki_rusage.ru_oublock, + -1, + -1); +} + + +/* + * Return extended memory info for a process as a Python tuple. + */ +static PyObject * +psutil_proc_memory_info(PyObject *self, PyObject *args) +{ + long pid; + struct kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) { + return NULL; + } + if (psutil_kinfo_proc(pid, &kp) == -1) { + return NULL; + } + return Py_BuildValue("(lllll)", + ptoa(kp.ki_rssize), // rss + (long)kp.ki_size, // vms + ptoa(kp.ki_tsize), // text + ptoa(kp.ki_dsize), // data + ptoa(kp.ki_ssize)); // stack +} + + +/* + * Return virtual memory usage statistics. + */ +static PyObject * +psutil_virtual_mem(PyObject *self, PyObject *args) +{ + unsigned int total, active, inactive, wired, cached, free; + size_t size = sizeof(total); + struct vmtotal vm; + int mib[] = {CTL_VM, VM_METER}; + long pagesize = getpagesize(); +#if __FreeBSD_version > 702101 + long buffers; +#else + int buffers; +#endif + size_t buffers_size = sizeof(buffers); + + if (sysctlbyname("vm.stats.vm.v_page_count", &total, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_active_count", &active, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_inactive_count", + &inactive, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_wire_count", &wired, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_cache_count", &cached, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_free_count", &free, &size, NULL, 0)) + goto error; + if (sysctlbyname("vfs.bufspace", &buffers, &buffers_size, NULL, 0)) + goto error; + + size = sizeof(vm); + if (sysctl(mib, 2, &vm, &size, NULL, 0) != 0) + goto error; + + return Py_BuildValue("KKKKKKKK", + (unsigned long long) total * pagesize, + (unsigned long long) free * pagesize, + (unsigned long long) active * pagesize, + (unsigned long long) inactive * pagesize, + (unsigned long long) wired * pagesize, + (unsigned long long) cached * pagesize, + (unsigned long long) buffers, + (unsigned long long) (vm.t_vmshr + vm.t_rmshr) * pagesize // shared + ); + +error: + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + +#ifndef _PATH_DEVNULL +#define _PATH_DEVNULL "/dev/null" +#endif + +/* + * Return swap memory stats (see 'swapinfo' cmdline tool) + */ +static PyObject * +psutil_swap_mem(PyObject *self, PyObject *args) +{ + kvm_t *kd; + struct kvm_swap kvmsw[1]; + unsigned int swapin, swapout, nodein, nodeout; + size_t size = sizeof(unsigned int); + + kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open failed"); + if (kd == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kvm_open failed"); + return NULL; + } + + if (kvm_getswapinfo(kd, kvmsw, 1, 0) < 0) { + kvm_close(kd); + PyErr_SetString(PyExc_RuntimeError, "kvm_getswapinfo failed"); + return NULL; + } + + kvm_close(kd); + + if (sysctlbyname("vm.stats.vm.v_swapin", &swapin, &size, NULL, 0) == -1) + goto sbn_error; + if (sysctlbyname("vm.stats.vm.v_swapout", &swapout, &size, NULL, 0) == -1) + goto sbn_error; + if (sysctlbyname("vm.stats.vm.v_vnodein", &nodein, &size, NULL, 0) == -1) + goto sbn_error; + if (sysctlbyname("vm.stats.vm.v_vnodeout", &nodeout, &size, NULL, 0) == -1) + goto sbn_error; + + return Py_BuildValue("(iiiII)", + kvmsw[0].ksw_total, // total + kvmsw[0].ksw_used, // used + kvmsw[0].ksw_total - kvmsw[0].ksw_used, // free + swapin + swapout, // swap in + nodein + nodeout); // swap out + +sbn_error: + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + +/* + * Return a Python tuple representing user, kernel and idle CPU times + */ +static PyObject * +psutil_cpu_times(PyObject *self, PyObject *args) +{ + long cpu_time[CPUSTATES]; + size_t size; + + size = sizeof(cpu_time); + + if (sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + return Py_BuildValue("(ddddd)", + (double)cpu_time[CP_USER] / CLOCKS_PER_SEC, + (double)cpu_time[CP_NICE] / CLOCKS_PER_SEC, + (double)cpu_time[CP_SYS] / CLOCKS_PER_SEC, + (double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC, + (double)cpu_time[CP_INTR] / CLOCKS_PER_SEC + ); +} + + +/* + * XXX + * These functions are available on FreeBSD 8 only. + * In the upper python layer we do various tricks to avoid crashing + * and/or to provide alternatives where possible. + */ + + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 +/* + * Return files opened by process as a list of (path, fd) tuples + */ +static PyObject * +psutil_proc_open_files(PyObject *self, PyObject *args) +{ + long pid; + int i, cnt; + struct kinfo_file *freep = NULL; + struct kinfo_file *kif; + struct kinfo_proc kipp; + PyObject *retList = PyList_New(0); + PyObject *tuple = NULL; + + if (retList == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + if (psutil_kinfo_proc(pid, &kipp) == -1) + goto error; + + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_ad_or_nsp(pid); + goto error; + } + + for (i = 0; i < cnt; i++) { + kif = &freep[i]; + if ((kif->kf_type == KF_TYPE_VNODE) && + (kif->kf_vnode_type == KF_VTYPE_VREG)) + { + tuple = Py_BuildValue("(si)", kif->kf_path, kif->kf_fd); + if (tuple == NULL) + goto error; + if (PyList_Append(retList, tuple)) + goto error; + Py_DECREF(tuple); + } + } + free(freep); + return retList; + +error: + Py_XDECREF(tuple); + Py_DECREF(retList); + if (freep != NULL) + free(freep); + return NULL; +} + + +/* + * Return files opened by process as a list of (path, fd) tuples + */ +static PyObject * +psutil_proc_num_fds(PyObject *self, PyObject *args) +{ + long pid; + int cnt; + + struct kinfo_file *freep; + struct kinfo_proc kipp; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_kinfo_proc(pid, &kipp) == -1) + return NULL; + + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_ad_or_nsp(pid); + return NULL; + } + free(freep); + + return Py_BuildValue("i", cnt); +} + + +/* + * Return process current working directory. + */ +static PyObject * +psutil_proc_cwd(PyObject *self, PyObject *args) +{ + long pid; + PyObject *path = NULL; + struct kinfo_file *freep = NULL; + struct kinfo_file *kif; + struct kinfo_proc kipp; + + int i, cnt; + + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + if (psutil_kinfo_proc(pid, &kipp) == -1) + goto error; + + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_ad_or_nsp(pid); + goto error; + } + + for (i = 0; i < cnt; i++) { + kif = &freep[i]; + if (kif->kf_fd == KF_FD_TYPE_CWD) { + path = Py_BuildValue("s", kif->kf_path); + if (!path) + goto error; + break; + } + } + /* + * For lower pids it seems we can't retrieve any information + * (lsof can't do that it either). Since this happens even + * as root we return an empty string instead of AccessDenied. + */ + if (path == NULL) { + path = Py_BuildValue("s", ""); + } + free(freep); + return path; + +error: + Py_XDECREF(path); + if (freep != NULL) + free(freep); + return NULL; +} + + +// The tcplist fetching and walking is borrowed from netstat/inet.c. +static char * +psutil_fetch_tcplist(void) +{ + char *buf; + size_t len; + int error; + + for (;;) { + if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + buf = malloc(len); + if (buf == NULL) { + PyErr_NoMemory(); + return NULL; + } + if (sysctlbyname("net.inet.tcp.pcblist", buf, &len, NULL, 0) < 0) { + free(buf); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + return buf; + } +} + +static int +psutil_sockaddr_port(int family, struct sockaddr_storage *ss) +{ + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin; + + if (family == AF_INET) { + sin = (struct sockaddr_in *)ss; + return (sin->sin_port); + } else { + sin6 = (struct sockaddr_in6 *)ss; + return (sin6->sin6_port); + } +} + +static void * +psutil_sockaddr_addr(int family, struct sockaddr_storage *ss) +{ + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin; + + if (family == AF_INET) { + sin = (struct sockaddr_in *)ss; + return (&sin->sin_addr); + } else { + sin6 = (struct sockaddr_in6 *)ss; + return (&sin6->sin6_addr); + } +} + +static socklen_t +psutil_sockaddr_addrlen(int family) +{ + if (family == AF_INET) + return (sizeof(struct in_addr)); + else + return (sizeof(struct in6_addr)); +} + +static int +psutil_sockaddr_matches(int family, int port, void *pcb_addr, + struct sockaddr_storage *ss) +{ + if (psutil_sockaddr_port(family, ss) != port) + return (0); + return (memcmp(psutil_sockaddr_addr(family, ss), pcb_addr, + psutil_sockaddr_addrlen(family)) == 0); +} + +static struct tcpcb * +psutil_search_tcplist(char *buf, struct kinfo_file *kif) +{ + struct tcpcb *tp; + struct inpcb *inp; + struct xinpgen *xig, *oxig; + struct xsocket *so; + + oxig = xig = (struct xinpgen *)buf; + for (xig = (struct xinpgen *)((char *)xig + xig->xig_len); + xig->xig_len > sizeof(struct xinpgen); + xig = (struct xinpgen *)((char *)xig + xig->xig_len)) { + tp = &((struct xtcpcb *)xig)->xt_tp; + inp = &((struct xtcpcb *)xig)->xt_inp; + so = &((struct xtcpcb *)xig)->xt_socket; + + if (so->so_type != kif->kf_sock_type || + so->xso_family != kif->kf_sock_domain || + so->xso_protocol != kif->kf_sock_protocol) + continue; + + if (kif->kf_sock_domain == AF_INET) { + if (!psutil_sockaddr_matches( + AF_INET, inp->inp_lport, &inp->inp_laddr, + &kif->kf_sa_local)) + continue; + if (!psutil_sockaddr_matches( + AF_INET, inp->inp_fport, &inp->inp_faddr, + &kif->kf_sa_peer)) + continue; + } else { + if (!psutil_sockaddr_matches( + AF_INET6, inp->inp_lport, &inp->in6p_laddr, + &kif->kf_sa_local)) + continue; + if (!psutil_sockaddr_matches( + AF_INET6, inp->inp_fport, &inp->in6p_faddr, + &kif->kf_sa_peer)) + continue; + } + + return (tp); + } + return NULL; +} + + +// a signaler for connections without an actual status +static int PSUTIL_CONN_NONE = 128; + +/* + * Return connections opened by process. + */ +static PyObject * +psutil_proc_connections(PyObject *self, PyObject *args) +{ + long pid; + int i, cnt; + + struct kinfo_file *freep = NULL; + struct kinfo_file *kif; + char *tcplist = NULL; + struct tcpcb *tcp; + + PyObject *retList = PyList_New(0); + PyObject *tuple = NULL; + PyObject *laddr = NULL; + PyObject *raddr = NULL; + PyObject *af_filter = NULL; + PyObject *type_filter = NULL; + PyObject *_family = NULL; + PyObject *_type = NULL; + + if (retList == NULL) { + return NULL; + } + if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) { + goto error; + } + if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) { + PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); + goto error; + } + + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_ad_or_nsp(pid); + goto error; + } + + tcplist = psutil_fetch_tcplist(); + if (tcplist == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (i = 0; i < cnt; i++) { + int lport, rport, state; + char lip[200], rip[200]; + char path[PATH_MAX]; + int inseq; + tuple = NULL; + laddr = NULL; + raddr = NULL; + + kif = &freep[i]; + if (kif->kf_type == KF_TYPE_SOCKET) + { + // apply filters + _family = PyLong_FromLong((long)kif->kf_sock_domain); + inseq = PySequence_Contains(af_filter, _family); + Py_DECREF(_family); + if (inseq == 0) { + continue; + } + _type = PyLong_FromLong((long)kif->kf_sock_type); + inseq = PySequence_Contains(type_filter, _type); + Py_DECREF(_type); + if (inseq == 0) { + continue; + } + + // IPv4 / IPv6 socket + if ((kif->kf_sock_domain == AF_INET) || + (kif->kf_sock_domain == AF_INET6)) { + // fill status + state = PSUTIL_CONN_NONE; + if (kif->kf_sock_type == SOCK_STREAM) { + tcp = psutil_search_tcplist(tcplist, kif); + if (tcp != NULL) + state = (int)tcp->t_state; + } + + // build addr and port + inet_ntop( + kif->kf_sock_domain, + psutil_sockaddr_addr(kif->kf_sock_domain, + &kif->kf_sa_local), + lip, + sizeof(lip)); + inet_ntop( + kif->kf_sock_domain, + psutil_sockaddr_addr(kif->kf_sock_domain, + &kif->kf_sa_peer), + rip, + sizeof(rip)); + lport = htons(psutil_sockaddr_port(kif->kf_sock_domain, + &kif->kf_sa_local)); + rport = htons(psutil_sockaddr_port(kif->kf_sock_domain, + &kif->kf_sa_peer)); + + // construct python tuple/list + laddr = Py_BuildValue("(si)", lip, lport); + if (!laddr) + goto error; + if (rport != 0) { + raddr = Py_BuildValue("(si)", rip, rport); + } + else { + raddr = Py_BuildValue("()"); + } + if (!raddr) + goto error; + tuple = Py_BuildValue("(iiiNNi)", + kif->kf_fd, + kif->kf_sock_domain, + kif->kf_sock_type, + laddr, + raddr, + state); + if (!tuple) + goto error; + if (PyList_Append(retList, tuple)) + goto error; + Py_DECREF(tuple); + } + // UNIX socket + else if (kif->kf_sock_domain == AF_UNIX) { + struct sockaddr_un *sun; + + sun = (struct sockaddr_un *)&kif->kf_sa_local; + snprintf( + path, sizeof(path), "%.*s", + (sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), + sun->sun_path); + + tuple = Py_BuildValue("(iiisOi)", + kif->kf_fd, + kif->kf_sock_domain, + kif->kf_sock_type, + path, + Py_None, + PSUTIL_CONN_NONE); + if (!tuple) + goto error; + if (PyList_Append(retList, tuple)) + goto error; + Py_DECREF(tuple); + Py_INCREF(Py_None); + } + } + } + free(freep); + free(tcplist); + return retList; + +error: + Py_XDECREF(tuple); + Py_XDECREF(laddr); + Py_XDECREF(raddr); + Py_DECREF(retList); + if (freep != NULL) + free(freep); + if (tcplist != NULL) + free(tcplist); + return NULL; +} + + +/* + * Return a Python list of tuple representing per-cpu times + */ +static PyObject * +psutil_per_cpu_times(PyObject *self, PyObject *args) +{ + static int maxcpus; + int mib[2]; + int ncpu; + size_t len; + size_t size; + int i; + PyObject *py_retlist = PyList_New(0); + PyObject *py_cputime = NULL; + + if (py_retlist == NULL) + return NULL; + + // retrieve maxcpus value + size = sizeof(maxcpus); + if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) { + Py_DECREF(py_retlist); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + long cpu_time[maxcpus][CPUSTATES]; + + // retrieve the number of cpus + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + len = sizeof(ncpu); + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + // per-cpu info + size = sizeof(cpu_time); + if (sysctlbyname("kern.cp_times", &cpu_time, &size, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (i = 0; i < ncpu; i++) { + py_cputime = Py_BuildValue( + "(ddddd)", + (double)cpu_time[i][CP_USER] / CLOCKS_PER_SEC, + (double)cpu_time[i][CP_NICE] / CLOCKS_PER_SEC, + (double)cpu_time[i][CP_SYS] / CLOCKS_PER_SEC, + (double)cpu_time[i][CP_IDLE] / CLOCKS_PER_SEC, + (double)cpu_time[i][CP_INTR] / CLOCKS_PER_SEC); + if (!py_cputime) + goto error; + if (PyList_Append(py_retlist, py_cputime)) + goto error; + Py_DECREF(py_cputime); + } + + return py_retlist; + +error: + Py_XDECREF(py_cputime); + Py_DECREF(py_retlist); + return NULL; +} + + +// remove spaces from string +void remove_spaces(char *str) { + char *p1 = str; + char *p2 = str; + do + while (*p2 == ' ') + p2++; + while (*p1++ = *p2++); +} + + +/* + * Return a list of tuples for every process memory maps. + * 'procstat' cmdline utility has been used as an example. + */ +static PyObject * +psutil_proc_memory_maps(PyObject *self, PyObject *args) +{ + long pid; + int ptrwidth; + int i, cnt; + char addr[30]; + char perms[4]; + const char *path; + struct kinfo_proc kp; + struct kinfo_vmentry *freep = NULL; + struct kinfo_vmentry *kve; + ptrwidth = 2 * sizeof(void *); + PyObject *pytuple = NULL; + PyObject *retlist = PyList_New(0); + + if (retlist == NULL) { + return NULL; + } + if (! PyArg_ParseTuple(args, "l", &pid)) { + goto error; + } + if (psutil_kinfo_proc(pid, &kp) == -1) { + goto error; + } + + freep = kinfo_getvmmap(pid, &cnt); + if (freep == NULL) { + psutil_raise_ad_or_nsp(pid); + goto error; + } + for (i = 0; i < cnt; i++) { + pytuple = NULL; + kve = &freep[i]; + addr[0] = '\0'; + perms[0] = '\0'; + sprintf(addr, "%#*jx-%#*jx", ptrwidth, (uintmax_t)kve->kve_start, + ptrwidth, (uintmax_t)kve->kve_end); + remove_spaces(addr); + strlcat(perms, kve->kve_protection & KVME_PROT_READ ? "r" : "-", + sizeof(perms)); + strlcat(perms, kve->kve_protection & KVME_PROT_WRITE ? "w" : "-", + sizeof(perms)); + strlcat(perms, kve->kve_protection & KVME_PROT_EXEC ? "x" : "-", + sizeof(perms)); + + if (strlen(kve->kve_path) == 0) { + switch (kve->kve_type) { + case KVME_TYPE_NONE: + path = "[none]"; + break; + case KVME_TYPE_DEFAULT: + path = "[default]"; + break; + case KVME_TYPE_VNODE: + path = "[vnode]"; + break; + case KVME_TYPE_SWAP: + path = "[swap]"; + break; + case KVME_TYPE_DEVICE: + path = "[device]"; + break; + case KVME_TYPE_PHYS: + path = "[phys]"; + break; + case KVME_TYPE_DEAD: + path = "[dead]"; + break; + case KVME_TYPE_SG: + path = "[sg]"; + break; + case KVME_TYPE_UNKNOWN: + path = "[unknown]"; + break; + default: + path = "[?]"; + break; + } + } + else { + path = kve->kve_path; + } + + pytuple = Py_BuildValue("sssiiii", + addr, // "start-end" address + perms, // "rwx" permissions + path, // path + kve->kve_resident, // rss + kve->kve_private_resident, // private + kve->kve_ref_count, // ref count + kve->kve_shadow_count); // shadow count + if (!pytuple) + goto error; + if (PyList_Append(retlist, pytuple)) + goto error; + Py_DECREF(pytuple); + } + free(freep); + return retlist; + +error: + Py_XDECREF(pytuple); + Py_DECREF(retlist); + if (freep != NULL) + free(freep); + return NULL; +} +#endif + + +/* + * Return a list of tuples including device, mount point and fs type + * for all partitions mounted on the system. + */ +static PyObject * +psutil_disk_partitions(PyObject *self, PyObject *args) +{ + int num; + int i; + long len; + uint64_t flags; + char opts[200]; + struct statfs *fs = NULL; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + + // get the number of mount points + Py_BEGIN_ALLOW_THREADS + num = getfsstat(NULL, 0, MNT_NOWAIT); + Py_END_ALLOW_THREADS + if (num == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + len = sizeof(*fs) * num; + fs = malloc(len); + if (fs == NULL) { + PyErr_NoMemory(); + goto error; + } + + Py_BEGIN_ALLOW_THREADS + num = getfsstat(fs, len, MNT_NOWAIT); + Py_END_ALLOW_THREADS + if (num == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (i = 0; i < num; i++) { + py_tuple = NULL; + opts[0] = 0; + flags = fs[i].f_flags; + + // see sys/mount.h + if (flags & MNT_RDONLY) + strlcat(opts, "ro", sizeof(opts)); + else + strlcat(opts, "rw", sizeof(opts)); + if (flags & MNT_SYNCHRONOUS) + strlcat(opts, ",sync", sizeof(opts)); + if (flags & MNT_NOEXEC) + strlcat(opts, ",noexec", sizeof(opts)); + if (flags & MNT_NOSUID) + strlcat(opts, ",nosuid", sizeof(opts)); + if (flags & MNT_UNION) + strlcat(opts, ",union", sizeof(opts)); + if (flags & MNT_ASYNC) + strlcat(opts, ",async", sizeof(opts)); + if (flags & MNT_SUIDDIR) + strlcat(opts, ",suiddir", sizeof(opts)); + if (flags & MNT_SOFTDEP) + strlcat(opts, ",softdep", sizeof(opts)); + if (flags & MNT_NOSYMFOLLOW) + strlcat(opts, ",nosymfollow", sizeof(opts)); + if (flags & MNT_GJOURNAL) + strlcat(opts, ",gjournal", sizeof(opts)); + if (flags & MNT_MULTILABEL) + strlcat(opts, ",multilabel", sizeof(opts)); + if (flags & MNT_ACLS) + strlcat(opts, ",acls", sizeof(opts)); + if (flags & MNT_NOATIME) + strlcat(opts, ",noatime", sizeof(opts)); + if (flags & MNT_NOCLUSTERR) + strlcat(opts, ",noclusterr", sizeof(opts)); + if (flags & MNT_NOCLUSTERW) + strlcat(opts, ",noclusterw", sizeof(opts)); + if (flags & MNT_NFS4ACLS) + strlcat(opts, ",nfs4acls", sizeof(opts)); + + py_tuple = Py_BuildValue("(ssss)", + fs[i].f_mntfromname, // device + fs[i].f_mntonname, // mount point + fs[i].f_fstypename, // fs type + opts); // options + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + + free(fs); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (fs != NULL) + free(fs); + return NULL; +} + + +/* + * Return a Python list of named tuples with overall network I/O information + */ +static PyObject * +psutil_net_io_counters(PyObject *self, PyObject *args) +{ + char *buf = NULL, *lim, *next; + struct if_msghdr *ifm; + int mib[6]; + size_t len; + PyObject *py_retdict = PyDict_New(); + PyObject *py_ifc_info = NULL; + if (py_retdict == NULL) + return NULL; + + mib[0] = CTL_NET; // networking subsystem + mib[1] = PF_ROUTE; // type of information + mib[2] = 0; // protocol (IPPROTO_xxx) + mib[3] = 0; // address family + mib[4] = NET_RT_IFLIST; // operation + mib[5] = 0; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + buf = malloc(len); + if (buf == NULL) { + PyErr_NoMemory(); + goto error; + } + + if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + lim = buf + len; + + for (next = buf; next < lim; ) { + py_ifc_info = NULL; + ifm = (struct if_msghdr *)next; + next += ifm->ifm_msglen; + + if (ifm->ifm_type == RTM_IFINFO) { + struct if_msghdr *if2m = (struct if_msghdr *)ifm; + struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1); + char ifc_name[32]; + + strncpy(ifc_name, sdl->sdl_data, sdl->sdl_nlen); + ifc_name[sdl->sdl_nlen] = 0; + // XXX: ignore usbus interfaces: + // http://lists.freebsd.org/pipermail/freebsd-current/ + // 2011-October/028752.html + // 'ifconfig -a' doesn't show them, nor do we. + if (strncmp(ifc_name, "usbus", 5) == 0) { + continue; + } + + py_ifc_info = Py_BuildValue("(kkkkkkki)", + if2m->ifm_data.ifi_obytes, + if2m->ifm_data.ifi_ibytes, + if2m->ifm_data.ifi_opackets, + if2m->ifm_data.ifi_ipackets, + if2m->ifm_data.ifi_ierrors, + if2m->ifm_data.ifi_oerrors, + if2m->ifm_data.ifi_iqdrops, + 0); // dropout not supported + if (!py_ifc_info) + goto error; + if (PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info)) + goto error; + Py_DECREF(py_ifc_info); + } + else { + continue; + } + } + + free(buf); + return py_retdict; + +error: + Py_XDECREF(py_ifc_info); + Py_DECREF(py_retdict); + if (buf != NULL) + free(buf); + return NULL; +} + + +/* + * Return a Python dict of tuples for disk I/O information + */ +static PyObject * +psutil_disk_io_counters(PyObject *self, PyObject *args) +{ + int i; + struct statinfo stats; + + PyObject *py_retdict = PyDict_New(); + PyObject *py_disk_info = NULL; + if (py_retdict == NULL) + return NULL; + + if (devstat_checkversion(NULL) < 0) { + PyErr_Format(PyExc_RuntimeError, "devstat_checkversion() failed"); + goto error; + } + + stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); + if (stats.dinfo == NULL) { + PyErr_NoMemory(); + goto error; + } + bzero(stats.dinfo, sizeof(struct devinfo)); + + if (devstat_getdevs(NULL, &stats) == -1) { + PyErr_Format(PyExc_RuntimeError, "devstat_getdevs() failed"); + goto error; + } + + for (i = 0; i < stats.dinfo->numdevs; i++) { + py_disk_info = NULL; + struct devstat current; + char disk_name[128]; + current = stats.dinfo->devices[i]; + snprintf(disk_name, sizeof(disk_name), "%s%d", + current.device_name, + current.unit_number); + + py_disk_info = Py_BuildValue( + "(KKKKLL)", + current.operations[DEVSTAT_READ], // no reads + current.operations[DEVSTAT_WRITE], // no writes + current.bytes[DEVSTAT_READ], // bytes read + current.bytes[DEVSTAT_WRITE], // bytes written + (long long)devstat_compute_etime( + ¤t.duration[DEVSTAT_READ], NULL), // r time + (long long)devstat_compute_etime( + ¤t.duration[DEVSTAT_WRITE], NULL)); // w time + if (!py_disk_info) + goto error; + if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info)) + goto error; + Py_DECREF(py_disk_info); + } + + if (stats.dinfo->mem_ptr) { + free(stats.dinfo->mem_ptr); + } + free(stats.dinfo); + return py_retdict; + +error: + Py_XDECREF(py_disk_info); + Py_DECREF(py_retdict); + if (stats.dinfo != NULL) + free(stats.dinfo); + return NULL; +} + + +/* + * Return currently connected users as a list of tuples. + */ +static PyObject * +psutil_users(PyObject *self, PyObject *args) +{ + PyObject *ret_list = PyList_New(0); + PyObject *tuple = NULL; + + if (ret_list == NULL) + return NULL; + +#if __FreeBSD_version < 900000 + struct utmp ut; + FILE *fp; + + fp = fopen(_PATH_UTMP, "r"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + while (fread(&ut, sizeof(ut), 1, fp) == 1) { + if (*ut.ut_name == '\0') + continue; + tuple = Py_BuildValue( + "(sssf)", + ut.ut_name, // username + ut.ut_line, // tty + ut.ut_host, // hostname + (float)ut.ut_time); // start time + if (!tuple) { + fclose(fp); + goto error; + } + if (PyList_Append(ret_list, tuple)) { + fclose(fp); + goto error; + } + Py_DECREF(tuple); + } + + fclose(fp); +#else + struct utmpx *utx; + + while ((utx = getutxent()) != NULL) { + if (utx->ut_type != USER_PROCESS) + continue; + tuple = Py_BuildValue( + "(sssf)", + utx->ut_user, // username + utx->ut_line, // tty + utx->ut_host, // hostname + (float)utx->ut_tv.tv_sec // start time + ); + + if (!tuple) { + endutxent(); + goto error; + } + if (PyList_Append(ret_list, tuple)) { + endutxent(); + goto error; + } + Py_DECREF(tuple); + } + + endutxent(); +#endif + return ret_list; + +error: + Py_XDECREF(tuple); + Py_DECREF(ret_list); + return NULL; +} + + + +/* + * System-wide open connections. + */ + +#define HASHSIZE 1009 +static struct xfile *psutil_xfiles; +static int psutil_nxfiles; + +int +psutil_populate_xfiles() +{ + size_t len; + + if ((psutil_xfiles = malloc(len = sizeof *psutil_xfiles)) == NULL) { + PyErr_NoMemory(); + return 0; + } + while (sysctlbyname("kern.file", psutil_xfiles, &len, 0, 0) == -1) { + if (errno != ENOMEM) { + PyErr_SetFromErrno(0); + return 0; + } + len *= 2; + if ((psutil_xfiles = realloc(psutil_xfiles, len)) == NULL) { + PyErr_NoMemory(); + return 0; + } + } + if (len > 0 && psutil_xfiles->xf_size != sizeof *psutil_xfiles) { + PyErr_Format(PyExc_RuntimeError, "struct xfile size mismatch"); + return 0; + } + psutil_nxfiles = len / sizeof *psutil_xfiles; + return 1; +} + +int +psutil_get_pid_from_sock(int sock_hash) +{ + struct xfile *xf; + int hash, n; + for (xf = psutil_xfiles, n = 0; n < psutil_nxfiles; ++n, ++xf) { + if (xf->xf_data == NULL) + continue; + hash = (int)((uintptr_t)xf->xf_data % HASHSIZE); + if (sock_hash == hash) { + return xf->xf_pid; + } + } + return -1; +} + + +int psutil_gather_inet(int proto, PyObject *py_retlist) +{ + struct xinpgen *xig, *exig; + struct xinpcb *xip; + struct xtcpcb *xtp; + struct inpcb *inp; + struct xsocket *so; + struct sock *sock; + const char *varname; + size_t len, bufsize; + void *buf; + int hash, retry, vflag, type; + + PyObject *tuple = NULL; + PyObject *laddr = NULL; + PyObject *raddr = NULL; + + switch (proto) { + case IPPROTO_TCP: + varname = "net.inet.tcp.pcblist"; + type = SOCK_STREAM; + break; + case IPPROTO_UDP: + varname = "net.inet.udp.pcblist"; + type = SOCK_DGRAM; + break; + } + + buf = NULL; + bufsize = 8192; + retry = 5; + do { + for (;;) { + buf = realloc(buf, bufsize); + if (buf == NULL) { + // XXX + continue; + } + len = bufsize; + if (sysctlbyname(varname, buf, &len, NULL, 0) == 0) + break; + if (errno != ENOMEM) { + PyErr_SetFromErrno(0); + goto error; + } + bufsize *= 2; + } + xig = (struct xinpgen *)buf; + exig = (struct xinpgen *)(void *)((char *)buf + len - sizeof *exig); + if (xig->xig_len != sizeof *xig || exig->xig_len != sizeof *exig) { + PyErr_Format(PyExc_RuntimeError, "struct xinpgen size mismatch"); + goto error; + } + } while (xig->xig_gen != exig->xig_gen && retry--); + + + for (;;) { + xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); + if (xig >= exig) + break; + + switch (proto) { + case IPPROTO_TCP: + xtp = (struct xtcpcb *)xig; + if (xtp->xt_len != sizeof *xtp) { + PyErr_Format(PyExc_RuntimeError, "struct xtcpcb size mismatch"); + goto error; + } + break; + case IPPROTO_UDP: + xip = (struct xinpcb *)xig; + if (xip->xi_len != sizeof *xip) { + PyErr_Format(PyExc_RuntimeError, "struct xinpcb size mismatch"); + goto error; + } + inp = &xip->xi_inp; + so = &xip->xi_socket; + break; + } + + inp = &xtp->xt_inp; + so = &xtp->xt_socket; + char lip[200], rip[200]; + int family, lport, rport, pid, status; + + hash = (int)((uintptr_t)so->xso_so % HASHSIZE); + pid = psutil_get_pid_from_sock(hash); + if (pid < 0) + continue; + lport = ntohs(inp->inp_lport); + rport = ntohs(inp->inp_fport); + status = xtp->xt_tp.t_state; + + if (inp->inp_vflag & INP_IPV4) { + family = AF_INET; + inet_ntop(AF_INET, &inp->inp_laddr.s_addr, lip, sizeof(lip)); + inet_ntop(AF_INET, &inp->inp_faddr.s_addr, rip, sizeof(rip)); + } + else if (inp->inp_vflag & INP_IPV6) { + family = AF_INET6; + inet_ntop(AF_INET6, &inp->in6p_laddr.s6_addr, lip, sizeof(lip)); + inet_ntop(AF_INET6, &inp->in6p_faddr.s6_addr, rip, sizeof(rip)); + } + + // construct python tuple/list + laddr = Py_BuildValue("(si)", lip, lport); + if (!laddr) + goto error; + if (rport != 0) { + raddr = Py_BuildValue("(si)", rip, rport); + } + else { + raddr = Py_BuildValue("()"); + } + if (!raddr) + goto error; + tuple = Py_BuildValue("(iiiNNii)", -1, family, type, laddr, raddr, + status, pid); + if (!tuple) + goto error; + if (PyList_Append(py_retlist, tuple)) + goto error; + Py_DECREF(tuple); + } + + free(buf); + return 1; + +error: + Py_XDECREF(tuple); + Py_XDECREF(laddr); + Py_XDECREF(raddr); + free(buf); + return 0; +} + + +int psutil_gather_unix(int proto, PyObject *py_retlist) +{ + struct xunpgen *xug, *exug; + struct xunpcb *xup; + struct sock *sock; + const char *varname, *protoname; + size_t len, bufsize; + void *buf; + int hash, retry; + int family, lport, rport, pid; + struct sockaddr_un *sun; + char path[PATH_MAX]; + + PyObject *tuple = NULL; + PyObject *laddr = NULL; + PyObject *raddr = NULL; + + switch (proto) { + case SOCK_STREAM: + varname = "net.local.stream.pcblist"; + protoname = "stream"; + break; + case SOCK_DGRAM: + varname = "net.local.dgram.pcblist"; + protoname = "dgram"; + break; + } + + buf = NULL; + bufsize = 8192; + retry = 5; + + do { + for (;;) { + buf = realloc(buf, bufsize); + if (buf == NULL) { + PyErr_NoMemory(); + goto error; + } + len = bufsize; + if (sysctlbyname(varname, buf, &len, NULL, 0) == 0) + break; + if (errno != ENOMEM) { + PyErr_SetFromErrno(0); + goto error; + } + bufsize *= 2; + } + xug = (struct xunpgen *)buf; + exug = (struct xunpgen *)(void *) + ((char *)buf + len - sizeof *exug); + if (xug->xug_len != sizeof *xug || exug->xug_len != sizeof *exug) { + PyErr_Format(PyExc_RuntimeError, "struct xinpgen size mismatch"); + goto error; + } + } while (xug->xug_gen != exug->xug_gen && retry--); + + for (;;) { + xug = (struct xunpgen *)(void *)((char *)xug + xug->xug_len); + if (xug >= exug) + break; + xup = (struct xunpcb *)xug; + if (xup->xu_len != sizeof *xup) { + warnx("struct xunpgen size mismatch"); + goto error; + } + + hash = (int)((uintptr_t) xup->xu_socket.xso_so % HASHSIZE); + pid = psutil_get_pid_from_sock(hash); + if (pid < 0) + continue; + + sun = (struct sockaddr_un *)&xup->xu_addr; + snprintf(path, sizeof(path), "%.*s", + (sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), + sun->sun_path); + + tuple = Py_BuildValue("(iiisOii)", -1, AF_UNIX, proto, path, Py_None, + PSUTIL_CONN_NONE, pid); + if (!tuple) + goto error; + if (PyList_Append(py_retlist, tuple)) + goto error; + Py_DECREF(tuple); + Py_INCREF(Py_None); + } + + free(buf); + return 1; + +error: + Py_XDECREF(tuple); + Py_XDECREF(laddr); + Py_XDECREF(raddr); + free(buf); + return 0; +} + + +/* + * Return system-wide open connections. + */ +static PyObject* +psutil_net_connections(PyObject* self, PyObject* args) +{ + PyObject *af_filter = NULL; + PyObject *type_filter = NULL; + PyObject *py_retlist = PyList_New(0); + + if (psutil_populate_xfiles() != 1) + goto error; + + if (psutil_gather_inet(IPPROTO_TCP, py_retlist) == 0) + goto error; + if (psutil_gather_inet(IPPROTO_UDP, py_retlist) == 0) + goto error; + if (psutil_gather_unix(SOCK_STREAM, py_retlist) == 0) + goto error; + if (psutil_gather_unix(SOCK_DGRAM, py_retlist) == 0) + goto error; + + free(psutil_xfiles); + return py_retlist; + +error: + Py_DECREF(py_retlist); + free(psutil_xfiles); + return NULL; +} + + +/* + * define the psutil C module methods and initialize the module. + */ +static PyMethodDef +PsutilMethods[] = +{ + // --- per-process functions + + {"proc_name", psutil_proc_name, METH_VARARGS, + "Return process name"}, + {"proc_connections", psutil_proc_connections, METH_VARARGS, + "Return connections opened by process"}, + {"proc_exe", psutil_proc_exe, METH_VARARGS, + "Return process pathname executable"}, + {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS, + "Return process cmdline as a list of cmdline arguments"}, + {"proc_ppid", psutil_proc_ppid, METH_VARARGS, + "Return process ppid as an integer"}, + {"proc_uids", psutil_proc_uids, METH_VARARGS, + "Return process real effective and saved user ids as a Python tuple"}, + {"proc_gids", psutil_proc_gids, METH_VARARGS, + "Return process real effective and saved group ids as a Python tuple"}, + {"proc_cpu_times", psutil_proc_cpu_times, METH_VARARGS, + "Return tuple of user/kern time for the given PID"}, + {"proc_create_time", psutil_proc_create_time, METH_VARARGS, + "Return a float indicating the process create time expressed in " + "seconds since the epoch"}, + {"proc_memory_info", psutil_proc_memory_info, METH_VARARGS, + "Return extended memory info for a process as a Python tuple."}, + {"proc_num_threads", psutil_proc_num_threads, METH_VARARGS, + "Return number of threads used by process"}, + {"proc_num_ctx_switches", psutil_proc_num_ctx_switches, METH_VARARGS, + "Return the number of context switches performed by process"}, + {"proc_threads", psutil_proc_threads, METH_VARARGS, + "Return process threads"}, + {"proc_status", psutil_proc_status, METH_VARARGS, + "Return process status as an integer"}, + {"proc_io_counters", psutil_proc_io_counters, METH_VARARGS, + "Return process IO counters"}, + {"proc_tty_nr", psutil_proc_tty_nr, METH_VARARGS, + "Return process tty (terminal) number"}, +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 + {"proc_open_files", psutil_proc_open_files, METH_VARARGS, + "Return files opened by process as a list of (path, fd) tuples"}, + {"proc_cwd", psutil_proc_cwd, METH_VARARGS, + "Return process current working directory."}, + {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, + "Return a list of tuples for every process's memory map"}, + {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS, + "Return the number of file descriptors opened by this process"}, +#endif + + // --- system-related functions + + {"pids", psutil_pids, METH_VARARGS, + "Returns a list of PIDs currently running on the system"}, + {"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS, + "Return number of logical CPUs on the system"}, + {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, + "Return an XML string to determine the number physical CPUs."}, + {"virtual_mem", psutil_virtual_mem, METH_VARARGS, + "Return system virtual memory usage statistics"}, + {"swap_mem", psutil_swap_mem, METH_VARARGS, + "Return swap mem stats"}, + {"cpu_times", psutil_cpu_times, METH_VARARGS, + "Return system cpu times as a tuple (user, system, nice, idle, irc)"}, +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 + {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS, + "Return system per-cpu times as a list of tuples"}, +#endif + {"boot_time", psutil_boot_time, METH_VARARGS, + "Return the system boot time expressed in seconds since the epoch."}, + {"disk_partitions", psutil_disk_partitions, METH_VARARGS, + "Return a list of tuples including device, mount point and " + "fs type for all partitions mounted on the system."}, + {"net_io_counters", psutil_net_io_counters, METH_VARARGS, + "Return dict of tuples of networks I/O information."}, + {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS, + "Return a Python dict of tuples for disk I/O information"}, + {"users", psutil_users, METH_VARARGS, + "Return currently connected users as a list of tuples"}, + {"net_connections", psutil_net_connections, METH_VARARGS, + "Return system-wide open connections."}, + + {NULL, NULL, 0, NULL} +}; + +struct module_state { + PyObject *error; +}; + +#if PY_MAJOR_VERSION >= 3 +#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) +#else +#define GETSTATE(m) (&_state) +#endif + +#if PY_MAJOR_VERSION >= 3 + +static int +psutil_bsd_traverse(PyObject *m, visitproc visit, void *arg) { + Py_VISIT(GETSTATE(m)->error); + return 0; +} + +static int +psutil_bsd_clear(PyObject *m) { + Py_CLEAR(GETSTATE(m)->error); + return 0; +} + +static struct PyModuleDef + moduledef = { + PyModuleDef_HEAD_INIT, + "psutil_bsd", + NULL, + sizeof(struct module_state), + PsutilMethods, + NULL, + psutil_bsd_traverse, + psutil_bsd_clear, + NULL +}; + +#define INITERROR return NULL + +PyMODINIT_FUNC PyInit__psutil_bsd(void) + +#else +#define INITERROR return + +void init_psutil_bsd(void) +#endif +{ +#if PY_MAJOR_VERSION >= 3 + PyObject *module = PyModule_Create(&moduledef); +#else + PyObject *module = Py_InitModule("_psutil_bsd", PsutilMethods); +#endif + // process status constants + PyModule_AddIntConstant(module, "SSTOP", SSTOP); + PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); + PyModule_AddIntConstant(module, "SRUN", SRUN); + PyModule_AddIntConstant(module, "SIDL", SIDL); + PyModule_AddIntConstant(module, "SWAIT", SWAIT); + PyModule_AddIntConstant(module, "SLOCK", SLOCK); + PyModule_AddIntConstant(module, "SZOMB", SZOMB); + // connection status constants + PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED); + PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING); + PyModule_AddIntConstant(module, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT); + PyModule_AddIntConstant(module, "TCPS_LISTEN", TCPS_LISTEN); + PyModule_AddIntConstant(module, "TCPS_ESTABLISHED", TCPS_ESTABLISHED); + PyModule_AddIntConstant(module, "TCPS_SYN_SENT", TCPS_SYN_SENT); + PyModule_AddIntConstant(module, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED); + PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1); + PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2); + PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK); + PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT); + PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE); + + if (module == NULL) { + INITERROR; + } +#if PY_MAJOR_VERSION >= 3 + return module; +#endif +} diff --git a/psutil/arch/bsd/process_info_openbsd.c b/psutil/arch/bsd/process_info_openbsd.c new file mode 100644 index 000000000..1c1955663 --- /dev/null +++ b/psutil/arch/bsd/process_info_openbsd.c @@ -0,0 +1,285 @@ +/* + * 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_bsd module methods. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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(struct kinfo_proc **procList, size_t *procCount) +{ + int err; + struct kinfo_proc *result; + int done; + static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 }; + // Declaring name as const requires us to cast it when passing it to + // sysctl because the prototype doesn't include the const modifier. + size_t length; + + assert( procList != NULL); + assert(*procList == NULL); + assert(procCount != NULL); + + *procCount = 0; + + /* + * We start by calling sysctl with result == NULL and length == 0. + * That will succeed, and set length to the appropriate length. + * We then allocate a buffer of that size and call sysctl again + * with that buffer. If that succeeds, we're done. If that fails + * with ENOMEM, we have to throw away our buffer and loop. Note + * that the loop causes use to call sysctl with NULL again; this + * is necessary because the ENOMEM failure case sets length to + * the amount of data returned, not the amount of data that + * could have been returned. + */ + result = NULL; + done = 0; + do { + assert(result == NULL); + // Call sysctl with a NULL buffer. + length = 0; + err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, + NULL, &length, NULL, 0); + if (err == -1) + err = errno; + + // Allocate an appropriately sized buffer based on the results + // from the previous call. + if (err == 0) { + result = malloc(length); + if (result == NULL) + err = ENOMEM; + } + + // Call sysctl again with the new buffer. If we get an ENOMEM + // error, toss away our buffer and start again. + if (err == 0) { + err = sysctl((int *) name, (sizeof(name) / sizeof(*name)) - 1, + result, &length, NULL, 0); + if (err == -1) + err = errno; + if (err == 0) { + done = 1; + } + else if (err == ENOMEM) { + assert(result != NULL); + free(result); + result = NULL; + err = 0; + } + } + } while (err == 0 && ! done); + + // Clean up and establish post conditions. + if (err != 0 && result != NULL) { + free(result); + result = NULL; + } + + *procList = result; + *procCount = length / sizeof(struct kinfo_proc); + + assert((err == 0) == (*procList != NULL)); + return err; +} + + +char +*psutil_get_cmd_path(long pid, size_t *pathsize) +{ + int mib[4]; + char *path; + size_t size = 0; + + /* + * Make a sysctl() call to get the raw argument space of the process. + */ + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = pid; + + // call with a null buffer first to determine if we need a buffer + if (sysctl(mib, 4, NULL, &size, NULL, 0) == -1) { + return NULL; + } + + path = malloc(size); + if (path == NULL) { + PyErr_NoMemory(); + return NULL; + } + + *pathsize = size; + if (sysctl(mib, 4, path, &size, NULL, 0) == -1) { + free(path); + return NULL; // Insufficient privileges + } + + return path; +} + + +/* + * XXX no longer used; it probably makese sense to remove it. + * Borrowed from psi Python System Information project + * + * Get command arguments and environment variables. + * + * Based on code from ps. + * + * Returns: + * 0 for success; + * -1 for failure (Exception raised); + * 1 for insufficient privileges. + */ +char +*psutil_get_cmd_args(long pid, size_t *argsize) +{ + int mib[4], argmax; + size_t size = sizeof(argmax); + char *procargs = NULL; + + // 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) + return NULL; + + // Allocate space for the arguments. + procargs = (char *)malloc(argmax); + if (procargs == NULL) { + PyErr_NoMemory(); + return NULL; + } + + /* + * Make a sysctl() call to get the raw argument space of the process. + */ + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_ARGS; + mib[3] = pid; + + size = argmax; + if (sysctl(mib, 4, procargs, &size, NULL, 0) == -1) { + free(procargs); + return NULL; // Insufficient privileges + } + + // return string and set the length of arguments + *argsize = size; + return procargs; +} + + +// returns the command line as a python list object +PyObject * +psutil_get_arg_list(long pid) +{ + char *argstr = NULL; + int pos = 0; + size_t argsize = 0; + PyObject *retlist = Py_BuildValue("[]"); + PyObject *item = NULL; + + if (pid < 0) { + return retlist; + } + + argstr = psutil_get_cmd_args(pid, &argsize); + if (argstr == NULL) { + goto error; + } + + // args are returned as a flattened string with \0 separators between + // arguments add each string to the list then step forward to the next + // separator + if (argsize > 0) { + while (pos < argsize) { + item = Py_BuildValue("s", &argstr[pos]); + if (!item) + goto error; + if (PyList_Append(retlist, item)) + goto error; + Py_DECREF(item); + pos = pos + strlen(&argstr[pos]) + 1; + } + } + + free(argstr); + return retlist; + +error: + Py_XDECREF(item); + Py_DECREF(retlist); + if (argstr != NULL) + free(argstr); + return NULL; +} + + +/* + * Return 1 if PID exists in the current process list, else 0. + */ +int +psutil_pid_exists(long pid) +{ + int kill_ret; + 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; +} + + +/* + * Set exception to AccessDenied if pid exists else NoSuchProcess. + */ +int +psutil_raise_ad_or_nsp(pid) { + if (psutil_pid_exists(pid) == 0) { + NoSuchProcess(); + } + else { + AccessDenied(); + } +} diff --git a/setup.py b/setup.py index ce1c991c1..3426d96b2 100644 --- a/setup.py +++ b/setup.py @@ -104,6 +104,18 @@ def get_winver(): libraries=["devstat"]), posix_extension, ] +# OpenBSD +elif sys.platform.startswith("openbsd"): + extensions = [Extension( + '_psutil_bsd', + sources=[ + 'psutil/_psutil_openbsd.c', + 'psutil/_psutil_common.c', + 'psutil/arch/bsd/process_info_openbsd.c' + ], + libraries=["kvm"]), + posix_extension, + ] # Linux elif sys.platform.startswith("linux"): extensions = [Extension( @@ -155,6 +167,7 @@ def main(): 'Operating System :: Microsoft', 'Operating System :: OS Independent', 'Operating System :: POSIX :: BSD :: FreeBSD', + 'Operating System :: POSIX :: BSD :: OpenBSD', 'Operating System :: POSIX :: Linux', 'Operating System :: POSIX :: SunOS/Solaris', 'Operating System :: POSIX', From c217d3499269561dd70c867ffa038ce993d929c5 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Fri, 26 Dec 2014 21:31:46 +0100 Subject: [PATCH 02/74] First stab at merging patches from wip port against 0.4.1 --- psutil/_psutil_openbsd.c | 84 +++++++------- psutil/arch/bsd/process_info_openbsd.c | 148 ++++++++++--------------- 2 files changed, 100 insertions(+), 132 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 5a9f9c08b..8727ff4ad 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -1,9 +1,9 @@ /* - * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Copyright (c) 2014, Landry Breuil. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * - * FreeBSD platform-specific module methods for _psutil_bsd + * OpenBSD platform-specific module methods for _psutil_bsd */ @@ -16,8 +16,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -36,14 +36,7 @@ #include // for TCP connection states #include // for inet_ntop() -#if __FreeBSD_version < 900000 #include // system users -#else -#include -#endif -#include // get io counters -#include // needed for vmtotal struct -#include // process open files, shared libs (kinfo_getvmmap) #include #include // net io counters @@ -60,6 +53,7 @@ // convert a timeval struct to a double #define TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) +#define KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) /* @@ -68,7 +62,7 @@ static int psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) { - int mib[4]; + int mib[6]; size_t size; mib[0] = CTL_KERN; mib[1] = KERN_PROC; @@ -77,7 +71,10 @@ psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) size = sizeof(struct kinfo_proc); - if (sysctl((int *)mib, 4, proc, &size, NULL, 0) == -1) { + mib[4] = size; + mib[5] = 1; + + if (sysctl((int*)mib, 6, proc, &size, NULL, 0) == -1) { PyErr_SetFromErrno(PyExc_OSError); return -1; } @@ -116,7 +113,7 @@ psutil_pids(PyObject *self, PyObject *args) if (num_processes > 0) { orig_address = proclist; // save so we can free it after we're done for (idx = 0; idx < num_processes; idx++) { - pid = Py_BuildValue("i", proclist->ki_pid); + pid = Py_BuildValue("i", proclist->p_pid); if (!pid) goto error; if (PyList_Append(retlist, pid)) @@ -173,7 +170,7 @@ psutil_proc_name(PyObject *self, PyObject *args) if (psutil_kinfo_proc(pid, &kp) == -1) { return NULL; } - return Py_BuildValue("s", kp.ki_comm); + return Py_BuildValue("s", kp.p_comm); } @@ -257,7 +254,7 @@ psutil_proc_ppid(PyObject *self, PyObject *args) if (psutil_kinfo_proc(pid, &kp) == -1) { return NULL; } - return Py_BuildValue("l", (long)kp.ki_ppid); + return Py_BuildValue("l", (long)kp.p_ppid); } @@ -275,7 +272,7 @@ psutil_proc_status(PyObject *self, PyObject *args) if (psutil_kinfo_proc(pid, &kp) == -1) { return NULL; } - return Py_BuildValue("i", (int)kp.ki_stat); + return Py_BuildValue("i", (int)kp.p_stat); } @@ -295,9 +292,9 @@ psutil_proc_uids(PyObject *self, PyObject *args) return NULL; } return Py_BuildValue("lll", - (long)kp.ki_ruid, - (long)kp.ki_uid, - (long)kp.ki_svuid); + (long)kp.p_ruid, + (long)kp.p_uid, + (long)kp.p_svuid); } @@ -317,9 +314,9 @@ psutil_proc_gids(PyObject *self, PyObject *args) return NULL; } return Py_BuildValue("lll", - (long)kp.ki_rgid, - (long)kp.ki_groups[0], - (long)kp.ki_svuid); + (long)kp.p_rgid, + (long)kp.p_groups[0], + (long)kp.p_svuid); } @@ -338,7 +335,7 @@ psutil_proc_tty_nr(PyObject *self, PyObject *args) if (psutil_kinfo_proc(pid, &kp) == -1) { return NULL; } - return Py_BuildValue("i", kp.ki_tdev); + return Py_BuildValue("i", kp.p_tdev); } @@ -376,7 +373,8 @@ psutil_proc_num_threads(PyObject *self, PyObject *args) if (psutil_kinfo_proc(pid, &kp) == -1) { return NULL; } - return Py_BuildValue("l", (long)kp.ki_numthreads); +/* TODO: get all the procs with kvm_getprocs() and count those iwth the desired ki_pid */ + return Py_BuildValue("l", (long)0); } @@ -408,7 +406,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) // we need to re-query for thread information, so don't use *kipp mib[0] = CTL_KERN; mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD; + mib[2] = KERN_PROC_PID /* | KERN_PROC_INC_THREAD */; mib[3] = pid; size = 0; @@ -441,9 +439,9 @@ psutil_proc_threads(PyObject *self, PyObject *args) for (i = 0; i < size / sizeof(*kipp); i++) { kipp = &kip[i]; pyTuple = Py_BuildValue("Idd", - kipp->ki_tid, - TV2DOUBLE(kipp->ki_rusage.ru_utime), - TV2DOUBLE(kipp->ki_rusage.ru_stime)); + 0, //thread id? + kipp->p_uutime_sec, + kipp->p_ustime_sec if (pyTuple == NULL) goto error; if (PyList_Append(retList, pyTuple)) @@ -479,8 +477,8 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args) return NULL; } // convert from microseconds to seconds - user_t = TV2DOUBLE(kp.ki_rusage.ru_utime); - sys_t = TV2DOUBLE(kp.ki_rusage.ru_stime); + user_t = TV2DOUBLE(kp.p_uutime); + sys_t = TV2DOUBLE(kp.p_ustime); return Py_BuildValue("(dd)", user_t, sys_t); } @@ -577,8 +575,8 @@ psutil_proc_io_counters(PyObject *self, PyObject *args) } // there's apparently no way to determine bytes count, hence return -1. return Py_BuildValue("(llll)", - kp.ki_rusage.ru_inblock, - kp.ki_rusage.ru_oublock, + kp.uru_inblock, + kp.uru_oublock, -1, -1); } @@ -587,6 +585,7 @@ psutil_proc_io_counters(PyObject *self, PyObject *args) /* * Return extended memory info for a process as a Python tuple. */ +#define ptoa(x) ((paddr_t)(x) << PAGE_SHIFT) static PyObject * psutil_proc_memory_info(PyObject *self, PyObject *args) { @@ -599,7 +598,7 @@ psutil_proc_memory_info(PyObject *self, PyObject *args) return NULL; } return Py_BuildValue("(lllll)", - ptoa(kp.ki_rssize), // rss + ptoa(kp.p_vm_rssize), // rss (long)kp.ki_size, // vms ptoa(kp.ki_tsize), // text ptoa(kp.ki_dsize), // data @@ -1194,14 +1193,6 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) if (py_retlist == NULL) return NULL; - // retrieve maxcpus value - size = sizeof(maxcpus); - if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) { - Py_DECREF(py_retlist); - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - long cpu_time[maxcpus][CPUSTATES]; // retrieve the number of cpus mib[0] = CTL_HW; @@ -1211,12 +1202,15 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) PyErr_SetFromErrno(PyExc_OSError); goto error; } + long cpu_time[ncpu][CPUSTATES]; // per-cpu info + mib[0] = CTL_KERN; + mib[1] = KERN_CPTIME; size = sizeof(cpu_time); - if (sysctlbyname("kern.cp_times", &cpu_time, &size, NULL, 0) == -1) { + if (sysctl(mib, 2, &cpu_time, &size, NULL, 0) == -1) { PyErr_SetFromErrno(PyExc_OSError); - goto error; + return NULL; } for (i = 0; i < ncpu; i++) { @@ -2186,8 +2180,8 @@ void init_psutil_bsd(void) PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); PyModule_AddIntConstant(module, "SRUN", SRUN); PyModule_AddIntConstant(module, "SIDL", SIDL); - PyModule_AddIntConstant(module, "SWAIT", SWAIT); - PyModule_AddIntConstant(module, "SLOCK", SLOCK); + PyModule_AddIntConstant(module, "SWAIT", -1); + PyModule_AddIntConstant(module, "SLOCK", -1); PyModule_AddIntConstant(module, "SZOMB", SZOMB); // connection status constants PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED); diff --git a/psutil/arch/bsd/process_info_openbsd.c b/psutil/arch/bsd/process_info_openbsd.c index 1c1955663..a1b09d585 100644 --- a/psutil/arch/bsd/process_info_openbsd.c +++ b/psutil/arch/bsd/process_info_openbsd.c @@ -14,16 +14,17 @@ #include #include #include +#include #include -#include #include +#include #include #include #include +#include #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 @@ -42,73 +43,46 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) // Declaring name as const requires us to cast it when passing it to // sysctl because the prototype doesn't include the const modifier. size_t length; + char errbuf[_POSIX2_LINE_MAX]; + struct kinfo_proc *x; + int cnt; + kvm_t *kd; assert( procList != NULL); assert(*procList == NULL); assert(procCount != NULL); - *procCount = 0; + kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); - /* - * We start by calling sysctl with result == NULL and length == 0. - * That will succeed, and set length to the appropriate length. - * We then allocate a buffer of that size and call sysctl again - * with that buffer. If that succeeds, we're done. If that fails - * with ENOMEM, we have to throw away our buffer and loop. Note - * that the loop causes use to call sysctl with NULL again; this - * is necessary because the ENOMEM failure case sets length to - * the amount of data returned, not the amount of data that - * could have been returned. - */ - result = NULL; - done = 0; - do { - assert(result == NULL); - // Call sysctl with a NULL buffer. - length = 0; - err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, - NULL, &length, NULL, 0); - if (err == -1) - err = errno; - - // Allocate an appropriately sized buffer based on the results - // from the previous call. - if (err == 0) { - result = malloc(length); - if (result == NULL) - err = ENOMEM; - } + if (kd == NULL) { + fprintf(stderr, "WWWWWWWWWWWWWWWWWW\n"); + return errno; + } - // Call sysctl again with the new buffer. If we get an ENOMEM - // error, toss away our buffer and start again. - if (err == 0) { - err = sysctl((int *) name, (sizeof(name) / sizeof(*name)) - 1, - result, &length, NULL, 0); - if (err == -1) - err = errno; - if (err == 0) { - done = 1; - } - else if (err == ENOMEM) { - assert(result != NULL); - free(result); - result = NULL; - err = 0; - } - } - } while (err == 0 && ! done); + result = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cnt); + if (result == NULL) { + fprintf(stderr, "UUUUUUUUUUUUUUUUUU\n"); + err(1, NULL); + return errno; + } + + *procCount = (size_t)cnt; + + size_t mlen = cnt * sizeof(struct kinfo_proc); - // Clean up and establish post conditions. - if (err != 0 && result != NULL) { - free(result); - result = NULL; + if ((*procList = malloc(mlen)) == NULL) { + fprintf(stderr, "ZZZZZZZZZZZZZZZZZZ\n"); + err(1, NULL); + return errno; } - *procList = result; - *procCount = length / sizeof(struct kinfo_proc); + memcpy(*procList, result, mlen); - assert((err == 0) == (*procList != NULL)); - return err; + assert(*procList != NULL); + + kvm_close(kd); + + return 0; } @@ -124,7 +98,7 @@ char */ mib[0] = CTL_KERN; mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PATHNAME; + mib[2] = KERN_PROC_ARGS; mib[3] = pid; // call with a null buffer first to determine if we need a buffer @@ -202,14 +176,33 @@ char return procargs; } +char ** +get_argv(long pid) +{ + static char **argv; + char **p; + int argv_mib[] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV}; + size_t argv_size = 128; + /* Loop and reallocate until we have enough space to fit argv. */ + for (;; argv_size *= 2) { + if ((argv = realloc(argv, argv_size)) == NULL) + err(1, NULL); + if (sysctl(argv_mib, 4, argv, &argv_size, NULL, 0) == 0) + break; + if (errno == ESRCH) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + if (errno != ENOMEM) + err(1, NULL); + } // returns the command line as a python list object PyObject * psutil_get_arg_list(long pid) { - char *argstr = NULL; - int pos = 0; - size_t argsize = 0; + static char **argv; + char **p; PyObject *retlist = Py_BuildValue("[]"); PyObject *item = NULL; @@ -217,35 +210,16 @@ psutil_get_arg_list(long pid) return retlist; } - argstr = psutil_get_cmd_args(pid, &argsize); - if (argstr == NULL) { - goto error; - } + if ((argv = get_argv(pid)) == NULL) + return NULL; - // args are returned as a flattened string with \0 separators between - // arguments add each string to the list then step forward to the next - // separator - if (argsize > 0) { - while (pos < argsize) { - item = Py_BuildValue("s", &argstr[pos]); - if (!item) - goto error; - if (PyList_Append(retlist, item)) - goto error; - Py_DECREF(item); - pos = pos + strlen(&argstr[pos]) + 1; - } + for (p = argv; *p != NULL; p++) { + item = Py_BuildValue("s", *p); + PyList_Append(retlist, item); + Py_DECREF(item); } - - free(argstr); return retlist; -error: - Py_XDECREF(item); - Py_DECREF(retlist); - if (argstr != NULL) - free(argstr); - return NULL; } From 1aca8dc63c7b72a18fd70a4331549b0e1a0013cd Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Fri, 26 Dec 2014 21:52:40 +0100 Subject: [PATCH 03/74] It builds! --- psutil/_psutil_openbsd.c | 122 ++++++++++--------------- psutil/arch/bsd/process_info_openbsd.c | 4 +- 2 files changed, 48 insertions(+), 78 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 8727ff4ad..0034c6bbe 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -21,9 +21,12 @@ #include #include #include +#include /* for CPUSTATES & CP_* */ +#include /* for struct vmtotal and VM_METER */ +#include +#include #include -#include #include // for struct xsocket #include #include @@ -32,6 +35,8 @@ #include #include #include +#include +#include #include // for struct xtcpcb #include // for TCP connection states #include // for inet_ntop() @@ -174,6 +179,7 @@ psutil_proc_name(PyObject *self, PyObject *args) } +#if 0 /* * Return process pathname executable. * Thanks to Robert N. M. Watson: @@ -213,7 +219,7 @@ psutil_proc_exe(PyObject *self, PyObject *args) } return Py_BuildValue("s", pathname); } - +#endif /* * Return process cmdline as a Python list of cmdline arguments. @@ -354,8 +360,8 @@ psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) return NULL; } return Py_BuildValue("(ll)", - kp.ki_rusage.ru_nvcsw, - kp.ki_rusage.ru_nivcsw); + kp.p_uru_nvcsw, + kp.p_uru_nivcsw); } @@ -441,7 +447,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) pyTuple = Py_BuildValue("Idd", 0, //thread id? kipp->p_uutime_sec, - kipp->p_ustime_sec + kipp->p_ustime_sec); if (pyTuple == NULL) goto error; if (PyList_Append(retList, pyTuple)) @@ -477,8 +483,8 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args) return NULL; } // convert from microseconds to seconds - user_t = TV2DOUBLE(kp.p_uutime); - sys_t = TV2DOUBLE(kp.p_ustime); + user_t = KPT2DOUBLE(kp.p_uutime); + sys_t = KPT2DOUBLE(kp.p_ustime); return Py_BuildValue("(dd)", user_t, sys_t); } @@ -554,7 +560,7 @@ psutil_proc_create_time(PyObject *self, PyObject *args) if (psutil_kinfo_proc(pid, &kp) == -1) { return NULL; } - return Py_BuildValue("d", TV2DOUBLE(kp.ki_start)); + return Py_BuildValue("d", KPT2DOUBLE(kp.p_ustart)); } @@ -575,8 +581,8 @@ psutil_proc_io_counters(PyObject *self, PyObject *args) } // there's apparently no way to determine bytes count, hence return -1. return Py_BuildValue("(llll)", - kp.uru_inblock, - kp.uru_oublock, + kp.p_uru_inblock, + kp.p_uru_oublock, -1, -1); } @@ -599,10 +605,10 @@ psutil_proc_memory_info(PyObject *self, PyObject *args) } return Py_BuildValue("(lllll)", ptoa(kp.p_vm_rssize), // rss - (long)kp.ki_size, // vms - ptoa(kp.ki_tsize), // text - ptoa(kp.ki_dsize), // data - ptoa(kp.ki_ssize)); // stack + (long)kp.p_vm_map_size, // vms + ptoa(kp.p_vm_tsize), // text + ptoa(kp.p_vm_dsize), // data + ptoa(kp.p_vm_ssize)); // stack } @@ -671,44 +677,20 @@ psutil_virtual_mem(PyObject *self, PyObject *args) static PyObject * psutil_swap_mem(PyObject *self, PyObject *args) { - kvm_t *kd; - struct kvm_swap kvmsw[1]; - unsigned int swapin, swapout, nodein, nodeout; - size_t size = sizeof(unsigned int); - - kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open failed"); - if (kd == NULL) { - PyErr_SetString(PyExc_RuntimeError, "kvm_open failed"); - return NULL; - } - - if (kvm_getswapinfo(kd, kvmsw, 1, 0) < 0) { - kvm_close(kd); - PyErr_SetString(PyExc_RuntimeError, "kvm_getswapinfo failed"); - return NULL; - } - - kvm_close(kd); - - if (sysctlbyname("vm.stats.vm.v_swapin", &swapin, &size, NULL, 0) == -1) - goto sbn_error; - if (sysctlbyname("vm.stats.vm.v_swapout", &swapout, &size, NULL, 0) == -1) - goto sbn_error; - if (sysctlbyname("vm.stats.vm.v_vnodein", &nodein, &size, NULL, 0) == -1) - goto sbn_error; - if (sysctlbyname("vm.stats.vm.v_vnodeout", &nodeout, &size, NULL, 0) == -1) - goto sbn_error; + int mib[] = {CTL_VM, VM_METER}; + struct vmtotal vmtotal; + size_t size; + size = sizeof(vmtotal); + if (sysctl(mib, 2, &vmtotal, &size, NULL, 0) < 0) + errx(1,"failed to get vm.meter"); return Py_BuildValue("(iiiII)", - kvmsw[0].ksw_total, // total - kvmsw[0].ksw_used, // used - kvmsw[0].ksw_total - kvmsw[0].ksw_used, // free - swapin + swapout, // swap in - nodein + nodeout); // swap out + vmtotal.t_rm + vmtotal.t_free, + vmtotal.t_rm, + vmtotal.t_free, + 0 /* XXX swap in */, + 0 /* XXX swap out */); -sbn_error: - PyErr_SetFromErrno(PyExc_OSError); - return NULL; } @@ -1422,30 +1404,12 @@ psutil_disk_partitions(PyObject *self, PyObject *args) strlcat(opts, ",noexec", sizeof(opts)); if (flags & MNT_NOSUID) strlcat(opts, ",nosuid", sizeof(opts)); - if (flags & MNT_UNION) - strlcat(opts, ",union", sizeof(opts)); if (flags & MNT_ASYNC) strlcat(opts, ",async", sizeof(opts)); - if (flags & MNT_SUIDDIR) - strlcat(opts, ",suiddir", sizeof(opts)); if (flags & MNT_SOFTDEP) strlcat(opts, ",softdep", sizeof(opts)); - if (flags & MNT_NOSYMFOLLOW) - strlcat(opts, ",nosymfollow", sizeof(opts)); - if (flags & MNT_GJOURNAL) - strlcat(opts, ",gjournal", sizeof(opts)); - if (flags & MNT_MULTILABEL) - strlcat(opts, ",multilabel", sizeof(opts)); - if (flags & MNT_ACLS) - strlcat(opts, ",acls", sizeof(opts)); if (flags & MNT_NOATIME) strlcat(opts, ",noatime", sizeof(opts)); - if (flags & MNT_NOCLUSTERR) - strlcat(opts, ",noclusterr", sizeof(opts)); - if (flags & MNT_NOCLUSTERW) - strlcat(opts, ",noclusterw", sizeof(opts)); - if (flags & MNT_NFS4ACLS) - strlcat(opts, ",nfs4acls", sizeof(opts)); py_tuple = Py_BuildValue("(ssss)", fs[i].f_mntfromname, // device @@ -1563,6 +1527,7 @@ psutil_net_io_counters(PyObject *self, PyObject *args) } +#if 0 /* * Return a Python dict of tuples for disk I/O information */ @@ -1633,7 +1598,7 @@ psutil_disk_io_counters(PyObject *self, PyObject *args) free(stats.dinfo); return NULL; } - +#endif /* * Return currently connected users as a list of tuples. @@ -1718,7 +1683,7 @@ psutil_users(PyObject *self, PyObject *args) /* * System-wide open connections. */ - +#if 0 #define HASHSIZE 1009 static struct xfile *psutil_xfiles; static int psutil_nxfiles; @@ -1767,7 +1732,6 @@ psutil_get_pid_from_sock(int sock_hash) return -1; } - int psutil_gather_inet(int proto, PyObject *py_retlist) { struct xinpgen *xig, *exig; @@ -2013,10 +1977,10 @@ psutil_net_connections(PyObject* self, PyObject* args) PyObject *af_filter = NULL; PyObject *type_filter = NULL; PyObject *py_retlist = PyList_New(0); - +/* if (psutil_populate_xfiles() != 1) goto error; - +*/ if (psutil_gather_inet(IPPROTO_TCP, py_retlist) == 0) goto error; if (psutil_gather_inet(IPPROTO_UDP, py_retlist) == 0) @@ -2026,15 +1990,16 @@ psutil_net_connections(PyObject* self, PyObject* args) if (psutil_gather_unix(SOCK_DGRAM, py_retlist) == 0) goto error; - free(psutil_xfiles); +// free(psutil_xfiles); return py_retlist; error: Py_DECREF(py_retlist); - free(psutil_xfiles); +// free(psutil_xfiles); return NULL; } +#endif /* * define the psutil C module methods and initialize the module. @@ -2048,8 +2013,10 @@ PsutilMethods[] = "Return process name"}, {"proc_connections", psutil_proc_connections, METH_VARARGS, "Return connections opened by process"}, +/* {"proc_exe", psutil_proc_exe, METH_VARARGS, "Return process pathname executable"}, +*/ {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS, "Return process cmdline as a list of cmdline arguments"}, {"proc_ppid", psutil_proc_ppid, METH_VARARGS, @@ -2073,8 +2040,10 @@ PsutilMethods[] = "Return process threads"}, {"proc_status", psutil_proc_status, METH_VARARGS, "Return process status as an integer"}, +/* {"proc_io_counters", psutil_proc_io_counters, METH_VARARGS, "Return process IO counters"}, +*/ {"proc_tty_nr", psutil_proc_tty_nr, METH_VARARGS, "Return process tty (terminal) number"}, #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 @@ -2117,9 +2086,10 @@ PsutilMethods[] = "Return a Python dict of tuples for disk I/O information"}, {"users", psutil_users, METH_VARARGS, "Return currently connected users as a list of tuples"}, +#if 0 {"net_connections", psutil_net_connections, METH_VARARGS, "Return system-wide open connections."}, - +#endif {NULL, NULL, 0, NULL} }; @@ -2195,7 +2165,7 @@ void init_psutil_bsd(void) PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2); PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK); PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT); - PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE); + PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", 128); /*PSUTIL_CONN_NONE */ if (module == NULL) { INITERROR; diff --git a/psutil/arch/bsd/process_info_openbsd.c b/psutil/arch/bsd/process_info_openbsd.c index a1b09d585..46872fa6f 100644 --- a/psutil/arch/bsd/process_info_openbsd.c +++ b/psutil/arch/bsd/process_info_openbsd.c @@ -36,10 +36,9 @@ int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { - int err; struct kinfo_proc *result; int done; - static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 }; + static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC, 0 }; // Declaring name as const requires us to cast it when passing it to // sysctl because the prototype doesn't include the const modifier. size_t length; @@ -196,6 +195,7 @@ get_argv(long pid) if (errno != ENOMEM) err(1, NULL); } +} // returns the command line as a python list object PyObject * From 0470086e13d4d02a28a8ccf6708065d251018046 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Fri, 26 Dec 2014 22:19:47 +0100 Subject: [PATCH 04/74] Make this actuall build - switch mem/swap to VM_UVMEXP & swapctl - #if 0 out cpu_count_phys - use KERN_CPTIME in cpu_times - provide an empty disk_io_counters implem, needed by tests - disable proc_connections for now --- psutil/_psutil_openbsd.c | 117 ++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 57 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 0034c6bbe..5f250db7f 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -22,7 +22,7 @@ #include #include #include /* for CPUSTATES & CP_* */ -#include /* for struct vmtotal and VM_METER */ +#include #include #include #include @@ -515,6 +515,7 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args) } +#if 0 /* * Return an XML string from which we'll determine the number of * physical CPU cores in the system. @@ -543,7 +544,7 @@ psutil_cpu_count_phys(PyObject *self, PyObject *args) Py_INCREF(Py_None); return Py_None; } - +#endif /* * Return a Python float indicating the process create time expressed in @@ -620,50 +621,25 @@ psutil_virtual_mem(PyObject *self, PyObject *args) { unsigned int total, active, inactive, wired, cached, free; size_t size = sizeof(total); - struct vmtotal vm; - int mib[] = {CTL_VM, VM_METER}; + struct uvmexp uvmexp; + int mib[] = {CTL_VM, VM_UVMEXP}; long pagesize = getpagesize(); -#if __FreeBSD_version > 702101 - long buffers; -#else - int buffers; -#endif - size_t buffers_size = sizeof(buffers); - - if (sysctlbyname("vm.stats.vm.v_page_count", &total, &size, NULL, 0)) - goto error; - if (sysctlbyname("vm.stats.vm.v_active_count", &active, &size, NULL, 0)) - goto error; - if (sysctlbyname("vm.stats.vm.v_inactive_count", - &inactive, &size, NULL, 0)) - goto error; - if (sysctlbyname("vm.stats.vm.v_wire_count", &wired, &size, NULL, 0)) - goto error; - if (sysctlbyname("vm.stats.vm.v_cache_count", &cached, &size, NULL, 0)) - goto error; - if (sysctlbyname("vm.stats.vm.v_free_count", &free, &size, NULL, 0)) - goto error; - if (sysctlbyname("vfs.bufspace", &buffers, &buffers_size, NULL, 0)) - goto error; - - size = sizeof(vm); - if (sysctl(mib, 2, &vm, &size, NULL, 0) != 0) - goto error; - + size = sizeof(uvmexp); + if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) { + warnx(1,"failed to get vm.uvmexp"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } return Py_BuildValue("KKKKKKKK", - (unsigned long long) total * pagesize, - (unsigned long long) free * pagesize, - (unsigned long long) active * pagesize, - (unsigned long long) inactive * pagesize, - (unsigned long long) wired * pagesize, - (unsigned long long) cached * pagesize, - (unsigned long long) buffers, - (unsigned long long) (vm.t_vmshr + vm.t_rmshr) * pagesize // shared + (unsigned long long) uvmexp.npages * pagesize, + (unsigned long long) uvmexp.free * pagesize, + (unsigned long long) uvmexp.active * pagesize, + (unsigned long long) uvmexp.inactive * pagesize, + (unsigned long long) uvmexp.wired * pagesize, + (unsigned long long) 0, + (unsigned long long) 0, + (unsigned long long) 0 ); - -error: - PyErr_SetFromErrno(PyExc_OSError); - return NULL; } @@ -677,17 +653,41 @@ psutil_virtual_mem(PyObject *self, PyObject *args) static PyObject * psutil_swap_mem(PyObject *self, PyObject *args) { - int mib[] = {CTL_VM, VM_METER}; - struct vmtotal vmtotal; - size_t size; - size = sizeof(vmtotal); - if (sysctl(mib, 2, &vmtotal, &size, NULL, 0) < 0) - errx(1,"failed to get vm.meter"); + unsigned long swap_total, swap_free; + struct swapent *swdev; + int nswap, i; + if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) == 0) { + warn(1,"failed to get swap device count"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + if ((swdev = calloc(nswap, sizeof(*swdev))) == NULL) { + warn(1,"failed to allocate memory for swdev structures"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + if (swapctl(SWAP_STATS, swdev, nswap) == -1) { + free(swdev); + warn(1,"failed to get swap stats"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + /* Total things up */ + swap_total = swap_free = 0; + for (i = 0; i < nswap; i++) { + if (swdev[i].se_flags & SWF_ENABLE) { + swap_free += (swdev[i].se_nblks - swdev[i].se_inuse); + swap_total += swdev[i].se_nblks; + } + } return Py_BuildValue("(iiiII)", - vmtotal.t_rm + vmtotal.t_free, - vmtotal.t_rm, - vmtotal.t_free, + swap_total * DEV_BSIZE, + (swap_total - swap_free) * DEV_BSIZE, + swap_free * DEV_BSIZE, 0 /* XXX swap in */, 0 /* XXX swap out */); @@ -702,10 +702,11 @@ psutil_cpu_times(PyObject *self, PyObject *args) { long cpu_time[CPUSTATES]; size_t size; + int mib[] = {CTL_KERN, KERN_CPTIME}; size = sizeof(cpu_time); - - if (sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0) == -1) { + if (sysctl(mib, 2, &cpu_time, &size, NULL, 0) < 0) { + warnx(1,"failed to get kern.cptime"); PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -1527,13 +1528,13 @@ psutil_net_io_counters(PyObject *self, PyObject *args) } -#if 0 /* * Return a Python dict of tuples for disk I/O information */ static PyObject * psutil_disk_io_counters(PyObject *self, PyObject *args) { +#if 0 int i; struct statinfo stats; @@ -1596,9 +1597,9 @@ psutil_disk_io_counters(PyObject *self, PyObject *args) Py_DECREF(py_retdict); if (stats.dinfo != NULL) free(stats.dinfo); +#endif return NULL; } -#endif /* * Return currently connected users as a list of tuples. @@ -2011,9 +2012,9 @@ PsutilMethods[] = {"proc_name", psutil_proc_name, METH_VARARGS, "Return process name"}, +/* {"proc_connections", psutil_proc_connections, METH_VARARGS, "Return connections opened by process"}, -/* {"proc_exe", psutil_proc_exe, METH_VARARGS, "Return process pathname executable"}, */ @@ -2063,8 +2064,10 @@ PsutilMethods[] = "Returns a list of PIDs currently running on the system"}, {"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS, "Return number of logical CPUs on the system"}, +/* {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, "Return an XML string to determine the number physical CPUs."}, +*/ {"virtual_mem", psutil_virtual_mem, METH_VARARGS, "Return system virtual memory usage statistics"}, {"swap_mem", psutil_swap_mem, METH_VARARGS, From e1e0ef929ddb9f0df6a9a15790e30d443cfae0b6 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 11:45:31 +0100 Subject: [PATCH 05/74] PAGESIZE should be 1 on OpenBSD, DEV_BSIZE is used in _psutil_openbsd.c --- psutil/_psbsd.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index 83bfbd16a..453cacdf7 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -81,6 +81,8 @@ def virtual_memory(): def swap_memory(): """System swap memory as (total, used, free, sin, sout) namedtuple.""" + if sys.platform.startswith("openbsd"): + PAGESIZE = 1 total, used, free, sin, sout = [x * PAGESIZE for x in cext.swap_mem()] percent = usage_percent(used, total, _round=1) return _common.sswap(total, used, free, percent, sin, sout) From 51c48a6b74c9757c24c7186b2aedcd36c1e4dde7 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 11:45:47 +0100 Subject: [PATCH 06/74] Fix warn() invocations --- psutil/_psutil_openbsd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 5f250db7f..555f45fe2 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -626,7 +626,7 @@ psutil_virtual_mem(PyObject *self, PyObject *args) long pagesize = getpagesize(); size = sizeof(uvmexp); if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) { - warnx(1,"failed to get vm.uvmexp"); + warn("failed to get vm.uvmexp"); PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -657,20 +657,20 @@ psutil_swap_mem(PyObject *self, PyObject *args) struct swapent *swdev; int nswap, i; if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) == 0) { - warn(1,"failed to get swap device count"); + warn("failed to get swap device count"); PyErr_SetFromErrno(PyExc_OSError); return NULL; } if ((swdev = calloc(nswap, sizeof(*swdev))) == NULL) { - warn(1,"failed to allocate memory for swdev structures"); + warn("failed to allocate memory for swdev structures"); PyErr_SetFromErrno(PyExc_OSError); return NULL; } if (swapctl(SWAP_STATS, swdev, nswap) == -1) { free(swdev); - warn(1,"failed to get swap stats"); + warn("failed to get swap stats"); PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -706,7 +706,7 @@ psutil_cpu_times(PyObject *self, PyObject *args) size = sizeof(cpu_time); if (sysctl(mib, 2, &cpu_time, &size, NULL, 0) < 0) { - warnx(1,"failed to get kern.cptime"); + warnx("failed to get kern.cptime"); PyErr_SetFromErrno(PyExc_OSError); return NULL; } From 3b5edefdcb94d8ae002f17e9a57bcbf02ebce468 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 11:46:21 +0100 Subject: [PATCH 07/74] use the proper type in Py_BuildValue to return an unsigned long --- psutil/_psutil_openbsd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 555f45fe2..8c59b155f 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -683,8 +683,7 @@ psutil_swap_mem(PyObject *self, PyObject *args) swap_total += swdev[i].se_nblks; } } - - return Py_BuildValue("(iiiII)", + return Py_BuildValue("(LLLII)", swap_total * DEV_BSIZE, (swap_total - swap_free) * DEV_BSIZE, swap_free * DEV_BSIZE, From c6b4cfb270dc9890aae27ce2e0b6b03f9592db59 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 13:19:32 +0100 Subject: [PATCH 08/74] Add a kinfo_getfile() function mimic'ing what FreeBSD's one does in libutil --- psutil/arch/bsd/process_info.h | 3 ++ psutil/arch/bsd/process_info_openbsd.c | 40 ++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/psutil/arch/bsd/process_info.h b/psutil/arch/bsd/process_info.h index 858bd88a5..9140d33ba 100644 --- a/psutil/arch/bsd/process_info.h +++ b/psutil/arch/bsd/process_info.h @@ -8,6 +8,9 @@ typedef struct kinfo_proc kinfo_proc; +#ifdef __OpenBSD__ +struct kinfo_file * kinfo_getfile(long pid, int* cnt); +#endif char *psutil_get_cmd_args(long pid, size_t *argsize); char *psutil_get_cmd_path(long pid, size_t *pathsize); int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount); diff --git a/psutil/arch/bsd/process_info_openbsd.c b/psutil/arch/bsd/process_info_openbsd.c index 46872fa6f..83d01f27e 100644 --- a/psutil/arch/bsd/process_info_openbsd.c +++ b/psutil/arch/bsd/process_info_openbsd.c @@ -257,3 +257,43 @@ psutil_raise_ad_or_nsp(pid) { AccessDenied(); } } + +/* + * mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an int as arg + * and returns an array with cnt struct kinfo_file + */ +struct kinfo_file * +kinfo_getfile(long pid, int* cnt) { + + int mib[6]; + size_t len; + struct kinfo_file* kf; + mib[0] = CTL_KERN; + mib[1] = KERN_FILE; + mib[2] = KERN_FILE_BYPID; + mib[3] = (int) pid; + mib[4] = sizeof(struct kinfo_file); + mib[5] = 0; + + /* get the size of what would be returned */ + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { + warn("failed in first call to KERN_FILE_BYPID"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + if ((kf = malloc(len)) == NULL) { + warn("failed malloc before second KERN_FILE_BYPID call"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + mib[5] = (int)(len / sizeof(struct kinfo_file)); + if (sysctl(mib, 6, kf, &len, NULL, 0) < 0) { + warn("failed in second call to KERN_FILE_BYPID"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + *cnt = (int)(len / sizeof(struct kinfo_file)); +/* printf ("returning %d files for pid %d\n", *cnt,pid); */ + return kf; +} From 1174a608b8d98cb9334f71860eaae85d398c5020 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 13:21:14 +0100 Subject: [PATCH 09/74] Implement psutil_per_cpu_times() --- psutil/_psutil_openbsd.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 8c59b155f..bb78e7a8c 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -1164,7 +1164,7 @@ static PyObject * psutil_per_cpu_times(PyObject *self, PyObject *args) { static int maxcpus; - int mib[2]; + int mib[3]; int ncpu; size_t len; size_t size; @@ -1184,25 +1184,27 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) PyErr_SetFromErrno(PyExc_OSError); goto error; } - long cpu_time[ncpu][CPUSTATES]; - - // per-cpu info - mib[0] = CTL_KERN; - mib[1] = KERN_CPTIME; - size = sizeof(cpu_time); - if (sysctl(mib, 2, &cpu_time, &size, NULL, 0) == -1) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } + long cpu_time[CPUSTATES]; for (i = 0; i < ncpu; i++) { + // per-cpu info + mib[0] = CTL_KERN; + mib[1] = KERN_CPTIME2; + mib[2] = i; + size = sizeof(cpu_time); + if (sysctl(mib, 3, &cpu_time, &size, NULL, 0) == -1) { + warn("failed to get kern.cptime2"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + py_cputime = Py_BuildValue( "(ddddd)", - (double)cpu_time[i][CP_USER] / CLOCKS_PER_SEC, - (double)cpu_time[i][CP_NICE] / CLOCKS_PER_SEC, - (double)cpu_time[i][CP_SYS] / CLOCKS_PER_SEC, - (double)cpu_time[i][CP_IDLE] / CLOCKS_PER_SEC, - (double)cpu_time[i][CP_INTR] / CLOCKS_PER_SEC); + (double)cpu_time[CP_USER] / CLOCKS_PER_SEC, + (double)cpu_time[CP_NICE] / CLOCKS_PER_SEC, + (double)cpu_time[CP_SYS] / CLOCKS_PER_SEC, + (double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC, + (double)cpu_time[CP_INTR] / CLOCKS_PER_SEC); if (!py_cputime) goto error; if (PyList_Append(py_retlist, py_cputime)) From 3bfd846ab5dc5a9519b9894da46cd550efbe50db Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 13:21:44 +0100 Subject: [PATCH 10/74] Remove unused utmpx code, is only for FreeBSD >= 9 --- psutil/_psutil_openbsd.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index bb78e7a8c..617377fd7 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -1614,7 +1614,6 @@ psutil_users(PyObject *self, PyObject *args) if (ret_list == NULL) return NULL; -#if __FreeBSD_version < 900000 struct utmp ut; FILE *fp; @@ -1645,33 +1644,7 @@ psutil_users(PyObject *self, PyObject *args) } fclose(fp); -#else - struct utmpx *utx; - - while ((utx = getutxent()) != NULL) { - if (utx->ut_type != USER_PROCESS) - continue; - tuple = Py_BuildValue( - "(sssf)", - utx->ut_user, // username - utx->ut_line, // tty - utx->ut_host, // hostname - (float)utx->ut_tv.tv_sec // start time - ); - if (!tuple) { - endutxent(); - goto error; - } - if (PyList_Append(ret_list, tuple)) { - endutxent(); - goto error; - } - Py_DECREF(tuple); - } - - endutxent(); -#endif return ret_list; error: From 4858433017ac36604d2e217d7b5932957891e966 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 13:23:51 +0100 Subject: [PATCH 11/74] Return an empty string for psutil_proc_cwd() - there's no way to get that info. At best you get an inode or the filesystem the process is running within.. --- psutil/_psutil_openbsd.c | 50 +++------------------------------------- 1 file changed, 3 insertions(+), 47 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 617377fd7..1294a1117 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -808,60 +808,16 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) return Py_BuildValue("i", cnt); } - /* - * Return process current working directory. + * No way to get cwd on OpenBSD */ static PyObject * psutil_proc_cwd(PyObject *self, PyObject *args) { - long pid; - PyObject *path = NULL; - struct kinfo_file *freep = NULL; - struct kinfo_file *kif; - struct kinfo_proc kipp; - - int i, cnt; - - if (! PyArg_ParseTuple(args, "l", &pid)) - goto error; - if (psutil_kinfo_proc(pid, &kipp) == -1) - goto error; - - freep = kinfo_getfile(pid, &cnt); - if (freep == NULL) { - psutil_raise_ad_or_nsp(pid); - goto error; - } - - for (i = 0; i < cnt; i++) { - kif = &freep[i]; - if (kif->kf_fd == KF_FD_TYPE_CWD) { - path = Py_BuildValue("s", kif->kf_path); - if (!path) - goto error; - break; - } - } - /* - * For lower pids it seems we can't retrieve any information - * (lsof can't do that it either). Since this happens even - * as root we return an empty string instead of AccessDenied. - */ - if (path == NULL) { - path = Py_BuildValue("s", ""); - } - free(freep); - return path; - -error: - Py_XDECREF(path); - if (freep != NULL) - free(freep); - return NULL; + return Py_BuildValue("s", ""); } - +#if 0 // The tcplist fetching and walking is borrowed from netstat/inet.c. static char * psutil_fetch_tcplist(void) From 07b6d654202235bcfd36e8cf14586e1d266417fa Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 13:25:07 +0100 Subject: [PATCH 12/74] Proper implementation for psutil_proc_open_files(), returning empty paths --- psutil/_psutil_openbsd.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 1294a1117..67374f949 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -25,6 +25,10 @@ #include #include #include +#include /* for VREG */ +#define _KERNEL /* for DTYPE_VNODE */ +#include +#undef _KERNEL #include #include // for struct xsocket @@ -721,16 +725,7 @@ psutil_cpu_times(PyObject *self, PyObject *args) /* - * XXX - * These functions are available on FreeBSD 8 only. - * In the upper python layer we do various tricks to avoid crashing - * and/or to provide alternatives where possible. - */ - - -#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 -/* - * Return files opened by process as a list of (path, fd) tuples + * Return files opened by process as a list of ("", fd) tuples */ static PyObject * psutil_proc_open_files(PyObject *self, PyObject *args) @@ -758,10 +753,10 @@ psutil_proc_open_files(PyObject *self, PyObject *args) for (i = 0; i < cnt; i++) { kif = &freep[i]; - if ((kif->kf_type == KF_TYPE_VNODE) && - (kif->kf_vnode_type == KF_VTYPE_VREG)) + if ((kif->f_type == DTYPE_VNODE) && + (kif->v_type == VREG)) { - tuple = Py_BuildValue("(si)", kif->kf_path, kif->kf_fd); + tuple = Py_BuildValue("(si)", "", kif->fd_fd); if (tuple == NULL) goto error; if (PyList_Append(retList, tuple)) @@ -1111,7 +1106,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) free(tcplist); return NULL; } - +#endif /* * Return a Python list of tuple representing per-cpu times @@ -1177,6 +1172,7 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) } +#if 0 // remove spaces from string void remove_spaces(char *str) { char *p1 = str; @@ -1977,16 +1973,16 @@ PsutilMethods[] = */ {"proc_tty_nr", psutil_proc_tty_nr, METH_VARARGS, "Return process tty (terminal) number"}, -#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 - {"proc_open_files", psutil_proc_open_files, METH_VARARGS, - "Return files opened by process as a list of (path, fd) tuples"}, {"proc_cwd", psutil_proc_cwd, METH_VARARGS, "Return process current working directory."}, + {"proc_open_files", psutil_proc_open_files, METH_VARARGS, + "Return files opened by process as a list of (path, fd) tuples"}, +#if 0 {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, "Return a list of tuples for every process's memory map"}, +#endif {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS, "Return the number of file descriptors opened by this process"}, -#endif // --- system-related functions From eca6032db71c385564d416a8127487784c388f2b Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 13:25:39 +0100 Subject: [PATCH 13/74] enable per_cpu_times method --- psutil/_psutil_openbsd.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 67374f949..3383df11e 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -2000,10 +2000,8 @@ PsutilMethods[] = "Return swap mem stats"}, {"cpu_times", psutil_cpu_times, METH_VARARGS, "Return system cpu times as a tuple (user, system, nice, idle, irc)"}, -#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS, "Return system per-cpu times as a list of tuples"}, -#endif {"boot_time", psutil_boot_time, METH_VARARGS, "Return the system boot time expressed in seconds since the epoch."}, {"disk_partitions", psutil_disk_partitions, METH_VARARGS, From eef37e5b36ef4a50ebc7ca9c377d939e724b99a6 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 15:16:05 +0100 Subject: [PATCH 14/74] Implement psutil_disk_io_counters() No way to distinguish between read and write times, so assume half spent in both.. --- psutil/_psutil_openbsd.c | 64 ++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 3383df11e..f52cfc05a 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -19,6 +19,7 @@ #include #include #include +#include /* struct diskstats */ #include #include #include /* for CPUSTATES & CP_* */ @@ -1487,70 +1488,61 @@ psutil_net_io_counters(PyObject *self, PyObject *args) static PyObject * psutil_disk_io_counters(PyObject *self, PyObject *args) { -#if 0 - int i; - struct statinfo stats; + int i, dk_ndrive, mib[3]; + size_t len; + struct diskstats *stats; PyObject *py_retdict = PyDict_New(); PyObject *py_disk_info = NULL; if (py_retdict == NULL) return NULL; - if (devstat_checkversion(NULL) < 0) { - PyErr_Format(PyExc_RuntimeError, "devstat_checkversion() failed"); + mib[0] = CTL_HW; + mib[1] = HW_DISKSTATS; + len = 0; + if (sysctl(mib, 2, NULL, &len, NULL, 0) < 0) { + warn("can't get hw.diskstats size"); + PyErr_SetFromErrno(PyExc_OSError); goto error; } + dk_ndrive = (int)(len / sizeof(struct diskstats)); - stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); - if (stats.dinfo == NULL) { + stats = malloc(len); + if (stats == NULL) { + warn("can't malloc"); PyErr_NoMemory(); goto error; } - bzero(stats.dinfo, sizeof(struct devinfo)); - - if (devstat_getdevs(NULL, &stats) == -1) { - PyErr_Format(PyExc_RuntimeError, "devstat_getdevs() failed"); + if (sysctl(mib, 2, stats, &len, NULL, 0) < 0 ) { + warn("could not read hw.diskstats"); + PyErr_SetFromErrno(PyExc_OSError); goto error; } - for (i = 0; i < stats.dinfo->numdevs; i++) { - py_disk_info = NULL; - struct devstat current; - char disk_name[128]; - current = stats.dinfo->devices[i]; - snprintf(disk_name, sizeof(disk_name), "%s%d", - current.device_name, - current.unit_number); - + for (i = 0; i < dk_ndrive; i++) { py_disk_info = Py_BuildValue( "(KKKKLL)", - current.operations[DEVSTAT_READ], // no reads - current.operations[DEVSTAT_WRITE], // no writes - current.bytes[DEVSTAT_READ], // bytes read - current.bytes[DEVSTAT_WRITE], // bytes written - (long long)devstat_compute_etime( - ¤t.duration[DEVSTAT_READ], NULL), // r time - (long long)devstat_compute_etime( - ¤t.duration[DEVSTAT_WRITE], NULL)); // w time + stats[i].ds_rxfer, + stats[i].ds_wxfer, + stats[i].ds_rbytes, + stats[i].ds_wbytes, + (long long) TV2DOUBLE(stats[i].ds_time) / 2, /* assume half read - half writes.. */ + (long long) TV2DOUBLE(stats[i].ds_time) / 2); if (!py_disk_info) goto error; - if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info)) + if (PyDict_SetItemString(py_retdict, stats[i].ds_name, py_disk_info)) goto error; Py_DECREF(py_disk_info); } - if (stats.dinfo->mem_ptr) { - free(stats.dinfo->mem_ptr); - } - free(stats.dinfo); + free(stats); return py_retdict; error: Py_XDECREF(py_disk_info); Py_DECREF(py_retdict); - if (stats.dinfo != NULL) - free(stats.dinfo); -#endif + if (stats != NULL) + free(stats); return NULL; } From 6c97eabcd541ed06fe1d680a60a2ea8abf01a040 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 15:19:02 +0100 Subject: [PATCH 15/74] remove #if 0 proc_exe implem, wont happen. return process name instead --- psutil/_psutil_openbsd.c | 46 ++-------------------------------------- 1 file changed, 2 insertions(+), 44 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index f52cfc05a..5e1e04d58 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -184,48 +184,6 @@ psutil_proc_name(PyObject *self, PyObject *args) } -#if 0 -/* - * Return process pathname executable. - * Thanks to Robert N. M. Watson: - * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_bin.c?v=8-CURRENT - */ -static PyObject * -psutil_proc_exe(PyObject *self, PyObject *args) -{ - long pid; - char pathname[PATH_MAX]; - int error; - int mib[4]; - size_t size; - - if (! PyArg_ParseTuple(args, "l", &pid)) { - return NULL; - } - - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PATHNAME; - mib[3] = pid; - - size = sizeof(pathname); - error = sysctl(mib, 4, pathname, &size, NULL, 0); - if (error == -1) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - if (size == 0 || strlen(pathname) == 0) { - if (psutil_pid_exists(pid) == 0) { - return NoSuchProcess(); - } - else { - strcpy(pathname, ""); - } - } - return Py_BuildValue("s", pathname); -} -#endif - /* * Return process cmdline as a Python list of cmdline arguments. */ @@ -1933,9 +1891,9 @@ PsutilMethods[] = /* {"proc_connections", psutil_proc_connections, METH_VARARGS, "Return connections opened by process"}, - {"proc_exe", psutil_proc_exe, METH_VARARGS, - "Return process pathname executable"}, */ + {"proc_exe", psutil_proc_name, METH_VARARGS, + "Return process name"}, {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS, "Return process cmdline as a list of cmdline arguments"}, {"proc_ppid", psutil_proc_ppid, METH_VARARGS, From a0a353806ed08ac51730fe94543b308b52978e41 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 22:57:54 +0100 Subject: [PATCH 16/74] remove psutil_cpu_count_phys, wont be implemented --- psutil/_psutil_openbsd.c | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 5e1e04d58..ec185814c 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -478,37 +478,6 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args) } -#if 0 -/* - * Return an XML string from which we'll determine the number of - * physical CPU cores in the system. - */ -static PyObject * -psutil_cpu_count_phys(PyObject *self, PyObject *args) -{ - void *topology = NULL; - size_t size = 0; - - if (sysctlbyname("kern.sched.topology_spec", NULL, &size, NULL, 0)) - goto error; - - topology = malloc(size); - if (!topology) { - PyErr_NoMemory(); - return NULL; - } - - if (sysctlbyname("kern.sched.topology_spec", topology, &size, NULL, 0)) - goto error; - - return Py_BuildValue("s", topology); - -error: - Py_INCREF(Py_None); - return Py_None; -} -#endif - /* * Return a Python float indicating the process create time expressed in * seconds since the epoch. From ecf7f419564806b5a856c81c7cebd04a5302af23 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 22:59:23 +0100 Subject: [PATCH 17/74] add function to get a string from an addru --- psutil/_psutil_openbsd.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index ec185814c..e215b2aba 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -797,6 +797,23 @@ psutil_sockaddr_addr(int family, struct sockaddr_storage *ss) return (&sin6->sin6_addr); } } +#endif +// see sys/kern/kern_sysctl.c lines 1100 and usr.bin/fstat/fstat.c print_inet_details() +char * +psutil_addr_from_addru(int family, uint32_t addr[4]) +{ + struct in_addr a; + memcpy(&a, addr, sizeof(a)); + if (family == AF_INET) { + if (a.s_addr == INADDR_ANY) + return "*"; + else + return inet_ntoa(a); + } else { + /* XXX TODO */ + return NULL; + } +} static socklen_t psutil_sockaddr_addrlen(int family) From 63d6dc5db11c5ab61f037d5a1dbe61785f8d39d7 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 23:00:46 +0100 Subject: [PATCH 18/74] Wip on psutil_proc_connections, lightly tested but seem to do the job --- psutil/_psutil_openbsd.c | 82 +++++++++++++++------------------------- 1 file changed, 30 insertions(+), 52 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index e215b2aba..9ab531c0b 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -824,6 +824,7 @@ psutil_sockaddr_addrlen(int family) return (sizeof(struct in6_addr)); } +#if 0 static int psutil_sockaddr_matches(int family, int port, void *pcb_addr, struct sockaddr_storage *ss) @@ -880,7 +881,7 @@ psutil_search_tcplist(char *buf, struct kinfo_file *kif) return NULL; } - +#endif // a signaler for connections without an actual status static int PSUTIL_CONN_NONE = 128; @@ -924,15 +925,15 @@ psutil_proc_connections(PyObject *self, PyObject *args) goto error; } +/* tcplist = psutil_fetch_tcplist(); if (tcplist == NULL) { PyErr_SetFromErrno(PyExc_OSError); goto error; } - +*/ for (i = 0; i < cnt; i++) { - int lport, rport, state; - char lip[200], rip[200]; + int state; char path[PATH_MAX]; int inseq; tuple = NULL; @@ -940,16 +941,16 @@ psutil_proc_connections(PyObject *self, PyObject *args) raddr = NULL; kif = &freep[i]; - if (kif->kf_type == KF_TYPE_SOCKET) + if (kif->f_type == DTYPE_SOCKET) { // apply filters - _family = PyLong_FromLong((long)kif->kf_sock_domain); + _family = PyLong_FromLong((long)kif->so_family); inseq = PySequence_Contains(af_filter, _family); Py_DECREF(_family); if (inseq == 0) { continue; } - _type = PyLong_FromLong((long)kif->kf_sock_type); + _type = PyLong_FromLong((long)kif->so_type); inseq = PySequence_Contains(type_filter, _type); Py_DECREF(_type); if (inseq == 0) { @@ -957,40 +958,27 @@ psutil_proc_connections(PyObject *self, PyObject *args) } // IPv4 / IPv6 socket - if ((kif->kf_sock_domain == AF_INET) || - (kif->kf_sock_domain == AF_INET6)) { + if ((kif->so_family == AF_INET) || + (kif->so_family == AF_INET6)) { // fill status state = PSUTIL_CONN_NONE; - if (kif->kf_sock_type == SOCK_STREAM) { - tcp = psutil_search_tcplist(tcplist, kif); - if (tcp != NULL) - state = (int)tcp->t_state; + if (kif->so_type == SOCK_STREAM) { + /* need to read so_pcb + state = kif->so_state; + printf("state=%d\n",state); + */ } - // build addr and port - inet_ntop( - kif->kf_sock_domain, - psutil_sockaddr_addr(kif->kf_sock_domain, - &kif->kf_sa_local), - lip, - sizeof(lip)); - inet_ntop( - kif->kf_sock_domain, - psutil_sockaddr_addr(kif->kf_sock_domain, - &kif->kf_sa_peer), - rip, - sizeof(rip)); - lport = htons(psutil_sockaddr_port(kif->kf_sock_domain, - &kif->kf_sa_local)); - rport = htons(psutil_sockaddr_port(kif->kf_sock_domain, - &kif->kf_sa_peer)); - // construct python tuple/list - laddr = Py_BuildValue("(si)", lip, lport); + laddr = Py_BuildValue("(si)", + psutil_addr_from_addru(kif->so_family, kif->inp_laddru), + ntohs(kif->inp_lport)); if (!laddr) goto error; - if (rport != 0) { - raddr = Py_BuildValue("(si)", rip, rport); + if (ntohs(kif->inp_fport) != 0) { + raddr = Py_BuildValue("(si)", + psutil_addr_from_addru(kif->so_family, kif->inp_faddru), + ntohs(kif->inp_fport)); } else { raddr = Py_BuildValue("()"); @@ -998,9 +986,9 @@ psutil_proc_connections(PyObject *self, PyObject *args) if (!raddr) goto error; tuple = Py_BuildValue("(iiiNNi)", - kif->kf_fd, - kif->kf_sock_domain, - kif->kf_sock_type, + kif->fd_fd, + kif->so_family, + kif->so_type, laddr, raddr, state); @@ -1011,20 +999,13 @@ psutil_proc_connections(PyObject *self, PyObject *args) Py_DECREF(tuple); } // UNIX socket - else if (kif->kf_sock_domain == AF_UNIX) { - struct sockaddr_un *sun; - - sun = (struct sockaddr_un *)&kif->kf_sa_local; - snprintf( - path, sizeof(path), "%.*s", - (sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), - sun->sun_path); + else if (kif->so_family == AF_UNIX) { tuple = Py_BuildValue("(iiisOi)", - kif->kf_fd, - kif->kf_sock_domain, - kif->kf_sock_type, - path, + kif->fd_fd, + kif->so_family, + kif->so_type, + kif->unp_path, Py_None, PSUTIL_CONN_NONE); if (!tuple) @@ -1051,7 +1032,6 @@ psutil_proc_connections(PyObject *self, PyObject *args) free(tcplist); return NULL; } -#endif /* * Return a Python list of tuple representing per-cpu times @@ -1874,10 +1854,8 @@ PsutilMethods[] = {"proc_name", psutil_proc_name, METH_VARARGS, "Return process name"}, -/* {"proc_connections", psutil_proc_connections, METH_VARARGS, "Return connections opened by process"}, -*/ {"proc_exe", psutil_proc_name, METH_VARARGS, "Return process name"}, {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS, From b960e1a70590619a04c568fb7019155055ea6518 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 28 Dec 2014 23:02:03 +0100 Subject: [PATCH 19/74] return the same value for count_logical and count_physical on OpenBSD --- psutil/_psbsd.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index 453cacdf7..1bcc62417 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -134,6 +134,8 @@ def cpu_count_physical(): # We may get None in case "sysctl kern.sched.topology_spec" # is not supported on this BSD version, in which case we'll mimic # os.cpu_count() and return None. + if sys.platform.startswith("openbsd"): + return cext.cpu_count_logical() s = cext.cpu_count_phys() if s is not None: # get rid of padding chars appended at the end of the string From 3c5f259ca329befd3cbb6f54afa625140f96fe76 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 5 Apr 2015 11:36:05 +0200 Subject: [PATCH 20/74] need netdb.h on OpenBSD too for NI_* defines --- psutil/_psutil_posix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/psutil/_psutil_posix.c b/psutil/_psutil_posix.c index 183dab0e1..b5eabd79c 100644 --- a/psutil/_psutil_posix.c +++ b/psutil/_psutil_posix.c @@ -19,7 +19,7 @@ #include #endif // end linux -#if defined(__FreeBSD__) || defined(__APPLE__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) #include #include #include From a606d7f442b0dd286e19a1a78821372668380770 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 5 Apr 2015 11:43:24 +0200 Subject: [PATCH 21/74] follow changes from #578 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fddb2b955..d83e1e9b6 100644 --- a/setup.py +++ b/setup.py @@ -120,7 +120,7 @@ def get_winver(): # OpenBSD elif sys.platform.startswith("openbsd"): extensions = [Extension( - '_psutil_bsd', + 'psutil._psutil_bsd', sources=[ 'psutil/_psutil_openbsd.c', 'psutil/_psutil_common.c', From 93c5e929c9fd97ec0da19b66d0bd4e5538a53068 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 5 Apr 2015 11:43:46 +0200 Subject: [PATCH 22/74] treat OpenBSD as a BSD platform for tests --- test/test_psutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_psutil.py b/test/test_psutil.py index b53ff6801..0cec2f3ef 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -92,7 +92,7 @@ WIN_VISTA = (6, 0, 0) LINUX = sys.platform.startswith("linux") OSX = sys.platform.startswith("darwin") -BSD = sys.platform.startswith("freebsd") +BSD = sys.platform.startswith("freebsd") or sys.platform.startswith("openbsd") SUNOS = sys.platform.startswith("sunos") VALID_PROC_STATUSES = [getattr(psutil, x) for x in dir(psutil) if x.startswith('STATUS_')] From e8954bdfb6b9486f81a18c7b5a44b34031b4289d Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 5 Apr 2015 11:48:08 +0200 Subject: [PATCH 23/74] more changes from #578 --- psutil/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/psutil/__init__.py b/psutil/__init__.py index 008e72ffb..636e7613c 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -123,7 +123,7 @@ from . import _psbsd as _psplatform elif sys.platform.startswith("openbsd"): - import psutil._psbsd as _psplatform + from . import _psbsd as _psplatform elif sys.platform.startswith("sunos"): from . import _pssunos as _psplatform From d478f9be0d11257d6b1b0441731ad7c734d6d8c6 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 5 Apr 2015 11:48:30 +0200 Subject: [PATCH 24/74] OpenBSD has AF_LINK too --- psutil/_psutil_posix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/psutil/_psutil_posix.c b/psutil/_psutil_posix.c index b5eabd79c..462a46223 100644 --- a/psutil/_psutil_posix.c +++ b/psutil/_psutil_posix.c @@ -116,7 +116,7 @@ psutil_convert_ipaddr(struct sockaddr *addr, int family) data = (const char *)lladdr->sll_addr; } #endif -#if defined(__FreeBSD__) || defined(__APPLE__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) else if (addr->sa_family == AF_LINK) { // Note: prior to Python 3.4 socket module does not expose // AF_LINK so we'll do. @@ -519,7 +519,7 @@ void init_psutil_posix(void) PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods); #endif -#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__sun) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__sun) PyModule_AddIntConstant(module, "AF_LINK", AF_LINK); #endif From 3432ceee9d800951999a5a53a626d5046da35e32 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 5 Apr 2015 12:02:13 +0200 Subject: [PATCH 25/74] Fix after changes from #564 --- psutil/_psutil_openbsd.c | 1 + setup.py | 1 + 2 files changed, 2 insertions(+) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 9ab531c0b..d39e1f9e3 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -1986,6 +1986,7 @@ void init_psutil_bsd(void) #else PyObject *module = Py_InitModule("_psutil_bsd", PsutilMethods); #endif + PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); // process status constants PyModule_AddIntConstant(module, "SSTOP", SSTOP); PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); diff --git a/setup.py b/setup.py index d83e1e9b6..d91e390bb 100644 --- a/setup.py +++ b/setup.py @@ -126,6 +126,7 @@ def get_winver(): 'psutil/_psutil_common.c', 'psutil/arch/bsd/process_info_openbsd.c' ], + define_macros=[VERSION_MACRO], libraries=["kvm"]), posix_extension, ] From 54fa6914148c968f51bd642c6c5e65abd4b7cc1c Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Sun, 5 Apr 2015 17:07:47 +0200 Subject: [PATCH 26/74] use the correct type for cptime2 --- psutil/_psutil_openbsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index d39e1f9e3..ac89c41dd 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -1060,7 +1060,7 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) PyErr_SetFromErrno(PyExc_OSError); goto error; } - long cpu_time[CPUSTATES]; + uint64_t cpu_time[CPUSTATES]; for (i = 0; i < ncpu; i++) { // per-cpu info From ccb461f36e0120cf0f8e7f531733a7034699c2af Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Tue, 7 Apr 2015 18:02:16 +0200 Subject: [PATCH 27/74] BSD-specific tests are in fact FreeBSD only --- test/test_psutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_psutil.py b/test/test_psutil.py index 0cec2f3ef..b53ff6801 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -92,7 +92,7 @@ WIN_VISTA = (6, 0, 0) LINUX = sys.platform.startswith("linux") OSX = sys.platform.startswith("darwin") -BSD = sys.platform.startswith("freebsd") or sys.platform.startswith("openbsd") +BSD = sys.platform.startswith("freebsd") SUNOS = sys.platform.startswith("sunos") VALID_PROC_STATUSES = [getattr(psutil, x) for x in dir(psutil) if x.startswith('STATUS_')] From 5fd6a2a1ebe14d8dd62c02a49f28b365021eedcd Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Tue, 7 Apr 2015 18:06:15 +0200 Subject: [PATCH 28/74] Revert "BSD-specific tests are in fact FreeBSD only" This reverts commit ccb461f36e0120cf0f8e7f531733a7034699c2af. --- test/test_psutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_psutil.py b/test/test_psutil.py index b53ff6801..0cec2f3ef 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -92,7 +92,7 @@ WIN_VISTA = (6, 0, 0) LINUX = sys.platform.startswith("linux") OSX = sys.platform.startswith("darwin") -BSD = sys.platform.startswith("freebsd") +BSD = sys.platform.startswith("freebsd") or sys.platform.startswith("openbsd") SUNOS = sys.platform.startswith("sunos") VALID_PROC_STATUSES = [getattr(psutil, x) for x in dir(psutil) if x.startswith('STATUS_')] From e6febc67201671a5d42463c495b17df1081681bc Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Tue, 7 Apr 2015 18:58:22 +0200 Subject: [PATCH 29/74] alias SONPROC (process currently on processor) as SRUN --- psutil/_psutil_openbsd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index ac89c41dd..95b22e314 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -1995,6 +1995,7 @@ void init_psutil_bsd(void) PyModule_AddIntConstant(module, "SWAIT", -1); PyModule_AddIntConstant(module, "SLOCK", -1); PyModule_AddIntConstant(module, "SZOMB", SZOMB); + PyModule_AddIntConstant(module, "SRUN", SONPROC); // connection status constants PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED); PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING); From 5ce83517003f7f401733b564b6bc127197f12786 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Tue, 7 Apr 2015 18:58:38 +0200 Subject: [PATCH 30/74] actually return argv when sysctl call succeeds --- psutil/arch/bsd/process_info_openbsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/psutil/arch/bsd/process_info_openbsd.c b/psutil/arch/bsd/process_info_openbsd.c index 83d01f27e..8229dc322 100644 --- a/psutil/arch/bsd/process_info_openbsd.c +++ b/psutil/arch/bsd/process_info_openbsd.c @@ -187,7 +187,7 @@ get_argv(long pid) if ((argv = realloc(argv, argv_size)) == NULL) err(1, NULL); if (sysctl(argv_mib, 4, argv, &argv_size, NULL, 0) == 0) - break; + return argv; if (errno == ESRCH) { PyErr_SetFromErrno(PyExc_OSError); return NULL; From 541f4ba84a12aa5204852921fcd79c55cfad25a6 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Tue, 7 Apr 2015 19:02:25 +0200 Subject: [PATCH 31/74] import sys to get uname --- psutil/_psbsd.py | 1 + 1 file changed, 1 insertion(+) diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index 44fb30820..bb712054d 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -9,6 +9,7 @@ import errno import functools import os +import sys import xml.etree.ElementTree as ET from collections import namedtuple From b70a2cb9635244208062e95bc58de7afb4a116f1 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Tue, 7 Apr 2015 19:09:12 +0200 Subject: [PATCH 32/74] fix overflow in swap size calculation on 32-bits --- psutil/_psutil_openbsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 95b22e314..e339af341 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -585,7 +585,7 @@ psutil_virtual_mem(PyObject *self, PyObject *args) static PyObject * psutil_swap_mem(PyObject *self, PyObject *args) { - unsigned long swap_total, swap_free; + uint64_t swap_total, swap_free; struct swapent *swdev; int nswap, i; if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) == 0) { From 7edb5590c44f1d6ce7d461bf5e17d168645d6e7b Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Tue, 7 Apr 2015 19:17:31 +0200 Subject: [PATCH 33/74] enable net_if_stats implem on OpenBSD too, examples/ifconfig.py works --- psutil/_psutil_posix.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/psutil/_psutil_posix.c b/psutil/_psutil_posix.c index 462a46223..ec80ef564 100644 --- a/psutil/_psutil_posix.c +++ b/psutil/_psutil_posix.c @@ -230,7 +230,7 @@ psutil_net_if_addrs(PyObject* self, PyObject* args) * net_if_stats() implementation. This is here because it is common * to both OSX and FreeBSD and I didn't know where else to put it. */ -#if defined(__FreeBSD__) || defined(__APPLE__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) #include #include @@ -267,8 +267,8 @@ int psutil_get_nic_speed(int ifm_active) { case(IFM_1000_SX): // 1000BaseSX - multi-mode fiber case(IFM_1000_LX): // 1000baseLX - single-mode fiber case(IFM_1000_CX): // 1000baseCX - 150ohm STP -#if defined(IFM_1000_TX) && !defined(OPENBSD) - // FreeBSD 4 and others (but NOT OpenBSD)? +#if defined(IFM_1000_TX) && !defined(__OpenBSD__) + // FreeBSD 4 and others (but NOT OpenBSD) -> #define IFM_1000_T in net/if_media.h case(IFM_1000_TX): #endif #ifdef IFM_1000_FX @@ -460,7 +460,7 @@ PsutilMethods[] = "Set process priority"}, {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS, "Retrieve NICs information"}, -#if defined(__FreeBSD__) || defined(__APPLE__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) {"net_if_stats", psutil_net_if_stats, METH_VARARGS, "Return NIC stats."}, #endif From 32c3db968ee2bbea2aef446fd054d16c832a9068 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Sun, 6 Sep 2015 22:08:57 +0200 Subject: [PATCH 34/74] fix some tests --- psutil/_psutil_openbsd.c | 9 +++++++-- test/{_bsd.py => _freebsd.py} | 12 ++++++------ test/test_psutil.py | 10 ++++++---- 3 files changed, 19 insertions(+), 12 deletions(-) rename test/{_bsd.py => _freebsd.py} (95%) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index e339af341..7b77303f0 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -4,6 +4,12 @@ * found in the LICENSE file. * * OpenBSD platform-specific module methods for _psutil_bsd + * Missing compared to FreeBSD implementation: + * + * - psutil.net_connections() + * - psutil.Process.get/set_cpu_affinity() (not supported natively) + * - psutil.Process.memory_maps() + * - psutil.Process.cwd() */ @@ -1033,6 +1039,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) return NULL; } + /* * Return a Python list of tuple representing per-cpu times */ @@ -1881,10 +1888,8 @@ PsutilMethods[] = "Return process threads"}, {"proc_status", psutil_proc_status, METH_VARARGS, "Return process status as an integer"}, -/* {"proc_io_counters", psutil_proc_io_counters, METH_VARARGS, "Return process IO counters"}, -*/ {"proc_tty_nr", psutil_proc_tty_nr, METH_VARARGS, "Return process tty (terminal) number"}, {"proc_cwd", psutil_proc_cwd, METH_VARARGS, diff --git a/test/_bsd.py b/test/_freebsd.py similarity index 95% rename from test/_bsd.py rename to test/_freebsd.py index da08383af..8726c9085 100644 --- a/test/_bsd.py +++ b/test/_freebsd.py @@ -6,7 +6,7 @@ # TODO: add test for comparing connections with 'sockstat' cmd -"""BSD specific tests. These are implicitly run by test_psutil.py.""" +"""FreeBSD specific tests. These are implicitly run by test_psutil.py.""" import os import subprocess @@ -16,8 +16,8 @@ import psutil from psutil._compat import PY3 -from test_psutil import (MEMORY_TOLERANCE, BSD, sh, get_test_subprocess, which, - retry_before_failing, reap_children, unittest) +from test_psutil import (MEMORY_TOLERANCE, FREEBSD, sh, get_test_subprocess, + which, retry_before_failing, reap_children, unittest) PAGESIZE = os.sysconf("SC_PAGE_SIZE") @@ -50,8 +50,8 @@ def muse(field): return int(line.split()[1]) -@unittest.skipUnless(BSD, "not a BSD system") -class BSDSpecificTestCase(unittest.TestCase): +@unittest.skipUnless(FREEBSD, "not a FreeBSD system") +class FreeBSDSpecificTestCase(unittest.TestCase): @classmethod def setUpClass(cls): @@ -243,7 +243,7 @@ def test_buffers(self): def main(): test_suite = unittest.TestSuite() - test_suite.addTest(unittest.makeSuite(BSDSpecificTestCase)) + test_suite.addTest(unittest.makeSuite(FreeBSDSpecificTestCase)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() diff --git a/test/test_psutil.py b/test/test_psutil.py index ceea6dbbc..4cba5b743 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -98,7 +98,9 @@ WIN_VISTA = (6, 0, 0) LINUX = sys.platform.startswith("linux") OSX = sys.platform.startswith("darwin") -BSD = sys.platform.startswith("freebsd") or sys.platform.startswith("openbsd") +FREEBSD = sys.platform.startswith("freebsd") +OPENBSD = sys.platform.startswith("openbsd") +BSD = FREEBSD or OPENBSD SUNOS = sys.platform.startswith("sunos") VALID_PROC_STATUSES = [getattr(psutil, x) for x in dir(psutil) if x.startswith('STATUS_')] @@ -1849,7 +1851,7 @@ def test_cwd_2(self): p = psutil.Process(sproc.pid) call_until(p.cwd, "ret == os.path.dirname(os.getcwd())") - @unittest.skipUnless(WINDOWS or LINUX or BSD, + @unittest.skipUnless(WINDOWS or LINUX or FREEBSD, 'not available on this platform') @unittest.skipIf(LINUX and TRAVIS, "unknown failure on travis") def test_cpu_affinity(self): @@ -3183,8 +3185,8 @@ def main(): tests.append(TestDualProcessImplementation) elif OSX: from _osx import OSXSpecificTestCase as stc - elif BSD: - from _bsd import BSDSpecificTestCase as stc + elif FREEBSD: + from _freebsd import FreeBSDSpecificTestCase as stc elif SUNOS: from _sunos import SunOSSpecificTestCase as stc if stc is not None: From 2b1695943b9b24947e2d099d8da140e3ac18b18f Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Sun, 6 Sep 2015 23:11:43 +0200 Subject: [PATCH 35/74] make the code more similar to master --- psutil/_psutil_openbsd.c | 508 +++++++++++++++++---------------------- 1 file changed, 223 insertions(+), 285 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 7b77303f0..3d8528f3b 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -76,8 +76,7 @@ * Utility function which fills a kinfo_proc struct based on process pid */ static int -psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) -{ +psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) { int mib[6]; size_t size; mib[0] = CTL_KERN; @@ -108,18 +107,16 @@ psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) * Return a Python list of all the PIDs running on the system. */ static PyObject * -psutil_pids(PyObject *self, PyObject *args) -{ +psutil_pids(PyObject *self, PyObject *args) { kinfo_proc *proclist = NULL; kinfo_proc *orig_address = NULL; size_t num_processes; size_t idx; - PyObject *retlist = PyList_New(0); - PyObject *pid = NULL; + PyObject *py_retlist = PyList_New(0); + PyObject *py_pid = NULL; - if (retlist == NULL) { + if (py_retlist == NULL) return NULL; - } if (psutil_get_proc_list(&proclist, &num_processes) != 0) { PyErr_SetString(PyExc_RuntimeError, "failed to retrieve process list."); @@ -129,25 +126,24 @@ psutil_pids(PyObject *self, PyObject *args) if (num_processes > 0) { orig_address = proclist; // save so we can free it after we're done for (idx = 0; idx < num_processes; idx++) { - pid = Py_BuildValue("i", proclist->p_pid); - if (!pid) + py_pid = Py_BuildValue("i", proclist->p_pid); + if (!py_pid) goto error; - if (PyList_Append(retlist, pid)) + if (PyList_Append(py_retlist, py_pid)) goto error; - Py_DECREF(pid); + Py_DECREF(py_pid); proclist++; } free(orig_address); } - return retlist; + return py_retlist; error: - Py_XDECREF(pid); - Py_DECREF(retlist); - if (orig_address != NULL) { + Py_XDECREF(py_pid); + Py_DECREF(py_retlist); + if (orig_address != NULL) free(orig_address); - } return NULL; } @@ -157,8 +153,7 @@ psutil_pids(PyObject *self, PyObject *args) * seconds since the epoch. */ static PyObject * -psutil_boot_time(PyObject *self, PyObject *args) -{ +psutil_boot_time(PyObject *self, PyObject *args) { // fetch sysctl "kern.boottime" static int request[2] = { CTL_KERN, KERN_BOOTTIME }; struct timeval boottime; @@ -176,16 +171,13 @@ psutil_boot_time(PyObject *self, PyObject *args) * Return process name from kinfo_proc as a Python string. */ static PyObject * -psutil_proc_name(PyObject *self, PyObject *args) -{ +psutil_proc_name(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("s", kp.p_comm); } @@ -194,24 +186,21 @@ psutil_proc_name(PyObject *self, PyObject *args) * Return process cmdline as a Python list of cmdline arguments. */ static PyObject * -psutil_proc_cmdline(PyObject *self, PyObject *args) -{ +psutil_proc_cmdline(PyObject *self, PyObject *args) { long pid; - PyObject *arglist = NULL; + PyObject *py_retlist = NULL; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } // get the commandline, defined in arch/bsd/process_info.c - arglist = psutil_get_arg_list(pid); + py_retlist = psutil_get_arg_list(pid); // psutil_get_arg_list() returns NULL only if psutil_cmd_args // failed with ESRCH (no process with that PID) - if (NULL == arglist) { + if (NULL == py_retlist) return PyErr_SetFromErrno(PyExc_OSError); - } - return Py_BuildValue("N", arglist); + return Py_BuildValue("N", py_retlist); } @@ -219,16 +208,13 @@ psutil_proc_cmdline(PyObject *self, PyObject *args) * Return process parent pid from kinfo_proc as a Python integer. */ static PyObject * -psutil_proc_ppid(PyObject *self, PyObject *args) -{ +psutil_proc_ppid(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("l", (long)kp.p_ppid); } @@ -237,16 +223,13 @@ psutil_proc_ppid(PyObject *self, PyObject *args) * Return process status as a Python integer. */ static PyObject * -psutil_proc_status(PyObject *self, PyObject *args) -{ +psutil_proc_status(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("i", (int)kp.p_stat); } @@ -256,16 +239,13 @@ psutil_proc_status(PyObject *self, PyObject *args) * as a Python tuple. */ static PyObject * -psutil_proc_uids(PyObject *self, PyObject *args) -{ +psutil_proc_uids(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("lll", (long)kp.p_ruid, (long)kp.p_uid, @@ -278,16 +258,13 @@ psutil_proc_uids(PyObject *self, PyObject *args) * as a Python tuple. */ static PyObject * -psutil_proc_gids(PyObject *self, PyObject *args) -{ +psutil_proc_gids(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("lll", (long)kp.p_rgid, (long)kp.p_groups[0], @@ -300,16 +277,13 @@ psutil_proc_gids(PyObject *self, PyObject *args) * as a Python tuple. */ static PyObject * -psutil_proc_tty_nr(PyObject *self, PyObject *args) -{ +psutil_proc_tty_nr(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("i", kp.p_tdev); } @@ -318,16 +292,13 @@ psutil_proc_tty_nr(PyObject *self, PyObject *args) * Return the number of context switches performed by process as a tuple. */ static PyObject * -psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) -{ +psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("(ll)", kp.p_uru_nvcsw, kp.p_uru_nivcsw); @@ -338,16 +309,13 @@ psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) * Return number of threads used by process as a Python integer. */ static PyObject * -psutil_proc_num_threads(PyObject *self, PyObject *args) -{ +psutil_proc_num_threads(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } /* TODO: get all the procs with kvm_getprocs() and count those iwth the desired ki_pid */ return Py_BuildValue("l", (long)0); } @@ -361,8 +329,7 @@ psutil_proc_num_threads(PyObject *self, PyObject *args) * procstat_threads.c?v=8-CURRENT */ static PyObject * -psutil_proc_threads(PyObject *self, PyObject *args) -{ +psutil_proc_threads(PyObject *self, PyObject *args) { long pid; int mib[4]; struct kinfo_proc *kip = NULL; @@ -370,10 +337,10 @@ psutil_proc_threads(PyObject *self, PyObject *args) int error; unsigned int i; size_t size; - PyObject *retList = PyList_New(0); - PyObject *pyTuple = NULL; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; - if (retList == NULL) + if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; @@ -413,22 +380,22 @@ psutil_proc_threads(PyObject *self, PyObject *args) for (i = 0; i < size / sizeof(*kipp); i++) { kipp = &kip[i]; - pyTuple = Py_BuildValue("Idd", + py_tuple = Py_BuildValue("Idd", 0, //thread id? kipp->p_uutime_sec, kipp->p_ustime_sec); - if (pyTuple == NULL) + if (py_tuple == NULL) goto error; - if (PyList_Append(retList, pyTuple)) + if (PyList_Append(py_retlist, py_tuple)) goto error; - Py_DECREF(pyTuple); + Py_DECREF(py_tuple); } free(kip); - return retList; + return py_retlist; error: - Py_XDECREF(pyTuple); - Py_DECREF(retList); + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); if (kip != NULL) { free(kip); } @@ -440,17 +407,14 @@ psutil_proc_threads(PyObject *self, PyObject *args) * Return a Python tuple (user_time, kernel_time) */ static PyObject * -psutil_proc_cpu_times(PyObject *self, PyObject *args) -{ +psutil_proc_cpu_times(PyObject *self, PyObject *args) { long pid; double user_t, sys_t; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } // convert from microseconds to seconds user_t = KPT2DOUBLE(kp.p_uutime); sys_t = KPT2DOUBLE(kp.p_ustime); @@ -463,8 +427,7 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args) * XXX this could be shared with OSX */ static PyObject * -psutil_cpu_count_logical(PyObject *self, PyObject *args) -{ +psutil_cpu_count_logical(PyObject *self, PyObject *args) { int mib[2]; int ncpu; size_t len; @@ -489,16 +452,13 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args) * seconds since the epoch. */ static PyObject * -psutil_proc_create_time(PyObject *self, PyObject *args) -{ +psutil_proc_create_time(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("d", KPT2DOUBLE(kp.p_ustart)); } @@ -508,16 +468,13 @@ psutil_proc_create_time(PyObject *self, PyObject *args) * seconds since the epoch. */ static PyObject * -psutil_proc_io_counters(PyObject *self, PyObject *args) -{ +psutil_proc_io_counters(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } // there's apparently no way to determine bytes count, hence return -1. return Py_BuildValue("(llll)", kp.p_uru_inblock, @@ -532,16 +489,13 @@ psutil_proc_io_counters(PyObject *self, PyObject *args) */ #define ptoa(x) ((paddr_t)(x) << PAGE_SHIFT) static PyObject * -psutil_proc_memory_info(PyObject *self, PyObject *args) -{ +psutil_proc_memory_info(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - } return Py_BuildValue("(lllll)", ptoa(kp.p_vm_rssize), // rss (long)kp.p_vm_map_size, // vms @@ -555,14 +509,14 @@ psutil_proc_memory_info(PyObject *self, PyObject *args) * Return virtual memory usage statistics. */ static PyObject * -psutil_virtual_mem(PyObject *self, PyObject *args) -{ +psutil_virtual_mem(PyObject *self, PyObject *args) { unsigned int total, active, inactive, wired, cached, free; size_t size = sizeof(total); struct uvmexp uvmexp; int mib[] = {CTL_VM, VM_UVMEXP}; long pagesize = getpagesize(); size = sizeof(uvmexp); + if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) { warn("failed to get vm.uvmexp"); PyErr_SetFromErrno(PyExc_OSError); @@ -589,11 +543,11 @@ psutil_virtual_mem(PyObject *self, PyObject *args) * Return swap memory stats (see 'swapinfo' cmdline tool) */ static PyObject * -psutil_swap_mem(PyObject *self, PyObject *args) -{ +psutil_swap_mem(PyObject *self, PyObject *args) { uint64_t swap_total, swap_free; struct swapent *swdev; int nswap, i; + if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) == 0) { warn("failed to get swap device count"); PyErr_SetFromErrno(PyExc_OSError); @@ -635,8 +589,7 @@ psutil_swap_mem(PyObject *self, PyObject *args) * Return a Python tuple representing user, kernel and idle CPU times */ static PyObject * -psutil_cpu_times(PyObject *self, PyObject *args) -{ +psutil_cpu_times(PyObject *self, PyObject *args) { long cpu_time[CPUSTATES]; size_t size; int mib[] = {CTL_KERN, KERN_CPTIME}; @@ -662,17 +615,16 @@ psutil_cpu_times(PyObject *self, PyObject *args) * Return files opened by process as a list of ("", fd) tuples */ static PyObject * -psutil_proc_open_files(PyObject *self, PyObject *args) -{ +psutil_proc_open_files(PyObject *self, PyObject *args) { long pid; int i, cnt; struct kinfo_file *freep = NULL; struct kinfo_file *kif; struct kinfo_proc kipp; - PyObject *retList = PyList_New(0); - PyObject *tuple = NULL; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; - if (retList == NULL) + if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; @@ -690,20 +642,20 @@ psutil_proc_open_files(PyObject *self, PyObject *args) if ((kif->f_type == DTYPE_VNODE) && (kif->v_type == VREG)) { - tuple = Py_BuildValue("(si)", "", kif->fd_fd); - if (tuple == NULL) + py_tuple = Py_BuildValue("(si)", "", kif->fd_fd); + if (py_tuple == NULL) goto error; - if (PyList_Append(retList, tuple)) + if (PyList_Append(py_retlist, py_tuple)) goto error; - Py_DECREF(tuple); + Py_DECREF(py_tuple); } } free(freep); - return retList; + return py_retlist; error: - Py_XDECREF(tuple); - Py_DECREF(retList); + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); if (freep != NULL) free(freep); return NULL; @@ -714,8 +666,7 @@ psutil_proc_open_files(PyObject *self, PyObject *args) * Return files opened by process as a list of (path, fd) tuples */ static PyObject * -psutil_proc_num_fds(PyObject *self, PyObject *args) -{ +psutil_proc_num_fds(PyObject *self, PyObject *args) { long pid; int cnt; @@ -741,16 +692,14 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) * No way to get cwd on OpenBSD */ static PyObject * -psutil_proc_cwd(PyObject *self, PyObject *args) -{ +psutil_proc_cwd(PyObject *self, PyObject *args) { return Py_BuildValue("s", ""); } #if 0 // The tcplist fetching and walking is borrowed from netstat/inet.c. static char * -psutil_fetch_tcplist(void) -{ +psutil_fetch_tcplist(void) { char *buf; size_t len; int error; @@ -775,23 +724,22 @@ psutil_fetch_tcplist(void) } static int -psutil_sockaddr_port(int family, struct sockaddr_storage *ss) -{ +psutil_sockaddr_port(int family, struct sockaddr_storage *ss) { struct sockaddr_in6 *sin6; struct sockaddr_in *sin; if (family == AF_INET) { sin = (struct sockaddr_in *)ss; return (sin->sin_port); - } else { + } + else { sin6 = (struct sockaddr_in6 *)ss; return (sin6->sin6_port); } } static void * -psutil_sockaddr_addr(int family, struct sockaddr_storage *ss) -{ +psutil_sockaddr_addr(int family, struct sockaddr_storage *ss) { struct sockaddr_in6 *sin6; struct sockaddr_in *sin; @@ -806,8 +754,7 @@ psutil_sockaddr_addr(int family, struct sockaddr_storage *ss) #endif // see sys/kern/kern_sysctl.c lines 1100 and usr.bin/fstat/fstat.c print_inet_details() char * -psutil_addr_from_addru(int family, uint32_t addr[4]) -{ +psutil_addr_from_addru(int family, uint32_t addr[4]) { struct in_addr a; memcpy(&a, addr, sizeof(a)); if (family == AF_INET) { @@ -822,8 +769,7 @@ psutil_addr_from_addru(int family, uint32_t addr[4]) } static socklen_t -psutil_sockaddr_addrlen(int family) -{ +psutil_sockaddr_addrlen(int family) { if (family == AF_INET) return (sizeof(struct in_addr)); else @@ -833,8 +779,7 @@ psutil_sockaddr_addrlen(int family) #if 0 static int psutil_sockaddr_matches(int family, int port, void *pcb_addr, - struct sockaddr_storage *ss) -{ + struct sockaddr_storage *ss) { if (psutil_sockaddr_port(family, ss) != port) return (0); return (memcmp(psutil_sockaddr_addr(family, ss), pcb_addr, @@ -842,8 +787,7 @@ psutil_sockaddr_matches(int family, int port, void *pcb_addr, } static struct tcpcb * -psutil_search_tcplist(char *buf, struct kinfo_file *kif) -{ +psutil_search_tcplist(char *buf, struct kinfo_file *kif) { struct tcpcb *tp; struct inpcb *inp; struct xinpgen *xig, *oxig; @@ -895,8 +839,7 @@ static int PSUTIL_CONN_NONE = 128; * Return connections opened by process. */ static PyObject * -psutil_proc_connections(PyObject *self, PyObject *args) -{ +psutil_proc_connections(PyObject *self, PyObject *args) { long pid; int i, cnt; @@ -905,22 +848,21 @@ psutil_proc_connections(PyObject *self, PyObject *args) char *tcplist = NULL; struct tcpcb *tcp; - PyObject *retList = PyList_New(0); - PyObject *tuple = NULL; - PyObject *laddr = NULL; - PyObject *raddr = NULL; - PyObject *af_filter = NULL; - PyObject *type_filter = NULL; - PyObject *_family = NULL; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_laddr = NULL; + PyObject *py_raddr = NULL; + PyObject *py_af_filter = NULL; + PyObject *py_type_filter = NULL; + PyObject *py_family = NULL; PyObject *_type = NULL; - if (retList == NULL) { + if (py_retlist == NULL) return NULL; - } - if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) { + if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) { goto error; } - if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) { + if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); goto error; } @@ -942,22 +884,22 @@ psutil_proc_connections(PyObject *self, PyObject *args) int state; char path[PATH_MAX]; int inseq; - tuple = NULL; - laddr = NULL; - raddr = NULL; + py_tuple = NULL; + py_laddr = NULL; + py_raddr = NULL; kif = &freep[i]; if (kif->f_type == DTYPE_SOCKET) { // apply filters - _family = PyLong_FromLong((long)kif->so_family); - inseq = PySequence_Contains(af_filter, _family); - Py_DECREF(_family); + py_family = PyLong_FromLong((long)kif->so_family); + inseq = PySequence_Contains(py_af_filter, py_family); + Py_DECREF(py_family); if (inseq == 0) { continue; } _type = PyLong_FromLong((long)kif->so_type); - inseq = PySequence_Contains(type_filter, _type); + inseq = PySequence_Contains(py_type_filter, _type); Py_DECREF(_type); if (inseq == 0) { continue; @@ -976,62 +918,66 @@ psutil_proc_connections(PyObject *self, PyObject *args) } // construct python tuple/list - laddr = Py_BuildValue("(si)", - psutil_addr_from_addru(kif->so_family, kif->inp_laddru), - ntohs(kif->inp_lport)); - if (!laddr) + py_laddr = Py_BuildValue( + "(si)", + psutil_addr_from_addru(kif->so_family, kif->inp_laddru), + ntohs(kif->inp_lport)); + if (!py_laddr) goto error; if (ntohs(kif->inp_fport) != 0) { - raddr = Py_BuildValue("(si)", - psutil_addr_from_addru(kif->so_family, kif->inp_faddru), - ntohs(kif->inp_fport)); + py_raddr = Py_BuildValue( + "(si)", + psutil_addr_from_addru(kif->so_family, kif->inp_faddru), + ntohs(kif->inp_fport)); } else { - raddr = Py_BuildValue("()"); + py_raddr = Py_BuildValue("()"); } - if (!raddr) + if (!py_raddr) goto error; - tuple = Py_BuildValue("(iiiNNi)", - kif->fd_fd, - kif->so_family, - kif->so_type, - laddr, - raddr, - state); - if (!tuple) + py_tuple = Py_BuildValue( + "(iiiNNi)", + kif->fd_fd, + kif->so_family, + kif->so_type, + py_laddr, + py_raddr, + state); + if (!py_tuple) goto error; - if (PyList_Append(retList, tuple)) + if (PyList_Append(py_retlist, py_tuple)) goto error; - Py_DECREF(tuple); + Py_DECREF(py_tuple); } // UNIX socket else if (kif->so_family == AF_UNIX) { - tuple = Py_BuildValue("(iiisOi)", - kif->fd_fd, - kif->so_family, - kif->so_type, - kif->unp_path, - Py_None, - PSUTIL_CONN_NONE); - if (!tuple) + py_tuple = Py_BuildValue( + "(iiisOi)", + kif->fd_fd, + kif->so_family, + kif->so_type, + kif->unp_path, + Py_None, + PSUTIL_CONN_NONE); + if (!py_tuple) goto error; - if (PyList_Append(retList, tuple)) + if (PyList_Append(py_retlist, py_tuple)) goto error; - Py_DECREF(tuple); + Py_DECREF(py_tuple); Py_INCREF(Py_None); } } } free(freep); free(tcplist); - return retList; + return py_retlist; error: - Py_XDECREF(tuple); - Py_XDECREF(laddr); - Py_XDECREF(raddr); - Py_DECREF(retList); + Py_XDECREF(py_tuple); + Py_XDECREF(py_laddr); + Py_XDECREF(py_raddr); + Py_DECREF(py_retlist); if (freep != NULL) free(freep); if (tcplist != NULL) @@ -1044,8 +990,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) * Return a Python list of tuple representing per-cpu times */ static PyObject * -psutil_per_cpu_times(PyObject *self, PyObject *args) -{ +psutil_per_cpu_times(PyObject *self, PyObject *args) { static int maxcpus; int mib[3]; int ncpu; @@ -1121,8 +1066,7 @@ void remove_spaces(char *str) { * 'procstat' cmdline utility has been used as an example. */ static PyObject * -psutil_proc_memory_maps(PyObject *self, PyObject *args) -{ +psutil_proc_memory_maps(PyObject *self, PyObject *args) { long pid; int ptrwidth; int i, cnt; @@ -1133,18 +1077,16 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) struct kinfo_vmentry *freep = NULL; struct kinfo_vmentry *kve; ptrwidth = 2 * sizeof(void *); - PyObject *pytuple = NULL; + PyObject *py_tuple = NULL; PyObject *retlist = PyList_New(0); if (retlist == NULL) { return NULL; } - if (! PyArg_ParseTuple(args, "l", &pid)) { + if (! PyArg_ParseTuple(args, "l", &pid)) goto error; - } - if (psutil_kinfo_proc(pid, &kp) == -1) { + if (psutil_kinfo_proc(pid, &kp) == -1) goto error; - } freep = kinfo_getvmmap(pid, &cnt); if (freep == NULL) { @@ -1152,7 +1094,7 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) goto error; } for (i = 0; i < cnt; i++) { - pytuple = NULL; + py_tuple = NULL; kve = &freep[i]; addr[0] = '\0'; perms[0] = '\0'; @@ -1204,7 +1146,7 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) path = kve->kve_path; } - pytuple = Py_BuildValue("sssiiii", + py_tuple = Py_BuildValue("sssiiii", addr, // "start-end" address perms, // "rwx" permissions path, // path @@ -1212,17 +1154,17 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) kve->kve_private_resident, // private kve->kve_ref_count, // ref count kve->kve_shadow_count); // shadow count - if (!pytuple) + if (!py_tuple) goto error; - if (PyList_Append(retlist, pytuple)) + if (PyList_Append(retlist, py_tuple)) goto error; - Py_DECREF(pytuple); + Py_DECREF(py_tuple); } free(freep); return retlist; error: - Py_XDECREF(pytuple); + Py_XDECREF(py_tuple); Py_DECREF(retlist); if (freep != NULL) free(freep); @@ -1236,8 +1178,7 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) * for all partitions mounted on the system. */ static PyObject * -psutil_disk_partitions(PyObject *self, PyObject *args) -{ +psutil_disk_partitions(PyObject *self, PyObject *args) { int num; int i; long len; @@ -1325,8 +1266,7 @@ psutil_disk_partitions(PyObject *self, PyObject *args) * Return a Python list of named tuples with overall network I/O information */ static PyObject * -psutil_net_io_counters(PyObject *self, PyObject *args) -{ +psutil_net_io_counters(PyObject *self, PyObject *args) { char *buf = NULL, *lim, *next; struct if_msghdr *ifm; int mib[6]; @@ -1417,8 +1357,7 @@ psutil_net_io_counters(PyObject *self, PyObject *args) * Return a Python dict of tuples for disk I/O information */ static PyObject * -psutil_disk_io_counters(PyObject *self, PyObject *args) -{ +psutil_disk_io_counters(PyObject *self, PyObject *args) { int i, dk_ndrive, mib[3]; size_t len; struct diskstats *stats; @@ -1481,12 +1420,11 @@ psutil_disk_io_counters(PyObject *self, PyObject *args) * Return currently connected users as a list of tuples. */ static PyObject * -psutil_users(PyObject *self, PyObject *args) -{ - PyObject *ret_list = PyList_New(0); - PyObject *tuple = NULL; +psutil_users(PyObject *self, PyObject *args) { + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; - if (ret_list == NULL) + if (py_retlist == NULL) return NULL; struct utmp ut; @@ -1501,30 +1439,30 @@ psutil_users(PyObject *self, PyObject *args) while (fread(&ut, sizeof(ut), 1, fp) == 1) { if (*ut.ut_name == '\0') continue; - tuple = Py_BuildValue( + py_tuple = Py_BuildValue( "(sssf)", ut.ut_name, // username ut.ut_line, // tty ut.ut_host, // hostname (float)ut.ut_time); // start time - if (!tuple) { + if (!py_tuple) { fclose(fp); goto error; } - if (PyList_Append(ret_list, tuple)) { + if (PyList_Append(py_retlist, py_tuple)) { fclose(fp); goto error; } - Py_DECREF(tuple); + Py_DECREF(py_tuple); } fclose(fp); - return ret_list; + return py_retlist; error: - Py_XDECREF(tuple); - Py_DECREF(ret_list); + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); return NULL; } @@ -1595,19 +1533,19 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) void *buf; int hash, retry, vflag, type; - PyObject *tuple = NULL; - PyObject *laddr = NULL; - PyObject *raddr = NULL; + PyObject *py_tuple = NULL; + PyObject *py_laddr = NULL; + PyObject *py_raddr = NULL; switch (proto) { - case IPPROTO_TCP: - varname = "net.inet.tcp.pcblist"; - type = SOCK_STREAM; - break; - case IPPROTO_UDP: - varname = "net.inet.udp.pcblist"; - type = SOCK_DGRAM; - break; + case IPPROTO_TCP: + varname = "net.inet.tcp.pcblist"; + type = SOCK_STREAM; + break; + case IPPROTO_UDP: + varname = "net.inet.udp.pcblist"; + type = SOCK_DGRAM; + break; } buf = NULL; @@ -1687,19 +1625,19 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) } // construct python tuple/list - laddr = Py_BuildValue("(si)", lip, lport); - if (!laddr) + py_laddr = Py_BuildValue("(si)", lip, lport); + if (!py_laddr) goto error; if (rport != 0) { - raddr = Py_BuildValue("(si)", rip, rport); + py_raddr = Py_BuildValue("(si)", rip, rport); } else { - raddr = Py_BuildValue("()"); + py_raddr = Py_BuildValue("()"); } - if (!raddr) + if (!py_raddr) goto error; - tuple = Py_BuildValue("(iiiNNii)", -1, family, type, laddr, raddr, - status, pid); + tuple = Py_BuildValue("(iiiNNii)", -1, family, type, py_laddr, + py_raddr, status, pid); if (!tuple) goto error; if (PyList_Append(py_retlist, tuple)) @@ -1711,9 +1649,9 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) return 1; error: - Py_XDECREF(tuple); - Py_XDECREF(laddr); - Py_XDECREF(raddr); + Py_XDECREF(py_tuple); + Py_XDECREF(py_laddr); + Py_XDECREF(py_raddr); free(buf); return 0; } @@ -1732,19 +1670,19 @@ int psutil_gather_unix(int proto, PyObject *py_retlist) struct sockaddr_un *sun; char path[PATH_MAX]; - PyObject *tuple = NULL; - PyObject *laddr = NULL; - PyObject *raddr = NULL; + PyObject *py_tuple = NULL; + PyObject *py_laddr = NULL; + PyObject *py_raddr = NULL; switch (proto) { - case SOCK_STREAM: - varname = "net.local.stream.pcblist"; - protoname = "stream"; - break; - case SOCK_DGRAM: - varname = "net.local.dgram.pcblist"; - protoname = "dgram"; - break; + case SOCK_STREAM: + varname = "net.local.stream.pcblist"; + protoname = "stream"; + break; + case SOCK_DGRAM: + varname = "net.local.dgram.pcblist"; + protoname = "dgram"; + break; } buf = NULL; @@ -1796,11 +1734,12 @@ int psutil_gather_unix(int proto, PyObject *py_retlist) (sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), sun->sun_path); - tuple = Py_BuildValue("(iiisOii)", -1, AF_UNIX, proto, path, Py_None, - PSUTIL_CONN_NONE, pid); - if (!tuple) + py_tuple = Py_BuildValue( + "(iiisOii)", -1, AF_UNIX, proto, path, Py_None, + PSUTIL_CONN_NONE, pid); + if (!py_tuple) goto error; - if (PyList_Append(py_retlist, tuple)) + if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(tuple); Py_INCREF(Py_None); @@ -1810,9 +1749,9 @@ int psutil_gather_unix(int proto, PyObject *py_retlist) return 1; error: - Py_XDECREF(tuple); - Py_XDECREF(laddr); - Py_XDECREF(raddr); + Py_XDECREF(py_tuple); + Py_XDECREF(py_laddr); + Py_XDECREF(py_raddr); free(buf); return 0; } @@ -1824,13 +1763,14 @@ int psutil_gather_unix(int proto, PyObject *py_retlist) static PyObject* psutil_net_connections(PyObject* self, PyObject* args) { - PyObject *af_filter = NULL; - PyObject *type_filter = NULL; + PyObject *py_af_filter = NULL; + PyObject *py_type_filter = NULL; PyObject *py_retlist = PyList_New(0); -/* + + if (py_retlist == NULL) + return NULL; if (psutil_populate_xfiles() != 1) goto error; -*/ if (psutil_gather_inet(IPPROTO_TCP, py_retlist) == 0) goto error; if (psutil_gather_inet(IPPROTO_UDP, py_retlist) == 0) @@ -1855,8 +1795,7 @@ psutil_net_connections(PyObject* self, PyObject* args) * define the psutil C module methods and initialize the module. */ static PyMethodDef -PsutilMethods[] = -{ +PsutilMethods[] = { // --- per-process functions {"proc_name", psutil_proc_name, METH_VARARGS, @@ -2015,9 +1954,8 @@ void init_psutil_bsd(void) PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT); PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", 128); /*PSUTIL_CONN_NONE */ - if (module == NULL) { + if (module == NULL) INITERROR; - } #if PY_MAJOR_VERSION >= 3 return module; #endif From c83bca37349952a5d5c0d437d1649afb78c9a0ca Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Mon, 7 Sep 2015 00:02:29 +0200 Subject: [PATCH 36/74] Fallback on using which(cmdline()[0]) since exe() does not exist on OpenBSD --- psutil/__init__.py | 5 +--- psutil/_compat.py | 53 ++++++++++++++++++++++++++++++++++++++++ psutil/_psbsd.py | 16 +++++++++++- psutil/_psutil_openbsd.c | 2 -- test/test_psutil.py | 19 +------------- 5 files changed, 70 insertions(+), 25 deletions(-) diff --git a/psutil/__init__.py b/psutil/__init__.py index 95b650155..636bf5a83 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -118,10 +118,7 @@ elif sys.platform.startswith("darwin"): from . import _psosx as _psplatform -elif sys.platform.startswith("freebsd"): - from . import _psbsd as _psplatform - -elif sys.platform.startswith("openbsd"): +elif sys.platform.startswith("freebsd") or sys.platform.startswith("openbsd"): from . import _psbsd as _psplatform elif sys.platform.startswith("sunos"): diff --git a/psutil/_compat.py b/psutil/_compat.py index 5920c9216..3d984998f 100644 --- a/psutil/_compat.py +++ b/psutil/_compat.py @@ -6,6 +6,7 @@ import collections import functools +import os import sys __all__ = ["PY3", "long", "xrange", "unicode", "callable", "lru_cache"] @@ -185,3 +186,55 @@ def cache_clear(): return functools.update_wrapper(wrapper, user_function) return decorating_function + + +# python 3.3 +try: + from shutil import which +except ImportError: + def which(cmd, mode=os.F_OK | os.X_OK, path=None): + """Given a command, mode, and a PATH string, return the path which + conforms to the given mode on the PATH, or None if there is no such + file. + + `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result + of os.environ.get("PATH"), or can be overridden with a custom search + path. + """ + def _access_check(fn, mode): + return (os.path.exists(fn) and os.access(fn, mode) + and not os.path.isdir(fn)) + + if os.path.dirname(cmd): + if _access_check(cmd, mode): + return cmd + return None + + if path is None: + path = os.environ.get("PATH", os.defpath) + if not path: + return None + path = path.split(os.pathsep) + + if sys.platform == "win32": + if os.curdir not in path: + path.insert(0, os.curdir) + + pathext = os.environ.get("PATHEXT", "").split(os.pathsep) + if any(cmd.lower().endswith(ext.lower()) for ext in pathext): + files = [cmd] + else: + files = [cmd + ext for ext in pathext] + else: + files = [cmd] + + seen = set() + for dir in path: + normdir = os.path.normcase(dir) + if normdir not in seen: + seen.add(normdir) + for thefile in files: + name = os.path.join(dir, thefile) + if _access_check(name, mode): + return name + return None diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index ba7a87850..1c147033b 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -17,12 +17,16 @@ from . import _psutil_posix as cext_posix from ._common import conn_tmap, usage_percent, sockfam_to_enum from ._common import socktype_to_enum +from ._compat import which __extra__all__ = [] # --- constants +FREEBSD = sys.platform.startswith("freebsd") +OPENBSD = sys.platform.startswith("openbsd") + PROC_STATUSES = { cext.SSTOP: _common.STATUS_STOPPED, cext.SSLEEP: _common.STATUS_SLEEPING, @@ -277,7 +281,17 @@ def name(self): @wrap_exceptions def exe(self): - return cext.proc_exe(self.pid) + if FREEBSD: + return cext.proc_exe(self.pid) + else: + # exe cannot be determined on OpenBSD; references: + # https://chromium.googlesource.com/chromium/src/base/+/ + # master/base_paths_posix.cc + # We try our best guess by using which against the first + # cmdline arg (may return None). + cmdline = self.cmdline() + if cmdline: + return which(cmdline[0]) @wrap_exceptions def cmdline(self): diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 3d8528f3b..5891817e6 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -1802,8 +1802,6 @@ PsutilMethods[] = { "Return process name"}, {"proc_connections", psutil_proc_connections, METH_VARARGS, "Return connections opened by process"}, - {"proc_exe", psutil_proc_name, METH_VARARGS, - "Return process name"}, {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS, "Return process cmdline as a list of cmdline arguments"}, {"proc_ppid", psutil_proc_ppid, METH_VARARGS, diff --git a/test/test_psutil.py b/test/test_psutil.py index 4cba5b743..5c1739900 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -53,7 +53,7 @@ import mock # requires "pip install mock" import psutil -from psutil._compat import PY3, callable, long, unicode +from psutil._compat import PY3, callable, long, unicode, which if sys.version_info < (2, 7): import unittest2 as unittest # https://pypi.python.org/pypi/unittest2 @@ -209,23 +209,6 @@ def sh(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE): return stdout.strip() -def which(program): - """Same as UNIX which command. Return None on command not found.""" - def is_exe(fpath): - return os.path.isfile(fpath) and os.access(fpath, os.X_OK) - - fpath, fname = os.path.split(program) - if fpath: - if is_exe(program): - return program - else: - for path in os.environ["PATH"].split(os.pathsep): - exe_file = os.path.join(path, program) - if is_exe(exe_file): - return exe_file - return None - - if POSIX: def get_kernel_version(): """Return a tuple such as (2, 6, 36).""" From 1374b42c92bd95b607547cf26ebdd3c60525c232 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Fri, 6 Nov 2015 18:30:01 +0100 Subject: [PATCH 37/74] implement net_connections() by iterating over all processes --- psutil/_psbsd.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index a381ef397..a68944a28 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -198,6 +198,20 @@ def users(): def net_connections(kind): + if OPENBSD: + ret = [] + for pid in pids(): + try: + cons = Process(pid).connections() + except NoSuchProcess: + continue + else: + for conn in cons: + conn = list(conn) + conn.append(pid) + ret.append(_common.sconn(*conn)) + return ret + if kind not in _common.conn_tmap: raise ValueError("invalid %r kind argument; choose between %s" % (kind, ', '.join([repr(x) for x in conn_tmap]))) @@ -294,6 +308,8 @@ def exe(self): cmdline = self.cmdline() if cmdline: return which(cmdline[0]) + else: + return "" @wrap_exceptions def cmdline(self): From 04102058124bc41a0630a5d6e5d8f22eb035e26d Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Sat, 7 Nov 2015 23:51:44 +0100 Subject: [PATCH 38/74] implement process cwd --- psutil/_psutil_openbsd.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 5891817e6..40a3541b7 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -688,14 +688,33 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) { return Py_BuildValue("i", cnt); } + /* - * No way to get cwd on OpenBSD + * Process current working directory. + * Reference: + * http://anoncvs.spacehopper.org/openbsd-src/tree/bin/ps/print.c#n179 */ static PyObject * psutil_proc_cwd(PyObject *self, PyObject *args) { - return Py_BuildValue("s", ""); + long pid; + struct kinfo_proc kp; + char path[MAXPATHLEN]; + size_t pathlen = sizeof path; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_kinfo_proc(pid, &kp) == -1) + return NULL; + + int name[] = { CTL_KERN, KERN_PROC_CWD, pid }; + if (sysctl(name, 3, path, &pathlen, NULL, 0) != 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + return Py_BuildValue("s", path); } + #if 0 // The tcplist fetching and walking is borrowed from netstat/inet.c. static char * From eeac17f3b01bd82c61a3067558a2e559ba358ba6 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Sun, 8 Nov 2015 00:41:15 +0100 Subject: [PATCH 39/74] #615: fix proc memory vms to match ps --- psutil/_psutil_openbsd.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 40a3541b7..b98b44a4b 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -3,13 +3,16 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * - * OpenBSD platform-specific module methods for _psutil_bsd + * OpenBSD platform-specific module methods for openbsd. + + * References: + * - OpenBSD source code: http://anoncvs.spacehopper.org/openbsd-src/ + * * Missing compared to FreeBSD implementation: * * - psutil.net_connections() * - psutil.Process.get/set_cpu_affinity() (not supported natively) * - psutil.Process.memory_maps() - * - psutil.Process.cwd() */ @@ -496,12 +499,15 @@ psutil_proc_memory_info(PyObject *self, PyObject *args) { return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; - return Py_BuildValue("(lllll)", - ptoa(kp.p_vm_rssize), // rss - (long)kp.p_vm_map_size, // vms - ptoa(kp.p_vm_tsize), // text - ptoa(kp.p_vm_dsize), // data - ptoa(kp.p_vm_ssize)); // stack + return Py_BuildValue( + "(lllll)", + ptoa(kp.p_vm_rssize), // rss + // vms, this is how ps does it, see: + // http://anoncvs.spacehopper.org/openbsd-src/tree/bin/ps/print.c#n461 + ptoa(kp.p_vm_dsize + kp.p_vm_ssize + kp.p_vm_tsize), // vms + ptoa(kp.p_vm_tsize), // text + ptoa(kp.p_vm_dsize), // data + ptoa(kp.p_vm_ssize)); // stack } From 67da39e5e7b6e6ecd8ceef00db6f028ffd3ce6e1 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Sun, 8 Nov 2015 04:55:23 +0100 Subject: [PATCH 40/74] #615: implement OpenBSD process threads() --- TODO | 2 + docs/index.rst | 3 +- psutil/__init__.py | 1 + psutil/_psbsd.py | 1 + psutil/_psutil_openbsd.c | 88 ++++++++++++++++++---------------------- test/test_psutil.py | 8 +++- 6 files changed, 53 insertions(+), 50 deletions(-) diff --git a/TODO b/TODO index a428da187..4a5e0f169 100644 --- a/TODO +++ b/TODO @@ -35,6 +35,8 @@ HIGHER PRIORITY * Process.threads(): thread names; patch for OSX available at: https://code.google.com/p/plcrashreporter/issues/detail?id=65 + Sample code: + https://github.com/janmojzis/pstree/blob/master/proc_kvm.c * Asynchronous psutil.Popen (see http://bugs.python.org/issue1191964) diff --git a/docs/index.rst b/docs/index.rst index 31ba1fc3d..9a9622dc3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -892,7 +892,8 @@ Process class .. method:: threads() Return threads opened by process as a list of namedtuples including thread - id and thread CPU times (user/system). + id and thread CPU times (user/system). On OpenBSD this method requires + root access. .. method:: cpu_times() diff --git a/psutil/__init__.py b/psutil/__init__.py index 048ac527e..4c96746f5 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -754,6 +754,7 @@ def threads(self): """Return threads opened by process as a list of (id, user_time, system_time) namedtuples representing thread id and thread CPU times (user/system). + On OpenBSD this method requires root access. """ return self._proc.threads() diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index a68944a28..0d5c471e3 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -366,6 +366,7 @@ def num_ctx_switches(self): @wrap_exceptions def threads(self): + # Note: on OpenSBD this (/dev/mem) requires root access. rawlist = cext.proc_threads(self.pid) retlist = [] for thread_id, utime, stime in rawlist: diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index b98b44a4b..e8936a987 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -327,19 +327,20 @@ psutil_proc_num_threads(PyObject *self, PyObject *args) { /* * Retrieves all threads used by process returning a list of tuples * including thread id, user time and system time. - * Thanks to Robert N. M. Watson: + * Thanks to Robert N. M. Watson (FreeBSD): * http://fxr.googlebit.com/source/usr.bin/procstat/ * procstat_threads.c?v=8-CURRENT + * OpenBSD reference: + * https://github.com/janmojzis/pstree/blob/master/proc_kvm.c + * Note: OpenBSD requires root access. */ static PyObject * psutil_proc_threads(PyObject *self, PyObject *args) { long pid; - int mib[4]; - struct kinfo_proc *kip = NULL; - struct kinfo_proc *kipp = NULL; - int error; - unsigned int i; - size_t size; + kvm_t *kd = NULL; + int nentries, i; + char errbuf[4096]; + struct kinfo_proc *kp; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; @@ -348,60 +349,51 @@ psutil_proc_threads(PyObject *self, PyObject *args) { if (! PyArg_ParseTuple(args, "l", &pid)) goto error; - // we need to re-query for thread information, so don't use *kipp - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID /* | KERN_PROC_INC_THREAD */; - mib[3] = pid; - - size = 0; - error = sysctl(mib, 4, NULL, &size, NULL, 0); - if (error == -1) { - PyErr_SetFromErrno(PyExc_OSError); - goto error; - } - if (size == 0) { - NoSuchProcess(); + kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf); + if (! kd) { + if (strstr(errbuf, "Permission denied") != NULL) + AccessDenied(); + else + PyErr_Format(PyExc_RuntimeError, "kvm_openfiles() failed"); goto error; } - kip = malloc(size); - if (kip == NULL) { - PyErr_NoMemory(); + kp = kvm_getprocs( + kd, KERN_PROC_PID | KERN_PROC_SHOW_THREADS | KERN_PROC_KTHREAD, pid, + sizeof(*kp), &nentries); + if (! kp) { + if (strstr(errbuf, "Permission denied") != NULL) + AccessDenied(); + else + PyErr_Format(PyExc_RuntimeError, "kvm_getprocs() failed"); goto error; } - error = sysctl(mib, 4, kip, &size, NULL, 0); - if (error == -1) { - PyErr_SetFromErrno(PyExc_OSError); - goto error; - } - if (size == 0) { - NoSuchProcess(); - goto error; + for (i = 0; i < nentries; i++) { + if (kp[i].p_tid < 0) + continue; + if (kp[i].p_pid == pid) { + py_tuple = Py_BuildValue( + "Idd", + kp[i].p_tid, + KPT2DOUBLE(kp[i].p_uutime), + KPT2DOUBLE(kp[i].p_ustime)); + if (py_tuple == NULL) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } } - for (i = 0; i < size / sizeof(*kipp); i++) { - kipp = &kip[i]; - py_tuple = Py_BuildValue("Idd", - 0, //thread id? - kipp->p_uutime_sec, - kipp->p_ustime_sec); - if (py_tuple == NULL) - goto error; - if (PyList_Append(py_retlist, py_tuple)) - goto error; - Py_DECREF(py_tuple); - } - free(kip); + kvm_close(kd); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); - if (kip != NULL) { - free(kip); - } + if (kd != NULL) + kvm_close(kd); return NULL; } diff --git a/test/test_psutil.py b/test/test_psutil.py index 8d0ef3346..ecdb1eb77 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -1591,7 +1591,13 @@ def test_num_handles(self): def test_threads(self): p = psutil.Process() - step1 = p.threads() + if OPENBSD: + try: + step1 = p.threads() + except psutil.AccessDenied: + raise unittest.SkipTest("on OpenBSD this requires root access") + else: + step1 = p.threads() thread = ThreadTask() thread.start() From 2ce156bc2540598a91e9c311eb1d553143d7b3aa Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Sun, 8 Nov 2015 05:10:49 +0100 Subject: [PATCH 41/74] #615: implement OpenBSD process num_threads() --- psutil/_psbsd.py | 6 +++++- psutil/_psutil_openbsd.c | 18 ------------------ test/test_psutil.py | 8 +++++++- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index 0d5c471e3..dd8418bc3 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -358,7 +358,11 @@ def create_time(self): @wrap_exceptions def num_threads(self): - return cext.proc_num_threads(self.pid) + if hasattr(cext, "proc_num_threads"): + # FreeBSD + return cext.proc_num_threads(self.pid) + else: + return len(self.threads()) @wrap_exceptions def num_ctx_switches(self): diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index e8936a987..02e48ee00 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -308,22 +308,6 @@ psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) { } -/* - * Return number of threads used by process as a Python integer. - */ -static PyObject * -psutil_proc_num_threads(PyObject *self, PyObject *args) { - long pid; - struct kinfo_proc kp; - if (! PyArg_ParseTuple(args, "l", &pid)) - return NULL; - if (psutil_kinfo_proc(pid, &kp) == -1) - return NULL; -/* TODO: get all the procs with kvm_getprocs() and count those iwth the desired ki_pid */ - return Py_BuildValue("l", (long)0); -} - - /* * Retrieves all threads used by process returning a list of tuples * including thread id, user time and system time. @@ -1834,8 +1818,6 @@ PsutilMethods[] = { "seconds since the epoch"}, {"proc_memory_info", psutil_proc_memory_info, METH_VARARGS, "Return extended memory info for a process as a Python tuple."}, - {"proc_num_threads", psutil_proc_num_threads, METH_VARARGS, - "Return number of threads used by process"}, {"proc_num_ctx_switches", psutil_proc_num_ctx_switches, METH_VARARGS, "Return the number of context switches performed by process"}, {"proc_threads", psutil_proc_threads, METH_VARARGS, diff --git a/test/test_psutil.py b/test/test_psutil.py index ecdb1eb77..2f5a6d59e 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -1571,7 +1571,13 @@ def test_num_threads(self): # thread number, since we always have with 1 thread per process, # but this does not apply across all platforms (OSX, Windows) p = psutil.Process() - step1 = p.num_threads() + if OPENBSD: + try: + step1 = p.num_threads() + except psutil.AccessDenied: + raise unittest.SkipTest("on OpenBSD this requires root access") + else: + step1 = p.num_threads() thread = ThreadTask() thread.start() From f7e00828f33dec8c2653aaa857f4a64aa586947b Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Sun, 8 Nov 2015 06:13:37 +0100 Subject: [PATCH 42/74] #615: disable cpu_affinity() on OpenBSD 'cause it's not supported --- docs/index.rst | 2 +- psutil/__init__.py | 2 +- psutil/_psbsd.py | 54 ++++++++++++++++++++++++---------------------- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 9a9622dc3..d47a64cf1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -960,7 +960,7 @@ Process class >>> p.cpu_affinity(all_cpus) >>> - Availability: Linux, Windows, BSD + Availability: Linux, Windows, FreeBSD .. versionchanged:: 2.2.0 added support for FreeBSD diff --git a/psutil/__init__.py b/psutil/__init__.py index 4c96746f5..47ef5cfd1 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -715,7 +715,7 @@ def rlimit(self, resource, limits=None): else: return self._proc.rlimit(resource, limits) - # Windows, Linux and BSD only + # Windows, Linux and FreeBSD only if hasattr(_psplatform.Process, "cpu_affinity_get"): def cpu_affinity(self, cpus=None): diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index dd8418bc3..7b7b1d2c8 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -466,30 +466,32 @@ def _not_implemented(self): memory_maps = _not_implemented num_fds = _not_implemented - @wrap_exceptions - def cpu_affinity_get(self): - return cext.proc_cpu_affinity_get(self.pid) + if FREEBSD: + @wrap_exceptions + def cpu_affinity_get(self): + return cext.proc_cpu_affinity_get(self.pid) - @wrap_exceptions - def cpu_affinity_set(self, cpus): - # Pre-emptively check if CPUs are valid because the C - # function has a weird behavior in case of invalid CPUs, - # see: https://github.com/giampaolo/psutil/issues/586 - allcpus = tuple(range(len(per_cpu_times()))) - for cpu in cpus: - if cpu not in allcpus: - raise ValueError("invalid CPU #%i (choose between %s)" - % (cpu, allcpus)) - try: - cext.proc_cpu_affinity_set(self.pid, cpus) - except OSError as err: - # 'man cpuset_setaffinity' about EDEADLK: - # <> - if err.errno in (errno.EINVAL, errno.EDEADLK): - for cpu in cpus: - if cpu not in allcpus: - raise ValueError("invalid CPU #%i (choose between %s)" - % (cpu, allcpus)) - raise + @wrap_exceptions + def cpu_affinity_set(self, cpus): + # Pre-emptively check if CPUs are valid because the C + # function has a weird behavior in case of invalid CPUs, + # see: https://github.com/giampaolo/psutil/issues/586 + allcpus = tuple(range(len(per_cpu_times()))) + for cpu in cpus: + if cpu not in allcpus: + raise ValueError("invalid CPU #%i (choose between %s)" + % (cpu, allcpus)) + try: + cext.proc_cpu_affinity_set(self.pid, cpus) + except OSError as err: + # 'man cpuset_setaffinity' about EDEADLK: + # <> + if err.errno in (errno.EINVAL, errno.EDEADLK): + for cpu in cpus: + if cpu not in allcpus: + raise ValueError( + "invalid CPU #%i (choose between %s)" % ( + cpu, allcpus)) + raise From 5808a06d6fe2181912757df4cf809d53584f1592 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Sun, 8 Nov 2015 10:29:46 +0100 Subject: [PATCH 43/74] 615: conn TCP status --- psutil/_psutil_openbsd.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 02e48ee00..a5054da5c 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -912,10 +912,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) { // fill status state = PSUTIL_CONN_NONE; if (kif->so_type == SOCK_STREAM) { - /* need to read so_pcb - state = kif->so_state; - printf("state=%d\n",state); - */ + state = kif->t_state; } // construct python tuple/list From 774834592b4c973d460063150f931b0ee7d806d8 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Sun, 8 Nov 2015 12:53:04 +0100 Subject: [PATCH 44/74] C refactoring --- psutil/_psutil_openbsd.c | 172 ++++++++++----------------------------- 1 file changed, 41 insertions(+), 131 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index a5054da5c..25a2ca910 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -61,6 +61,7 @@ #include // net io counters #include #include +#include // for NI_MAXHOST #include // process open files/connections #include @@ -697,63 +698,8 @@ psutil_proc_cwd(PyObject *self, PyObject *args) { } -#if 0 -// The tcplist fetching and walking is borrowed from netstat/inet.c. -static char * -psutil_fetch_tcplist(void) { - char *buf; - size_t len; - int error; - - for (;;) { - if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) < 0) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - buf = malloc(len); - if (buf == NULL) { - PyErr_NoMemory(); - return NULL; - } - if (sysctlbyname("net.inet.tcp.pcblist", buf, &len, NULL, 0) < 0) { - free(buf); - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - return buf; - } -} - -static int -psutil_sockaddr_port(int family, struct sockaddr_storage *ss) { - struct sockaddr_in6 *sin6; - struct sockaddr_in *sin; - - if (family == AF_INET) { - sin = (struct sockaddr_in *)ss; - return (sin->sin_port); - } - else { - sin6 = (struct sockaddr_in6 *)ss; - return (sin6->sin6_port); - } -} - -static void * -psutil_sockaddr_addr(int family, struct sockaddr_storage *ss) { - struct sockaddr_in6 *sin6; - struct sockaddr_in *sin; - - if (family == AF_INET) { - sin = (struct sockaddr_in *)ss; - return (&sin->sin_addr); - } else { - sin6 = (struct sockaddr_in6 *)ss; - return (&sin6->sin6_addr); - } -} -#endif -// see sys/kern/kern_sysctl.c lines 1100 and usr.bin/fstat/fstat.c print_inet_details() +// see sys/kern/kern_sysctl.c lines 1100 and +// usr.bin/fstat/fstat.c print_inet_details() char * psutil_addr_from_addru(int family, uint32_t addr[4]) { struct in_addr a; @@ -763,76 +709,40 @@ psutil_addr_from_addru(int family, uint32_t addr[4]) { return "*"; else return inet_ntoa(a); - } else { + } + else { /* XXX TODO */ return NULL; } } -static socklen_t -psutil_sockaddr_addrlen(int family) { - if (family == AF_INET) - return (sizeof(struct in_addr)); - else - return (sizeof(struct in6_addr)); -} - -#if 0 -static int -psutil_sockaddr_matches(int family, int port, void *pcb_addr, - struct sockaddr_storage *ss) { - if (psutil_sockaddr_port(family, ss) != port) - return (0); - return (memcmp(psutil_sockaddr_addr(family, ss), pcb_addr, - psutil_sockaddr_addrlen(family)) == 0); -} - -static struct tcpcb * -psutil_search_tcplist(char *buf, struct kinfo_file *kif) { - struct tcpcb *tp; - struct inpcb *inp; - struct xinpgen *xig, *oxig; - struct xsocket *so; - oxig = xig = (struct xinpgen *)buf; - for (xig = (struct xinpgen *)((char *)xig + xig->xig_len); - xig->xig_len > sizeof(struct xinpgen); - xig = (struct xinpgen *)((char *)xig + xig->xig_len)) { - tp = &((struct xtcpcb *)xig)->xt_tp; - inp = &((struct xtcpcb *)xig)->xt_inp; - so = &((struct xtcpcb *)xig)->xt_socket; - - if (so->so_type != kif->kf_sock_type || - so->xso_family != kif->kf_sock_domain || - so->xso_protocol != kif->kf_sock_protocol) - continue; +const char * +inet6_addrstr(struct in6_addr *p) +{ + struct sockaddr_in6 sin6; + static char hbuf[NI_MAXHOST]; + const int niflags = NI_NUMERICHOST; + + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_addr = *p; + if (IN6_IS_ADDR_LINKLOCAL(p) && + *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) { + sin6.sin6_scope_id = + ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); + sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0; + } - if (kif->kf_sock_domain == AF_INET) { - if (!psutil_sockaddr_matches( - AF_INET, inp->inp_lport, &inp->inp_laddr, - &kif->kf_sa_local)) - continue; - if (!psutil_sockaddr_matches( - AF_INET, inp->inp_fport, &inp->inp_faddr, - &kif->kf_sa_peer)) - continue; - } else { - if (!psutil_sockaddr_matches( - AF_INET6, inp->inp_lport, &inp->in6p_laddr, - &kif->kf_sa_local)) - continue; - if (!psutil_sockaddr_matches( - AF_INET6, inp->inp_fport, &inp->in6p_faddr, - &kif->kf_sa_peer)) - continue; - } + if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, + hbuf, sizeof(hbuf), NULL, 0, niflags)) + return "invalid"; - return (tp); - } - return NULL; + return hbuf; } -#endif + // a signaler for connections without an actual status static int PSUTIL_CONN_NONE = 128; @@ -874,15 +784,10 @@ psutil_proc_connections(PyObject *self, PyObject *args) { goto error; } -/* - tcplist = psutil_fetch_tcplist(); - if (tcplist == NULL) { - PyErr_SetFromErrno(PyExc_OSError); - goto error; - } -*/ for (i = 0; i < cnt; i++) { int state; + int lport; + int rport; char path[PATH_MAX]; int inseq; py_tuple = NULL; @@ -890,8 +795,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) { py_raddr = NULL; kif = &freep[i]; - if (kif->f_type == DTYPE_SOCKET) - { + if (kif->f_type == DTYPE_SOCKET) { // apply filters py_family = PyLong_FromLong((long)kif->so_family); inseq = PySequence_Contains(py_af_filter, py_family); @@ -910,19 +814,24 @@ psutil_proc_connections(PyObject *self, PyObject *args) { if ((kif->so_family == AF_INET) || (kif->so_family == AF_INET6)) { // fill status - state = PSUTIL_CONN_NONE; - if (kif->so_type == SOCK_STREAM) { + if (kif->so_type == SOCK_STREAM) state = kif->t_state; - } + else + state = PSUTIL_CONN_NONE; + + // ports + lport = ntohs(kif->inp_lport); + rport = ntohs(kif->inp_fport); // construct python tuple/list py_laddr = Py_BuildValue( "(si)", psutil_addr_from_addru(kif->so_family, kif->inp_laddru), - ntohs(kif->inp_lport)); + lport); if (!py_laddr) goto error; - if (ntohs(kif->inp_fport) != 0) { + + if (rport != 0) { py_raddr = Py_BuildValue( "(si)", psutil_addr_from_addru(kif->so_family, kif->inp_faddru), @@ -931,6 +840,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) { else { py_raddr = Py_BuildValue("()"); } + if (!py_raddr) goto error; py_tuple = Py_BuildValue( From de979004d8e4eb314a7564ead62afec95adf7780 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Sun, 8 Nov 2015 13:16:12 +0100 Subject: [PATCH 45/74] #615: open_connections() IPv6 addr --- psutil/_psbsd.py | 2 +- psutil/_psutil_openbsd.c | 78 +++++++++++++++++++++++----------------- test/test_psutil.py | 4 +-- 3 files changed, 49 insertions(+), 35 deletions(-) diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index 7b7b1d2c8..c864f2068 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -202,7 +202,7 @@ def net_connections(kind): ret = [] for pid in pids(): try: - cons = Process(pid).connections() + cons = Process(pid).connections(kind) except NoSuchProcess: continue else: diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 25a2ca910..d7ad4c13c 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -701,24 +701,15 @@ psutil_proc_cwd(PyObject *self, PyObject *args) { // see sys/kern/kern_sysctl.c lines 1100 and // usr.bin/fstat/fstat.c print_inet_details() char * -psutil_addr_from_addru(int family, uint32_t addr[4]) { +psutil_convert_ipv4(int family, uint32_t addr[4]) { struct in_addr a; memcpy(&a, addr, sizeof(a)); - if (family == AF_INET) { - if (a.s_addr == INADDR_ANY) - return "*"; - else - return inet_ntoa(a); - } - else { - /* XXX TODO */ - return NULL; - } + return inet_ntoa(a); } const char * -inet6_addrstr(struct in6_addr *p) +psutil_inet6_addrstr(struct in6_addr *p) { struct sockaddr_in6 sin6; static char hbuf[NI_MAXHOST]; @@ -770,9 +761,8 @@ psutil_proc_connections(PyObject *self, PyObject *args) { if (py_retlist == NULL) return NULL; - if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) { + if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) goto error; - } if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); goto error; @@ -789,7 +779,9 @@ psutil_proc_connections(PyObject *self, PyObject *args) { int lport; int rport; char path[PATH_MAX]; + char addrbuf[NI_MAXHOST + 2]; int inseq; + struct in6_addr laddr6; py_tuple = NULL; py_laddr = NULL; py_raddr = NULL; @@ -800,19 +792,16 @@ psutil_proc_connections(PyObject *self, PyObject *args) { py_family = PyLong_FromLong((long)kif->so_family); inseq = PySequence_Contains(py_af_filter, py_family); Py_DECREF(py_family); - if (inseq == 0) { + if (inseq == 0) continue; - } _type = PyLong_FromLong((long)kif->so_type); inseq = PySequence_Contains(py_type_filter, _type); Py_DECREF(_type); - if (inseq == 0) { + if (inseq == 0) continue; - } // IPv4 / IPv6 socket - if ((kif->so_family == AF_INET) || - (kif->so_family == AF_INET6)) { + if ((kif->so_family == AF_INET) || (kif->so_family == AF_INET6)) { // fill status if (kif->so_type == SOCK_STREAM) state = kif->t_state; @@ -823,19 +812,45 @@ psutil_proc_connections(PyObject *self, PyObject *args) { lport = ntohs(kif->inp_lport); rport = ntohs(kif->inp_fport); - // construct python tuple/list - py_laddr = Py_BuildValue( - "(si)", - psutil_addr_from_addru(kif->so_family, kif->inp_laddru), - lport); - if (!py_laddr) - goto error; + // local address, IPv4 + if (kif->so_family == AF_INET) { + py_laddr = Py_BuildValue( + "(si)", + psutil_convert_ipv4(kif->so_family, kif->inp_laddru), + lport); + if (!py_laddr) + goto error; + } + else { + // local address, IPv6 + memcpy(&laddr6, kif->inp_laddru, sizeof(laddr6)); + (void *)(uintptr_t)kif->inp_ppcb; + snprintf(addrbuf, sizeof(addrbuf), "%s", + psutil_inet6_addrstr(&laddr6)); + py_laddr = Py_BuildValue("(si)", addrbuf, lport); + if (!py_laddr) + goto error; + } if (rport != 0) { - py_raddr = Py_BuildValue( - "(si)", - psutil_addr_from_addru(kif->so_family, kif->inp_faddru), - ntohs(kif->inp_fport)); + // remote address, IPv4 + if (kif->so_family == AF_INET) { + py_raddr = Py_BuildValue( + "(si)", + psutil_convert_ipv4( + kif->so_family, kif->inp_faddru), + rport); + } + else { + // remote address, IPv6 + memcpy(&laddr6, kif->inp_faddru, sizeof(laddr6)); + (void *)(uintptr_t)kif->inp_ppcb; + snprintf(addrbuf, sizeof(addrbuf), "%s", + psutil_inet6_addrstr(&laddr6)); + py_raddr = Py_BuildValue("(si)", addrbuf, rport); + if (!py_raddr) + goto error; + } } else { py_raddr = Py_BuildValue("()"); @@ -859,7 +874,6 @@ psutil_proc_connections(PyObject *self, PyObject *args) { } // UNIX socket else if (kif->so_family == AF_UNIX) { - py_tuple = Py_BuildValue( "(iiisOi)", kif->fd_fd, diff --git a/test/test_psutil.py b/test/test_psutil.py index 2f5a6d59e..14478ff2b 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -1937,8 +1937,8 @@ def compare_proc_sys_cons(self, pid, proc_cons): for c in psutil.net_connections(kind='all'): if c.pid == pid: sys_cons.append(pconn(*c[:-1])) - if BSD: - # on BSD all fds are set to -1 + if FREEBSD: + # on FreeBSD all fds are set to -1 proc_cons = [pconn(*[-1] + list(x[1:])) for x in proc_cons] self.assertEqual(sorted(proc_cons), sorted(sys_cons)) From ba5d61d047c930ead6aedbd4d5ab7ab7990684f5 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Mon, 9 Nov 2015 13:40:09 +0100 Subject: [PATCH 46/74] #615: fix process status() --- psutil/__init__.py | 10 +++++-- psutil/_psbsd.py | 57 ++++++++++++++++++++++++++++++++-------- psutil/_psutil_openbsd.c | 23 +++++++++++----- test/test_psutil.py | 6 +++++ 4 files changed, 77 insertions(+), 19 deletions(-) diff --git a/psutil/__init__.py b/psutil/__init__.py index 47ef5cfd1..d88b844a6 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -1029,8 +1029,14 @@ def _send_signal(self, sig): os.kill(self.pid, sig) except OSError as err: if err.errno == errno.ESRCH: - self._gone = True - raise NoSuchProcess(self.pid, self._name) + if (sys.platform.startswith("openbsd") and \ + pid_exists(self.pid)): + # We do this because os.kill() lies in case of + # zombie processes. + raise ZombieProcess(self.pid, self._name, self._ppid) + else: + self._gone = True + raise NoSuchProcess(self.pid, self._name) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._name) raise diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index 60fcdd48b..54e332894 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -29,15 +29,37 @@ FREEBSD = sys.platform.startswith("freebsd") OPENBSD = sys.platform.startswith("openbsd") -PROC_STATUSES = { - cext.SIDL: _common.STATUS_IDLE, - cext.SRUN: _common.STATUS_RUNNING, - cext.SSLEEP: _common.STATUS_SLEEPING, - cext.SSTOP: _common.STATUS_STOPPED, - cext.SZOMB: _common.STATUS_ZOMBIE, - cext.SWAIT: _common.STATUS_WAITING, - cext.SLOCK: _common.STATUS_LOCKED, -} +if FREEBSD: + PROC_STATUSES = { + cext.SIDL: _common.STATUS_IDLE, + cext.SRUN: _common.STATUS_RUNNING, + cext.SSLEEP: _common.STATUS_SLEEPING, + cext.SSTOP: _common.STATUS_STOPPED, + cext.SZOMB: _common.STATUS_ZOMBIE, + cext.SWAIT: _common.STATUS_WAITING, + cext.SLOCK: _common.STATUS_LOCKED, + } +elif OPENBSD: + PROC_STATUSES = { + cext.SIDL: _common.STATUS_IDLE, + cext.SSLEEP: _common.STATUS_SLEEPING, + cext.SSTOP: _common.STATUS_STOPPED, + # According to /usr/include/sys/proc.h SZOMB is unused. + # test_zombie_process() shows that SDEAD is the right + # equivalent. Also it appears there's no equivalent of + # psutil.STATUS_DEAD. SDEAD really means STATUS_ZOMBIE. + # cext.SZOMB: _common.STATUS_ZOMBIE, + cext.SDEAD: _common.STATUS_ZOMBIE, + # From http://www.eecs.harvard.edu/~margo/cs161/videos/proc.h.txt + # OpenBSD has SRUN and SONPROC: SRUN indicates that a process + # is runnable but *not* yet running, i.e. is on a run queue. + # SONPROC indicates that the process is actually executing on + # a CPU, i.e. it is no longer on a run queue. + # As such we'll map SRUN to STATUS_WAKING and SONPROC to + # STATUS_RUNNING + cext.SRUN: _common.STATUS_WAKING, + cext.SONPROC: _common.STATUS_RUNNING, + } TCP_STATUSES = { cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED, @@ -249,8 +271,20 @@ def net_if_stats(): return ret +if OPENBSD: + def pid_exists(pid): + exists = _psposix.pid_exists(pid) + if not exists: + # We do this because _psposix.pid_exists() lies in case of + # zombie processes. + return pid in pids() + else: + return True +else: + pid_exists = _psposix.pid_exists + + pids = cext.pids -pid_exists = _psposix.pid_exists disk_usage = _psposix.disk_usage net_io_counters = cext.net_io_counters disk_io_counters = cext.disk_io_counters @@ -271,7 +305,8 @@ def wrapper(self, *args, **kwargs): ZombieProcess is None): raise if err.errno == errno.ESRCH: - if not pid_exists(self.pid): + # if not pid_exists(self.pid): + if self.pid not in pids(): raise NoSuchProcess(self.pid, self._name) else: raise ZombieProcess(self.pid, self._name, self._ppid) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index d7ad4c13c..1c3c21697 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -1850,14 +1850,25 @@ void init_psutil_bsd(void) #endif PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); // process status constants - PyModule_AddIntConstant(module, "SSTOP", SSTOP); - PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); - PyModule_AddIntConstant(module, "SRUN", SRUN); + +#ifdef __FreeBSD__ PyModule_AddIntConstant(module, "SIDL", SIDL); - PyModule_AddIntConstant(module, "SWAIT", -1); - PyModule_AddIntConstant(module, "SLOCK", -1); + PyModule_AddIntConstant(module, "SRUN", SRUN); + PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); + PyModule_AddIntConstant(module, "SSTOP", SSTOP); PyModule_AddIntConstant(module, "SZOMB", SZOMB); - PyModule_AddIntConstant(module, "SRUN", SONPROC); + PyModule_AddIntConstant(module, "SWAIT", SWAIT); + PyModule_AddIntConstant(module, "SLOCK", SLOCK); +#elif __OpenBSD__ + PyModule_AddIntConstant(module, "SIDL", SIDL); + PyModule_AddIntConstant(module, "SRUN", SRUN); + PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); + PyModule_AddIntConstant(module, "SSTOP", SSTOP); + PyModule_AddIntConstant(module, "SZOMB", SZOMB); // unused + PyModule_AddIntConstant(module, "SDEAD", SDEAD); + PyModule_AddIntConstant(module, "SONPROC", SONPROC); +#endif + // connection status constants PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED); PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING); diff --git a/test/test_psutil.py b/test/test_psutil.py index 0e4fe2da0..9a3a963c4 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -1627,6 +1627,12 @@ def test_threads(self): def test_threads_2(self): p = psutil.Process() + if OPENBSD: + try: + p.threads() + except psutil.AccessDenied: + raise unittest.SkipTest( + "on OpenBSD this requires root access") self.assertAlmostEqual(p.cpu_times().user, p.threads()[0].user_time, delta=0.1) self.assertAlmostEqual(p.cpu_times().system, From cc6b10e45cb8fdb4841ce4379aa46152735098a0 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Mon, 9 Nov 2015 13:46:46 +0100 Subject: [PATCH 47/74] make Process.connections() raise NSP --- psutil/_psbsd.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index 54e332894..b1c83fdf0 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -225,7 +225,7 @@ def net_connections(kind): for pid in pids(): try: cons = Process(pid).connections(kind) - except NoSuchProcess: + except (NoSuchProcess, ZombieProcess): continue else: for conn in cons: @@ -428,6 +428,11 @@ def connections(self, kind='inet'): status = TCP_STATUSES[status] nt = _common.pconn(fd, fam, type, laddr, raddr, status) ret.append(nt) + if OPENBSD: + # On OpenBSD the underlying C function does not raise NSP + # in case the process is gone (and the returned list may + # incomplete). + self.name() # raise NSP if the process disappeared on us return ret @wrap_exceptions From 1b7b42bce315461293240171fafd0dabe6f7cd7b Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Mon, 9 Nov 2015 15:00:22 +0100 Subject: [PATCH 48/74] #615: disable memory_maps on OpenBSD --- docs/index.rst | 2 ++ psutil/__init__.py | 53 +++++++++++++++++++++++---------------------- psutil/_psbsd.py | 5 +++++ test/test_psutil.py | 7 ++++++ 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index d47a64cf1..9561b45c1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1043,6 +1043,8 @@ Process class ...] >>> + Availability: All platforms except OpenBSD. + .. method:: children(recursive=False) Return the children of this process as a list of :Class:`Process` objects, diff --git a/psutil/__init__.py b/psutil/__init__.py index d88b844a6..9e68d5b07 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -167,6 +167,7 @@ _TOTAL_PHYMEM = None _POSIX = os.name == 'posix' _WINDOWS = os.name == 'nt' +_OPENBSD = sys.platform.startswith("openbsd") _timer = getattr(time, 'monotonic', time.time) @@ -962,32 +963,33 @@ def memory_percent(self): except ZeroDivisionError: return 0.0 - def memory_maps(self, grouped=True): - """Return process' mapped memory regions as a list of namedtuples - whose fields are variable depending on the platform. + if not _OPENBSD: + def memory_maps(self, grouped=True): + """Return process' mapped memory regions as a list of namedtuples + whose fields are variable depending on the platform. - If 'grouped' is True the mapped regions with the same 'path' - are grouped together and the different memory fields are summed. + If 'grouped' is True the mapped regions with the same 'path' + are grouped together and the different memory fields are summed. - If 'grouped' is False every mapped region is shown as a single - entity and the namedtuple will also include the mapped region's - address space ('addr') and permission set ('perms'). - """ - it = self._proc.memory_maps() - if grouped: - d = {} - for tupl in it: - path = tupl[2] - nums = tupl[3:] - try: - d[path] = map(lambda x, y: x + y, d[path], nums) - except KeyError: - d[path] = nums - nt = _psplatform.pmmap_grouped - return [nt(path, *d[path]) for path in d] # NOQA - else: - nt = _psplatform.pmmap_ext - return [nt(*x) for x in it] + If 'grouped' is False every mapped region is shown as a single + entity and the namedtuple will also include the mapped region's + address space ('addr') and permission set ('perms'). + """ + it = self._proc.memory_maps() + if grouped: + d = {} + for tupl in it: + path = tupl[2] + nums = tupl[3:] + try: + d[path] = map(lambda x, y: x + y, d[path], nums) + except KeyError: + d[path] = nums + nt = _psplatform.pmmap_grouped + return [nt(path, *d[path]) for path in d] # NOQA + else: + nt = _psplatform.pmmap_ext + return [nt(*x) for x in it] def open_files(self): """Return files opened by process as a list of @@ -1029,8 +1031,7 @@ def _send_signal(self, sig): os.kill(self.pid, sig) except OSError as err: if err.errno == errno.ESRCH: - if (sys.platform.startswith("openbsd") and \ - pid_exists(self.pid)): + if _OPENBSD and pid_exists(self.pid): # We do this because os.kill() lies in case of # zombie processes. raise ZombieProcess(self.pid, self._name, self._ppid) diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index b1c83fdf0..3cd392a04 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -411,6 +411,11 @@ def threads(self): for thread_id, utime, stime in rawlist: ntuple = _common.pthread(thread_id, utime, stime) retlist.append(ntuple) + if OPENBSD: + # On OpenBSD the underlying C function does not raise NSP + # in case the process is gone (and the returned list may + # incomplete). + self.name() # raise NSP if the process disappeared on us return retlist @wrap_exceptions diff --git a/test/test_psutil.py b/test/test_psutil.py index 9a3a963c4..1d4ef8f4f 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -1661,6 +1661,7 @@ def test_memory_info(self): # def test_memory_info_ex(self): # # tested later in fetch all test suite + @unittest.skipIf(OPENBSD, "not available on OpenBSD") def test_memory_maps(self): p = psutil.Process() maps = p.memory_maps() @@ -2284,6 +2285,11 @@ def test_halfway_terminated_process(self): name) except psutil.NoSuchProcess: pass + except psutil.AccessDenied: + if OPENBSD and name in ('threads', 'num_threads'): + pass + else: + raise except NotImplementedError: pass else: @@ -3096,6 +3102,7 @@ def test_netstat(self): def test_ifconfig(self): self.assert_stdout('ifconfig.py') + @unittest.skipIf(OPENBSD, "OpenBSD does not support memory maps") def test_pmap(self): self.assert_stdout('pmap.py', args=str(os.getpid())) From f5bcc2a39f83967048d6f1963dac1139652a4e49 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Mon, 9 Nov 2015 15:17:41 +0100 Subject: [PATCH 49/74] fix failing test --- test/test_psutil.py | 70 +++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/test/test_psutil.py b/test/test_psutil.py index 1d4ef8f4f..b79dc084d 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -2128,6 +2128,7 @@ def test_num_fds(self): self.assertEqual(p.num_fds(), start) @skip_on_not_implemented(only_if=LINUX) + @unittest.skipIf(OPENBSD, "not reliable on OpenBSD") def test_num_ctx_switches(self): p = psutil.Process() before = sum(p.num_ctx_switches()) @@ -2515,7 +2516,7 @@ def test_fetch_all(self): if ret not in (0, 0.0, [], None, ''): assert ret, ret meth = getattr(self, name) - meth(ret) + meth(ret, p) except Exception as err: s = '\n' + '=' * 70 + '\n' s += "FAIL: test_%s (proc=%s" % (name, p) @@ -2525,6 +2526,7 @@ def test_fetch_all(self): s += '-' * 70 s += "\n%s" % traceback.format_exc() s = "\n".join((" " * 4) + i for i in s.splitlines()) + s += '\n' failures.append(s) break @@ -2535,10 +2537,10 @@ def test_fetch_all(self): # special cases. self.assertTrue(valid_procs > 0) - def cmdline(self, ret): + def cmdline(self, ret, proc): pass - def exe(self, ret): + def exe(self, ret, proc): if not ret: self.assertEqual(ret, '') else: @@ -2551,49 +2553,55 @@ def exe(self, ret): # XXX may fail on OSX self.assertTrue(os.access(ret, os.X_OK)) - def ppid(self, ret): + def ppid(self, ret, proc): self.assertTrue(ret >= 0) - def name(self, ret): + def name(self, ret, proc): self.assertIsInstance(ret, (str, unicode)) self.assertTrue(ret) - def create_time(self, ret): - self.assertTrue(ret > 0) + def create_time(self, ret, proc): + try: + self.assertGreaterEqual(ret, 0) + except AssertionError: + if OPENBSD and proc.status == psutil.STATUS_ZOMBIE: + pass + else: + raise # this can't be taken for granted on all platforms # self.assertGreaterEqual(ret, psutil.boot_time()) # make sure returned value can be pretty printed # with strftime time.strftime("%Y %m %d %H:%M:%S", time.localtime(ret)) - def uids(self, ret): + def uids(self, ret, proc): for uid in ret: self.assertTrue(uid >= 0) self.assertIn(uid, self._uids) - def gids(self, ret): + def gids(self, ret, proc): # note: testing all gids as above seems not to be reliable for # gid == 30 (nodoby); not sure why. for gid in ret: self.assertTrue(gid >= 0) # self.assertIn(uid, self.gids - def username(self, ret): + def username(self, ret, proc): self.assertTrue(ret) if POSIX: self.assertIn(ret, self._usernames) - def status(self, ret): + def status(self, ret, proc): self.assertTrue(ret != "") self.assertTrue(ret != '?') self.assertIn(ret, VALID_PROC_STATUSES) - def io_counters(self, ret): + def io_counters(self, ret, proc): for field in ret: if field != -1: self.assertTrue(field >= 0) - def ionice(self, ret): + def ionice(self, ret, proc): if LINUX: self.assertTrue(ret.ioclass >= 0) self.assertTrue(ret.value >= 0) @@ -2601,24 +2609,24 @@ def ionice(self, ret): self.assertTrue(ret >= 0) self.assertIn(ret, (0, 1, 2)) - def num_threads(self, ret): + def num_threads(self, ret, proc): self.assertTrue(ret >= 1) - def threads(self, ret): + def threads(self, ret, proc): for t in ret: self.assertTrue(t.id >= 0) self.assertTrue(t.user_time >= 0) self.assertTrue(t.system_time >= 0) - def cpu_times(self, ret): + def cpu_times(self, ret, proc): self.assertTrue(ret.user >= 0) self.assertTrue(ret.system >= 0) - def memory_info(self, ret): + def memory_info(self, ret, proc): self.assertTrue(ret.rss >= 0) self.assertTrue(ret.vms >= 0) - def memory_info_ex(self, ret): + def memory_info_ex(self, ret, proc): for name in ret._fields: self.assertTrue(getattr(ret, name) >= 0) if POSIX and ret.vms != 0: @@ -2633,7 +2641,7 @@ def memory_info_ex(self, ret): assert ret.peak_nonpaged_pool >= ret.nonpaged_pool, ret assert ret.peak_pagefile >= ret.pagefile, ret - def open_files(self, ret): + def open_files(self, ret, proc): for f in ret: if WINDOWS: assert f.fd == -1, f @@ -2642,15 +2650,15 @@ def open_files(self, ret): assert os.path.isabs(f.path), f assert os.path.isfile(f.path), f - def num_fds(self, ret): + def num_fds(self, ret, proc): self.assertTrue(ret >= 0) - def connections(self, ret): + def connections(self, ret, proc): self.assertEqual(len(ret), len(set(ret))) for conn in ret: check_connection_ntuple(conn) - def cwd(self, ret): + def cwd(self, ret, proc): if ret is not None: # BSD may return None assert os.path.isabs(ret), ret try: @@ -2662,21 +2670,21 @@ def cwd(self, ret): else: self.assertTrue(stat.S_ISDIR(st.st_mode)) - def memory_percent(self, ret): + def memory_percent(self, ret, proc): assert 0 <= ret <= 100, ret - def is_running(self, ret): + def is_running(self, ret, proc): self.assertTrue(ret) - def cpu_affinity(self, ret): + def cpu_affinity(self, ret, proc): assert ret != [], ret - def terminal(self, ret): + def terminal(self, ret, proc): if ret is not None: assert os.path.isabs(ret), ret assert os.path.exists(ret), ret - def memory_maps(self, ret): + def memory_maps(self, ret, proc): for nt in ret: for fname in nt._fields: value = getattr(nt, fname) @@ -2692,13 +2700,13 @@ def memory_maps(self, ret): self.assertIsInstance(value, (int, long)) assert value >= 0, value - def num_handles(self, ret): + def num_handles(self, ret, proc): if WINDOWS: self.assertGreaterEqual(ret, 0) else: self.assertGreaterEqual(ret, 0) - def nice(self, ret): + def nice(self, ret, proc): if POSIX: assert -20 <= ret <= 20, ret else: @@ -2706,11 +2714,11 @@ def nice(self, ret): if x.endswith('_PRIORITY_CLASS')] self.assertIn(ret, priorities) - def num_ctx_switches(self, ret): + def num_ctx_switches(self, ret, proc): self.assertTrue(ret.voluntary >= 0) self.assertTrue(ret.involuntary >= 0) - def rlimit(self, ret): + def rlimit(self, ret, proc): self.assertEqual(len(ret), 2) self.assertGreaterEqual(ret[0], -1) self.assertGreaterEqual(ret[1], -1) From 6e170f63e4c66b0fe0b3d3bb1b1585089caf9f78 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Mon, 9 Nov 2015 15:25:12 +0100 Subject: [PATCH 50/74] fix pid 0 test --- psutil/_psbsd.py | 4 ++++ test/test_psutil.py | 9 ++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index 3cd392a04..8b980b2d8 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -348,6 +348,8 @@ def exe(self): @wrap_exceptions def cmdline(self): + if OPENBSD and self.pid == 0: + return None # ...else it crashes return cext.proc_cmdline(self.pid) @wrap_exceptions @@ -491,6 +493,8 @@ def cwd(self): """Return process current working directory.""" # sometimes we get an empty string, in which case we turn # it into None + if OPENBSD and self.pid == 0: + return None # ...else raises EINVAL return cext.proc_cwd(self.pid) or None @wrap_exceptions diff --git a/test/test_psutil.py b/test/test_psutil.py index b79dc084d..9ca4d1751 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -2388,7 +2388,7 @@ def succeed_or_zombie_p_exc(fun, *args, **kwargs): def test_pid_0(self): # Process(0) is supposed to work on all platforms except Linux - if 0 not in psutil.pids(): + if 0 not in psutil.pids() and not OPENBSD: self.assertRaises(psutil.NoSuchProcess, psutil.Process, 0) return @@ -2429,8 +2429,11 @@ def test_pid_0(self): except psutil.AccessDenied: pass - self.assertIn(0, psutil.pids()) - self.assertTrue(psutil.pid_exists(0)) + p.as_dict() + + if not OPENBSD: + self.assertIn(0, psutil.pids()) + self.assertTrue(psutil.pid_exists(0)) def test_Popen(self): # Popen class test From 7f4004b9e55aad22d4bb37079694fcd6b76a901f Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 00:45:27 +0100 Subject: [PATCH 51/74] first step to merge OpenBSD and FreeBSD impl into one file --- psutil/_psutil_openbsd.c | 592 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 551 insertions(+), 41 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 1c3c21697..1796015da 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -1,15 +1,15 @@ /* - * Copyright (c) 2014, Landry Breuil. All rights reserved. + * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil (OpenBSD). + * All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * - * OpenBSD platform-specific module methods for openbsd. + * Platform-specific module methods for FreeBSD and OpenBSD. - * References: + * OpenBSD references: * - OpenBSD source code: http://anoncvs.spacehopper.org/openbsd-src/ * - * Missing compared to FreeBSD implementation: - * + * OpenBSD: missing compared to FreeBSD implementation: * - psutil.net_connections() * - psutil.Process.get/set_cpu_affinity() (not supported natively) * - psutil.Process.memory_maps() @@ -28,17 +28,9 @@ #include #include #include -#include /* struct diskstats */ #include #include -#include /* for CPUSTATES & CP_* */ -#include -#include #include -#include /* for VREG */ -#define _KERNEL /* for DTYPE_VNODE */ -#include -#undef _KERNEL #include #include // for struct xsocket @@ -55,13 +47,11 @@ #include // for TCP connection states #include // for inet_ntop() -#include // system users #include #include // net io counters #include #include -#include // for NI_MAXHOST #include // process open files/connections #include @@ -70,10 +60,45 @@ #include "_psutil_common.h" #include "arch/bsd/process_info.h" +#ifdef __FreeBSD__ + #include + #include + #include // get io counters + #include // needed for vmtotal struct + #include // process open files, shared libs (kinfo_getvmmap) + + #if __FreeBSD_version < 900000 + #include // system users + #else + #include + #endif +#endif + +#ifdef __OpenBSD__ + #include + #include // for NI_MAXHOST + #include // for VREG + #define _KERNEL // for DTYPE_VNODE + #include + #undef _KERNEL + #include // struct diskstats + #include // for CPUSTATES & CP_* + #include + #include +#endif + -// convert a timeval struct to a double #define TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) -#define KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) + +#ifdef __FreeBSD__ + // convert a timeval struct to a double + // convert a bintime struct to milliseconds + #define BT2MSEC(bt) (bt.sec * 1000 + ( ( (uint64_t) 1000000000 * (uint32_t) (bt.frac >> 32) ) >> 32 ) / 1000000) +#endif + +#ifdef __OpenBSD__ + #define KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) +#endif /* @@ -81,19 +106,32 @@ */ static int psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) { - int mib[6]; - size_t size; + int ret; + size_t size = sizeof(struct kinfo_proc); + +#ifdef __FreeBSD__ + int mib[4]; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = pid; - size = sizeof(struct kinfo_proc); + ret = sysctl((int*)mib, 4, proc, &size, NULL, 0); +#endif +#ifdef __OpenBSD__ + int mib[6]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = pid; mib[4] = size; mib[5] = 1; - if (sysctl((int*)mib, 6, proc, &size, NULL, 0) == -1) { + ret = sysctl((int*)mib, 6, proc, &size, NULL, 0); +#endif + + if (ret == -1) { PyErr_SetFromErrno(PyExc_OSError); return -1; } @@ -130,7 +168,11 @@ psutil_pids(PyObject *self, PyObject *args) { if (num_processes > 0) { orig_address = proclist; // save so we can free it after we're done for (idx = 0; idx < num_processes; idx++) { +#ifdef __FreeBSD__ + py_pid = Py_BuildValue("i", proclist->ki_pid); +#elif __OpenBSD__ py_pid = Py_BuildValue("i", proclist->p_pid); +#endif if (!py_pid) goto error; if (PyList_Append(py_retlist, py_pid)) @@ -182,10 +224,57 @@ psutil_proc_name(PyObject *self, PyObject *args) { return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; +#ifdef __FreeBSD__ + return Py_BuildValue("s", kp.ki_comm); +#elif __OpenBSD__ return Py_BuildValue("s", kp.p_comm); +#endif } +#ifdef __FreeBSD__ +/* + * Return process pathname executable. + * Thanks to Robert N. M. Watson: + * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_bin.c?v=8-CURRENT + */ +static PyObject * +psutil_proc_exe(PyObject *self, PyObject *args) { + long pid; + char pathname[PATH_MAX]; + int error; + int mib[4]; + int ret; + size_t size; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = pid; + + size = sizeof(pathname); + error = sysctl(mib, 4, pathname, &size, NULL, 0); + if (error == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + if (size == 0 || strlen(pathname) == 0) { + ret = psutil_pid_exists(pid); + if (ret == -1) + return NULL; + else if (ret == 0) + return NoSuchProcess(); + else + strcpy(pathname, ""); + } + return Py_BuildValue("s", pathname); +} +#endif + + /* * Return process cmdline as a Python list of cmdline arguments. */ @@ -198,7 +287,11 @@ psutil_proc_cmdline(PyObject *self, PyObject *args) { return NULL; // get the commandline, defined in arch/bsd/process_info.c +#ifdef __FreeBSD__ + py_retlist = psutil_get_cmdline(pid); +#elif __OpenBSD__ py_retlist = psutil_get_arg_list(pid); +#endif // psutil_get_arg_list() returns NULL only if psutil_cmd_args // failed with ESRCH (no process with that PID) @@ -219,7 +312,11 @@ psutil_proc_ppid(PyObject *self, PyObject *args) { return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; +#ifdef __FreeBSD__ + return Py_BuildValue("l", (long)kp.ki_ppid); +#elif __OpenBSD__ return Py_BuildValue("l", (long)kp.p_ppid); +#endif } @@ -234,7 +331,11 @@ psutil_proc_status(PyObject *self, PyObject *args) { return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; +#ifdef __FreeBSD__ + return Py_BuildValue("i", (int)kp.ki_stat); +#elif __OpenBSD__ return Py_BuildValue("i", (int)kp.p_stat); +#endif } @@ -251,9 +352,15 @@ psutil_proc_uids(PyObject *self, PyObject *args) { if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("lll", +#ifdef __FreeBSD__ + (long)kp.ki_ruid, + (long)kp.ki_uid, + (long)kp.ki_svuid); +#elif __OpenBSD__ (long)kp.p_ruid, (long)kp.p_uid, (long)kp.p_svuid); +#endif } @@ -270,9 +377,15 @@ psutil_proc_gids(PyObject *self, PyObject *args) { if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("lll", +#ifdef __FreeBSD__ + (long)kp.ki_rgid, + (long)kp.ki_groups[0], + (long)kp.ki_svuid); +#elif __OpenBSD__ (long)kp.p_rgid, (long)kp.p_groups[0], (long)kp.p_svuid); +#endif } @@ -288,7 +401,11 @@ psutil_proc_tty_nr(PyObject *self, PyObject *args) { return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; +#ifdef __FreeBSD__ + return Py_BuildValue("i", kp.ki_tdev); +#elif __OpenBSD__ return Py_BuildValue("i", kp.p_tdev); +#endif } @@ -304,9 +421,31 @@ psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) { if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("(ll)", +#ifdef __FreeBSD__ + kp.ki_rusage.ru_nvcsw, + kp.ki_rusage.ru_nivcsw); +#elif __OpenBSD__ kp.p_uru_nvcsw, kp.p_uru_nivcsw); +#endif +} + + +#ifdef __FreeBSD__ +/* + * Return number of threads used by process as a Python integer. + */ +static PyObject * +psutil_proc_num_threads(PyObject *self, PyObject *args) { + long pid; + struct kinfo_proc kp; + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_kinfo_proc(pid, &kp) == -1) + return NULL; + return Py_BuildValue("l", (long)kp.ki_numthreads); } +#endif /* @@ -319,6 +458,83 @@ psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) { * https://github.com/janmojzis/pstree/blob/master/proc_kvm.c * Note: OpenBSD requires root access. */ + +#ifdef __FreeBSD__ +static PyObject * +psutil_proc_threads(PyObject *self, PyObject *args) { + long pid; + int mib[4]; + struct kinfo_proc *kip = NULL; + struct kinfo_proc *kipp = NULL; + int error; + unsigned int i; + size_t size; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + + // we need to re-query for thread information, so don't use *kipp + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD; + mib[3] = pid; + + size = 0; + error = sysctl(mib, 4, NULL, &size, NULL, 0); + if (error == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + if (size == 0) { + NoSuchProcess(); + goto error; + } + + kip = malloc(size); + if (kip == NULL) { + PyErr_NoMemory(); + goto error; + } + + error = sysctl(mib, 4, kip, &size, NULL, 0); + if (error == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + if (size == 0) { + NoSuchProcess(); + goto error; + } + + for (i = 0; i < size / sizeof(*kipp); i++) { + kipp = &kip[i]; + py_tuple = Py_BuildValue("Idd", + kipp->ki_tid, + TV2DOUBLE(kipp->ki_rusage.ru_utime), + TV2DOUBLE(kipp->ki_rusage.ru_stime)); + if (py_tuple == NULL) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + free(kip); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (kip != NULL) + free(kip); + return NULL; +} +#endif + +#ifdef __OpenBSD__ static PyObject * psutil_proc_threads(PyObject *self, PyObject *args) { long pid; @@ -381,6 +597,42 @@ psutil_proc_threads(PyObject *self, PyObject *args) { kvm_close(kd); return NULL; } +#endif + + +#ifdef __FreeBSD__ +/* + * Return an XML string from which we'll determine the number of + * physical CPU cores in the system. + */ +static PyObject * +psutil_cpu_count_phys(PyObject *self, PyObject *args) { + void *topology = NULL; + size_t size = 0; + PyObject *py_str; + + if (sysctlbyname("kern.sched.topology_spec", NULL, &size, NULL, 0)) + goto error; + + topology = malloc(size); + if (!topology) { + PyErr_NoMemory(); + return NULL; + } + + if (sysctlbyname("kern.sched.topology_spec", topology, &size, NULL, 0)) + goto error; + + py_str = Py_BuildValue("s", topology); + free(topology); + return py_str; + +error: + if (topology != NULL) + free(topology); + Py_RETURN_NONE; +} +#endif /* @@ -396,8 +648,13 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args) { if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; // convert from microseconds to seconds +#ifdef __FreeBSD__ + user_t = TV2DOUBLE(kp.ki_rusage.ru_utime); + sys_t = TV2DOUBLE(kp.ki_rusage.ru_stime); +#elif __OpenBSD__ user_t = KPT2DOUBLE(kp.p_uutime); sys_t = KPT2DOUBLE(kp.p_ustime); +#endif return Py_BuildValue("(dd)", user_t, sys_t); } @@ -416,14 +673,10 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args) { mib[1] = HW_NCPU; len = sizeof(ncpu); - if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) { - // mimic os.cpu_count() - Py_INCREF(Py_None); - return Py_None; - } - else { + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) + Py_RETURN_NONE; // mimic os.cpu_count() + else return Py_BuildValue("i", ncpu); - } } @@ -439,7 +692,11 @@ psutil_proc_create_time(PyObject *self, PyObject *args) { return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; +#ifdef __FreeBSD__ + return Py_BuildValue("d", TV2DOUBLE(kp.ki_start)); +#elif __OpenBSD__ return Py_BuildValue("d", KPT2DOUBLE(kp.p_ustart)); +#endif } @@ -457,8 +714,13 @@ psutil_proc_io_counters(PyObject *self, PyObject *args) { return NULL; // there's apparently no way to determine bytes count, hence return -1. return Py_BuildValue("(llll)", +#ifdef __FreeBSD__ + kp.ki_rusage.ru_inblock, + kp.ki_rusage.ru_oublock, +#elif __OpenBSD__ kp.p_uru_inblock, kp.p_uru_oublock, +#endif -1, -1); } @@ -478,6 +740,13 @@ psutil_proc_memory_info(PyObject *self, PyObject *args) { return NULL; return Py_BuildValue( "(lllll)", +#ifdef __FreeBSD__ + ptoa(kp.ki_rssize), // rss + (long)kp.ki_size, // vms + ptoa(kp.ki_tsize), // text + ptoa(kp.ki_dsize), // data + ptoa(kp.ki_ssize)); // stack +#elif __OpenBSD__ ptoa(kp.p_vm_rssize), // rss // vms, this is how ps does it, see: // http://anoncvs.spacehopper.org/openbsd-src/tree/bin/ps/print.c#n461 @@ -485,6 +754,7 @@ psutil_proc_memory_info(PyObject *self, PyObject *args) { ptoa(kp.p_vm_tsize), // text ptoa(kp.p_vm_dsize), // data ptoa(kp.p_vm_ssize)); // stack +#endif } @@ -495,6 +765,54 @@ static PyObject * psutil_virtual_mem(PyObject *self, PyObject *args) { unsigned int total, active, inactive, wired, cached, free; size_t size = sizeof(total); + +#ifdef __FreeBSD__ + struct vmtotal vm; + int mib[] = {CTL_VM, VM_METER}; + long pagesize = getpagesize(); +#if __FreeBSD_version > 702101 + long buffers; +#else + int buffers; +#endif + size_t buffers_size = sizeof(buffers); + + if (sysctlbyname("vm.stats.vm.v_page_count", &total, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_active_count", &active, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_inactive_count", + &inactive, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_wire_count", &wired, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_cache_count", &cached, &size, NULL, 0)) + goto error; + if (sysctlbyname("vm.stats.vm.v_free_count", &free, &size, NULL, 0)) + goto error; + if (sysctlbyname("vfs.bufspace", &buffers, &buffers_size, NULL, 0)) + goto error; + + size = sizeof(vm); + if (sysctl(mib, 2, &vm, &size, NULL, 0) != 0) + goto error; + + return Py_BuildValue("KKKKKKKK", + (unsigned long long) total * pagesize, + (unsigned long long) free * pagesize, + (unsigned long long) active * pagesize, + (unsigned long long) inactive * pagesize, + (unsigned long long) wired * pagesize, + (unsigned long long) cached * pagesize, + (unsigned long long) buffers, + (unsigned long long) (vm.t_vmshr + vm.t_rmshr) * pagesize // shared + ); + +error: + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + +#elif __OpenBSD__ struct uvmexp uvmexp; int mib[] = {CTL_VM, VM_UVMEXP}; long pagesize = getpagesize(); @@ -515,6 +833,7 @@ psutil_virtual_mem(PyObject *self, PyObject *args) { (unsigned long long) 0, (unsigned long long) 0 ); +#endif } @@ -527,6 +846,47 @@ psutil_virtual_mem(PyObject *self, PyObject *args) { */ static PyObject * psutil_swap_mem(PyObject *self, PyObject *args) { +#ifdef __FreeBSD__ + kvm_t *kd; + struct kvm_swap kvmsw[1]; + unsigned int swapin, swapout, nodein, nodeout; + size_t size = sizeof(unsigned int); + + kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open failed"); + if (kd == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kvm_open failed"); + return NULL; + } + + if (kvm_getswapinfo(kd, kvmsw, 1, 0) < 0) { + kvm_close(kd); + PyErr_SetString(PyExc_RuntimeError, "kvm_getswapinfo failed"); + return NULL; + } + + kvm_close(kd); + + if (sysctlbyname("vm.stats.vm.v_swapin", &swapin, &size, NULL, 0) == -1) + goto sbn_error; + if (sysctlbyname("vm.stats.vm.v_swapout", &swapout, &size, NULL, 0) == -1) + goto sbn_error; + if (sysctlbyname("vm.stats.vm.v_vnodein", &nodein, &size, NULL, 0) == -1) + goto sbn_error; + if (sysctlbyname("vm.stats.vm.v_vnodeout", &nodeout, &size, NULL, 0) == -1) + goto sbn_error; + + return Py_BuildValue("(iiiII)", + kvmsw[0].ksw_total, // total + kvmsw[0].ksw_used, // used + kvmsw[0].ksw_total - kvmsw[0].ksw_used, // free + swapin + swapout, // swap in + nodein + nodeout); // swap out + +sbn_error: + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + +#elif __OpenBSD__ uint64_t swap_total, swap_free; struct swapent *swdev; int nswap, i; @@ -564,7 +924,7 @@ psutil_swap_mem(PyObject *self, PyObject *args) { swap_free * DEV_BSIZE, 0 /* XXX swap in */, 0 /* XXX swap out */); - +#endif } @@ -574,12 +934,16 @@ psutil_swap_mem(PyObject *self, PyObject *args) { static PyObject * psutil_cpu_times(PyObject *self, PyObject *args) { long cpu_time[CPUSTATES]; - size_t size; - int mib[] = {CTL_KERN, KERN_CPTIME}; + size_t size = sizeof(cpu_time); + int ret; - size = sizeof(cpu_time); - if (sysctl(mib, 2, &cpu_time, &size, NULL, 0) < 0) { - warnx("failed to get kern.cptime"); +#ifdef __FreeBSD__ + ret = sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0); +#elif __OpenBSD__ + int mib[] = {CTL_KERN, KERN_CPTIME}; + ret = sysctl(mib, 2, &cpu_time, &size, NULL, 0); +#endif + if (ret == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -597,6 +961,141 @@ psutil_cpu_times(PyObject *self, PyObject *args) { /* * Return files opened by process as a list of ("", fd) tuples */ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 + /* + * Return files opened by process as a list of (path, fd) tuples. + * TODO: this is broken as it may report empty paths. 'procstat' + * utility has the same problem see: + * https://github.com/giampaolo/psutil/issues/595 + */ +static PyObject * +psutil_proc_open_files(PyObject *self, PyObject *args) { + long pid; + int i, cnt; + struct kinfo_file *freep = NULL; + struct kinfo_file *kif; + struct kinfo_proc kipp; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + if (psutil_kinfo_proc(pid, &kipp) == -1) + goto error; + + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_ad_or_nsp(pid); + goto error; + } + + for (i = 0; i < cnt; i++) { + kif = &freep[i]; + if ((kif->kf_type == KF_TYPE_VNODE) && + (kif->kf_vnode_type == KF_VTYPE_VREG)) + { + py_tuple = Py_BuildValue("(si)", kif->kf_path, kif->kf_fd); + if (py_tuple == NULL) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + } + free(freep); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (freep != NULL) + free(freep); + return NULL; +} + + +/* + * Return files opened by process as a list of (path, fd) tuples + */ +static PyObject * +psutil_proc_num_fds(PyObject *self, PyObject *args) { + long pid; + int cnt; + + struct kinfo_file *freep; + struct kinfo_proc kipp; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_kinfo_proc(pid, &kipp) == -1) + return NULL; + + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_ad_or_nsp(pid); + return NULL; + } + free(freep); + + return Py_BuildValue("i", cnt); +} + + +/* + * Return process current working directory. + */ +static PyObject * +psutil_proc_cwd(PyObject *self, PyObject *args) { + long pid; + struct kinfo_file *freep = NULL; + struct kinfo_file *kif; + struct kinfo_proc kipp; + PyObject *py_path = NULL; + + int i, cnt; + + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + if (psutil_kinfo_proc(pid, &kipp) == -1) + goto error; + + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_ad_or_nsp(pid); + goto error; + } + + for (i = 0; i < cnt; i++) { + kif = &freep[i]; + if (kif->kf_fd == KF_FD_TYPE_CWD) { + py_path = Py_BuildValue("s", kif->kf_path); + if (!py_path) + goto error; + break; + } + } + /* + * For lower pids it seems we can't retrieve any information + * (lsof can't do that it either). Since this happens even + * as root we return an empty string instead of AccessDenied. + */ + if (py_path == NULL) + py_path = Py_BuildValue("s", ""); + free(freep); + return py_path; + +error: + Py_XDECREF(py_path); + if (freep != NULL) + free(freep); + return NULL; +} +#endif + + +#ifdef __OpenBSD__ static PyObject * psutil_proc_open_files(PyObject *self, PyObject *args) { long pid; @@ -643,6 +1142,7 @@ psutil_proc_open_files(PyObject *self, PyObject *args) { free(freep); return NULL; } +#endif /* @@ -1753,12 +2253,26 @@ PsutilMethods[] = { "Return process current working directory."}, {"proc_open_files", psutil_proc_open_files, METH_VARARGS, "Return files opened by process as a list of (path, fd) tuples"}, -#if 0 + {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS, + "Return the number of file descriptors opened by this process"}, +#ifdef __FreeBSD__ + {"proc_exe", psutil_proc_exe, METH_VARARGS, + "Return process pathname executable"}, + {"proc_num_threads", psutil_proc_num_threads, METH_VARARGS, + "Return number of threads used by process"}, {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, "Return a list of tuples for every process's memory map"}, + {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS, + "Return process CPU affinity."}, + {"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS, + "Set process CPU affinity."}, + {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, + "Return an XML string to determine the number physical CPUs."}, +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 + {"proc_open_files", psutil_proc_open_files, METH_VARARGS, + "Return files opened by process as a list of (path, fd) tuples"}, +#endif #endif - {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS, - "Return the number of file descriptors opened by this process"}, // --- system-related functions @@ -1766,10 +2280,6 @@ PsutilMethods[] = { "Returns a list of PIDs currently running on the system"}, {"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS, "Return number of logical CPUs on the system"}, -/* - {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, - "Return an XML string to determine the number physical CPUs."}, -*/ {"virtual_mem", psutil_virtual_mem, METH_VARARGS, "Return system virtual memory usage statistics"}, {"swap_mem", psutil_swap_mem, METH_VARARGS, From 16ad39b56dfb88b50c486431a09c13b9ac2182c3 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 01:22:16 +0100 Subject: [PATCH 52/74] remove unused C functions --- psutil/_psutil_openbsd.c | 2 + psutil/arch/bsd/process_info_openbsd.c | 95 +------------------------- 2 files changed, 3 insertions(+), 94 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 1796015da..d64f748ab 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -1408,6 +1408,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) { } +#ifdef __OpenBSD__ /* * Return a Python list of tuple representing per-cpu times */ @@ -1469,6 +1470,7 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) { Py_DECREF(py_retlist); return NULL; } +#endif #if 0 diff --git a/psutil/arch/bsd/process_info_openbsd.c b/psutil/arch/bsd/process_info_openbsd.c index 8229dc322..dfe3a4bc2 100644 --- a/psutil/arch/bsd/process_info_openbsd.c +++ b/psutil/arch/bsd/process_info_openbsd.c @@ -85,96 +85,6 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) } -char -*psutil_get_cmd_path(long pid, size_t *pathsize) -{ - int mib[4]; - char *path; - size_t size = 0; - - /* - * Make a sysctl() call to get the raw argument space of the process. - */ - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_ARGS; - mib[3] = pid; - - // call with a null buffer first to determine if we need a buffer - if (sysctl(mib, 4, NULL, &size, NULL, 0) == -1) { - return NULL; - } - - path = malloc(size); - if (path == NULL) { - PyErr_NoMemory(); - return NULL; - } - - *pathsize = size; - if (sysctl(mib, 4, path, &size, NULL, 0) == -1) { - free(path); - return NULL; // Insufficient privileges - } - - return path; -} - - -/* - * XXX no longer used; it probably makese sense to remove it. - * Borrowed from psi Python System Information project - * - * Get command arguments and environment variables. - * - * Based on code from ps. - * - * Returns: - * 0 for success; - * -1 for failure (Exception raised); - * 1 for insufficient privileges. - */ -char -*psutil_get_cmd_args(long pid, size_t *argsize) -{ - int mib[4], argmax; - size_t size = sizeof(argmax); - char *procargs = NULL; - - // 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) - return NULL; - - // Allocate space for the arguments. - procargs = (char *)malloc(argmax); - if (procargs == NULL) { - PyErr_NoMemory(); - return NULL; - } - - /* - * Make a sysctl() call to get the raw argument space of the process. - */ - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_ARGS; - mib[3] = pid; - - size = argmax; - if (sysctl(mib, 4, procargs, &size, NULL, 0) == -1) { - free(procargs); - return NULL; // Insufficient privileges - } - - // return string and set the length of arguments - *argsize = size; - return procargs; -} - char ** get_argv(long pid) { @@ -258,6 +168,7 @@ psutil_raise_ad_or_nsp(pid) { } } + /* * mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an int as arg * and returns an array with cnt struct kinfo_file @@ -277,23 +188,19 @@ kinfo_getfile(long pid, int* cnt) { /* get the size of what would be returned */ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { - warn("failed in first call to KERN_FILE_BYPID"); PyErr_SetFromErrno(PyExc_OSError); return NULL; } if ((kf = malloc(len)) == NULL) { - warn("failed malloc before second KERN_FILE_BYPID call"); PyErr_SetFromErrno(PyExc_OSError); return NULL; } mib[5] = (int)(len / sizeof(struct kinfo_file)); if (sysctl(mib, 6, kf, &len, NULL, 0) < 0) { - warn("failed in second call to KERN_FILE_BYPID"); PyErr_SetFromErrno(PyExc_OSError); return NULL; } *cnt = (int)(len / sizeof(struct kinfo_file)); -/* printf ("returning %d files for pid %d\n", *cnt,pid); */ return kf; } From e702926a3306fa8fb74d4034b0071bea4a37482c Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 01:36:26 +0100 Subject: [PATCH 53/74] move C files around --- psutil/_psutil_openbsd.c | 7 +- .../openbsd.c} | 100 ++++++++---------- setup.py | 2 +- 3 files changed, 52 insertions(+), 57 deletions(-) rename psutil/arch/{bsd/process_info_openbsd.c => openbsd/openbsd.c} (90%) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index d64f748ab..5d723aa5e 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -58,7 +58,12 @@ #include "_psutil_bsd.h" #include "_psutil_common.h" -#include "arch/bsd/process_info.h" + +#ifdef __FreeBSD__ + #include "arch/bsd/process_info.h" +#elif __OpenBSD__ + #include "arch/openbsd/openbsd.h" +#endif #ifdef __FreeBSD__ #include diff --git a/psutil/arch/bsd/process_info_openbsd.c b/psutil/arch/openbsd/openbsd.c similarity index 90% rename from psutil/arch/bsd/process_info_openbsd.c rename to psutil/arch/openbsd/openbsd.c index dfe3a4bc2..3f8da3bf7 100644 --- a/psutil/arch/bsd/process_info_openbsd.c +++ b/psutil/arch/openbsd/openbsd.c @@ -1,13 +1,12 @@ /* - * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil. + * 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_bsd module methods. + * Platform-specific module methods for OpenBSD. */ - #include #include #include @@ -23,7 +22,44 @@ #include #include -#include "process_info.h" +#include "openbsd.h" + + +/* + * mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an int as arg + * and returns an array with cnt struct kinfo_file + */ +struct kinfo_file * +kinfo_getfile(long pid, int* cnt) { + int mib[6]; + size_t len; + struct kinfo_file* kf; + mib[0] = CTL_KERN; + mib[1] = KERN_FILE; + mib[2] = KERN_FILE_BYPID; + mib[3] = (int) pid; + mib[4] = sizeof(struct kinfo_file); + mib[5] = 0; + + /* get the size of what would be returned */ + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + if ((kf = malloc(len)) == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + mib[5] = (int)(len / sizeof(struct kinfo_file)); + if (sysctl(mib, 6, kf, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + *cnt = (int)(len / sizeof(struct kinfo_file)); + return kf; +} + /* * Returns a list of all BSD processes on the system. This routine @@ -34,8 +70,7 @@ * On error, the function returns a BSD errno value. */ int -psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) -{ +psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { struct kinfo_proc *result; int done; static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC, 0 }; @@ -54,13 +89,11 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); if (kd == NULL) { - fprintf(stderr, "WWWWWWWWWWWWWWWWWW\n"); return errno; } result = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cnt); if (result == NULL) { - fprintf(stderr, "UUUUUUUUUUUUUUUUUU\n"); err(1, NULL); return errno; } @@ -70,15 +103,12 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) size_t mlen = cnt * sizeof(struct kinfo_proc); if ((*procList = malloc(mlen)) == NULL) { - fprintf(stderr, "ZZZZZZZZZZZZZZZZZZ\n"); err(1, NULL); return errno; } memcpy(*procList, result, mlen); - assert(*procList != NULL); - kvm_close(kd); return 0; @@ -86,8 +116,7 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) char ** -get_argv(long pid) -{ +get_argv(long pid) { static char **argv; char **p; int argv_mib[] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV}; @@ -109,8 +138,7 @@ get_argv(long pid) // returns the command line as a python list object PyObject * -psutil_get_arg_list(long pid) -{ +psutil_get_arg_list(long pid) { static char **argv; char **p; PyObject *retlist = Py_BuildValue("[]"); @@ -137,8 +165,7 @@ psutil_get_arg_list(long pid) * Return 1 if PID exists in the current process list, else 0. */ int -psutil_pid_exists(long pid) -{ +psutil_pid_exists(long pid) { int kill_ret; if (pid < 0) { return 0; @@ -167,40 +194,3 @@ psutil_raise_ad_or_nsp(pid) { AccessDenied(); } } - - -/* - * mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an int as arg - * and returns an array with cnt struct kinfo_file - */ -struct kinfo_file * -kinfo_getfile(long pid, int* cnt) { - - int mib[6]; - size_t len; - struct kinfo_file* kf; - mib[0] = CTL_KERN; - mib[1] = KERN_FILE; - mib[2] = KERN_FILE_BYPID; - mib[3] = (int) pid; - mib[4] = sizeof(struct kinfo_file); - mib[5] = 0; - - /* get the size of what would be returned */ - if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - if ((kf = malloc(len)) == NULL) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - mib[5] = (int)(len / sizeof(struct kinfo_file)); - if (sysctl(mib, 6, kf, &len, NULL, 0) < 0) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - - *cnt = (int)(len / sizeof(struct kinfo_file)); - return kf; -} diff --git a/setup.py b/setup.py index 2401ccbb4..450055299 100644 --- a/setup.py +++ b/setup.py @@ -144,7 +144,7 @@ def get_winver(): sources=[ 'psutil/_psutil_openbsd.c', 'psutil/_psutil_common.c', - 'psutil/arch/bsd/process_info_openbsd.c' + 'psutil/arch/openbsd/openbsd.c' ], define_macros=[VERSION_MACRO], libraries=["kvm"]) From 66a7b561d014ea068c0e0bd43091ef6d34aae559 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 01:49:35 +0100 Subject: [PATCH 54/74] rename C fun --- psutil/_psutil_openbsd.c | 12 ++++++------ psutil/arch/openbsd/openbsd.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 5d723aa5e..e177f2bbb 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -990,7 +990,7 @@ psutil_proc_open_files(PyObject *self, PyObject *args) { if (psutil_kinfo_proc(pid, &kipp) == -1) goto error; - freep = kinfo_getfile(pid, &cnt); + freep = psutil_kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); goto error; @@ -1037,7 +1037,7 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) { if (psutil_kinfo_proc(pid, &kipp) == -1) return NULL; - freep = kinfo_getfile(pid, &cnt); + freep = psutil_kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); return NULL; @@ -1066,7 +1066,7 @@ psutil_proc_cwd(PyObject *self, PyObject *args) { if (psutil_kinfo_proc(pid, &kipp) == -1) goto error; - freep = kinfo_getfile(pid, &cnt); + freep = psutil_kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); goto error; @@ -1118,7 +1118,7 @@ psutil_proc_open_files(PyObject *self, PyObject *args) { if (psutil_kinfo_proc(pid, &kipp) == -1) goto error; - freep = kinfo_getfile(pid, &cnt); + freep = psutil_kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); goto error; @@ -1166,7 +1166,7 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) { if (psutil_kinfo_proc(pid, &kipp) == -1) return NULL; - freep = kinfo_getfile(pid, &cnt); + freep = psutil_kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); return NULL; @@ -1273,7 +1273,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) { goto error; } - freep = kinfo_getfile(pid, &cnt); + freep = psutil_kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); goto error; diff --git a/psutil/arch/openbsd/openbsd.c b/psutil/arch/openbsd/openbsd.c index 3f8da3bf7..64d30ec0b 100644 --- a/psutil/arch/openbsd/openbsd.c +++ b/psutil/arch/openbsd/openbsd.c @@ -30,7 +30,7 @@ * and returns an array with cnt struct kinfo_file */ struct kinfo_file * -kinfo_getfile(long pid, int* cnt) { +psutil_kinfo_getfile(long pid, int* cnt) { int mib[6]; size_t len; struct kinfo_file* kf; From e81c5e90110115e9cc39e302365cd83311209ac9 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 01:58:32 +0100 Subject: [PATCH 55/74] check Py* functions ret value --- psutil/arch/openbsd/openbsd.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/psutil/arch/openbsd/openbsd.c b/psutil/arch/openbsd/openbsd.c index 64d30ec0b..7db1f9202 100644 --- a/psutil/arch/openbsd/openbsd.c +++ b/psutil/arch/openbsd/openbsd.c @@ -141,23 +141,31 @@ PyObject * psutil_get_arg_list(long pid) { static char **argv; char **p; - PyObject *retlist = Py_BuildValue("[]"); - PyObject *item = NULL; + PyObject *py_arg = NULL; + PyObject *py_retlist = Py_BuildValue("[]"); - if (pid < 0) { - return retlist; - } + if (!py_retlist) + return NULL; + if (pid < 0) + return py_retlist; if ((argv = get_argv(pid)) == NULL) - return NULL; + goto error; for (p = argv; *p != NULL; p++) { - item = Py_BuildValue("s", *p); - PyList_Append(retlist, item); - Py_DECREF(item); + py_arg = Py_BuildValue("s", *p); + if (!py_arg) + goto error; + if (PyList_Append(py_retlist, py_arg)) + goto error; + Py_DECREF(py_arg); } - return retlist; + return py_retlist; +error: + Py_XDECREF(py_arg); + Py_DECREF(py_retlist); + return NULL; } From 0ebe433d93bb55674b44d4e4874d5cd793c93bc2 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 02:15:53 +0100 Subject: [PATCH 56/74] fix compiler warnings --- psutil/_psutil_openbsd.c | 8 +------- psutil/arch/openbsd/openbsd.c | 8 ++++---- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index e177f2bbb..87fb33cbd 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -291,14 +291,8 @@ psutil_proc_cmdline(PyObject *self, PyObject *args) { if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - // get the commandline, defined in arch/bsd/process_info.c -#ifdef __FreeBSD__ py_retlist = psutil_get_cmdline(pid); -#elif __OpenBSD__ - py_retlist = psutil_get_arg_list(pid); -#endif - - // psutil_get_arg_list() returns NULL only if psutil_cmd_args + // psutil_get_cmdline() returns NULL only if psutil_cmd_args // failed with ESRCH (no process with that PID) if (NULL == py_retlist) return PyErr_SetFromErrno(PyExc_OSError); diff --git a/psutil/arch/openbsd/openbsd.c b/psutil/arch/openbsd/openbsd.c index 7db1f9202..fa63ba12d 100644 --- a/psutil/arch/openbsd/openbsd.c +++ b/psutil/arch/openbsd/openbsd.c @@ -116,7 +116,7 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { char ** -get_argv(long pid) { +_psutil_get_argv(long pid) { static char **argv; char **p; int argv_mib[] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV}; @@ -138,7 +138,7 @@ get_argv(long pid) { // returns the command line as a python list object PyObject * -psutil_get_arg_list(long pid) { +psutil_get_cmdline(long pid) { static char **argv; char **p; PyObject *py_arg = NULL; @@ -149,7 +149,7 @@ psutil_get_arg_list(long pid) { if (pid < 0) return py_retlist; - if ((argv = get_argv(pid)) == NULL) + if ((argv = _psutil_get_argv(pid)) == NULL) goto error; for (p = argv; *p != NULL; p++) { @@ -194,7 +194,7 @@ psutil_pid_exists(long pid) { * Set exception to AccessDenied if pid exists else NoSuchProcess. */ int -psutil_raise_ad_or_nsp(pid) { +psutil_raise_ad_or_nsp(long pid) { if (psutil_pid_exists(pid) == 0) { NoSuchProcess(); } From 2c83fa84073fca317c269a764eada7446e7632cf Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 02:22:50 +0100 Subject: [PATCH 57/74] move psutil_kinfo_proc + add header file --- psutil/_psutil_openbsd.c | 24 +++++------------------- psutil/arch/openbsd/openbsd.c | 30 ++++++++++++++++++++++++++++++ psutil/arch/openbsd/openbsd.h | 18 ++++++++++++++++++ 3 files changed, 53 insertions(+), 19 deletions(-) create mode 100644 psutil/arch/openbsd/openbsd.h diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 87fb33cbd..ae25e99e3 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -106,37 +106,22 @@ #endif +#ifdef __FreeBSD__ /* * Utility function which fills a kinfo_proc struct based on process pid */ static int psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) { - int ret; - size_t size = sizeof(struct kinfo_proc); - -#ifdef __FreeBSD__ int mib[4]; + size_t size; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = pid; - ret = sysctl((int*)mib, 4, proc, &size, NULL, 0); -#endif - -#ifdef __OpenBSD__ - int mib[6]; - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = pid; - mib[4] = size; - mib[5] = 1; - - ret = sysctl((int*)mib, 6, proc, &size, NULL, 0); -#endif + size = sizeof(struct kinfo_proc); - if (ret == -1) { + if (sysctl((int *)mib, 4, proc, &size, NULL, 0) == -1) { PyErr_SetFromErrno(PyExc_OSError); return -1; } @@ -148,6 +133,7 @@ psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) { } return 0; } +#endif /* diff --git a/psutil/arch/openbsd/openbsd.c b/psutil/arch/openbsd/openbsd.c index fa63ba12d..63249ea44 100644 --- a/psutil/arch/openbsd/openbsd.c +++ b/psutil/arch/openbsd/openbsd.c @@ -25,6 +25,36 @@ #include "openbsd.h" +/* + * Utility function which fills a kinfo_proc struct based on process pid + */ +int +psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc) { + int ret; + int mib[6]; + size_t size = sizeof(struct kinfo_proc); + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = pid; + mib[4] = size; + mib[5] = 1; + + ret = sysctl((int*)mib, 6, proc, &size, NULL, 0); + if (ret == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + // sysctl stores 0 in the size if we can't find the process information. + if (size == 0) { + NoSuchProcess(); + return -1; + } + return 0; +} + + /* * mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an int as arg * and returns an array with cnt struct kinfo_file diff --git a/psutil/arch/openbsd/openbsd.h b/psutil/arch/openbsd/openbsd.h new file mode 100644 index 000000000..96654934b --- /dev/null +++ b/psutil/arch/openbsd/openbsd.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil. + * 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_kinfo_proc(pid_t pid, struct kinfo_proc *proc); +struct kinfo_file * psutil_kinfo_getfile(long pid, int* cnt); +int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount); +char **_psutil_get_argv(long pid); +PyObject * psutil_get_cmdline(long pid); +int psutil_pid_exists(long pid); +int psutil_raise_ad_or_nsp(long pid); From 95a5f29bb45bc2cf616b06deed5c3fdb4ddb6aea Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 02:35:39 +0100 Subject: [PATCH 58/74] some styling --- psutil/_psutil_openbsd.c | 65 --------------------- psutil/arch/openbsd/openbsd.c | 105 ++++++++++++++++++---------------- psutil/arch/openbsd/openbsd.h | 3 + 3 files changed, 58 insertions(+), 115 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index ae25e99e3..e2cb9d055 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -519,71 +519,6 @@ psutil_proc_threads(PyObject *self, PyObject *args) { } #endif -#ifdef __OpenBSD__ -static PyObject * -psutil_proc_threads(PyObject *self, PyObject *args) { - long pid; - kvm_t *kd = NULL; - int nentries, i; - char errbuf[4096]; - struct kinfo_proc *kp; - PyObject *py_retlist = PyList_New(0); - PyObject *py_tuple = NULL; - - if (py_retlist == NULL) - return NULL; - if (! PyArg_ParseTuple(args, "l", &pid)) - goto error; - - kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf); - if (! kd) { - if (strstr(errbuf, "Permission denied") != NULL) - AccessDenied(); - else - PyErr_Format(PyExc_RuntimeError, "kvm_openfiles() failed"); - goto error; - } - - kp = kvm_getprocs( - kd, KERN_PROC_PID | KERN_PROC_SHOW_THREADS | KERN_PROC_KTHREAD, pid, - sizeof(*kp), &nentries); - if (! kp) { - if (strstr(errbuf, "Permission denied") != NULL) - AccessDenied(); - else - PyErr_Format(PyExc_RuntimeError, "kvm_getprocs() failed"); - goto error; - } - - for (i = 0; i < nentries; i++) { - if (kp[i].p_tid < 0) - continue; - if (kp[i].p_pid == pid) { - py_tuple = Py_BuildValue( - "Idd", - kp[i].p_tid, - KPT2DOUBLE(kp[i].p_uutime), - KPT2DOUBLE(kp[i].p_ustime)); - if (py_tuple == NULL) - goto error; - if (PyList_Append(py_retlist, py_tuple)) - goto error; - Py_DECREF(py_tuple); - } - } - - kvm_close(kd); - return py_retlist; - -error: - Py_XDECREF(py_tuple); - Py_DECREF(py_retlist); - if (kd != NULL) - kvm_close(kd); - return NULL; -} -#endif - #ifdef __FreeBSD__ /* diff --git a/psutil/arch/openbsd/openbsd.c b/psutil/arch/openbsd/openbsd.c index 63249ea44..c399a0ce6 100644 --- a/psutil/arch/openbsd/openbsd.c +++ b/psutil/arch/openbsd/openbsd.c @@ -25,11 +25,16 @@ #include "openbsd.h" -/* - * Utility function which fills a kinfo_proc struct based on process pid - */ +#define KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) + + +// ============================================================================ +// Utility functions +// ============================================================================ + int psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc) { + // Fills a kinfo_proc struct based on process pid. int ret; int mib[6]; size_t size = sizeof(struct kinfo_proc); @@ -55,12 +60,10 @@ psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc) { } -/* - * mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an int as arg - * and returns an array with cnt struct kinfo_file - */ struct kinfo_file * psutil_kinfo_getfile(long pid, int* cnt) { + // Mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an + // int as arg and returns an array with cnt struct kinfo_file. int mib[6]; size_t len; struct kinfo_file* kf; @@ -91,16 +94,53 @@ psutil_kinfo_getfile(long pid, int* cnt) { } -/* - * 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_pid_exists(long pid) { + // Return 1 if PID exists in the current process list, else 0, -1 + // on error. + // TODO: this should live in _psutil_posix.c but for some reason if I + // move it there I get a "include undefined symbol" error. + int ret; + if (pid < 0) + return 0; + ret = kill(pid , 0); + if (ret == 0) + return 1; + else { + if (ret == ESRCH) + return 0; + else if (ret == EPERM) + return 1; + else { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + } +} + + +int +psutil_raise_ad_or_nsp(long pid) { + // Set exception to AccessDenied if pid exists else NoSuchProcess. + if (psutil_pid_exists(pid) == 0) + NoSuchProcess(); + else + AccessDenied(); +} + + +// ============================================================================ +// Process related APIS +// ============================================================================ + int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { + // 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. struct kinfo_proc *result; int done; static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC, 0 }; @@ -197,38 +237,3 @@ psutil_get_cmdline(long pid) { Py_DECREF(py_retlist); return NULL; } - - -/* - * Return 1 if PID exists in the current process list, else 0. - */ -int -psutil_pid_exists(long pid) { - int kill_ret; - 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; -} - - -/* - * Set exception to AccessDenied if pid exists else NoSuchProcess. - */ -int -psutil_raise_ad_or_nsp(long pid) { - if (psutil_pid_exists(pid) == 0) { - NoSuchProcess(); - } - else { - AccessDenied(); - } -} diff --git a/psutil/arch/openbsd/openbsd.h b/psutil/arch/openbsd/openbsd.h index 96654934b..13188dcda 100644 --- a/psutil/arch/openbsd/openbsd.h +++ b/psutil/arch/openbsd/openbsd.h @@ -16,3 +16,6 @@ char **_psutil_get_argv(long pid); PyObject * psutil_get_cmdline(long pid); int psutil_pid_exists(long pid); int psutil_raise_ad_or_nsp(long pid); + +// +PyObject *psutil_proc_threads(PyObject *self, PyObject *args); From 706c0b610c7a5549846e6de66640ff5f5f11f4e9 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 02:48:54 +0100 Subject: [PATCH 59/74] move poc thread in openbsd.c --- psutil/_psutil_bsd.h | 2 ++ psutil/arch/openbsd/openbsd.c | 64 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/psutil/_psutil_bsd.h b/psutil/_psutil_bsd.h index 803957dac..a7d63b7cb 100644 --- a/psutil/_psutil_bsd.h +++ b/psutil/_psutil_bsd.h @@ -23,7 +23,9 @@ static PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args); static PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args); static PyObject* psutil_proc_ppid(PyObject* self, PyObject* args); static PyObject* psutil_proc_status(PyObject* self, PyObject* args); +#ifdef __FreeBSD__ static PyObject* psutil_proc_threads(PyObject* self, PyObject* args); +#endif static PyObject* psutil_proc_tty_nr(PyObject* self, PyObject* args); static PyObject* psutil_proc_uids(PyObject* self, PyObject* args); static PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args); diff --git a/psutil/arch/openbsd/openbsd.c b/psutil/arch/openbsd/openbsd.c index c399a0ce6..c9d7a8aaf 100644 --- a/psutil/arch/openbsd/openbsd.c +++ b/psutil/arch/openbsd/openbsd.c @@ -237,3 +237,67 @@ psutil_get_cmdline(long pid) { Py_DECREF(py_retlist); return NULL; } + + +PyObject * +psutil_proc_threads(PyObject *self, PyObject *args) { + long pid; + kvm_t *kd = NULL; + int nentries, i; + char errbuf[4096]; + struct kinfo_proc *kp; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + + kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf); + if (! kd) { + if (strstr(errbuf, "Permission denied") != NULL) + AccessDenied(); + else + PyErr_Format(PyExc_RuntimeError, "kvm_openfiles() failed"); + goto error; + } + + kp = kvm_getprocs( + kd, KERN_PROC_PID | KERN_PROC_SHOW_THREADS | KERN_PROC_KTHREAD, pid, + sizeof(*kp), &nentries); + if (! kp) { + if (strstr(errbuf, "Permission denied") != NULL) + AccessDenied(); + else + PyErr_Format(PyExc_RuntimeError, "kvm_getprocs() failed"); + goto error; + } + + for (i = 0; i < nentries; i++) { + if (kp[i].p_tid < 0) + continue; + if (kp[i].p_pid == pid) { + py_tuple = Py_BuildValue( + "Idd", + kp[i].p_tid, + KPT2DOUBLE(kp[i].p_uutime), + KPT2DOUBLE(kp[i].p_ustime)); + if (py_tuple == NULL) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + } + + kvm_close(kd); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (kd != NULL) + kvm_close(kd); + return NULL; +} From 74a8bfd050a1cb39f0a29f2cc45816ba950c4f8e Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 02:58:36 +0100 Subject: [PATCH 60/74] move virtual_mem C fun --- psutil/_psutil_bsd.h | 2 ++ psutil/_psutil_openbsd.c | 27 ++------------------------- psutil/arch/openbsd/openbsd.c | 27 +++++++++++++++++++++++++++ psutil/arch/openbsd/openbsd.h | 1 + 4 files changed, 32 insertions(+), 25 deletions(-) diff --git a/psutil/_psutil_bsd.h b/psutil/_psutil_bsd.h index a7d63b7cb..db7445f75 100644 --- a/psutil/_psutil_bsd.h +++ b/psutil/_psutil_bsd.h @@ -48,7 +48,9 @@ static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args); static PyObject* psutil_pids(PyObject* self, PyObject* args); static PyObject* psutil_swap_mem(PyObject* self, PyObject* args); static PyObject* psutil_users(PyObject* self, PyObject* args); +#ifdef __FreeBSD__ static PyObject* psutil_virtual_mem(PyObject* self, PyObject* args); +#endif #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args); diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index e2cb9d055..784da9d59 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -678,6 +678,7 @@ psutil_proc_memory_info(PyObject *self, PyObject *args) { } +#ifdef __FreeBSD__ /* * Return virtual memory usage statistics. */ @@ -685,8 +686,6 @@ static PyObject * psutil_virtual_mem(PyObject *self, PyObject *args) { unsigned int total, active, inactive, wired, cached, free; size_t size = sizeof(total); - -#ifdef __FreeBSD__ struct vmtotal vm; int mib[] = {CTL_VM, VM_METER}; long pagesize = getpagesize(); @@ -731,30 +730,8 @@ psutil_virtual_mem(PyObject *self, PyObject *args) { error: PyErr_SetFromErrno(PyExc_OSError); return NULL; - -#elif __OpenBSD__ - struct uvmexp uvmexp; - int mib[] = {CTL_VM, VM_UVMEXP}; - long pagesize = getpagesize(); - size = sizeof(uvmexp); - - if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) { - warn("failed to get vm.uvmexp"); - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - return Py_BuildValue("KKKKKKKK", - (unsigned long long) uvmexp.npages * pagesize, - (unsigned long long) uvmexp.free * pagesize, - (unsigned long long) uvmexp.active * pagesize, - (unsigned long long) uvmexp.inactive * pagesize, - (unsigned long long) uvmexp.wired * pagesize, - (unsigned long long) 0, - (unsigned long long) 0, - (unsigned long long) 0 - ); -#endif } +#endif #ifndef _PATH_DEVNULL diff --git a/psutil/arch/openbsd/openbsd.c b/psutil/arch/openbsd/openbsd.c index c9d7a8aaf..0c256cbec 100644 --- a/psutil/arch/openbsd/openbsd.c +++ b/psutil/arch/openbsd/openbsd.c @@ -301,3 +301,30 @@ psutil_proc_threads(PyObject *self, PyObject *args) { kvm_close(kd); return NULL; } + + +PyObject * +psutil_virtual_mem(PyObject *self, PyObject *args) { + unsigned int total, active, inactive, wired, cached, free; + size_t size = sizeof(total); + struct uvmexp uvmexp; + int mib[] = {CTL_VM, VM_UVMEXP}; + long pagesize = getpagesize(); + size = sizeof(uvmexp); + + if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) { + warn("failed to get vm.uvmexp"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + return Py_BuildValue("KKKKKKKK", + (unsigned long long) uvmexp.npages * pagesize, + (unsigned long long) uvmexp.free * pagesize, + (unsigned long long) uvmexp.active * pagesize, + (unsigned long long) uvmexp.inactive * pagesize, + (unsigned long long) uvmexp.wired * pagesize, + (unsigned long long) 0, + (unsigned long long) 0, + (unsigned long long) 0 + ); +} diff --git a/psutil/arch/openbsd/openbsd.h b/psutil/arch/openbsd/openbsd.h index 13188dcda..e6d248b86 100644 --- a/psutil/arch/openbsd/openbsd.h +++ b/psutil/arch/openbsd/openbsd.h @@ -19,3 +19,4 @@ int psutil_raise_ad_or_nsp(long pid); // PyObject *psutil_proc_threads(PyObject *self, PyObject *args); +PyObject *psutil_virtual_mem(PyObject *self, PyObject *args); From be551ba7391756935c61cd2b3ecce9722e1bc861 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 03:02:27 +0100 Subject: [PATCH 61/74] move swap_mem fun --- psutil/_psutil_bsd.h | 2 +- psutil/_psutil_openbsd.c | 43 ++--------------------------------- psutil/arch/openbsd/openbsd.c | 43 +++++++++++++++++++++++++++++++++++ psutil/arch/openbsd/openbsd.h | 1 + 4 files changed, 47 insertions(+), 42 deletions(-) diff --git a/psutil/_psutil_bsd.h b/psutil/_psutil_bsd.h index db7445f75..2a55b6b40 100644 --- a/psutil/_psutil_bsd.h +++ b/psutil/_psutil_bsd.h @@ -46,10 +46,10 @@ static PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args); static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args); static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args); static PyObject* psutil_pids(PyObject* self, PyObject* args); -static PyObject* psutil_swap_mem(PyObject* self, PyObject* args); static PyObject* psutil_users(PyObject* self, PyObject* args); #ifdef __FreeBSD__ static PyObject* psutil_virtual_mem(PyObject* self, PyObject* args); +static PyObject* psutil_swap_mem(PyObject* self, PyObject* args); #endif #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 784da9d59..57d6cfcb0 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -738,12 +738,12 @@ psutil_virtual_mem(PyObject *self, PyObject *args) { #define _PATH_DEVNULL "/dev/null" #endif +#ifdef __FreeBSD__ /* * Return swap memory stats (see 'swapinfo' cmdline tool) */ static PyObject * psutil_swap_mem(PyObject *self, PyObject *args) { -#ifdef __FreeBSD__ kvm_t *kd; struct kvm_swap kvmsw[1]; unsigned int swapin, swapout, nodein, nodeout; @@ -782,47 +782,8 @@ psutil_swap_mem(PyObject *self, PyObject *args) { sbn_error: PyErr_SetFromErrno(PyExc_OSError); return NULL; - -#elif __OpenBSD__ - uint64_t swap_total, swap_free; - struct swapent *swdev; - int nswap, i; - - if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) == 0) { - warn("failed to get swap device count"); - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - - if ((swdev = calloc(nswap, sizeof(*swdev))) == NULL) { - warn("failed to allocate memory for swdev structures"); - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - - if (swapctl(SWAP_STATS, swdev, nswap) == -1) { - free(swdev); - warn("failed to get swap stats"); - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - - /* Total things up */ - swap_total = swap_free = 0; - for (i = 0; i < nswap; i++) { - if (swdev[i].se_flags & SWF_ENABLE) { - swap_free += (swdev[i].se_nblks - swdev[i].se_inuse); - swap_total += swdev[i].se_nblks; - } - } - return Py_BuildValue("(LLLII)", - swap_total * DEV_BSIZE, - (swap_total - swap_free) * DEV_BSIZE, - swap_free * DEV_BSIZE, - 0 /* XXX swap in */, - 0 /* XXX swap out */); -#endif } +#endif /* diff --git a/psutil/arch/openbsd/openbsd.c b/psutil/arch/openbsd/openbsd.c index 0c256cbec..3bcc52a89 100644 --- a/psutil/arch/openbsd/openbsd.c +++ b/psutil/arch/openbsd/openbsd.c @@ -19,6 +19,7 @@ #include #include #include +#include // for swap_mem #include #include @@ -328,3 +329,45 @@ psutil_virtual_mem(PyObject *self, PyObject *args) { (unsigned long long) 0 ); } + + +PyObject * +psutil_swap_mem(PyObject *self, PyObject *args) { + uint64_t swap_total, swap_free; + struct swapent *swdev; + int nswap, i; + + if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) == 0) { + warn("failed to get swap device count"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + if ((swdev = calloc(nswap, sizeof(*swdev))) == NULL) { + warn("failed to allocate memory for swdev structures"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + if (swapctl(SWAP_STATS, swdev, nswap) == -1) { + free(swdev); + warn("failed to get swap stats"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + /* Total things up */ + swap_total = swap_free = 0; + for (i = 0; i < nswap; i++) { + if (swdev[i].se_flags & SWF_ENABLE) { + swap_free += (swdev[i].se_nblks - swdev[i].se_inuse); + swap_total += swdev[i].se_nblks; + } + } + return Py_BuildValue("(LLLII)", + swap_total * DEV_BSIZE, + (swap_total - swap_free) * DEV_BSIZE, + swap_free * DEV_BSIZE, + 0 /* XXX swap in */, + 0 /* XXX swap out */); +} diff --git a/psutil/arch/openbsd/openbsd.h b/psutil/arch/openbsd/openbsd.h index e6d248b86..e24bfc807 100644 --- a/psutil/arch/openbsd/openbsd.h +++ b/psutil/arch/openbsd/openbsd.h @@ -20,3 +20,4 @@ int psutil_raise_ad_or_nsp(long pid); // PyObject *psutil_proc_threads(PyObject *self, PyObject *args); PyObject *psutil_virtual_mem(PyObject *self, PyObject *args); +PyObject *psutil_swap_mem(PyObject *self, PyObject *args); From f5fd52c8b8de5276361e381fe506830c231dc17b Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 03:06:31 +0100 Subject: [PATCH 62/74] rename psutil_kinfo_getfile -> kinfo_getfile --- psutil/_psutil_openbsd.c | 12 ++++++------ psutil/arch/openbsd/openbsd.c | 2 +- psutil/arch/openbsd/openbsd.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 57d6cfcb0..b4d00efef 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -843,7 +843,7 @@ psutil_proc_open_files(PyObject *self, PyObject *args) { if (psutil_kinfo_proc(pid, &kipp) == -1) goto error; - freep = psutil_kinfo_getfile(pid, &cnt); + freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); goto error; @@ -890,7 +890,7 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) { if (psutil_kinfo_proc(pid, &kipp) == -1) return NULL; - freep = psutil_kinfo_getfile(pid, &cnt); + freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); return NULL; @@ -919,7 +919,7 @@ psutil_proc_cwd(PyObject *self, PyObject *args) { if (psutil_kinfo_proc(pid, &kipp) == -1) goto error; - freep = psutil_kinfo_getfile(pid, &cnt); + freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); goto error; @@ -971,7 +971,7 @@ psutil_proc_open_files(PyObject *self, PyObject *args) { if (psutil_kinfo_proc(pid, &kipp) == -1) goto error; - freep = psutil_kinfo_getfile(pid, &cnt); + freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); goto error; @@ -1019,7 +1019,7 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) { if (psutil_kinfo_proc(pid, &kipp) == -1) return NULL; - freep = psutil_kinfo_getfile(pid, &cnt); + freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); return NULL; @@ -1126,7 +1126,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) { goto error; } - freep = psutil_kinfo_getfile(pid, &cnt); + freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); goto error; diff --git a/psutil/arch/openbsd/openbsd.c b/psutil/arch/openbsd/openbsd.c index 3bcc52a89..c49c2bea9 100644 --- a/psutil/arch/openbsd/openbsd.c +++ b/psutil/arch/openbsd/openbsd.c @@ -62,7 +62,7 @@ psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc) { struct kinfo_file * -psutil_kinfo_getfile(long pid, int* cnt) { +kinfo_getfile(long pid, int* cnt) { // Mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an // int as arg and returns an array with cnt struct kinfo_file. int mib[6]; diff --git a/psutil/arch/openbsd/openbsd.h b/psutil/arch/openbsd/openbsd.h index e24bfc807..b7e33e546 100644 --- a/psutil/arch/openbsd/openbsd.h +++ b/psutil/arch/openbsd/openbsd.h @@ -10,7 +10,7 @@ typedef struct kinfo_proc kinfo_proc; int psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc); -struct kinfo_file * psutil_kinfo_getfile(long pid, int* cnt); +struct kinfo_file * kinfo_getfile(long pid, int* cnt); int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount); char **_psutil_get_argv(long pid); PyObject * psutil_get_cmdline(long pid); From 26e1ba189563f4306783e72b155e5ed2c467cb7e Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 03:21:36 +0100 Subject: [PATCH 63/74] move openbsd specific modules again --- psutil/_psutil_openbsd.c | 5 +---- psutil/arch/{openbsd => bsd}/openbsd.c | 4 ++++ psutil/arch/{openbsd => bsd}/openbsd.h | 0 setup.py | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) rename psutil/arch/{openbsd => bsd}/openbsd.c (98%) rename psutil/arch/{openbsd => bsd}/openbsd.h (100%) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index b4d00efef..0338c7867 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -62,7 +62,7 @@ #ifdef __FreeBSD__ #include "arch/bsd/process_info.h" #elif __OpenBSD__ - #include "arch/openbsd/openbsd.h" + #include "arch/bsd/openbsd.h" #endif #ifdef __FreeBSD__ @@ -439,9 +439,6 @@ psutil_proc_num_threads(PyObject *self, PyObject *args) { * Thanks to Robert N. M. Watson (FreeBSD): * http://fxr.googlebit.com/source/usr.bin/procstat/ * procstat_threads.c?v=8-CURRENT - * OpenBSD reference: - * https://github.com/janmojzis/pstree/blob/master/proc_kvm.c - * Note: OpenBSD requires root access. */ #ifdef __FreeBSD__ diff --git a/psutil/arch/openbsd/openbsd.c b/psutil/arch/bsd/openbsd.c similarity index 98% rename from psutil/arch/openbsd/openbsd.c rename to psutil/arch/bsd/openbsd.c index c49c2bea9..5030c5d1e 100644 --- a/psutil/arch/openbsd/openbsd.c +++ b/psutil/arch/bsd/openbsd.c @@ -242,6 +242,10 @@ psutil_get_cmdline(long pid) { PyObject * psutil_proc_threads(PyObject *self, PyObject *args) { + // OpenBSD reference: + // https://github.com/janmojzis/pstree/blob/master/proc_kvm.c + // Note: this requires root access, else it will fail trying + // to access /dev/kmem. long pid; kvm_t *kd = NULL; int nentries, i; diff --git a/psutil/arch/openbsd/openbsd.h b/psutil/arch/bsd/openbsd.h similarity index 100% rename from psutil/arch/openbsd/openbsd.h rename to psutil/arch/bsd/openbsd.h diff --git a/setup.py b/setup.py index 450055299..52bd8998a 100644 --- a/setup.py +++ b/setup.py @@ -144,7 +144,7 @@ def get_winver(): sources=[ 'psutil/_psutil_openbsd.c', 'psutil/_psutil_common.c', - 'psutil/arch/openbsd/openbsd.c' + 'psutil/arch/bsd/openbsd.c' ], define_macros=[VERSION_MACRO], libraries=["kvm"]) From 76e23b5e97f6d79c5a3c9f8f668d06045235666c Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 03:32:24 +0100 Subject: [PATCH 64/74] properly redefine proc_open_files --- psutil/_psutil_openbsd.c | 76 +++++++++------------------------------- 1 file changed, 16 insertions(+), 60 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 0338c7867..ca255eb45 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -813,16 +813,13 @@ psutil_cpu_times(PyObject *self, PyObject *args) { } -/* - * Return files opened by process as a list of ("", fd) tuples - */ -#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 /* * Return files opened by process as a list of (path, fd) tuples. * TODO: this is broken as it may report empty paths. 'procstat' * utility has the same problem see: * https://github.com/giampaolo/psutil/issues/595 */ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ static PyObject * psutil_proc_open_files(PyObject *self, PyObject *args) { long pid; @@ -848,10 +845,17 @@ psutil_proc_open_files(PyObject *self, PyObject *args) { for (i = 0; i < cnt; i++) { kif = &freep[i]; +#ifdef __FreeBSD__ if ((kif->kf_type == KF_TYPE_VNODE) && (kif->kf_vnode_type == KF_VTYPE_VREG)) { py_tuple = Py_BuildValue("(si)", kif->kf_path, kif->kf_fd); +#else + if ((kif->f_type == DTYPE_VNODE) && + (kif->v_type == VREG)) + { + py_tuple = Py_BuildValue("(si)", "", kif->fd_fd); +#endif if (py_tuple == NULL) goto error; if (PyList_Append(py_retlist, py_tuple)) @@ -869,8 +873,10 @@ psutil_proc_open_files(PyObject *self, PyObject *args) { free(freep); return NULL; } +#endif +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 /* * Return files opened by process as a list of (path, fd) tuples */ @@ -896,8 +902,10 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) { return Py_BuildValue("i", cnt); } +#endif +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 /* * Return process current working directory. */ @@ -950,56 +958,6 @@ psutil_proc_cwd(PyObject *self, PyObject *args) { #endif -#ifdef __OpenBSD__ -static PyObject * -psutil_proc_open_files(PyObject *self, PyObject *args) { - long pid; - int i, cnt; - struct kinfo_file *freep = NULL; - struct kinfo_file *kif; - struct kinfo_proc kipp; - PyObject *py_retlist = PyList_New(0); - PyObject *py_tuple = NULL; - - if (py_retlist == NULL) - return NULL; - if (! PyArg_ParseTuple(args, "l", &pid)) - goto error; - if (psutil_kinfo_proc(pid, &kipp) == -1) - goto error; - - freep = kinfo_getfile(pid, &cnt); - if (freep == NULL) { - psutil_raise_ad_or_nsp(pid); - goto error; - } - - for (i = 0; i < cnt; i++) { - kif = &freep[i]; - if ((kif->f_type == DTYPE_VNODE) && - (kif->v_type == VREG)) - { - py_tuple = Py_BuildValue("(si)", "", kif->fd_fd); - if (py_tuple == NULL) - goto error; - if (PyList_Append(py_retlist, py_tuple)) - goto error; - Py_DECREF(py_tuple); - } - } - free(freep); - return py_retlist; - -error: - Py_XDECREF(py_tuple); - Py_DECREF(py_retlist); - if (freep != NULL) - free(freep); - return NULL; -} -#endif - - /* * Return files opened by process as a list of (path, fd) tuples */ @@ -2108,10 +2066,12 @@ PsutilMethods[] = { "Return process tty (terminal) number"}, {"proc_cwd", psutil_proc_cwd, METH_VARARGS, "Return process current working directory."}, - {"proc_open_files", psutil_proc_open_files, METH_VARARGS, - "Return files opened by process as a list of (path, fd) tuples"}, {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS, "Return the number of file descriptors opened by this process"}, +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ + {"proc_open_files", psutil_proc_open_files, METH_VARARGS, + "Return files opened by process as a list of (path, fd) tuples"}, +#endif #ifdef __FreeBSD__ {"proc_exe", psutil_proc_exe, METH_VARARGS, "Return process pathname executable"}, @@ -2125,10 +2085,6 @@ PsutilMethods[] = { "Set process CPU affinity."}, {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, "Return an XML string to determine the number physical CPUs."}, -#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 - {"proc_open_files", psutil_proc_open_files, METH_VARARGS, - "Return files opened by process as a list of (path, fd) tuples"}, -#endif #endif // --- system-related functions From 203f77618c370bdf601435ef5ce2f92ebb4d2e55 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 03:40:09 +0100 Subject: [PATCH 65/74] move proc num fds --- psutil/_psutil_bsd.h | 12 ++++++++---- psutil/_psutil_openbsd.c | 30 +++--------------------------- psutil/arch/bsd/openbsd.c | 24 ++++++++++++++++++++++++ psutil/arch/bsd/openbsd.h | 1 + 4 files changed, 36 insertions(+), 31 deletions(-) diff --git a/psutil/_psutil_bsd.h b/psutil/_psutil_bsd.h index 2a55b6b40..3ff077b9f 100644 --- a/psutil/_psutil_bsd.h +++ b/psutil/_psutil_bsd.h @@ -19,13 +19,9 @@ static PyObject* psutil_proc_memory_info(PyObject* self, PyObject* args); static PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args); static PyObject* psutil_proc_name(PyObject* self, PyObject* args); static PyObject* psutil_proc_num_ctx_switches(PyObject* self, PyObject* args); -static PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args); static PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args); static PyObject* psutil_proc_ppid(PyObject* self, PyObject* args); static PyObject* psutil_proc_status(PyObject* self, PyObject* args); -#ifdef __FreeBSD__ -static PyObject* psutil_proc_threads(PyObject* self, PyObject* args); -#endif static PyObject* psutil_proc_tty_nr(PyObject* self, PyObject* args); static PyObject* psutil_proc_uids(PyObject* self, PyObject* args); static PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args); @@ -33,8 +29,16 @@ static PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args); #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 static PyObject* psutil_proc_open_files(PyObject* self, PyObject* args); +#endif +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 static PyObject* psutil_proc_cwd(PyObject* self, PyObject* args); #endif +#ifdef __FreeBSD__ +static PyObject* psutil_proc_threads(PyObject* self, PyObject* args); +#endif +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 +static PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args); +#endif // --- system-related functions diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index ca255eb45..44432dac8 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -958,33 +958,6 @@ psutil_proc_cwd(PyObject *self, PyObject *args) { #endif -/* - * Return files opened by process as a list of (path, fd) tuples - */ -static PyObject * -psutil_proc_num_fds(PyObject *self, PyObject *args) { - long pid; - int cnt; - - struct kinfo_file *freep; - struct kinfo_proc kipp; - - if (! PyArg_ParseTuple(args, "l", &pid)) - return NULL; - if (psutil_kinfo_proc(pid, &kipp) == -1) - return NULL; - - freep = kinfo_getfile(pid, &cnt); - if (freep == NULL) { - psutil_raise_ad_or_nsp(pid); - return NULL; - } - free(freep); - - return Py_BuildValue("i", cnt); -} - - /* * Process current working directory. * Reference: @@ -2066,12 +2039,15 @@ PsutilMethods[] = { "Return process tty (terminal) number"}, {"proc_cwd", psutil_proc_cwd, METH_VARARGS, "Return process current working directory."}, +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS, "Return the number of file descriptors opened by this process"}, +#endif #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ {"proc_open_files", psutil_proc_open_files, METH_VARARGS, "Return files opened by process as a list of (path, fd) tuples"}, #endif + #ifdef __FreeBSD__ {"proc_exe", psutil_proc_exe, METH_VARARGS, "Return process pathname executable"}, diff --git a/psutil/arch/bsd/openbsd.c b/psutil/arch/bsd/openbsd.c index 5030c5d1e..49e9f4062 100644 --- a/psutil/arch/bsd/openbsd.c +++ b/psutil/arch/bsd/openbsd.c @@ -375,3 +375,27 @@ psutil_swap_mem(PyObject *self, PyObject *args) { 0 /* XXX swap in */, 0 /* XXX swap out */); } + + +PyObject * +psutil_proc_num_fds(PyObject *self, PyObject *args) { + long pid; + int cnt; + + struct kinfo_file *freep; + struct kinfo_proc kipp; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_kinfo_proc(pid, &kipp) == -1) + return NULL; + + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_ad_or_nsp(pid); + return NULL; + } + free(freep); + + return Py_BuildValue("i", cnt); +} diff --git a/psutil/arch/bsd/openbsd.h b/psutil/arch/bsd/openbsd.h index b7e33e546..36444ce13 100644 --- a/psutil/arch/bsd/openbsd.h +++ b/psutil/arch/bsd/openbsd.h @@ -21,3 +21,4 @@ int psutil_raise_ad_or_nsp(long pid); PyObject *psutil_proc_threads(PyObject *self, PyObject *args); PyObject *psutil_virtual_mem(PyObject *self, PyObject *args); PyObject *psutil_swap_mem(PyObject *self, PyObject *args); +PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args); From 1fb02fcfec7e7fb306ce05b707c68c6439487d3d Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 03:42:25 +0100 Subject: [PATCH 66/74] move process cwd --- psutil/_psutil_openbsd.c | 26 -------------------------- psutil/arch/bsd/openbsd.c | 23 +++++++++++++++++++++++ psutil/arch/bsd/openbsd.h | 1 + 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 44432dac8..d20195380 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -958,32 +958,6 @@ psutil_proc_cwd(PyObject *self, PyObject *args) { #endif -/* - * Process current working directory. - * Reference: - * http://anoncvs.spacehopper.org/openbsd-src/tree/bin/ps/print.c#n179 - */ -static PyObject * -psutil_proc_cwd(PyObject *self, PyObject *args) { - long pid; - struct kinfo_proc kp; - char path[MAXPATHLEN]; - size_t pathlen = sizeof path; - - if (! PyArg_ParseTuple(args, "l", &pid)) - return NULL; - if (psutil_kinfo_proc(pid, &kp) == -1) - return NULL; - - int name[] = { CTL_KERN, KERN_PROC_CWD, pid }; - if (sysctl(name, 3, path, &pathlen, NULL, 0) != 0) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - return Py_BuildValue("s", path); -} - - // see sys/kern/kern_sysctl.c lines 1100 and // usr.bin/fstat/fstat.c print_inet_details() char * diff --git a/psutil/arch/bsd/openbsd.c b/psutil/arch/bsd/openbsd.c index 49e9f4062..20ff2f7a2 100644 --- a/psutil/arch/bsd/openbsd.c +++ b/psutil/arch/bsd/openbsd.c @@ -399,3 +399,26 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) { return Py_BuildValue("i", cnt); } + + +PyObject * +psutil_proc_cwd(PyObject *self, PyObject *args) { + // Reference: + // http://anoncvs.spacehopper.org/openbsd-src/tree/bin/ps/print.c#n179 + long pid; + struct kinfo_proc kp; + char path[MAXPATHLEN]; + size_t pathlen = sizeof path; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + if (psutil_kinfo_proc(pid, &kp) == -1) + return NULL; + + int name[] = { CTL_KERN, KERN_PROC_CWD, pid }; + if (sysctl(name, 3, path, &pathlen, NULL, 0) != 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + return Py_BuildValue("s", path); +} diff --git a/psutil/arch/bsd/openbsd.h b/psutil/arch/bsd/openbsd.h index 36444ce13..db44caa0b 100644 --- a/psutil/arch/bsd/openbsd.h +++ b/psutil/arch/bsd/openbsd.h @@ -22,3 +22,4 @@ PyObject *psutil_proc_threads(PyObject *self, PyObject *args); PyObject *psutil_virtual_mem(PyObject *self, PyObject *args); PyObject *psutil_swap_mem(PyObject *self, PyObject *args); PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args); +PyObject *psutil_proc_cwd(PyObject *self, PyObject *args); From c29ca33ca2c75ee20c1bcc163153c894d311586b Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 04:01:35 +0100 Subject: [PATCH 67/74] move proc connections --- psutil/_psutil_bsd.h | 4 +- psutil/_psutil_openbsd.c | 325 +++++++++++++++++++++++--------------- psutil/arch/bsd/openbsd.c | 213 ++++++++++++++++++++++++- psutil/arch/bsd/openbsd.h | 1 + 4 files changed, 416 insertions(+), 127 deletions(-) diff --git a/psutil/_psutil_bsd.h b/psutil/_psutil_bsd.h index 3ff077b9f..d6733d78a 100644 --- a/psutil/_psutil_bsd.h +++ b/psutil/_psutil_bsd.h @@ -9,7 +9,6 @@ // --- per-process functions static PyObject* psutil_proc_cmdline(PyObject* self, PyObject* args); -static PyObject* psutil_proc_connections(PyObject* self, PyObject* args); static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args); static PyObject* psutil_proc_create_time(PyObject* self, PyObject* args); static PyObject* psutil_proc_exe(PyObject* self, PyObject* args); @@ -39,6 +38,9 @@ static PyObject* psutil_proc_threads(PyObject* self, PyObject* args); #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 static PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args); #endif +#ifdef __FreeBSD__ +static PyObject* psutil_proc_connections(PyObject* self, PyObject* args); +#endif // --- system-related functions diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index d20195380..d138d0ce8 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -81,7 +81,6 @@ #ifdef __OpenBSD__ #include - #include // for NI_MAXHOST #include // for VREG #define _KERNEL // for DTYPE_VNODE #include @@ -958,39 +957,122 @@ psutil_proc_cwd(PyObject *self, PyObject *args) { #endif -// see sys/kern/kern_sysctl.c lines 1100 and -// usr.bin/fstat/fstat.c print_inet_details() -char * -psutil_convert_ipv4(int family, uint32_t addr[4]) { - struct in_addr a; - memcpy(&a, addr, sizeof(a)); - return inet_ntoa(a); +#ifdef __FreeBSD__ +// The tcplist fetching and walking is borrowed from netstat/inet.c. +static char * +psutil_fetch_tcplist(void) { + char *buf; + size_t len; + + for (;;) { + if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + buf = malloc(len); + if (buf == NULL) { + PyErr_NoMemory(); + return NULL; + } + if (sysctlbyname("net.inet.tcp.pcblist", buf, &len, NULL, 0) < 0) { + free(buf); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + return buf; + } } +static int +psutil_sockaddr_port(int family, struct sockaddr_storage *ss) { + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin; -const char * -psutil_inet6_addrstr(struct in6_addr *p) -{ - struct sockaddr_in6 sin6; - static char hbuf[NI_MAXHOST]; - const int niflags = NI_NUMERICHOST; - - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_addr = *p; - if (IN6_IS_ADDR_LINKLOCAL(p) && - *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) { - sin6.sin6_scope_id = - ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); - sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0; + if (family == AF_INET) { + sin = (struct sockaddr_in *)ss; + return (sin->sin_port); + } + else { + sin6 = (struct sockaddr_in6 *)ss; + return (sin6->sin6_port); + } +} + +static void * +psutil_sockaddr_addr(int family, struct sockaddr_storage *ss) { + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin; + + if (family == AF_INET) { + sin = (struct sockaddr_in *)ss; + return (&sin->sin_addr); + } + else { + sin6 = (struct sockaddr_in6 *)ss; + return (&sin6->sin6_addr); } +} - if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, - hbuf, sizeof(hbuf), NULL, 0, niflags)) - return "invalid"; +static socklen_t +psutil_sockaddr_addrlen(int family) { + if (family == AF_INET) + return (sizeof(struct in_addr)); + else + return (sizeof(struct in6_addr)); +} - return hbuf; +static int +psutil_sockaddr_matches(int family, int port, void *pcb_addr, + struct sockaddr_storage *ss) { + if (psutil_sockaddr_port(family, ss) != port) + return (0); + return (memcmp(psutil_sockaddr_addr(family, ss), pcb_addr, + psutil_sockaddr_addrlen(family)) == 0); +} + +static struct tcpcb * +psutil_search_tcplist(char *buf, struct kinfo_file *kif) { + struct tcpcb *tp; + struct inpcb *inp; + struct xinpgen *xig, *oxig; + struct xsocket *so; + + oxig = xig = (struct xinpgen *)buf; + for (xig = (struct xinpgen *)((char *)xig + xig->xig_len); + xig->xig_len > sizeof(struct xinpgen); + xig = (struct xinpgen *)((char *)xig + xig->xig_len)) { + tp = &((struct xtcpcb *)xig)->xt_tp; + inp = &((struct xtcpcb *)xig)->xt_inp; + so = &((struct xtcpcb *)xig)->xt_socket; + + if (so->so_type != kif->kf_sock_type || + so->xso_family != kif->kf_sock_domain || + so->xso_protocol != kif->kf_sock_protocol) + continue; + + if (kif->kf_sock_domain == AF_INET) { + if (!psutil_sockaddr_matches( + AF_INET, inp->inp_lport, &inp->inp_laddr, + &kif->kf_sa_local)) + continue; + if (!psutil_sockaddr_matches( + AF_INET, inp->inp_fport, &inp->inp_faddr, + &kif->kf_sa_peer)) + continue; + } else { + if (!psutil_sockaddr_matches( + AF_INET6, inp->inp_lport, &inp->in6p_laddr, + &kif->kf_sa_local)) + continue; + if (!psutil_sockaddr_matches( + AF_INET6, inp->inp_fport, &inp->in6p_faddr, + &kif->kf_sa_peer)) + continue; + } + + return (tp); + } + return NULL; } @@ -1017,7 +1099,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) { PyObject *py_af_filter = NULL; PyObject *py_type_filter = NULL; PyObject *py_family = NULL; - PyObject *_type = NULL; + PyObject *py_type = NULL; if (py_retlist == NULL) return NULL; @@ -1034,98 +1116,82 @@ psutil_proc_connections(PyObject *self, PyObject *args) { goto error; } + tcplist = psutil_fetch_tcplist(); + if (tcplist == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + for (i = 0; i < cnt; i++) { - int state; - int lport; - int rport; + int lport, rport, state; + char lip[200], rip[200]; char path[PATH_MAX]; - char addrbuf[NI_MAXHOST + 2]; int inseq; - struct in6_addr laddr6; py_tuple = NULL; py_laddr = NULL; py_raddr = NULL; kif = &freep[i]; - if (kif->f_type == DTYPE_SOCKET) { + if (kif->kf_type == KF_TYPE_SOCKET) { // apply filters - py_family = PyLong_FromLong((long)kif->so_family); + py_family = PyLong_FromLong((long)kif->kf_sock_domain); inseq = PySequence_Contains(py_af_filter, py_family); Py_DECREF(py_family); if (inseq == 0) continue; - _type = PyLong_FromLong((long)kif->so_type); - inseq = PySequence_Contains(py_type_filter, _type); - Py_DECREF(_type); + py_type = PyLong_FromLong((long)kif->kf_sock_type); + inseq = PySequence_Contains(py_type_filter, py_type); + Py_DECREF(py_type); if (inseq == 0) continue; - // IPv4 / IPv6 socket - if ((kif->so_family == AF_INET) || (kif->so_family == AF_INET6)) { + if ((kif->kf_sock_domain == AF_INET) || + (kif->kf_sock_domain == AF_INET6)) { // fill status - if (kif->so_type == SOCK_STREAM) - state = kif->t_state; - else - state = PSUTIL_CONN_NONE; - - // ports - lport = ntohs(kif->inp_lport); - rport = ntohs(kif->inp_fport); - - // local address, IPv4 - if (kif->so_family == AF_INET) { - py_laddr = Py_BuildValue( - "(si)", - psutil_convert_ipv4(kif->so_family, kif->inp_laddru), - lport); - if (!py_laddr) - goto error; - } - else { - // local address, IPv6 - memcpy(&laddr6, kif->inp_laddru, sizeof(laddr6)); - (void *)(uintptr_t)kif->inp_ppcb; - snprintf(addrbuf, sizeof(addrbuf), "%s", - psutil_inet6_addrstr(&laddr6)); - py_laddr = Py_BuildValue("(si)", addrbuf, lport); - if (!py_laddr) - goto error; + state = PSUTIL_CONN_NONE; + if (kif->kf_sock_type == SOCK_STREAM) { + tcp = psutil_search_tcplist(tcplist, kif); + if (tcp != NULL) + state = (int)tcp->t_state; } - if (rport != 0) { - // remote address, IPv4 - if (kif->so_family == AF_INET) { - py_raddr = Py_BuildValue( - "(si)", - psutil_convert_ipv4( - kif->so_family, kif->inp_faddru), - rport); - } - else { - // remote address, IPv6 - memcpy(&laddr6, kif->inp_faddru, sizeof(laddr6)); - (void *)(uintptr_t)kif->inp_ppcb; - snprintf(addrbuf, sizeof(addrbuf), "%s", - psutil_inet6_addrstr(&laddr6)); - py_raddr = Py_BuildValue("(si)", addrbuf, rport); - if (!py_raddr) - goto error; - } - } - else { + // build addr and port + inet_ntop( + kif->kf_sock_domain, + psutil_sockaddr_addr(kif->kf_sock_domain, + &kif->kf_sa_local), + lip, + sizeof(lip)); + inet_ntop( + kif->kf_sock_domain, + psutil_sockaddr_addr(kif->kf_sock_domain, + &kif->kf_sa_peer), + rip, + sizeof(rip)); + lport = htons(psutil_sockaddr_port(kif->kf_sock_domain, + &kif->kf_sa_local)); + rport = htons(psutil_sockaddr_port(kif->kf_sock_domain, + &kif->kf_sa_peer)); + + // construct python tuple/list + py_laddr = Py_BuildValue("(si)", lip, lport); + if (!py_laddr) + goto error; + if (rport != 0) + py_raddr = Py_BuildValue("(si)", rip, rport); + else py_raddr = Py_BuildValue("()"); - } - if (!py_raddr) goto error; py_tuple = Py_BuildValue( "(iiiNNi)", - kif->fd_fd, - kif->so_family, - kif->so_type, + kif->kf_fd, + kif->kf_sock_domain, + kif->kf_sock_type, py_laddr, py_raddr, - state); + state + ); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) @@ -1133,15 +1199,24 @@ psutil_proc_connections(PyObject *self, PyObject *args) { Py_DECREF(py_tuple); } // UNIX socket - else if (kif->so_family == AF_UNIX) { + else if (kif->kf_sock_domain == AF_UNIX) { + struct sockaddr_un *sun; + + sun = (struct sockaddr_un *)&kif->kf_sa_local; + snprintf( + path, sizeof(path), "%.*s", + (int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), + sun->sun_path); + py_tuple = Py_BuildValue( "(iiisOi)", - kif->fd_fd, - kif->so_family, - kif->so_type, - kif->unp_path, + kif->kf_fd, + kif->kf_sock_domain, + kif->kf_sock_type, + path, Py_None, - PSUTIL_CONN_NONE); + PSUTIL_CONN_NONE + ); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) @@ -1166,6 +1241,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) { free(tcplist); return NULL; } +#endif #ifdef __OpenBSD__ @@ -1661,8 +1737,7 @@ static struct xfile *psutil_xfiles; static int psutil_nxfiles; int -psutil_populate_xfiles() -{ +psutil_populate_xfiles() { size_t len; if ((psutil_xfiles = malloc(len = sizeof *psutil_xfiles)) == NULL) { @@ -1689,8 +1764,7 @@ psutil_populate_xfiles() } int -psutil_get_pid_from_sock(int sock_hash) -{ +psutil_get_pid_from_sock(int sock_hash) { struct xfile *xf; int hash, n; for (xf = psutil_xfiles, n = 0; n < psutil_nxfiles; ++n, ++xf) { @@ -1704,8 +1778,7 @@ psutil_get_pid_from_sock(int sock_hash) return -1; } -int psutil_gather_inet(int proto, PyObject *py_retlist) -{ +int psutil_gather_inet(int proto, PyObject *py_retlist) { struct xinpgen *xig, *exig; struct xinpcb *xip; struct xtcpcb *xtp; @@ -1766,22 +1839,22 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) break; switch (proto) { - case IPPROTO_TCP: - xtp = (struct xtcpcb *)xig; - if (xtp->xt_len != sizeof *xtp) { - PyErr_Format(PyExc_RuntimeError, "struct xtcpcb size mismatch"); - goto error; - } - break; - case IPPROTO_UDP: - xip = (struct xinpcb *)xig; - if (xip->xi_len != sizeof *xip) { - PyErr_Format(PyExc_RuntimeError, "struct xinpcb size mismatch"); - goto error; - } - inp = &xip->xi_inp; - so = &xip->xi_socket; - break; + case IPPROTO_TCP: + xtp = (struct xtcpcb *)xig; + if (xtp->xt_len != sizeof *xtp) { + PyErr_Format(PyExc_RuntimeError, "struct xtcpcb size mismatch"); + goto error; + } + break; + case IPPROTO_UDP: + xip = (struct xinpcb *)xig; + if (xip->xi_len != sizeof *xip) { + PyErr_Format(PyExc_RuntimeError, "struct xinpcb size mismatch"); + goto error; + } + inp = &xip->xi_inp; + so = &xip->xi_socket; + break; } inp = &xtp->xt_inp; @@ -1841,8 +1914,10 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) } -int psutil_gather_unix(int proto, PyObject *py_retlist) -{ +// Reference: +// https://gitorious.org/freebsd/freebsd/source/ +// f1d6f4778d2044502209708bc167c05f9aa48615:usr.bin/sockstat/sockstat.c +int psutil_gather_unix(int proto, PyObject *py_retlist) { struct xunpgen *xug, *exug; struct xunpcb *xup; struct sock *sock; diff --git a/psutil/arch/bsd/openbsd.c b/psutil/arch/bsd/openbsd.c index 20ff2f7a2..5bea4f096 100644 --- a/psutil/arch/bsd/openbsd.c +++ b/psutil/arch/bsd/openbsd.c @@ -22,10 +22,17 @@ #include // for swap_mem #include #include +// connection stuff +#include // for NI_MAXHOST +#include +#define _KERNEL // for DTYPE_* +#include +#undef _KERNEL #include "openbsd.h" - +// a signaler for connections without an actual status +int PSUTIL_CONN_NONE = 128; #define KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) @@ -422,3 +429,207 @@ psutil_proc_cwd(PyObject *self, PyObject *args) { } return Py_BuildValue("s", path); } + + +// see sys/kern/kern_sysctl.c lines 1100 and +// usr.bin/fstat/fstat.c print_inet_details() +static char * +psutil_convert_ipv4(int family, uint32_t addr[4]) { + struct in_addr a; + memcpy(&a, addr, sizeof(a)); + return inet_ntoa(a); +} + + +static char * +psutil_inet6_addrstr(struct in6_addr *p) +{ + struct sockaddr_in6 sin6; + static char hbuf[NI_MAXHOST]; + const int niflags = NI_NUMERICHOST; + + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_addr = *p; + if (IN6_IS_ADDR_LINKLOCAL(p) && + *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) { + sin6.sin6_scope_id = + ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); + sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0; + } + + if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, + hbuf, sizeof(hbuf), NULL, 0, niflags)) + return "invalid"; + + return hbuf; +} + + +PyObject * +psutil_proc_connections(PyObject *self, PyObject *args) { + long pid; + int i, cnt; + + struct kinfo_file *freep = NULL; + struct kinfo_file *kif; + char *tcplist = NULL; + struct tcpcb *tcp; + + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_laddr = NULL; + PyObject *py_raddr = NULL; + PyObject *py_af_filter = NULL; + PyObject *py_type_filter = NULL; + PyObject *py_family = NULL; + PyObject *_type = NULL; + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) + goto error; + if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { + PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); + goto error; + } + + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_ad_or_nsp(pid); + goto error; + } + + for (i = 0; i < cnt; i++) { + int state; + int lport; + int rport; + char path[PATH_MAX]; + char addrbuf[NI_MAXHOST + 2]; + int inseq; + struct in6_addr laddr6; + py_tuple = NULL; + py_laddr = NULL; + py_raddr = NULL; + + kif = &freep[i]; + if (kif->f_type == DTYPE_SOCKET) { + // apply filters + py_family = PyLong_FromLong((long)kif->so_family); + inseq = PySequence_Contains(py_af_filter, py_family); + Py_DECREF(py_family); + if (inseq == 0) + continue; + _type = PyLong_FromLong((long)kif->so_type); + inseq = PySequence_Contains(py_type_filter, _type); + Py_DECREF(_type); + if (inseq == 0) + continue; + + // IPv4 / IPv6 socket + if ((kif->so_family == AF_INET) || (kif->so_family == AF_INET6)) { + // fill status + if (kif->so_type == SOCK_STREAM) + state = kif->t_state; + else + state = PSUTIL_CONN_NONE; + + // ports + lport = ntohs(kif->inp_lport); + rport = ntohs(kif->inp_fport); + + // local address, IPv4 + if (kif->so_family == AF_INET) { + py_laddr = Py_BuildValue( + "(si)", + psutil_convert_ipv4(kif->so_family, kif->inp_laddru), + lport); + if (!py_laddr) + goto error; + } + else { + // local address, IPv6 + memcpy(&laddr6, kif->inp_laddru, sizeof(laddr6)); + (void *)(uintptr_t)kif->inp_ppcb; + snprintf(addrbuf, sizeof(addrbuf), "%s", + psutil_inet6_addrstr(&laddr6)); + py_laddr = Py_BuildValue("(si)", addrbuf, lport); + if (!py_laddr) + goto error; + } + + if (rport != 0) { + // remote address, IPv4 + if (kif->so_family == AF_INET) { + py_raddr = Py_BuildValue( + "(si)", + psutil_convert_ipv4( + kif->so_family, kif->inp_faddru), + rport); + } + else { + // remote address, IPv6 + memcpy(&laddr6, kif->inp_faddru, sizeof(laddr6)); + (void *)(uintptr_t)kif->inp_ppcb; + snprintf(addrbuf, sizeof(addrbuf), "%s", + psutil_inet6_addrstr(&laddr6)); + py_raddr = Py_BuildValue("(si)", addrbuf, rport); + if (!py_raddr) + goto error; + } + } + else { + py_raddr = Py_BuildValue("()"); + } + + if (!py_raddr) + goto error; + py_tuple = Py_BuildValue( + "(iiiNNi)", + kif->fd_fd, + kif->so_family, + kif->so_type, + py_laddr, + py_raddr, + state); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + // UNIX socket + else if (kif->so_family == AF_UNIX) { + py_tuple = Py_BuildValue( + "(iiisOi)", + kif->fd_fd, + kif->so_family, + kif->so_type, + kif->unp_path, + Py_None, + PSUTIL_CONN_NONE); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + Py_INCREF(Py_None); + } + } + } + free(freep); + free(tcplist); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_XDECREF(py_laddr); + Py_XDECREF(py_raddr); + Py_DECREF(py_retlist); + if (freep != NULL) + free(freep); + if (tcplist != NULL) + free(tcplist); + return NULL; +} diff --git a/psutil/arch/bsd/openbsd.h b/psutil/arch/bsd/openbsd.h index db44caa0b..dbe8b0b23 100644 --- a/psutil/arch/bsd/openbsd.h +++ b/psutil/arch/bsd/openbsd.h @@ -23,3 +23,4 @@ PyObject *psutil_virtual_mem(PyObject *self, PyObject *args); PyObject *psutil_swap_mem(PyObject *self, PyObject *args); PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args); PyObject *psutil_proc_cwd(PyObject *self, PyObject *args); +PyObject *psutil_proc_connections(PyObject *self, PyObject *args); From abf77b0a225915e6f04d7f660d66f5fe47ee57b0 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 04:06:27 +0100 Subject: [PATCH 68/74] make the code more similar to mastger --- psutil/_psutil_openbsd.c | 62 ++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index d138d0ce8..98e19555e 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -1309,7 +1309,7 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) { #endif -#if 0 +#ifdef __FreeBSD__ // remove spaces from string void remove_spaces(char *str) { char *p1 = str; @@ -1370,36 +1370,36 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) { if (strlen(kve->kve_path) == 0) { switch (kve->kve_type) { - case KVME_TYPE_NONE: - path = "[none]"; - break; - case KVME_TYPE_DEFAULT: - path = "[default]"; - break; - case KVME_TYPE_VNODE: - path = "[vnode]"; - break; - case KVME_TYPE_SWAP: - path = "[swap]"; - break; - case KVME_TYPE_DEVICE: - path = "[device]"; - break; - case KVME_TYPE_PHYS: - path = "[phys]"; - break; - case KVME_TYPE_DEAD: - path = "[dead]"; - break; - case KVME_TYPE_SG: - path = "[sg]"; - break; - case KVME_TYPE_UNKNOWN: - path = "[unknown]"; - break; - default: - path = "[?]"; - break; + case KVME_TYPE_NONE: + path = "[none]"; + break; + case KVME_TYPE_DEFAULT: + path = "[default]"; + break; + case KVME_TYPE_VNODE: + path = "[vnode]"; + break; + case KVME_TYPE_SWAP: + path = "[swap]"; + break; + case KVME_TYPE_DEVICE: + path = "[device]"; + break; + case KVME_TYPE_PHYS: + path = "[phys]"; + break; + case KVME_TYPE_DEAD: + path = "[dead]"; + break; + case KVME_TYPE_SG: + path = "[sg]"; + break; + case KVME_TYPE_UNKNOWN: + path = "[unknown]"; + break; + default: + path = "[?]"; + break; } } else { From f02845d75b29ca4988038dfd93af40329e10ce61 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 04:11:17 +0100 Subject: [PATCH 69/74] move per cpu times --- psutil/_psutil_openbsd.c | 44 ++++++++++++++-------------- psutil/arch/bsd/openbsd.c | 61 +++++++++++++++++++++++++++++++++++++++ psutil/arch/bsd/openbsd.h | 1 + 3 files changed, 84 insertions(+), 22 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 98e19555e..50c0b823a 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -1244,14 +1244,11 @@ psutil_proc_connections(PyObject *self, PyObject *args) { #endif -#ifdef __OpenBSD__ -/* - * Return a Python list of tuple representing per-cpu times - */ +#ifdef __FreeBSD__ static PyObject * psutil_per_cpu_times(PyObject *self, PyObject *args) { static int maxcpus; - int mib[3]; + int mib[2]; int ncpu; size_t len; size_t size; @@ -1262,6 +1259,14 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) { if (py_retlist == NULL) return NULL; + // retrieve maxcpus value + size = sizeof(maxcpus); + if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) { + Py_DECREF(py_retlist); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + long cpu_time[maxcpus][CPUSTATES]; // retrieve the number of cpus mib[0] = CTL_HW; @@ -1271,27 +1276,22 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) { PyErr_SetFromErrno(PyExc_OSError); goto error; } - uint64_t cpu_time[CPUSTATES]; - for (i = 0; i < ncpu; i++) { - // per-cpu info - mib[0] = CTL_KERN; - mib[1] = KERN_CPTIME2; - mib[2] = i; - size = sizeof(cpu_time); - if (sysctl(mib, 3, &cpu_time, &size, NULL, 0) == -1) { - warn("failed to get kern.cptime2"); - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } + // per-cpu info + size = sizeof(cpu_time); + if (sysctlbyname("kern.cp_times", &cpu_time, &size, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + for (i = 0; i < ncpu; i++) { py_cputime = Py_BuildValue( "(ddddd)", - (double)cpu_time[CP_USER] / CLOCKS_PER_SEC, - (double)cpu_time[CP_NICE] / CLOCKS_PER_SEC, - (double)cpu_time[CP_SYS] / CLOCKS_PER_SEC, - (double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC, - (double)cpu_time[CP_INTR] / CLOCKS_PER_SEC); + (double)cpu_time[i][CP_USER] / CLOCKS_PER_SEC, + (double)cpu_time[i][CP_NICE] / CLOCKS_PER_SEC, + (double)cpu_time[i][CP_SYS] / CLOCKS_PER_SEC, + (double)cpu_time[i][CP_IDLE] / CLOCKS_PER_SEC, + (double)cpu_time[i][CP_INTR] / CLOCKS_PER_SEC); if (!py_cputime) goto error; if (PyList_Append(py_retlist, py_cputime)) diff --git a/psutil/arch/bsd/openbsd.c b/psutil/arch/bsd/openbsd.c index 5bea4f096..d90796d79 100644 --- a/psutil/arch/bsd/openbsd.c +++ b/psutil/arch/bsd/openbsd.c @@ -25,6 +25,7 @@ // connection stuff #include // for NI_MAXHOST #include +#include // for CPUSTATES & CP_* #define _KERNEL // for DTYPE_* #include #undef _KERNEL @@ -633,3 +634,63 @@ psutil_proc_connections(PyObject *self, PyObject *args) { free(tcplist); return NULL; } + + +PyObject * +psutil_per_cpu_times(PyObject *self, PyObject *args) { + static int maxcpus; + int mib[3]; + int ncpu; + size_t len; + size_t size; + int i; + PyObject *py_retlist = PyList_New(0); + PyObject *py_cputime = NULL; + + if (py_retlist == NULL) + return NULL; + + + // retrieve the number of cpus + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + len = sizeof(ncpu); + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + uint64_t cpu_time[CPUSTATES]; + + for (i = 0; i < ncpu; i++) { + // per-cpu info + mib[0] = CTL_KERN; + mib[1] = KERN_CPTIME2; + mib[2] = i; + size = sizeof(cpu_time); + if (sysctl(mib, 3, &cpu_time, &size, NULL, 0) == -1) { + warn("failed to get kern.cptime2"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + py_cputime = Py_BuildValue( + "(ddddd)", + (double)cpu_time[CP_USER] / CLOCKS_PER_SEC, + (double)cpu_time[CP_NICE] / CLOCKS_PER_SEC, + (double)cpu_time[CP_SYS] / CLOCKS_PER_SEC, + (double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC, + (double)cpu_time[CP_INTR] / CLOCKS_PER_SEC); + if (!py_cputime) + goto error; + if (PyList_Append(py_retlist, py_cputime)) + goto error; + Py_DECREF(py_cputime); + } + + return py_retlist; + +error: + Py_XDECREF(py_cputime); + Py_DECREF(py_retlist); + return NULL; +} diff --git a/psutil/arch/bsd/openbsd.h b/psutil/arch/bsd/openbsd.h index dbe8b0b23..31cd83123 100644 --- a/psutil/arch/bsd/openbsd.h +++ b/psutil/arch/bsd/openbsd.h @@ -24,3 +24,4 @@ PyObject *psutil_swap_mem(PyObject *self, PyObject *args); PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args); PyObject *psutil_proc_cwd(PyObject *self, PyObject *args); PyObject *psutil_proc_connections(PyObject *self, PyObject *args); +PyObject *psutil_per_cpu_times(PyObject *self, PyObject *args); From bf582006dd543e68ca7d89641a1aaffd3576d722 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 04:19:37 +0100 Subject: [PATCH 70/74] make code more similar to original bsd --- psutil/_psutil_openbsd.c | 85 ++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 50c0b823a..6a31e447b 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -516,41 +516,6 @@ psutil_proc_threads(PyObject *self, PyObject *args) { #endif -#ifdef __FreeBSD__ -/* - * Return an XML string from which we'll determine the number of - * physical CPU cores in the system. - */ -static PyObject * -psutil_cpu_count_phys(PyObject *self, PyObject *args) { - void *topology = NULL; - size_t size = 0; - PyObject *py_str; - - if (sysctlbyname("kern.sched.topology_spec", NULL, &size, NULL, 0)) - goto error; - - topology = malloc(size); - if (!topology) { - PyErr_NoMemory(); - return NULL; - } - - if (sysctlbyname("kern.sched.topology_spec", topology, &size, NULL, 0)) - goto error; - - py_str = Py_BuildValue("s", topology); - free(topology); - return py_str; - -error: - if (topology != NULL) - free(topology); - Py_RETURN_NONE; -} -#endif - - /* * Return a Python tuple (user_time, kernel_time) */ @@ -596,6 +561,41 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args) { } +#ifdef __FreeBSD__ +/* + * Return an XML string from which we'll determine the number of + * physical CPU cores in the system. + */ +static PyObject * +psutil_cpu_count_phys(PyObject *self, PyObject *args) { + void *topology = NULL; + size_t size = 0; + PyObject *py_str; + + if (sysctlbyname("kern.sched.topology_spec", NULL, &size, NULL, 0)) + goto error; + + topology = malloc(size); + if (!topology) { + PyErr_NoMemory(); + return NULL; + } + + if (sysctlbyname("kern.sched.topology_spec", topology, &size, NULL, 0)) + goto error; + + py_str = Py_BuildValue("s", topology); + free(topology); + return py_str; + +error: + if (topology != NULL) + free(topology); + Py_RETURN_NONE; +} +#endif + + /* * Return a Python float indicating the process create time expressed in * seconds since the epoch. @@ -1330,7 +1330,7 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) { long pid; int ptrwidth; int i, cnt; - char addr[30]; + char [1000]; char perms[4]; const char *path; struct kinfo_proc kp; @@ -1338,9 +1338,9 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) { struct kinfo_vmentry *kve; ptrwidth = 2 * sizeof(void *); PyObject *py_tuple = NULL; - PyObject *retlist = PyList_New(0); + PyObject *py_retlist = PyList_New(0); - if (retlist == NULL) { + if (py_retlist == NULL) { return NULL; } if (! PyArg_ParseTuple(args, "l", &pid)) @@ -1416,16 +1416,16 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) { kve->kve_shadow_count); // shadow count if (!py_tuple) goto error; - if (PyList_Append(retlist, py_tuple)) + if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } free(freep); - return retlist; + return py_retlist; error: Py_XDECREF(py_tuple); - Py_DECREF(retlist); + Py_DECREF(py_retlist); if (freep != NULL) free(freep); return NULL; @@ -2229,7 +2229,8 @@ void init_psutil_bsd(void) PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2); PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK); PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT); - PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", 128); /*PSUTIL_CONN_NONE */ + // PSUTIL_CONN_NONE + PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", 128); if (module == NULL) INITERROR; From a224ee922441271fc221de136fdb7f542223b4a4 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 04:29:24 +0100 Subject: [PATCH 71/74] merge disk_partitions stuff --- psutil/_psutil_openbsd.c | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 6a31e447b..d453d24fe 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -1330,7 +1330,7 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) { long pid; int ptrwidth; int i, cnt; - char [1000]; + char addr[1000]; char perms[4]; const char *path; struct kinfo_proc kp; @@ -1340,9 +1340,8 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) { PyObject *py_tuple = NULL; PyObject *py_retlist = PyList_New(0); - if (py_retlist == NULL) { + if (py_retlist == NULL) return NULL; - } if (! PyArg_ParseTuple(args, "l", &pid)) goto error; if (psutil_kinfo_proc(pid, &kp) == -1) @@ -1485,19 +1484,51 @@ psutil_disk_partitions(PyObject *self, PyObject *args) { strlcat(opts, "ro", sizeof(opts)); else strlcat(opts, "rw", sizeof(opts)); +#ifdef __FreeBSD__ if (flags & MNT_SYNCHRONOUS) strlcat(opts, ",sync", sizeof(opts)); if (flags & MNT_NOEXEC) strlcat(opts, ",noexec", sizeof(opts)); if (flags & MNT_NOSUID) strlcat(opts, ",nosuid", sizeof(opts)); + if (flags & MNT_UNION) + strlcat(opts, ",union", sizeof(opts)); if (flags & MNT_ASYNC) strlcat(opts, ",async", sizeof(opts)); + if (flags & MNT_SUIDDIR) + strlcat(opts, ",suiddir", sizeof(opts)); if (flags & MNT_SOFTDEP) strlcat(opts, ",softdep", sizeof(opts)); + if (flags & MNT_NOSYMFOLLOW) + strlcat(opts, ",nosymfollow", sizeof(opts)); + if (flags & MNT_GJOURNAL) + strlcat(opts, ",gjournal", sizeof(opts)); + if (flags & MNT_MULTILABEL) + strlcat(opts, ",multilabel", sizeof(opts)); + if (flags & MNT_ACLS) + strlcat(opts, ",acls", sizeof(opts)); if (flags & MNT_NOATIME) strlcat(opts, ",noatime", sizeof(opts)); - + if (flags & MNT_NOCLUSTERR) + strlcat(opts, ",noclusterr", sizeof(opts)); + if (flags & MNT_NOCLUSTERW) + strlcat(opts, ",noclusterw", sizeof(opts)); + if (flags & MNT_NFS4ACLS) + strlcat(opts, ",nfs4acls", sizeof(opts)); +#elif __OpenBSD__ + if (flags & MNT_SYNCHRONOUS) + strlcat(opts, ",sync", sizeof(opts)); + if (flags & MNT_NOEXEC) + strlcat(opts, ",noexec", sizeof(opts)); + if (flags & MNT_NOSUID) + strlcat(opts, ",nosuid", sizeof(opts)); + if (flags & MNT_ASYNC) + strlcat(opts, ",async", sizeof(opts)); + if (flags & MNT_SOFTDEP) + strlcat(opts, ",softdep", sizeof(opts)); + if (flags & MNT_NOATIME) + strlcat(opts, ",noatime", sizeof(opts)); +#endif py_tuple = Py_BuildValue("(ssss)", fs[i].f_mntfromname, // device fs[i].f_mntonname, // mount point From 70bf8af0f17125408987a25ff1f4118e5e5b5832 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 04:35:02 +0100 Subject: [PATCH 72/74] move disk io stuff --- psutil/_psutil_bsd.h | 2 +- psutil/_psutil_openbsd.c | 65 ++++++++++++++++++++++----------------- psutil/arch/bsd/openbsd.c | 65 +++++++++++++++++++++++++++++++++++++++ psutil/arch/bsd/openbsd.h | 1 + 4 files changed, 103 insertions(+), 30 deletions(-) diff --git a/psutil/_psutil_bsd.h b/psutil/_psutil_bsd.h index d6733d78a..41d548be4 100644 --- a/psutil/_psutil_bsd.h +++ b/psutil/_psutil_bsd.h @@ -48,7 +48,6 @@ static PyObject* psutil_boot_time(PyObject* self, PyObject* args); static PyObject* psutil_cpu_count_logical(PyObject* self, PyObject* args); static PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args); static PyObject* psutil_cpu_times(PyObject* self, PyObject* args); -static PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args); static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args); static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args); static PyObject* psutil_pids(PyObject* self, PyObject* args); @@ -56,6 +55,7 @@ static PyObject* psutil_users(PyObject* self, PyObject* args); #ifdef __FreeBSD__ static PyObject* psutil_virtual_mem(PyObject* self, PyObject* args); static PyObject* psutil_swap_mem(PyObject* self, PyObject* args); +static PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args); #endif #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index d453d24fe..b76cb9956 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -85,7 +85,6 @@ #define _KERNEL // for DTYPE_VNODE #include #undef _KERNEL - #include // struct diskstats #include // for CPUSTATES & CP_* #include #include @@ -1644,68 +1643,76 @@ psutil_net_io_counters(PyObject *self, PyObject *args) { } +#ifdef __FreeBSD__ /* * Return a Python dict of tuples for disk I/O information */ static PyObject * psutil_disk_io_counters(PyObject *self, PyObject *args) { - int i, dk_ndrive, mib[3]; - size_t len; - struct diskstats *stats; + int i; + struct statinfo stats; PyObject *py_retdict = PyDict_New(); PyObject *py_disk_info = NULL; + if (py_retdict == NULL) return NULL; - - mib[0] = CTL_HW; - mib[1] = HW_DISKSTATS; - len = 0; - if (sysctl(mib, 2, NULL, &len, NULL, 0) < 0) { - warn("can't get hw.diskstats size"); - PyErr_SetFromErrno(PyExc_OSError); + if (devstat_checkversion(NULL) < 0) { + PyErr_Format(PyExc_RuntimeError, "devstat_checkversion() failed"); goto error; } - dk_ndrive = (int)(len / sizeof(struct diskstats)); - stats = malloc(len); - if (stats == NULL) { - warn("can't malloc"); + stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); + if (stats.dinfo == NULL) { PyErr_NoMemory(); goto error; } - if (sysctl(mib, 2, stats, &len, NULL, 0) < 0 ) { - warn("could not read hw.diskstats"); - PyErr_SetFromErrno(PyExc_OSError); + bzero(stats.dinfo, sizeof(struct devinfo)); + + if (devstat_getdevs(NULL, &stats) == -1) { + PyErr_Format(PyExc_RuntimeError, "devstat_getdevs() failed"); goto error; } - for (i = 0; i < dk_ndrive; i++) { + for (i = 0; i < stats.dinfo->numdevs; i++) { + py_disk_info = NULL; + struct devstat current; + char disk_name[128]; + current = stats.dinfo->devices[i]; + snprintf(disk_name, sizeof(disk_name), "%s%d", + current.device_name, + current.unit_number); + py_disk_info = Py_BuildValue( "(KKKKLL)", - stats[i].ds_rxfer, - stats[i].ds_wxfer, - stats[i].ds_rbytes, - stats[i].ds_wbytes, - (long long) TV2DOUBLE(stats[i].ds_time) / 2, /* assume half read - half writes.. */ - (long long) TV2DOUBLE(stats[i].ds_time) / 2); + current.operations[DEVSTAT_READ], // no reads + current.operations[DEVSTAT_WRITE], // no writes + current.bytes[DEVSTAT_READ], // bytes read + current.bytes[DEVSTAT_WRITE], // bytes written + (long long) BT2MSEC(current.duration[DEVSTAT_READ]), // r time + (long long) BT2MSEC(current.duration[DEVSTAT_WRITE]) // w time + ); // finished transactions if (!py_disk_info) goto error; - if (PyDict_SetItemString(py_retdict, stats[i].ds_name, py_disk_info)) + if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info)) goto error; Py_DECREF(py_disk_info); } - free(stats); + if (stats.dinfo->mem_ptr) + free(stats.dinfo->mem_ptr); + free(stats.dinfo); return py_retdict; error: Py_XDECREF(py_disk_info); Py_DECREF(py_retdict); - if (stats != NULL) - free(stats); + if (stats.dinfo != NULL) + free(stats.dinfo); return NULL; } +#endif + /* * Return currently connected users as a list of tuples. diff --git a/psutil/arch/bsd/openbsd.c b/psutil/arch/bsd/openbsd.c index d90796d79..5e949241a 100644 --- a/psutil/arch/bsd/openbsd.c +++ b/psutil/arch/bsd/openbsd.c @@ -29,12 +29,16 @@ #define _KERNEL // for DTYPE_* #include #undef _KERNEL +#include // struct diskstats + #include "openbsd.h" // a signaler for connections without an actual status int PSUTIL_CONN_NONE = 128; + #define KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) +#define TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) // ============================================================================ @@ -694,3 +698,64 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) { Py_DECREF(py_retlist); return NULL; } + + +PyObject * +psutil_disk_io_counters(PyObject *self, PyObject *args) { + int i, dk_ndrive, mib[3]; + size_t len; + struct diskstats *stats; + + PyObject *py_retdict = PyDict_New(); + PyObject *py_disk_info = NULL; + if (py_retdict == NULL) + return NULL; + + mib[0] = CTL_HW; + mib[1] = HW_DISKSTATS; + len = 0; + if (sysctl(mib, 2, NULL, &len, NULL, 0) < 0) { + warn("can't get hw.diskstats size"); + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + dk_ndrive = (int)(len / sizeof(struct diskstats)); + + stats = malloc(len); + if (stats == NULL) { + warn("can't malloc"); + PyErr_NoMemory(); + goto error; + } + if (sysctl(mib, 2, stats, &len, NULL, 0) < 0 ) { + warn("could not read hw.diskstats"); + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (i = 0; i < dk_ndrive; i++) { + py_disk_info = Py_BuildValue( + "(KKKKLL)", + stats[i].ds_rxfer, + stats[i].ds_wxfer, + stats[i].ds_rbytes, + stats[i].ds_wbytes, + (long long) TV2DOUBLE(stats[i].ds_time) / 2, /* assume half read - half writes.. */ + (long long) TV2DOUBLE(stats[i].ds_time) / 2); + if (!py_disk_info) + goto error; + if (PyDict_SetItemString(py_retdict, stats[i].ds_name, py_disk_info)) + goto error; + Py_DECREF(py_disk_info); + } + + free(stats); + return py_retdict; + +error: + Py_XDECREF(py_disk_info); + Py_DECREF(py_retdict); + if (stats != NULL) + free(stats); + return NULL; +} diff --git a/psutil/arch/bsd/openbsd.h b/psutil/arch/bsd/openbsd.h index 31cd83123..e859278e7 100644 --- a/psutil/arch/bsd/openbsd.h +++ b/psutil/arch/bsd/openbsd.h @@ -25,3 +25,4 @@ PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args); PyObject *psutil_proc_cwd(PyObject *self, PyObject *args); PyObject *psutil_proc_connections(PyObject *self, PyObject *args); PyObject *psutil_per_cpu_times(PyObject *self, PyObject *args); +PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args); From 995d5ca8ccfa5983749afe4e232414c66afe0141 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 05:26:02 +0100 Subject: [PATCH 73/74] more freebsd stuff back --- psutil/_psutil_openbsd.c | 200 +++++++++++++++++++++++++++++---------- 1 file changed, 148 insertions(+), 52 deletions(-) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index b76cb9956..8406d0830 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -1607,9 +1607,8 @@ psutil_net_io_counters(PyObject *self, PyObject *args) { // http://lists.freebsd.org/pipermail/freebsd-current/ // 2011-October/028752.html // 'ifconfig -a' doesn't show them, nor do we. - if (strncmp(ifc_name, "usbus", 5) == 0) { + if (strncmp(ifc_name, "usbus", 5) == 0) continue; - } py_ifc_info = Py_BuildValue("(kkkkkkki)", if2m->ifm_data.ifi_obytes, @@ -1765,11 +1764,10 @@ psutil_users(PyObject *self, PyObject *args) { } - +#ifdef __FreeBSD__ /* * System-wide open connections. */ -#if 0 #define HASHSIZE 1009 static struct xfile *psutil_xfiles; static int psutil_nxfiles; @@ -1809,24 +1807,28 @@ psutil_get_pid_from_sock(int sock_hash) { if (xf->xf_data == NULL) continue; hash = (int)((uintptr_t)xf->xf_data % HASHSIZE); - if (sock_hash == hash) { + if (sock_hash == hash) return xf->xf_pid; - } } return -1; } + +// Reference: +// https://gitorious.org/freebsd/freebsd/source/ +// f1d6f4778d2044502209708bc167c05f9aa48615:usr.bin/sockstat/sockstat.c int psutil_gather_inet(int proto, PyObject *py_retlist) { struct xinpgen *xig, *exig; struct xinpcb *xip; struct xtcpcb *xtp; struct inpcb *inp; struct xsocket *so; - struct sock *sock; - const char *varname; + const char *varname = NULL; size_t len, bufsize; void *buf; - int hash, retry, vflag, type; + int hash; + int retry; + int type; PyObject *py_tuple = NULL; PyObject *py_laddr = NULL; @@ -1849,10 +1851,8 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) { do { for (;;) { buf = realloc(buf, bufsize); - if (buf == NULL) { - // XXX - continue; - } + if (buf == NULL) + continue; // XXX len = bufsize; if (sysctlbyname(varname, buf, &len, NULL, 0) == 0) break; @@ -1872,6 +1872,8 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) { for (;;) { + int lport, rport, pid, status, family; + xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); if (xig >= exig) break; @@ -1880,25 +1882,31 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) { case IPPROTO_TCP: xtp = (struct xtcpcb *)xig; if (xtp->xt_len != sizeof *xtp) { - PyErr_Format(PyExc_RuntimeError, "struct xtcpcb size mismatch"); + PyErr_Format(PyExc_RuntimeError, + "struct xtcpcb size mismatch"); goto error; } + inp = &xtp->xt_inp; + so = &xtp->xt_socket; + status = xtp->xt_tp.t_state; break; case IPPROTO_UDP: xip = (struct xinpcb *)xig; if (xip->xi_len != sizeof *xip) { - PyErr_Format(PyExc_RuntimeError, "struct xinpcb size mismatch"); + PyErr_Format(PyExc_RuntimeError, + "struct xinpcb size mismatch"); goto error; } inp = &xip->xi_inp; so = &xip->xi_socket; + status = PSUTIL_CONN_NONE; break; + default: + PyErr_Format(PyExc_RuntimeError, "invalid proto"); + goto error; } - inp = &xtp->xt_inp; - so = &xtp->xt_socket; char lip[200], rip[200]; - int family, lport, rport, pid, status; hash = (int)((uintptr_t)so->xso_so % HASHSIZE); pid = psutil_get_pid_from_sock(hash); @@ -1906,7 +1914,6 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) { continue; lport = ntohs(inp->inp_lport); rport = ntohs(inp->inp_fport); - status = xtp->xt_tp.t_state; if (inp->inp_vflag & INP_IPV4) { family = AF_INET; @@ -1923,22 +1930,20 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) { py_laddr = Py_BuildValue("(si)", lip, lport); if (!py_laddr) goto error; - if (rport != 0) { + if (rport != 0) py_raddr = Py_BuildValue("(si)", rip, rport); - } - else { + else py_raddr = Py_BuildValue("()"); - } if (!py_raddr) goto error; - tuple = Py_BuildValue("(iiiNNii)", -1, family, type, py_laddr, - py_raddr, status, pid); - if (!tuple) + py_tuple = Py_BuildValue("(iiiNNii)", -1, family, type, py_laddr, + py_raddr, status, pid); + if (!py_tuple) goto error; - if (PyList_Append(py_retlist, tuple)) + if (PyList_Append(py_retlist, py_tuple)) goto error; - Py_DECREF(tuple); - } + Py_DECREF(py_tuple); + } free(buf); return 1; @@ -1952,18 +1957,17 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) { } -// Reference: -// https://gitorious.org/freebsd/freebsd/source/ -// f1d6f4778d2044502209708bc167c05f9aa48615:usr.bin/sockstat/sockstat.c int psutil_gather_unix(int proto, PyObject *py_retlist) { struct xunpgen *xug, *exug; struct xunpcb *xup; - struct sock *sock; - const char *varname, *protoname; - size_t len, bufsize; + const char *varname = NULL; + const char *protoname = NULL; + size_t len; + size_t bufsize; void *buf; - int hash, retry; - int family, lport, rport, pid; + int hash; + int retry; + int pid; struct sockaddr_un *sun; char path[PATH_MAX]; @@ -2016,10 +2020,8 @@ int psutil_gather_unix(int proto, PyObject *py_retlist) { if (xug >= exug) break; xup = (struct xunpcb *)xug; - if (xup->xu_len != sizeof *xup) { - warnx("struct xunpgen size mismatch"); + if (xup->xu_len != sizeof *xup) goto error; - } hash = (int)((uintptr_t) xup->xu_socket.xso_so % HASHSIZE); pid = psutil_get_pid_from_sock(hash); @@ -2028,17 +2030,16 @@ int psutil_gather_unix(int proto, PyObject *py_retlist) { sun = (struct sockaddr_un *)&xup->xu_addr; snprintf(path, sizeof(path), "%.*s", - (sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), + (int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), sun->sun_path); - py_tuple = Py_BuildValue( - "(iiisOii)", -1, AF_UNIX, proto, path, Py_None, - PSUTIL_CONN_NONE, pid); + py_tuple = Py_BuildValue("(iiisOii)", -1, AF_UNIX, proto, path, + Py_None, PSUTIL_CONN_NONE, pid); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; - Py_DECREF(tuple); + Py_DECREF(py_tuple); Py_INCREF(Py_None); } @@ -2058,10 +2059,7 @@ int psutil_gather_unix(int proto, PyObject *py_retlist) { * Return system-wide open connections. */ static PyObject* -psutil_net_connections(PyObject* self, PyObject* args) -{ - PyObject *py_af_filter = NULL; - PyObject *py_type_filter = NULL; +psutil_net_connections(PyObject* self, PyObject* args) { PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) @@ -2077,15 +2075,113 @@ psutil_net_connections(PyObject* self, PyObject* args) if (psutil_gather_unix(SOCK_DGRAM, py_retlist) == 0) goto error; -// free(psutil_xfiles); + free(psutil_xfiles); + return py_retlist; + +error: + Py_DECREF(py_retlist); + free(psutil_xfiles); + return NULL; +} + + +/* + * Get process CPU affinity. + * Reference: http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c + */ +static PyObject* +psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args) { + long pid; + int ret; + int i; + cpuset_t mask; + PyObject* py_retlist; + PyObject* py_cpu_num; + + if (!PyArg_ParseTuple(args, "i", &pid)) + return NULL; + ret = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, pid, + sizeof(mask), &mask); + if (ret != 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + py_retlist = PyList_New(0); + if (py_retlist == NULL) + return NULL; + + for (i = 0; i < CPU_SETSIZE; i++) { + if (CPU_ISSET(i, &mask)) { + py_cpu_num = Py_BuildValue("i", i); + if (py_cpu_num == NULL) + goto error; + if (PyList_Append(py_retlist, py_cpu_num)) + goto error; + } + } + return py_retlist; error: + Py_XDECREF(py_cpu_num); Py_DECREF(py_retlist); -// free(psutil_xfiles); return NULL; } + +/* + * Set process CPU affinity. + * Reference: http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c + */ +static PyObject * +psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) { + long pid; + int i; + int seq_len; + int ret; + cpuset_t cpu_set; + PyObject *py_cpu_set; + PyObject *py_cpu_seq = NULL; + + if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set)) + return NULL; + + py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer"); + if (!py_cpu_seq) + return NULL; + seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq); + + // calculate the mask + CPU_ZERO(&cpu_set); + for (i = 0; i < seq_len; i++) { + PyObject *item = PySequence_Fast_GET_ITEM(py_cpu_seq, i); +#if PY_MAJOR_VERSION >= 3 + long value = PyLong_AsLong(item); +#else + long value = PyInt_AsLong(item); +#endif + if (value == -1 && PyErr_Occurred()) + goto error; + CPU_SET(value, &cpu_set); + } + + // set affinity + ret = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, pid, + sizeof(cpu_set), &cpu_set); + if (ret != 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + Py_DECREF(py_cpu_seq); + Py_RETURN_NONE; + +error: + if (py_cpu_seq != NULL) + Py_DECREF(py_cpu_seq); + return NULL; +} #endif /* @@ -2175,7 +2271,7 @@ PsutilMethods[] = { "Return a Python dict of tuples for disk I/O information"}, {"users", psutil_users, METH_VARARGS, "Return currently connected users as a list of tuples"}, -#if 0 +#ifdef __FreeBSD__ {"net_connections", psutil_net_connections, METH_VARARGS, "Return system-wide open connections."}, #endif From d4becc3f156bdc7565a64061f1c5711eb9f6791a Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 12 Nov 2015 06:09:28 +0100 Subject: [PATCH 74/74] last fixes --- psutil/_psbsd.py | 5 ++-- psutil/_psutil_openbsd.c | 53 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index 8b980b2d8..57d847b94 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -111,7 +111,7 @@ def virtual_memory(): def swap_memory(): """System swap memory as (total, used, free, sin, sout) namedtuple.""" - if sys.platform.startswith("openbsd"): + if OPENBSD: PAGESIZE = 1 total, used, free, sin, sout = [x * PAGESIZE for x in cext.swap_mem()] percent = usage_percent(used, total, _round=1) @@ -305,8 +305,7 @@ def wrapper(self, *args, **kwargs): ZombieProcess is None): raise if err.errno == errno.ESRCH: - # if not pid_exists(self.pid): - if self.pid not in pids(): + if not pid_exists(self.pid): raise NoSuchProcess(self.pid, self._name) else: raise ZombieProcess(self.pid, self._name, self._ppid) diff --git a/psutil/_psutil_openbsd.c b/psutil/_psutil_openbsd.c index 8406d0830..9c979306a 100644 --- a/psutil/_psutil_openbsd.c +++ b/psutil/_psutil_openbsd.c @@ -32,7 +32,6 @@ #include #include #include - #include // for struct xsocket #include #include @@ -86,8 +85,6 @@ #include #undef _KERNEL #include // for CPUSTATES & CP_* - #include - #include #endif @@ -134,6 +131,24 @@ psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) { #endif +#ifdef __FreeBSD__ +/* + * Set exception to AccessDenied if pid exists else NoSuchProcess. + */ +void +psutil_raise_ad_or_nsp(long pid) { + int ret; + ret = psutil_pid_exists(pid); + if (ret == 0) + NoSuchProcess(); + else if (ret == 1) + AccessDenied(); + else + return NULL; +} +#endif + + /* * Return a Python list of all the PIDs running on the system. */ @@ -641,10 +656,13 @@ psutil_proc_io_counters(PyObject *self, PyObject *args) { } +#ifdef __OpenBSD__ +#define ptoa(x) ((paddr_t)(x) << PAGE_SHIFT) +#endif + /* * Return extended memory info for a process as a Python tuple. */ -#define ptoa(x) ((paddr_t)(x) << PAGE_SHIFT) static PyObject * psutil_proc_memory_info(PyObject *self, PyObject *args) { long pid; @@ -1724,6 +1742,7 @@ psutil_users(PyObject *self, PyObject *args) { if (py_retlist == NULL) return NULL; +#if __FreeBSD_version < 900000 || __OpenBSD__ struct utmp ut; FILE *fp; @@ -1754,7 +1773,33 @@ psutil_users(PyObject *self, PyObject *args) { } fclose(fp); +#else + struct utmpx *utx; + + while ((utx = getutxent()) != NULL) { + if (utx->ut_type != USER_PROCESS) + continue; + py_tuple = Py_BuildValue( + "(sssf)", + utx->ut_user, // username + utx->ut_line, // tty + utx->ut_host, // hostname + (float)utx->ut_tv.tv_sec // start time + ); + + if (!py_tuple) { + endutxent(); + goto error; + } + if (PyList_Append(py_retlist, py_tuple)) { + endutxent(); + goto error; + } + Py_DECREF(py_tuple); + } + endutxent(); +#endif return py_retlist; error: