/* * 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. * * Platform-specific module methods for FreeBSD and OpenBSD. * OpenBSD references: * - OpenBSD source code: https://github.com/openbsd/src * * OpenBSD / NetBSD: missing APIs compared to FreeBSD implementation: * - psutil.net_connections() * - psutil.Process.get/set_cpu_affinity() (not supported natively) * - psutil.Process.memory_maps() */ #if defined(PSUTIL_NETBSD) #define _KMEMUSER #endif #include #include #include #include #include #include #include #include #include #include #include #if !defined(__NetBSD__) #include #endif #include #include #include #include #include // for struct xsocket #include #include // for xinpcb struct #include #include #include #include #include #include #include #include // for struct xtcpcb #include // for TCP connection states #include // for inet_ntop() #include #include // net io counters #include #include #include // process open files/connections #include #include #include "_psutil_common.h" #include "_psutil_posix.h" #ifdef PSUTIL_FREEBSD #include "arch/freebsd/cpu.h" #include "arch/freebsd/mem.h" #include "arch/freebsd/disk.h" #include "arch/freebsd/sensors.h" #include "arch/freebsd/proc.h" #include "arch/freebsd/sys_socks.h" #include "arch/freebsd/proc_socks.h" #include #include // get io counters #include // process open files, shared libs (kinfo_getvmmap) #if __FreeBSD_version < 900000 #include // system users #else #include #endif #elif PSUTIL_OPENBSD #include "arch/openbsd/cpu.h" #include "arch/openbsd/disk.h" #include "arch/openbsd/mem.h" #include "arch/openbsd/proc.h" #include "arch/openbsd/socks.h" #include #include // for VREG #define _KERNEL // for DTYPE_VNODE #include #undef _KERNEL #include // for CPUSTATES & CP_* #elif PSUTIL_NETBSD #include "arch/netbsd/cpu.h" #include "arch/netbsd/disk.h" #include "arch/netbsd/mem.h" #include "arch/netbsd/proc.h" #include "arch/netbsd/socks.h" #include #include // for VREG #include // for CPUSTATES & CP_* #ifndef DTYPE_VNODE #define DTYPE_VNODE 1 #endif #endif // convert a timeval struct to a double #define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) #if defined(PSUTIL_OPENBSD) || defined (PSUTIL_NETBSD) #define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) #endif /* * 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 *py_retlist = PyList_New(0); PyObject *py_pid = NULL; if (py_retlist == NULL) return NULL; if (psutil_get_proc_list(&proclist, &num_processes) != 0) 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++) { #ifdef PSUTIL_FREEBSD py_pid = PyLong_FromPid(proclist->ki_pid); #elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD) py_pid = PyLong_FromPid(proclist->p_pid); #endif if (!py_pid) goto error; if (PyList_Append(py_retlist, py_pid)) goto error; Py_CLEAR(py_pid); proclist++; } free(orig_address); } return py_retlist; error: Py_XDECREF(py_pid); Py_DECREF(py_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) return PyErr_SetFromErrno(PyExc_OSError); return Py_BuildValue("d", (double)boottime.tv_sec); } /* * Collect different info about a process in one shot and return * them as a big Python tuple. */ static PyObject * psutil_proc_oneshot_info(PyObject *self, PyObject *args) { pid_t pid; long rss; long vms; long memtext; long memdata; long memstack; int oncpu; kinfo_proc kp; long pagesize = psutil_getpagesize(); char str[1000]; PyObject *py_name; PyObject *py_ppid; PyObject *py_retlist; if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; // Process #ifdef PSUTIL_FREEBSD sprintf(str, "%s", kp.ki_comm); #elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD) sprintf(str, "%s", kp.p_comm); #endif py_name = PyUnicode_DecodeFSDefault(str); if (! py_name) { // Likely a decoding error. We don't want to fail the whole // operation. The python module may retry with proc_name(). PyErr_Clear(); py_name = Py_None; } // Py_INCREF(py_name); // Calculate memory. #ifdef PSUTIL_FREEBSD rss = (long)kp.ki_rssize * pagesize; vms = (long)kp.ki_size; memtext = (long)kp.ki_tsize * pagesize; memdata = (long)kp.ki_dsize * pagesize; memstack = (long)kp.ki_ssize * pagesize; #else rss = (long)kp.p_vm_rssize * pagesize; #ifdef PSUTIL_OPENBSD // VMS, this is how ps determines it on OpenBSD: // https://github.com/openbsd/src/blob/ // 588f7f8c69786211f2d16865c552afb91b1c7cba/bin/ps/print.c#L505 vms = (long)(kp.p_vm_dsize + kp.p_vm_ssize + kp.p_vm_tsize) * pagesize; #elif PSUTIL_NETBSD // VMS, this is how top determines it on NetBSD: // https://github.com/IIJ-NetBSD/netbsd-src/blob/master/external/ // bsd/top/dist/machine/m_netbsd.c vms = (long)kp.p_vm_msize * pagesize; #endif memtext = (long)kp.p_vm_tsize * pagesize; memdata = (long)kp.p_vm_dsize * pagesize; memstack = (long)kp.p_vm_ssize * pagesize; #endif #ifdef PSUTIL_FREEBSD // what CPU we're on; top was used as an example: // https://svnweb.freebsd.org/base/head/usr.bin/top/machine.c? // view=markup&pathrev=273835 // XXX - note: for "intr" PID this is -1. if (kp.ki_stat == SRUN && kp.ki_oncpu != NOCPU) oncpu = kp.ki_oncpu; else oncpu = kp.ki_lastcpu; #else // On Net/OpenBSD we have kp.p_cpuid but it appears it's always // set to KI_NOCPU. Even if it's not, ki_lastcpu does not exist // so there's no way to determine where "sleeping" processes // were. Not supported. oncpu = -1; #endif #ifdef PSUTIL_FREEBSD py_ppid = PyLong_FromPid(kp.ki_ppid); #elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD) py_ppid = PyLong_FromPid(kp.p_ppid); #else py_ppid = Py_BuildfValue(-1); #endif if (! py_ppid) return NULL; // Return a single big tuple with all process info. py_retlist = Py_BuildValue( #if defined(__FreeBSD_version) && __FreeBSD_version >= 1200031 "(OillllllLdllllddddlllllbO)", #else "(OillllllidllllddddlllllbO)", #endif #ifdef PSUTIL_FREEBSD py_ppid, // (pid_t) ppid (int)kp.ki_stat, // (int) status // UIDs (long)kp.ki_ruid, // (long) real uid (long)kp.ki_uid, // (long) effective uid (long)kp.ki_svuid, // (long) saved uid // GIDs (long)kp.ki_rgid, // (long) real gid (long)kp.ki_groups[0], // (long) effective gid (long)kp.ki_svuid, // (long) saved gid // kp.ki_tdev, // (int or long long) tty nr PSUTIL_TV2DOUBLE(kp.ki_start), // (double) create time // ctx switches kp.ki_rusage.ru_nvcsw, // (long) ctx switches (voluntary) kp.ki_rusage.ru_nivcsw, // (long) ctx switches (unvoluntary) // IO count kp.ki_rusage.ru_inblock, // (long) read io count kp.ki_rusage.ru_oublock, // (long) write io count // CPU times: convert from micro seconds to seconds. PSUTIL_TV2DOUBLE(kp.ki_rusage.ru_utime), // (double) user time PSUTIL_TV2DOUBLE(kp.ki_rusage.ru_stime), // (double) sys time PSUTIL_TV2DOUBLE(kp.ki_rusage_ch.ru_utime), // (double) children utime PSUTIL_TV2DOUBLE(kp.ki_rusage_ch.ru_stime), // (double) children stime // memory rss, // (long) rss vms, // (long) vms memtext, // (long) mem text memdata, // (long) mem data memstack, // (long) mem stack // others oncpu, // (int) the CPU we are on #elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD) py_ppid, // (pid_t) ppid (int)kp.p_stat, // (int) status // UIDs (long)kp.p_ruid, // (long) real uid (long)kp.p_uid, // (long) effective uid (long)kp.p_svuid, // (long) saved uid // GIDs (long)kp.p_rgid, // (long) real gid (long)kp.p_groups[0], // (long) effective gid (long)kp.p_svuid, // (long) saved gid // kp.p_tdev, // (int) tty nr PSUTIL_KPT2DOUBLE(kp.p_ustart), // (double) create time // ctx switches kp.p_uru_nvcsw, // (long) ctx switches (voluntary) kp.p_uru_nivcsw, // (long) ctx switches (unvoluntary) // IO count kp.p_uru_inblock, // (long) read io count kp.p_uru_oublock, // (long) write io count // CPU times: convert from micro seconds to seconds. PSUTIL_KPT2DOUBLE(kp.p_uutime), // (double) user time PSUTIL_KPT2DOUBLE(kp.p_ustime), // (double) sys time // OpenBSD and NetBSD provide children user + system times summed // together (no distinction). kp.p_uctime_sec + kp.p_uctime_usec / 1000000.0, // (double) ch utime kp.p_uctime_sec + kp.p_uctime_usec / 1000000.0, // (double) ch stime // memory rss, // (long) rss vms, // (long) vms memtext, // (long) mem text memdata, // (long) mem data memstack, // (long) mem stack // others oncpu, // (int) the CPU we are on #endif py_name // (pystr) name ); Py_DECREF(py_name); Py_DECREF(py_ppid); return py_retlist; } /* * Return process name from kinfo_proc as a Python string. */ static PyObject * psutil_proc_name(PyObject *self, PyObject *args) { pid_t pid; kinfo_proc kp; char str[1000]; if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; #ifdef PSUTIL_FREEBSD sprintf(str, "%s", kp.ki_comm); #elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD) sprintf(str, "%s", kp.p_comm); #endif return PyUnicode_DecodeFSDefault(str); } /* * Return process environment as a Python dictionary */ PyObject * psutil_proc_environ(PyObject *self, PyObject *args) { int i, cnt = -1; long pid; char *s, **envs, errbuf[_POSIX2_LINE_MAX]; PyObject *py_value=NULL, *py_retdict=NULL; kvm_t *kd; #ifdef PSUTIL_NETBSD struct kinfo_proc2 *p; #else struct kinfo_proc *p; #endif if (!PyArg_ParseTuple(args, "l", &pid)) return NULL; #if defined(PSUTIL_FREEBSD) kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf); #else kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); #endif if (!kd) { convert_kvm_err("kvm_openfiles", errbuf); return NULL; } py_retdict = PyDict_New(); if (!py_retdict) goto error; #if defined(PSUTIL_FREEBSD) p = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt); #elif defined(PSUTIL_OPENBSD) p = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof(*p), &cnt); #elif defined(PSUTIL_NETBSD) p = kvm_getproc2(kd, KERN_PROC_PID, pid, sizeof(*p), &cnt); #endif if (!p) { NoSuchProcess("kvm_getprocs"); goto error; } if (cnt <= 0) { NoSuchProcess(cnt < 0 ? kvm_geterr(kd) : "kvm_getprocs: cnt==0"); goto error; } // On *BSD kernels there are a few kernel-only system processes without an // environment (See e.g. "procstat -e 0 | 1 | 2 ..." on FreeBSD.) // Some system process have no stats attached at all // (they are marked with P_SYSTEM.) // On FreeBSD, it's possible that the process is swapped or paged out, // then there no access to the environ stored in the process' user area. // On NetBSD, we cannot call kvm_getenvv2() for a zombie process. // To make unittest suite happy, return an empty environment. #if defined(PSUTIL_FREEBSD) #if (defined(__FreeBSD_version) && __FreeBSD_version >= 700000) if (!((p)->ki_flag & P_INMEM) || ((p)->ki_flag & P_SYSTEM)) { #else if ((p)->ki_flag & P_SYSTEM) { #endif #elif defined(PSUTIL_NETBSD) if ((p)->p_stat == SZOMB) { #elif defined(PSUTIL_OPENBSD) if ((p)->p_flag & P_SYSTEM) { #endif kvm_close(kd); return py_retdict; } #if defined(PSUTIL_NETBSD) envs = kvm_getenvv2(kd, p, 0); #else envs = kvm_getenvv(kd, p, 0); #endif if (!envs) { // Map to "psutil" general high-level exceptions switch (errno) { case 0: // Process has cleared it's environment, return empty one kvm_close(kd); return py_retdict; case EPERM: AccessDenied("kvm_getenvv -> EPERM"); break; case ESRCH: NoSuchProcess("kvm_getenvv -> ESRCH"); break; #if defined(PSUTIL_FREEBSD) case ENOMEM: // Unfortunately, under FreeBSD kvm_getenvv() returns // failure for certain processes ( e.g. try // "sudo procstat -e ".) // Map the error condition to 'AccessDenied'. sprintf(errbuf, "kvm_getenvv(pid=%ld, ki_uid=%d) -> ENOMEM", pid, p->ki_uid); AccessDenied(errbuf); break; #endif default: sprintf(errbuf, "kvm_getenvv(pid=%ld)", pid); PyErr_SetFromOSErrnoWithSyscall(errbuf); break; } goto error; } for (i = 0; envs[i] != NULL; i++) { s = strchr(envs[i], '='); if (!s) continue; *s++ = 0; py_value = PyUnicode_DecodeFSDefault(s); if (!py_value) goto error; if (PyDict_SetItemString(py_retdict, envs[i], py_value)) { goto error; } Py_DECREF(py_value); } kvm_close(kd); return py_retdict; error: Py_XDECREF(py_value); Py_XDECREF(py_retdict); kvm_close(kd); return NULL; } /* * Return the number of logical CPUs in the system. * XXX this could be shared with macOS */ 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) Py_RETURN_NONE; // mimic os.cpu_count() else return Py_BuildValue("i", ncpu); } /* * Return a Python tuple representing user, kernel and idle CPU times */ static PyObject * psutil_cpu_times(PyObject *self, PyObject *args) { #ifdef PSUTIL_NETBSD u_int64_t cpu_time[CPUSTATES]; #else long cpu_time[CPUSTATES]; #endif size_t size = sizeof(cpu_time); int ret; #if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD) ret = sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0); #elif PSUTIL_OPENBSD int mib[] = {CTL_KERN, KERN_CPTIME}; ret = sysctl(mib, 2, &cpu_time, &size, NULL, 0); #endif if (ret == -1) return PyErr_SetFromErrno(PyExc_OSError); 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 ); } /* * 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) || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD) static PyObject * psutil_proc_open_files(PyObject *self, PyObject *args) { pid_t pid; int i; int cnt; int regular; int fd; char *path; struct kinfo_file *freep = NULL; struct kinfo_file *kif; kinfo_proc kipp; PyObject *py_tuple = NULL; PyObject *py_path = NULL; PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid)) goto error; if (psutil_kinfo_proc(pid, &kipp) == -1) goto error; errno = 0; freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { #if !defined(PSUTIL_OPENBSD) psutil_raise_for_pid(pid, "kinfo_getfile()"); #endif goto error; } for (i = 0; i < cnt; i++) { kif = &freep[i]; #ifdef PSUTIL_FREEBSD regular = (kif->kf_type == KF_TYPE_VNODE) && \ (kif->kf_vnode_type == KF_VTYPE_VREG); fd = kif->kf_fd; path = kif->kf_path; #elif PSUTIL_OPENBSD regular = (kif->f_type == DTYPE_VNODE) && (kif->v_type == VREG); fd = kif->fd_fd; // XXX - it appears path is not exposed in the kinfo_file struct. path = ""; #elif PSUTIL_NETBSD regular = (kif->ki_ftype == DTYPE_VNODE) && (kif->ki_vtype == VREG); fd = kif->ki_fd; // XXX - it appears path is not exposed in the kinfo_file struct. path = ""; #endif if (regular == 1) { py_path = PyUnicode_DecodeFSDefault(path); if (! py_path) goto error; py_tuple = Py_BuildValue("(Oi)", py_path, fd); if (py_tuple == NULL) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_CLEAR(py_path); Py_CLEAR(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 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]; #ifdef PSUTIL_NETBSD struct statvfs *fs = NULL; #else struct statfs *fs = NULL; #endif PyObject *py_retlist = PyList_New(0); PyObject *py_dev = NULL; PyObject *py_mountp = NULL; PyObject *py_tuple = NULL; if (py_retlist == NULL) return NULL; // get the number of mount points Py_BEGIN_ALLOW_THREADS #ifdef PSUTIL_NETBSD num = getvfsstat(NULL, 0, MNT_NOWAIT); #else num = getfsstat(NULL, 0, MNT_NOWAIT); #endif 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 #ifdef PSUTIL_NETBSD num = getvfsstat(fs, len, MNT_NOWAIT); #else num = getfsstat(fs, len, MNT_NOWAIT); #endif 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; #ifdef PSUTIL_NETBSD flags = fs[i].f_flag; #else flags = fs[i].f_flags; #endif // 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_ASYNC) strlcat(opts, ",async", sizeof(opts)); if (flags & MNT_NOATIME) strlcat(opts, ",noatime", sizeof(opts)); if (flags & MNT_SOFTDEP) strlcat(opts, ",softdep", sizeof(opts)); #ifdef PSUTIL_FREEBSD if (flags & MNT_UNION) strlcat(opts, ",union", 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)); #ifdef MNT_GJOURNAL if (flags & MNT_GJOURNAL) strlcat(opts, ",gjournal", sizeof(opts)); #endif if (flags & MNT_MULTILABEL) strlcat(opts, ",multilabel", sizeof(opts)); if (flags & MNT_ACLS) strlcat(opts, ",acls", sizeof(opts)); if (flags & MNT_NOCLUSTERR) strlcat(opts, ",noclusterr", sizeof(opts)); if (flags & MNT_NOCLUSTERW) strlcat(opts, ",noclusterw", sizeof(opts)); #ifdef MNT_NFS4ACLS if (flags & MNT_NFS4ACLS) strlcat(opts, ",nfs4acls", sizeof(opts)); #endif #elif PSUTIL_NETBSD if (flags & MNT_NODEV) strlcat(opts, ",nodev", sizeof(opts)); if (flags & MNT_UNION) strlcat(opts, ",union", sizeof(opts)); if (flags & MNT_NOCOREDUMP) strlcat(opts, ",nocoredump", sizeof(opts)); #ifdef MNT_RELATIME if (flags & MNT_RELATIME) strlcat(opts, ",relatime", sizeof(opts)); #endif if (flags & MNT_IGNORE) strlcat(opts, ",ignore", sizeof(opts)); #ifdef MNT_DISCARD if (flags & MNT_DISCARD) strlcat(opts, ",discard", sizeof(opts)); #endif #ifdef MNT_EXTATTR if (flags & MNT_EXTATTR) strlcat(opts, ",extattr", sizeof(opts)); #endif if (flags & MNT_LOG) strlcat(opts, ",log", sizeof(opts)); if (flags & MNT_SYMPERM) strlcat(opts, ",symperm", sizeof(opts)); if (flags & MNT_NODEVMTIME) strlcat(opts, ",nodevmtime", sizeof(opts)); #endif py_dev = PyUnicode_DecodeFSDefault(fs[i].f_mntfromname); if (! py_dev) goto error; py_mountp = PyUnicode_DecodeFSDefault(fs[i].f_mntonname); if (! py_mountp) goto error; py_tuple = Py_BuildValue("(OOss)", py_dev, // device py_mountp, // 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_CLEAR(py_dev); Py_CLEAR(py_mountp); Py_CLEAR(py_tuple); } free(fs); return py_retlist; error: Py_XDECREF(py_dev); Py_XDECREF(py_mountp); 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, #ifdef _IFI_OQDROPS if2m->ifm_data.ifi_oqdrops #else 0 #endif ); if (!py_ifc_info) goto error; if (PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info)) goto error; Py_CLEAR(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 currently connected users as a list of tuples. */ static PyObject * psutil_users(PyObject *self, PyObject *args) { PyObject *py_retlist = PyList_New(0); PyObject *py_username = NULL; PyObject *py_tty = NULL; PyObject *py_hostname = NULL; PyObject *py_tuple = NULL; PyObject *py_pid = NULL; if (py_retlist == NULL) return NULL; #if (defined(__FreeBSD_version) && (__FreeBSD_version < 900000)) || PSUTIL_OPENBSD struct utmp ut; FILE *fp; Py_BEGIN_ALLOW_THREADS fp = fopen(_PATH_UTMP, "r"); Py_END_ALLOW_THREADS if (fp == NULL) { PyErr_SetFromErrnoWithFilename(PyExc_OSError, _PATH_UTMP); goto error; } while (fread(&ut, sizeof(ut), 1, fp) == 1) { if (*ut.ut_name == '\0') continue; py_username = PyUnicode_DecodeFSDefault(ut.ut_name); if (! py_username) goto error; py_tty = PyUnicode_DecodeFSDefault(ut.ut_line); if (! py_tty) goto error; py_hostname = PyUnicode_DecodeFSDefault(ut.ut_host); if (! py_hostname) goto error; py_tuple = Py_BuildValue( "(OOOdi)", py_username, // username py_tty, // tty py_hostname, // hostname (double)ut.ut_time, // start time #if defined(PSUTIL_OPENBSD) || (defined(__FreeBSD_version) && __FreeBSD_version < 900000) -1 // process id (set to None later) #else ut.ut_pid // TODO: use PyLong_FromPid #endif ); if (!py_tuple) { fclose(fp); goto error; } if (PyList_Append(py_retlist, py_tuple)) { fclose(fp); goto error; } Py_CLEAR(py_username); Py_CLEAR(py_tty); Py_CLEAR(py_hostname); Py_CLEAR(py_tuple); } fclose(fp); #else struct utmpx *utx; setutxent(); while ((utx = getutxent()) != NULL) { if (utx->ut_type != USER_PROCESS) continue; py_username = PyUnicode_DecodeFSDefault(utx->ut_user); if (! py_username) goto error; py_tty = PyUnicode_DecodeFSDefault(utx->ut_line); if (! py_tty) goto error; py_hostname = PyUnicode_DecodeFSDefault(utx->ut_host); if (! py_hostname) goto error; #ifdef PSUTIL_OPENBSD py_pid = Py_BuildValue("i", -1); // set to None later #else py_pid = PyLong_FromPid(utx->ut_pid); #endif if (! py_pid) goto error; py_tuple = Py_BuildValue( "(OOOdO)", py_username, // username py_tty, // tty py_hostname, // hostname (double)utx->ut_tv.tv_sec, // start time py_pid // process id ); if (!py_tuple) { endutxent(); goto error; } if (PyList_Append(py_retlist, py_tuple)) { endutxent(); goto error; } Py_CLEAR(py_username); Py_CLEAR(py_tty); Py_CLEAR(py_hostname); Py_CLEAR(py_tuple); Py_CLEAR(py_pid); } endutxent(); #endif return py_retlist; error: Py_XDECREF(py_username); Py_XDECREF(py_tty); Py_XDECREF(py_hostname); Py_XDECREF(py_tuple); Py_XDECREF(py_pid); Py_DECREF(py_retlist); return NULL; } /* * define the psutil C module methods and initialize the module. */ static PyMethodDef mod_methods[] = { // --- per-process functions {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS}, {"proc_name", psutil_proc_name, METH_VARARGS}, {"proc_oneshot_info", psutil_proc_oneshot_info, METH_VARARGS}, {"proc_threads", psutil_proc_threads, METH_VARARGS}, #if defined(PSUTIL_FREEBSD) {"proc_connections", psutil_proc_connections, METH_VARARGS}, #endif {"proc_cwd", psutil_proc_cwd, METH_VARARGS}, #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD) {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS}, {"proc_open_files", psutil_proc_open_files, METH_VARARGS}, #endif #if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD) {"proc_num_threads", psutil_proc_num_threads, METH_VARARGS}, #endif #if defined(PSUTIL_FREEBSD) {"cpu_topology", psutil_cpu_topology, METH_VARARGS}, {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS}, {"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS}, {"proc_exe", psutil_proc_exe, METH_VARARGS}, {"proc_getrlimit", psutil_proc_getrlimit, METH_VARARGS}, {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS}, {"proc_setrlimit", psutil_proc_setrlimit, METH_VARARGS}, #endif {"proc_environ", psutil_proc_environ, METH_VARARGS}, // --- system-related functions {"boot_time", psutil_boot_time, METH_VARARGS}, {"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS}, {"cpu_stats", psutil_cpu_stats, METH_VARARGS}, {"cpu_times", psutil_cpu_times, METH_VARARGS}, {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS}, {"disk_partitions", psutil_disk_partitions, METH_VARARGS}, {"net_connections", psutil_net_connections, METH_VARARGS}, {"net_io_counters", psutil_net_io_counters, METH_VARARGS}, {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS}, {"pids", psutil_pids, METH_VARARGS}, {"swap_mem", psutil_swap_mem, METH_VARARGS}, {"users", psutil_users, METH_VARARGS}, {"virtual_mem", psutil_virtual_mem, METH_VARARGS}, #if defined(PSUTIL_FREEBSD) || defined(PSUTIL_OPENBSD) {"cpu_freq", psutil_cpu_freq, METH_VARARGS}, #endif #if defined(PSUTIL_FREEBSD) {"sensors_battery", psutil_sensors_battery, METH_VARARGS}, {"sensors_cpu_temperature", psutil_sensors_cpu_temperature, METH_VARARGS}, #endif // --- others {"set_debug", psutil_set_debug, METH_VARARGS}, {NULL, NULL, 0, NULL} }; #if PY_MAJOR_VERSION >= 3 #define INITERR return NULL static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "_psutil_bsd", NULL, -1, mod_methods, NULL, NULL, NULL, NULL }; PyObject *PyInit__psutil_bsd(void) #else /* PY_MAJOR_VERSION */ #define INITERR return void init_psutil_bsd(void) #endif /* PY_MAJOR_VERSION */ { PyObject *v; #if PY_MAJOR_VERSION >= 3 PyObject *mod = PyModule_Create(&moduledef); #else PyObject *mod = Py_InitModule("_psutil_bsd", mod_methods); #endif if (mod == NULL) INITERR; if (PyModule_AddIntConstant(mod, "version", PSUTIL_VERSION)) INITERR; // process status constants #ifdef PSUTIL_FREEBSD if (PyModule_AddIntConstant(mod, "SIDL", SIDL)) INITERR; if (PyModule_AddIntConstant(mod, "SRUN", SRUN)) INITERR; if (PyModule_AddIntConstant(mod, "SSLEEP", SSLEEP)) INITERR; if (PyModule_AddIntConstant(mod, "SSTOP", SSTOP)) INITERR; if (PyModule_AddIntConstant(mod, "SZOMB", SZOMB)) INITERR; if (PyModule_AddIntConstant(mod, "SWAIT", SWAIT)) INITERR; if (PyModule_AddIntConstant(mod, "SLOCK", SLOCK)) INITERR; #elif PSUTIL_OPENBSD if (PyModule_AddIntConstant(mod, "SIDL", SIDL)) INITERR; if (PyModule_AddIntConstant(mod, "SRUN", SRUN)) INITERR; if (PyModule_AddIntConstant(mod, "SSLEEP", SSLEEP)) INITERR; if (PyModule_AddIntConstant(mod, "SSTOP", SSTOP)) INITERR; if (PyModule_AddIntConstant(mod, "SZOMB", SZOMB)) INITERR; // unused if (PyModule_AddIntConstant(mod, "SDEAD", SDEAD)) INITERR; if (PyModule_AddIntConstant(mod, "SONPROC", SONPROC)) INITERR; #elif defined(PSUTIL_NETBSD) if (PyModule_AddIntConstant(mod, "SIDL", LSIDL)) INITERR; if (PyModule_AddIntConstant(mod, "SRUN", LSRUN)) INITERR; if (PyModule_AddIntConstant(mod, "SSLEEP", LSSLEEP)) INITERR; if (PyModule_AddIntConstant(mod, "SSTOP", LSSTOP)) INITERR; if (PyModule_AddIntConstant(mod, "SZOMB", LSZOMB)) INITERR; #if __NetBSD_Version__ < 500000000 if (PyModule_AddIntConstant(mod, "SDEAD", LSDEAD)) INITERR; #endif if (PyModule_AddIntConstant(mod, "SONPROC", LSONPROC)) INITERR; // unique to NetBSD if (PyModule_AddIntConstant(mod, "SSUSPENDED", LSSUSPENDED)) INITERR; #endif // connection status constants if (PyModule_AddIntConstant(mod, "TCPS_CLOSED", TCPS_CLOSED)) INITERR; if (PyModule_AddIntConstant(mod, "TCPS_CLOSING", TCPS_CLOSING)) INITERR; if (PyModule_AddIntConstant(mod, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT)) INITERR; if (PyModule_AddIntConstant(mod, "TCPS_LISTEN", TCPS_LISTEN)) INITERR; if (PyModule_AddIntConstant(mod, "TCPS_ESTABLISHED", TCPS_ESTABLISHED)) INITERR; if (PyModule_AddIntConstant(mod, "TCPS_SYN_SENT", TCPS_SYN_SENT)) INITERR; if (PyModule_AddIntConstant(mod, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED)) INITERR; if (PyModule_AddIntConstant(mod, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1)) INITERR; if (PyModule_AddIntConstant(mod, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2)) INITERR; if (PyModule_AddIntConstant(mod, "TCPS_LAST_ACK", TCPS_LAST_ACK)) INITERR; if (PyModule_AddIntConstant(mod, "TCPS_TIME_WAIT", TCPS_TIME_WAIT)) INITERR; // PSUTIL_CONN_NONE if (PyModule_AddIntConstant(mod, "PSUTIL_CONN_NONE", 128)) INITERR; psutil_setup(); if (mod == NULL) INITERR; #if PY_MAJOR_VERSION >= 3 return mod; #endif }