pkgsrc-wip/py-psutil/patches/patch-psutil_arch_bsd_drago...

568 lines
15 KiB
C

$NetBSD$
--- psutil/arch/bsd/dragonfly.c.orig 2018-02-09 16:11:41.557735000 +0000
+++ psutil/arch/bsd/dragonfly.c
@@ -0,0 +1,562 @@
+/*
+ * 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.
+ *
+ * Platform-specific module methods for DragonFly BSD.
+ */
+
+#include <Python.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/vmmeter.h> // needed for vmtotal struct
+#include <devstat.h> // for swap mem
+#include <libutil.h> // process open files, shared libs (kinfo_getvmmap), cwd
+#include <kvm.h>
+
+#include "../../_psutil_common.h"
+#include "../../_psutil_posix.h"
+
+#define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
+#define PSUTIL_BT2MSEC(bt) (bt.sec * 1000 + (((uint64_t) 1000000000 * (uint32_t) \
+ (bt.frac >> 32) ) >> 32 ) / 1000000)
+#ifndef _PATH_DEVNULL
+#define _PATH_DEVNULL "/dev/null"
+#endif
+
+
+// ============================================================================
+// Utility functions
+// ============================================================================
+
+
+int
+psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) {
+ // Fills a kinfo_proc struct based on process pid.
+ 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;
+}
+
+
+// remove spaces from string
+static void psutil_remove_spaces(char *str) {
+ char *p1 = str;
+ char *p2 = str;
+ do
+ while (*p2 == ' ')
+ p2++;
+ while ((*p1++ = *p2++));
+}
+
+
+// ============================================================================
+// 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.
+
+ /* XXX: not implemented */
+
+ *procList = NULL;
+ *procCount = 0;
+
+ return 0;
+}
+
+
+/*
+ * 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.
+ */
+static 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_cmdline(long pid) {
+ char *argstr = NULL;
+ int pos = 0;
+ size_t argsize = 0;
+ PyObject *py_retlist = Py_BuildValue("[]");
+ PyObject *py_arg = NULL;
+
+ if (pid < 0)
+ return py_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) {
+#if PY_MAJOR_VERSION >= 3
+ py_arg = PyUnicode_DecodeFSDefault(&argstr[pos]);
+#else
+ py_arg = Py_BuildValue("s", &argstr[pos]);
+#endif
+ if (!py_arg)
+ goto error;
+ if (PyList_Append(py_retlist, py_arg))
+ goto error;
+ Py_DECREF(py_arg);
+ pos = pos + strlen(&argstr[pos]) + 1;
+ }
+ }
+
+ free(argstr);
+ return py_retlist;
+
+error:
+ Py_XDECREF(py_arg);
+ Py_DECREF(py_retlist);
+ if (argstr != NULL)
+ free(argstr);
+ return NULL;
+}
+
+
+/*
+ * Return process pathname executable.
+ * Thanks to Robert N. M. Watson:
+ * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_bin.c?v=8-CURRENT
+ */
+PyObject *
+psutil_proc_exe(PyObject *self, PyObject *args) {
+ long pid;
+ char pathname[PATH_MAX];
+ int error;
+ int mib[4];
+ int ret;
+ size_t size;
+ const char *encoding_errs;
+
+ 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) {
+ if (errno == ENOENT) {
+ // see: https://github.com/giampaolo/psutil/issues/907
+ return Py_BuildValue("s", "");
+ }
+ else {
+ 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, "");
+ }
+
+#if PY_MAJOR_VERSION >= 3
+ return PyUnicode_DecodeFSDefault(pathname);
+#else
+ return Py_BuildValue("s", pathname);
+#endif
+
+}
+
+
+PyObject *
+psutil_proc_num_threads(PyObject *self, PyObject *args) {
+ // Return number of threads used by process as a Python integer.
+ 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.kp_nthreads);
+}
+
+PyObject *
+psutil_proc_connections(PyObject *self, PyObject *args) {
+ /* XXX: not implemented */
+
+ return NULL;
+}
+
+PyObject *
+psutil_proc_threads(PyObject *self, PyObject *args) {
+ // Retrieves all threads used by process returning a list of tuples
+ // including thread id, user time and system time.
+
+ /* XXX: not implemented */
+ return NULL;
+}
+
+
+PyObject *
+psutil_cpu_count_phys(PyObject *self, PyObject *args) {
+ // Return an XML string from which we'll determine the number of
+ // physical CPU cores in the system.
+
+ /* XXX: not implemented */
+ return NULL;
+}
+
+
+/*
+ * Return virtual memory usage statistics.
+ */
+PyObject *
+psutil_virtual_mem(PyObject *self, PyObject *args) {
+ unsigned long total;
+ unsigned int active, inactive, wired, cached, free;
+ size_t size = sizeof(total);
+ struct vmtotal vm;
+ long pagesize = getpagesize();
+ long buffers;
+ size_t buffers_size = sizeof(buffers);
+
+ if (sysctlbyname("hw.physmem", &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;
+ // https://github.com/giampaolo/psutil/issues/997
+ if (sysctlbyname("vm.stats.vm.v_cache_count", &cached, &size, NULL, 0))
+ cached = 0;
+ 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 (sysctlbyname("vm.vmtotal", &vm, &size, NULL, 0))
+ goto error;
+
+ return Py_BuildValue("KKKKKKKK",
+ (unsigned long long) total,
+ (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;
+}
+
+
+PyObject *
+psutil_swap_mem(PyObject *self, PyObject *args) {
+ // Return swap memory stats (see 'swapinfo' cmdline tool)
+ 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() syscall failed");
+ return NULL;
+ }
+
+ if (kvm_getswapinfo(kd, kvmsw, 1, 0) < 0) {
+ kvm_close(kd);
+ PyErr_SetString(PyExc_RuntimeError,
+ "kvm_getswapinfo() syscall 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;
+}
+
+
+PyObject *
+psutil_proc_cwd(PyObject *self, PyObject *args) {
+ /* XXX: not implemented */
+
+ return NULL;
+}
+
+PyObject *
+psutil_proc_num_fds(PyObject *self, PyObject *args) {
+ /* XXX: not implemented */
+
+ return NULL;
+}
+
+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("hw.ncpu", &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;
+}
+
+
+PyObject *
+psutil_disk_io_counters(PyObject *self, PyObject *args) {
+ /* XXX: not implemented */
+ return NULL;
+}
+
+
+PyObject *
+psutil_proc_memory_maps(PyObject *self, PyObject *args) {
+ // Return a list of tuples for every process memory maps.
+ //'procstat' cmdline utility has been used as an example.
+
+ /* XXX: not implemented */
+ return NULL;
+}
+
+
+PyObject*
+psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args) {
+ // Get process CPU affinity.
+ // Reference:
+ // http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c
+
+ /* XXX: not implemented */
+ return NULL;
+}
+
+
+PyObject *
+psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) {
+ // Set process CPU affinity.
+ // Reference:
+ // http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c
+
+ /* XXX: not implemented */
+ return NULL;
+}
+
+
+PyObject *
+psutil_cpu_stats(PyObject *self, PyObject *args) {
+ unsigned int v_soft;
+ unsigned int v_intr;
+ unsigned int v_syscall;
+ unsigned int v_trap;
+ unsigned int v_swtch;
+ size_t size = sizeof(v_soft);
+
+ if (sysctlbyname("vm.stats.sys.v_soft", &v_soft, &size, NULL, 0))
+ goto error;
+ if (sysctlbyname("vm.stats.sys.v_intr", &v_intr, &size, NULL, 0))
+ goto error;
+ if (sysctlbyname("vm.stats.sys.v_syscall", &v_syscall, &size, NULL, 0))
+ goto error;
+ if (sysctlbyname("vm.stats.sys.v_trap", &v_trap, &size, NULL, 0))
+ goto error;
+ if (sysctlbyname("vm.stats.sys.v_swtch", &v_swtch, &size, NULL, 0))
+ goto error;
+
+ return Py_BuildValue(
+ "IIIII",
+ v_swtch, // ctx switches
+ v_intr, // interrupts
+ v_soft, // software interrupts
+ v_syscall, // syscalls
+ v_trap // traps
+ );
+
+error:
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+}
+
+
+/*
+ * Return battery information.
+ */
+PyObject *
+psutil_sensors_battery(PyObject *self, PyObject *args) {
+ int percent;
+ int minsleft;
+ int power_plugged;
+ size_t size = sizeof(percent);
+
+ if (sysctlbyname("hw.acpi.battery.life", &percent, &size, NULL, 0))
+ goto error;
+ if (sysctlbyname("hw.acpi.battery.time", &minsleft, &size, NULL, 0))
+ goto error;
+ if (sysctlbyname("hw.acpi.acline", &power_plugged, &size, NULL, 0))
+ goto error;
+ return Py_BuildValue("iii", percent, minsleft, power_plugged);
+
+error:
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+}