diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2018-06-26 16:57:36 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-06-26 16:57:36 -0700 |
commit | 2f60e997fc1c500e0c245979bbecf2761f36e820 (patch) | |
tree | 5459ce3b71fad107ec41c8b720811a8110a3380d /psutil/_psutil_osx.c | |
parent | 7a3ed446447ec845a7d03b32233b4ed7b48f3c26 (diff) | |
download | psutil-2f60e997fc1c500e0c245979bbecf2761f36e820.tar.gz |
Rename OSX to macOS (#1298)
rename OSX to macOS
Diffstat (limited to 'psutil/_psutil_osx.c')
-rw-r--r-- | psutil/_psutil_osx.c | 2144 |
1 files changed, 0 insertions, 2144 deletions
diff --git a/psutil/_psutil_osx.c b/psutil/_psutil_osx.c deleted file mode 100644 index 15f4d4f6..00000000 --- a/psutil/_psutil_osx.c +++ /dev/null @@ -1,2144 +0,0 @@ -/* - * 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. - * - * OS X platform-specific module methods for _psutil_osx - */ - -#include <Python.h> -#include <assert.h> -#include <errno.h> -#include <stdbool.h> -#include <stdlib.h> -#include <stdio.h> -#include <utmpx.h> -#include <sys/sysctl.h> -#include <sys/vmmeter.h> -#include <libproc.h> -#include <sys/proc_info.h> -#include <netinet/tcp_fsm.h> -#include <arpa/inet.h> -#include <net/if_dl.h> -#include <pwd.h> - -#include <mach/mach.h> -#include <mach/task.h> -#include <mach/mach_init.h> -#include <mach/host_info.h> -#include <mach/mach_host.h> -#include <mach/mach_traps.h> -#include <mach/mach_vm.h> -#include <mach/shared_region.h> - -#include <mach-o/loader.h> - -#include <CoreFoundation/CoreFoundation.h> -#include <IOKit/IOKitLib.h> -#include <IOKit/storage/IOBlockStorageDriver.h> -#include <IOKit/storage/IOMedia.h> -#include <IOKit/IOBSD.h> -#include <IOKit/ps/IOPowerSources.h> -#include <IOKit/ps/IOPSKeys.h> - -#include "_psutil_common.h" -#include "_psutil_posix.h" -#include "arch/osx/process_info.h" -#include "arch/osx/smc.h" - - -#define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) - -static PyObject *ZombieProcessError; - - -/* - * A wrapper around host_statistics() invoked with HOST_VM_INFO. - */ -int -psutil_sys_vminfo(vm_statistics_data_t *vmstat) { - kern_return_t ret; - mach_msg_type_number_t count = sizeof(*vmstat) / sizeof(integer_t); - mach_port_t mport = mach_host_self(); - - ret = host_statistics(mport, HOST_VM_INFO, (host_info_t)vmstat, &count); - if (ret != KERN_SUCCESS) { - PyErr_Format( - PyExc_RuntimeError, - "host_statistics(HOST_VM_INFO) syscall failed: %s", - mach_error_string(ret)); - return 0; - } - mach_port_deallocate(mach_task_self(), mport); - return 1; -} - - -/* - * Return 1 if pid refers to a zombie process else 0. - */ -int -psutil_is_zombie(long pid) -{ - struct kinfo_proc kp; - - if (psutil_get_kinfo_proc(pid, &kp) == -1) - return 0; - return (kp.kp_proc.p_stat == SZOMB) ? 1 : 0; -} - - -/* - * A wrapper around task_for_pid() which sucks big time: - * - it's not documented - * - errno is set only sometimes - * - sometimes errno is ENOENT (?!?) - * - for PIDs != getpid() or PIDs which are not members of the procmod - * it requires root - * As such we can only guess what the heck went wrong and fail either - * with NoSuchProcess, ZombieProcessError or giveup with AccessDenied. - * Here's some history: - * https://github.com/giampaolo/psutil/issues/1181 - * https://github.com/giampaolo/psutil/issues/1209 - * https://github.com/giampaolo/psutil/issues/1291#issuecomment-396062519 - */ -int -psutil_task_for_pid(long pid, mach_port_t *task) -{ - // See: https://github.com/giampaolo/psutil/issues/1181 - kern_return_t err = KERN_SUCCESS; - - err = task_for_pid(mach_task_self(), (pid_t)pid, task); - if (err != KERN_SUCCESS) { - if (psutil_pid_exists(pid) == 0) - NoSuchProcess("task_for_pid() failed"); - else if (psutil_is_zombie(pid) == 1) - PyErr_SetString(ZombieProcessError, "task_for_pid() failed"); - else { - psutil_debug( - "task_for_pid() failed (pid=%ld, err=%i, errno=%i, msg='%s'); " - "setting AccessDenied()", - pid, err, errno, mach_error_string(err)); - AccessDenied("task_for_pid() failed"); - } - 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 *py_pid = NULL; - PyObject *py_retlist = PyList_New(0); - - if (py_retlist == NULL) - return NULL; - - if (psutil_get_proc_list(&proclist, &num_processes) != 0) { - if (errno != 0) { - PyErr_SetFromErrno(PyExc_OSError); - } - else { - PyErr_SetString(PyExc_RuntimeError, - "failed to retrieve process list"); - } - goto error; - } - - if (num_processes > 0) { - // save the address of proclist so we can free it later - orig_address = proclist; - for (idx = 0; idx < num_processes; idx++) { - py_pid = Py_BuildValue("i", proclist->kp_proc.p_pid); - if (! py_pid) - goto error; - if (PyList_Append(py_retlist, py_pid)) - goto error; - Py_DECREF(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 multiple process info as a Python tuple in one shot by - * using sysctl() and filling up a kinfo_proc struct. - * It should be possible to do this for all processes without - * incurring into permission (EPERM) errors. - * This will also succeed for zombie processes returning correct - * information. - */ -static PyObject * -psutil_proc_kinfo_oneshot(PyObject *self, PyObject *args) { - long pid; - struct kinfo_proc kp; - PyObject *py_name; - PyObject *py_retlist; - - if (! PyArg_ParseTuple(args, "l", &pid)) - return NULL; - if (psutil_get_kinfo_proc(pid, &kp) == -1) - return NULL; - - py_name = PyUnicode_DecodeFSDefault(kp.kp_proc.p_comm); - 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_retlist = Py_BuildValue( - "lllllllidiO", - (long)kp.kp_eproc.e_ppid, // (long) ppid - (long)kp.kp_eproc.e_pcred.p_ruid, // (long) real uid - (long)kp.kp_eproc.e_ucred.cr_uid, // (long) effective uid - (long)kp.kp_eproc.e_pcred.p_svuid, // (long) saved uid - (long)kp.kp_eproc.e_pcred.p_rgid, // (long) real gid - (long)kp.kp_eproc.e_ucred.cr_groups[0], // (long) effective gid - (long)kp.kp_eproc.e_pcred.p_svgid, // (long) saved gid - kp.kp_eproc.e_tdev, // (int) tty nr - PSUTIL_TV2DOUBLE(kp.kp_proc.p_starttime), // (double) create time - (int)kp.kp_proc.p_stat, // (int) status - py_name // (pystr) name - ); - - if (py_retlist != NULL) { - // XXX shall we decref() also in case of Py_BuildValue() error? - Py_DECREF(py_name); - } - return py_retlist; -} - - -/* - * Return multiple process info as a Python tuple in one shot by - * using proc_pidinfo(PROC_PIDTASKINFO) and filling a proc_taskinfo - * struct. - * Contrarily from proc_kinfo above this function will fail with - * EACCES for PIDs owned by another user and with ESRCH for zombie - * processes. - */ -static PyObject * -psutil_proc_pidtaskinfo_oneshot(PyObject *self, PyObject *args) { - long pid; - struct proc_taskinfo pti; - - if (! PyArg_ParseTuple(args, "l", &pid)) - return NULL; - if (psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)) <= 0) - return NULL; - - return Py_BuildValue( - "(ddKKkkkk)", - (float)pti.pti_total_user / 1000000000.0, // (float) cpu user time - (float)pti.pti_total_system / 1000000000.0, // (float) cpu sys time - // Note about memory: determining other mem stats on OSX is a mess: - // http://www.opensource.apple.com/source/top/top-67/libtop.c?txt - // I just give up. - // struct proc_regioninfo pri; - // psutil_proc_pidinfo(pid, PROC_PIDREGIONINFO, 0, &pri, sizeof(pri)) - pti.pti_resident_size, // (uns long long) rss - pti.pti_virtual_size, // (uns long long) vms - pti.pti_faults, // (uns long) number of page faults (pages) - pti.pti_pageins, // (uns long) number of actual pageins (pages) - pti.pti_threadnum, // (uns long) num threads - // Unvoluntary value seems not to be available; - // pti.pti_csw probably refers to the sum of the two; - // getrusage() numbers seems to confirm this theory. - pti.pti_csw // (uns long) voluntary ctx switches - ); -} - - -/* - * 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_get_kinfo_proc(pid, &kp) == -1) - return NULL; - return PyUnicode_DecodeFSDefault(kp.kp_proc.p_comm); -} - - -/* - * Return process current working directory. - * Raises NSP in case of zombie process. - */ -static PyObject * -psutil_proc_cwd(PyObject *self, PyObject *args) { - long pid; - struct proc_vnodepathinfo pathinfo; - - if (! PyArg_ParseTuple(args, "l", &pid)) - return NULL; - - if (psutil_proc_pidinfo( - pid, PROC_PIDVNODEPATHINFO, 0, &pathinfo, sizeof(pathinfo)) <= 0) - { - return NULL; - } - - return PyUnicode_DecodeFSDefault(pathinfo.pvi_cdir.vip_path); -} - - -/* - * Return path of the process executable. - */ -static PyObject * -psutil_proc_exe(PyObject *self, PyObject *args) { - long pid; - char buf[PATH_MAX]; - int ret; - - if (! PyArg_ParseTuple(args, "l", &pid)) - return NULL; - errno = 0; - ret = proc_pidpath((pid_t)pid, &buf, sizeof(buf)); - if (ret == 0) { - if (pid == 0) - AccessDenied(""); - else - psutil_raise_for_pid(pid, "proc_pidpath()"); - return NULL; - } - return PyUnicode_DecodeFSDefault(buf); -} - - -/* - * Return process cmdline as a Python list of cmdline arguments. - */ -static PyObject * -psutil_proc_cmdline(PyObject *self, PyObject *args) { - long pid; - PyObject *py_retlist = NULL; - - if (! PyArg_ParseTuple(args, "l", &pid)) - return NULL; - - // get the commandline, defined in arch/osx/process_info.c - py_retlist = psutil_get_cmdline(pid); - return py_retlist; -} - - -/* - * Return process environment as a Python string. - */ -static PyObject * -psutil_proc_environ(PyObject *self, PyObject *args) { - long pid; - PyObject *py_retdict = NULL; - - if (! PyArg_ParseTuple(args, "l", &pid)) - return NULL; - - // get the environment block, defined in arch/osx/process_info.c - py_retdict = psutil_get_environ(pid); - return py_retdict; -} - - -/* - * 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) { - char buf[PATH_MAX]; - char addr_str[34]; - char perms[8]; - int pagesize = getpagesize(); - long pid; - kern_return_t err = KERN_SUCCESS; - mach_port_t task = MACH_PORT_NULL; - uint32_t depth = 1; - vm_address_t address = 0; - vm_size_t size = 0; - - PyObject *py_tuple = NULL; - PyObject *py_path = NULL; - PyObject *py_list = PyList_New(0); - - if (py_list == NULL) - return NULL; - - if (! PyArg_ParseTuple(args, "l", &pid)) - goto error; - - if (psutil_task_for_pid(pid, &task) != 0) - goto error; - - while (1) { - py_tuple = NULL; - struct vm_region_submap_info_64 info; - mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; - - err = vm_region_recurse_64(task, &address, &size, &depth, - (vm_region_info_64_t)&info, &count); - if (err == KERN_INVALID_ADDRESS) { - // TODO temporary - psutil_debug("vm_region_recurse_64 returned KERN_INVALID_ADDRESS"); - break; - } - if (err != KERN_SUCCESS) { - psutil_debug("vm_region_recurse_64 returned != KERN_SUCCESS"); - } - - if (info.is_submap) { - depth++; - } - else { - // Free/Reset the char[]s to avoid weird paths - memset(buf, 0, sizeof(buf)); - memset(addr_str, 0, sizeof(addr_str)); - memset(perms, 0, sizeof(perms)); - - sprintf(addr_str, - "%016lx-%016lx", - (long unsigned int)address, - (long unsigned int)address + size); - sprintf(perms, "%c%c%c/%c%c%c", - (info.protection & VM_PROT_READ) ? 'r' : '-', - (info.protection & VM_PROT_WRITE) ? 'w' : '-', - (info.protection & VM_PROT_EXECUTE) ? 'x' : '-', - (info.max_protection & VM_PROT_READ) ? 'r' : '-', - (info.max_protection & VM_PROT_WRITE) ? 'w' : '-', - (info.max_protection & VM_PROT_EXECUTE) ? 'x' : '-'); - - // proc_regionfilename() return value seems meaningless - // so we do what we can in order to not continue in case - // of error. - errno = 0; - proc_regionfilename((pid_t)pid, address, buf, sizeof(buf)); - if ((errno != 0) || ((sizeof(buf)) <= 0)) { - // TODO temporary - psutil_debug("proc_regionfilename() failed"); - psutil_raise_for_pid(pid, "proc_regionfilename()"); - goto error; - } - - if (info.share_mode == SM_COW && info.ref_count == 1) { - // Treat single reference SM_COW as SM_PRIVATE - info.share_mode = SM_PRIVATE; - } - - if (strlen(buf) == 0) { - switch (info.share_mode) { -// #ifdef SM_LARGE_PAGE - // case SM_LARGE_PAGE: - // Treat SM_LARGE_PAGE the same as SM_PRIVATE - // since they are not shareable and are wired. -// #endif - case SM_COW: - strcpy(buf, "[cow]"); - break; - case SM_PRIVATE: - strcpy(buf, "[prv]"); - break; - case SM_EMPTY: - strcpy(buf, "[nul]"); - break; - case SM_SHARED: - case SM_TRUESHARED: - strcpy(buf, "[shm]"); - break; - case SM_PRIVATE_ALIASED: - strcpy(buf, "[ali]"); - break; - case SM_SHARED_ALIASED: - strcpy(buf, "[s/a]"); - break; - default: - strcpy(buf, "[???]"); - } - } - - py_path = PyUnicode_DecodeFSDefault(buf); - if (! py_path) - goto error; - py_tuple = Py_BuildValue( - "ssOIIIIIH", - addr_str, // "start-end"address - perms, // "rwx" permissions - py_path, // path - info.pages_resident * pagesize, // rss - info.pages_shared_now_private * pagesize, // private - info.pages_swapped_out * pagesize, // swapped - info.pages_dirtied * pagesize, // dirtied - info.ref_count, // ref count - info.shadow_depth // shadow depth - ); - if (!py_tuple) - goto error; - if (PyList_Append(py_list, py_tuple)) - goto error; - Py_DECREF(py_tuple); - Py_DECREF(py_path); - } - - // increment address for the next map/file - address += size; - } - - if (task != MACH_PORT_NULL) - mach_port_deallocate(mach_task_self(), task); - - return py_list; - -error: - if (task != MACH_PORT_NULL) - mach_port_deallocate(mach_task_self(), task); - Py_XDECREF(py_tuple); - Py_XDECREF(py_path); - Py_DECREF(py_list); - return NULL; -} - - -/* - * Return the number of logical CPUs in the system. - * XXX this could be shared with BSD. - */ -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); - */ - int num; - size_t size = sizeof(int); - - if (sysctlbyname("hw.logicalcpu", &num, &size, NULL, 2)) - Py_RETURN_NONE; // mimic os.cpu_count() - else - return Py_BuildValue("i", num); -} - - -/* - * Return the number of physical CPUs in the system. - */ -static PyObject * -psutil_cpu_count_phys(PyObject *self, PyObject *args) { - int num; - size_t size = sizeof(int); - - if (sysctlbyname("hw.physicalcpu", &num, &size, NULL, 0)) - Py_RETURN_NONE; // mimic os.cpu_count() - else - return Py_BuildValue("i", num); -} - - -/* - * Indicates if the given virtual address on the given architecture is in the - * shared VM region. - */ -bool -psutil_in_shared_region(mach_vm_address_t addr, cpu_type_t type) { - mach_vm_address_t base; - mach_vm_address_t size; - - switch (type) { - case CPU_TYPE_ARM: - base = SHARED_REGION_BASE_ARM; - size = SHARED_REGION_SIZE_ARM; - break; - case CPU_TYPE_I386: - base = SHARED_REGION_BASE_I386; - size = SHARED_REGION_SIZE_I386; - break; - case CPU_TYPE_X86_64: - base = SHARED_REGION_BASE_X86_64; - size = SHARED_REGION_SIZE_X86_64; - break; - default: - return false; - } - - return base <= addr && addr < (base + size); -} - - -/* - * Returns the USS (unique set size) of the process. Reference: - * https://dxr.mozilla.org/mozilla-central/source/xpcom/base/ - * nsMemoryReporterManager.cpp - */ -static PyObject * -psutil_proc_memory_uss(PyObject *self, PyObject *args) { - long pid; - size_t len; - cpu_type_t cpu_type; - size_t private_pages = 0; - mach_vm_size_t size = 0; - mach_msg_type_number_t info_count = VM_REGION_TOP_INFO_COUNT; - kern_return_t kr; - vm_size_t page_size; - mach_vm_address_t addr = MACH_VM_MIN_ADDRESS; - mach_port_t task = MACH_PORT_NULL; - vm_region_top_info_data_t info; - mach_port_t object_name; - - if (! PyArg_ParseTuple(args, "l", &pid)) - return NULL; - - if (psutil_task_for_pid(pid, &task) != 0) - return NULL; - - len = sizeof(cpu_type); - if (sysctlbyname("sysctl.proc_cputype", &cpu_type, &len, NULL, 0) != 0) - return PyErr_SetFromErrno(PyExc_OSError); - - // Roughly based on libtop_update_vm_regions in - // http://www.opensource.apple.com/source/top/top-100.1.2/libtop.c - for (addr = 0; ; addr += size) { - kr = mach_vm_region( - task, &addr, &size, VM_REGION_TOP_INFO, (vm_region_info_t)&info, - &info_count, &object_name); - if (kr == KERN_INVALID_ADDRESS) { - // Done iterating VM regions. - break; - } - else if (kr != KERN_SUCCESS) { - PyErr_Format( - PyExc_RuntimeError, - "mach_vm_region(VM_REGION_TOP_INFO) syscall failed"); - return NULL; - } - - if (psutil_in_shared_region(addr, cpu_type) && - info.share_mode != SM_PRIVATE) { - continue; - } - - switch (info.share_mode) { -#ifdef SM_LARGE_PAGE - case SM_LARGE_PAGE: - // NB: Large pages are not shareable and always resident. -#endif - case SM_PRIVATE: - private_pages += info.private_pages_resident; - private_pages += info.shared_pages_resident; - break; - case SM_COW: - private_pages += info.private_pages_resident; - if (info.ref_count == 1) { - // Treat copy-on-write pages as private if they only - // have one reference. - private_pages += info.shared_pages_resident; - } - break; - case SM_SHARED: - default: - break; - } - } - - mach_port_deallocate(mach_task_self(), task); - - if (host_page_size(mach_host_self(), &page_size) != KERN_SUCCESS) - page_size = PAGE_SIZE; - - return Py_BuildValue("K", private_pages * page_size); -} - - -/* - * Return system virtual memory stats. - * See: - * http://opensource.apple.com/source/system_cmds/system_cmds-498.2/ - * vm_stat.tproj/vm_stat.c - */ -static PyObject * -psutil_virtual_mem(PyObject *self, PyObject *args) { - int mib[2]; - uint64_t total; - size_t len = sizeof(total); - vm_statistics_data_t vm; - int pagesize = getpagesize(); - // physical mem - mib[0] = CTL_HW; - mib[1] = HW_MEMSIZE; - - // This is also available as sysctlbyname("hw.memsize"). - if (sysctl(mib, 2, &total, &len, NULL, 0)) { - if (errno != 0) - PyErr_SetFromErrno(PyExc_OSError); - else - PyErr_Format( - PyExc_RuntimeError, "sysctl(HW_MEMSIZE) syscall failed"); - return NULL; - } - - // vm - if (!psutil_sys_vminfo(&vm)) - return NULL; - - return Py_BuildValue( - "KKKKK", - total, - (unsigned long long) vm.active_count * pagesize, - (unsigned long long) vm.inactive_count * pagesize, - (unsigned long long) vm.wire_count * pagesize, - // this is how vm_stat cmd does it - (unsigned long long) (vm.free_count - vm.speculative_count) * pagesize - ); -} - - -/* - * Return stats about swap memory. - */ -static PyObject * -psutil_swap_mem(PyObject *self, PyObject *args) { - int mib[2]; - size_t size; - struct xsw_usage totals; - vm_statistics_data_t vmstat; - int pagesize = getpagesize(); - - mib[0] = CTL_VM; - mib[1] = VM_SWAPUSAGE; - size = sizeof(totals); - if (sysctl(mib, 2, &totals, &size, NULL, 0) == -1) { - if (errno != 0) - PyErr_SetFromErrno(PyExc_OSError); - else - PyErr_Format( - PyExc_RuntimeError, "sysctl(VM_SWAPUSAGE) syscall failed"); - return NULL; - } - if (!psutil_sys_vminfo(&vmstat)) - return NULL; - - return Py_BuildValue( - "LLLKK", - totals.xsu_total, - totals.xsu_used, - totals.xsu_avail, - (unsigned long long)vmstat.pageins * pagesize, - (unsigned long long)vmstat.pageouts * pagesize); -} - - -/* - * Return a Python tuple representing user, kernel and idle CPU times - */ -static PyObject * -psutil_cpu_times(PyObject *self, PyObject *args) { - mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; - kern_return_t error; - host_cpu_load_info_data_t r_load; - - mach_port_t host_port = mach_host_self(); - error = host_statistics(host_port, HOST_CPU_LOAD_INFO, - (host_info_t)&r_load, &count); - if (error != KERN_SUCCESS) { - return PyErr_Format( - PyExc_RuntimeError, - "host_statistics(HOST_CPU_LOAD_INFO) syscall failed: %s", - mach_error_string(error)); - } - mach_port_deallocate(mach_task_self(), host_port); - - return Py_BuildValue( - "(dddd)", - (double)r_load.cpu_ticks[CPU_STATE_USER] / CLK_TCK, - (double)r_load.cpu_ticks[CPU_STATE_NICE] / CLK_TCK, - (double)r_load.cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK, - (double)r_load.cpu_ticks[CPU_STATE_IDLE] / CLK_TCK - ); -} - - -/* - * Return a Python list of tuple representing per-cpu times - */ -static PyObject * -psutil_per_cpu_times(PyObject *self, PyObject *args) { - natural_t cpu_count; - natural_t i; - processor_info_array_t info_array; - mach_msg_type_number_t info_count; - kern_return_t error; - processor_cpu_load_info_data_t *cpu_load_info = NULL; - int ret; - PyObject *py_retlist = PyList_New(0); - PyObject *py_cputime = NULL; - - if (py_retlist == NULL) - return NULL; - - mach_port_t host_port = mach_host_self(); - error = host_processor_info(host_port, PROCESSOR_CPU_LOAD_INFO, - &cpu_count, &info_array, &info_count); - if (error != KERN_SUCCESS) { - PyErr_Format( - PyExc_RuntimeError, - "host_processor_info(PROCESSOR_CPU_LOAD_INFO) syscall failed: %s", - mach_error_string(error)); - goto error; - } - mach_port_deallocate(mach_task_self(), host_port); - - cpu_load_info = (processor_cpu_load_info_data_t *) info_array; - - for (i = 0; i < cpu_count; i++) { - py_cputime = Py_BuildValue( - "(dddd)", - (double)cpu_load_info[i].cpu_ticks[CPU_STATE_USER] / CLK_TCK, - (double)cpu_load_info[i].cpu_ticks[CPU_STATE_NICE] / CLK_TCK, - (double)cpu_load_info[i].cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK, - (double)cpu_load_info[i].cpu_ticks[CPU_STATE_IDLE] / CLK_TCK - ); - if (!py_cputime) - goto error; - if (PyList_Append(py_retlist, py_cputime)) - goto error; - Py_DECREF(py_cputime); - } - - ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array, - info_count * sizeof(int)); - if (ret != KERN_SUCCESS) - PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); - return py_retlist; - -error: - Py_XDECREF(py_cputime); - Py_DECREF(py_retlist); - if (cpu_load_info != NULL) { - ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array, - info_count * sizeof(int)); - if (ret != KERN_SUCCESS) - PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); - } - return NULL; -} - - -/* - * Retrieve CPU frequency. - */ -static PyObject * -psutil_cpu_freq(PyObject *self, PyObject *args) { - int64_t curr; - int64_t min; - int64_t max; - size_t size = sizeof(int64_t); - - if (sysctlbyname("hw.cpufrequency", &curr, &size, NULL, 0)) - return PyErr_SetFromErrno(PyExc_OSError); - if (sysctlbyname("hw.cpufrequency_min", &min, &size, NULL, 0)) - return PyErr_SetFromErrno(PyExc_OSError); - if (sysctlbyname("hw.cpufrequency_max", &max, &size, NULL, 0)) - return PyErr_SetFromErrno(PyExc_OSError); - - return Py_BuildValue( - "KKK", - curr / 1000 / 1000, - min / 1000 / 1000, - max / 1000 / 1000); -} - - -/* - * 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 result; - size_t result_len = sizeof result; - time_t boot_time = 0; - - if (sysctl(request, 2, &result, &result_len, NULL, 0) == -1) - return PyErr_SetFromErrno(PyExc_OSError); - boot_time = result.tv_sec; - return Py_BuildValue("f", (float)boot_time); -} - -/* - * Return a Python float indicating the value of the temperature - * measured by an SMC key - */ -static PyObject * -psutil_smc_get_temperature(PyObject *self, PyObject *args) { - char* key; - float temp; - - if (! PyArg_ParseTuple(args, "s", &key)) { - return NULL; - } - temp = SMCGetTemperature(key); - return Py_BuildValue("d", temp); -} - - -/* - * Return a Python list of tuples of fan label and speed - */ -static PyObject * -psutil_sensors_fans(PyObject *self, PyObject *args) { - int key; - int speed; - char fan[7]; - int fan_count; - PyObject *py_tuple = NULL; - PyObject *py_retlist = PyList_New(0); - - if (py_retlist == NULL) - return NULL; - - fan_count = SMCGetFanNumber(SMC_KEY_FAN_NUM); - if (fan_count < 0) - fan_count = 0; - - for (key = 0; key < fan_count; key++) { - sprintf(fan, "Fan %d", key); - speed = SMCGetFanSpeed(key); - if (speed < 0) - continue; - py_tuple = Py_BuildValue("(si)", fan, speed); - if (!py_tuple) - goto error; - if (PyList_Append(py_retlist, py_tuple)) - goto error; - Py_XDECREF(py_tuple); - } - - return py_retlist; - -error: - Py_XDECREF(py_tuple); - Py_DECREF(py_retlist); - return NULL; -} - -/* - * 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; - int len; - uint64_t flags; - char opts[400]; - struct statfs *fs = NULL; - PyObject *py_dev = NULL; - PyObject *py_mountp = NULL; - PyObject *py_tuple = NULL; - PyObject *py_retlist = PyList_New(0); - - 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++) { - 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_EXPORTED) - strlcat(opts, ",exported", sizeof(opts)); - if (flags & MNT_QUARANTINE) - strlcat(opts, ",quarantine", sizeof(opts)); - if (flags & MNT_LOCAL) - strlcat(opts, ",local", sizeof(opts)); - if (flags & MNT_QUOTA) - strlcat(opts, ",quota", sizeof(opts)); - if (flags & MNT_ROOTFS) - strlcat(opts, ",rootfs", sizeof(opts)); - if (flags & MNT_DOVOLFS) - strlcat(opts, ",dovolfs", sizeof(opts)); - if (flags & MNT_DONTBROWSE) - strlcat(opts, ",dontbrowse", sizeof(opts)); - if (flags & MNT_IGNORE_OWNERSHIP) - strlcat(opts, ",ignore-ownership", sizeof(opts)); - if (flags & MNT_AUTOMOUNTED) - strlcat(opts, ",automounted", sizeof(opts)); - if (flags & MNT_JOURNALED) - strlcat(opts, ",journaled", sizeof(opts)); - if (flags & MNT_NOUSERXATTR) - strlcat(opts, ",nouserxattr", sizeof(opts)); - if (flags & MNT_DEFWRITE) - strlcat(opts, ",defwrite", sizeof(opts)); - if (flags & MNT_MULTILABEL) - strlcat(opts, ",multilabel", sizeof(opts)); - if (flags & MNT_NOATIME) - strlcat(opts, ",noatime", sizeof(opts)); - if (flags & MNT_UPDATE) - strlcat(opts, ",update", sizeof(opts)); - if (flags & MNT_RELOAD) - strlcat(opts, ",reload", sizeof(opts)); - if (flags & MNT_FORCE) - strlcat(opts, ",force", sizeof(opts)); - if (flags & MNT_CMDFLAGS) - strlcat(opts, ",cmdflags", sizeof(opts)); - - 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_DECREF(py_dev); - Py_DECREF(py_mountp); - Py_DECREF(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 process threads - */ -static PyObject * -psutil_proc_threads(PyObject *self, PyObject *args) { - long pid; - int err, ret; - kern_return_t kr; - unsigned int info_count = TASK_BASIC_INFO_COUNT; - mach_port_t task = MACH_PORT_NULL; - struct task_basic_info tasks_info; - thread_act_port_array_t thread_list = NULL; - thread_info_data_t thinfo_basic; - thread_basic_info_t basic_info_th; - mach_msg_type_number_t thread_count, thread_info_count, j; - - PyObject *py_tuple = NULL; - PyObject *py_retlist = PyList_New(0); - - if (py_retlist == NULL) - return NULL; - - if (! PyArg_ParseTuple(args, "l", &pid)) - goto error; - - if (psutil_task_for_pid(pid, &task) != 0) - goto error; - - info_count = TASK_BASIC_INFO_COUNT; - err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, - &info_count); - if (err != KERN_SUCCESS) { - // errcode 4 is "invalid argument" (access denied) - if (err == 4) { - AccessDenied(""); - } - else { - // otherwise throw a runtime error with appropriate error code - PyErr_Format(PyExc_RuntimeError, - "task_info(TASK_BASIC_INFO) syscall failed"); - } - goto error; - } - - err = task_threads(task, &thread_list, &thread_count); - if (err != KERN_SUCCESS) { - PyErr_Format(PyExc_RuntimeError, "task_threads() syscall failed"); - goto error; - } - - for (j = 0; j < thread_count; j++) { - py_tuple = NULL; - thread_info_count = THREAD_INFO_MAX; - kr = thread_info(thread_list[j], THREAD_BASIC_INFO, - (thread_info_t)thinfo_basic, &thread_info_count); - if (kr != KERN_SUCCESS) { - PyErr_Format(PyExc_RuntimeError, - "thread_info(THREAD_BASIC_INFO) syscall failed"); - goto error; - } - - basic_info_th = (thread_basic_info_t)thinfo_basic; - py_tuple = Py_BuildValue( - "Iff", - j + 1, - basic_info_th->user_time.seconds + \ - (float)basic_info_th->user_time.microseconds / 1000000.0, - basic_info_th->system_time.seconds + \ - (float)basic_info_th->system_time.microseconds / 1000000.0 - ); - if (!py_tuple) - goto error; - if (PyList_Append(py_retlist, py_tuple)) - goto error; - Py_DECREF(py_tuple); - } - - ret = vm_deallocate(task, (vm_address_t)thread_list, - thread_count * sizeof(int)); - if (ret != KERN_SUCCESS) - PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); - - mach_port_deallocate(mach_task_self(), task); - - return py_retlist; - -error: - if (task != MACH_PORT_NULL) - mach_port_deallocate(mach_task_self(), task); - Py_XDECREF(py_tuple); - Py_DECREF(py_retlist); - if (thread_list != NULL) { - ret = vm_deallocate(task, (vm_address_t)thread_list, - thread_count * sizeof(int)); - if (ret != KERN_SUCCESS) - PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); - } - return NULL; -} - - -/* - * Return process open files as a Python tuple. - * References: - * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/m78fd - * - /usr/include/sys/proc_info.h - */ -static PyObject * -psutil_proc_open_files(PyObject *self, PyObject *args) { - long pid; - int pidinfo_result; - int iterations; - int i; - unsigned long nb; - - struct proc_fdinfo *fds_pointer = NULL; - struct proc_fdinfo *fdp_pointer; - struct vnode_fdinfowithpath vi; - - PyObject *py_retlist = PyList_New(0); - PyObject *py_tuple = NULL; - PyObject *py_path = NULL; - - if (py_retlist == NULL) - return NULL; - - if (! PyArg_ParseTuple(args, "l", &pid)) - goto error; - - pidinfo_result = psutil_proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); - if (pidinfo_result <= 0) - goto error; - - fds_pointer = malloc(pidinfo_result); - if (fds_pointer == NULL) { - PyErr_NoMemory(); - goto error; - } - pidinfo_result = psutil_proc_pidinfo( - pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result); - if (pidinfo_result <= 0) - goto error; - - iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE); - - for (i = 0; i < iterations; i++) { - fdp_pointer = &fds_pointer[i]; - - if (fdp_pointer->proc_fdtype == PROX_FDTYPE_VNODE) { - errno = 0; - nb = proc_pidfdinfo((pid_t)pid, - fdp_pointer->proc_fd, - PROC_PIDFDVNODEPATHINFO, - &vi, - sizeof(vi)); - - // --- errors checking - if ((nb <= 0) || nb < sizeof(vi)) { - if ((errno == ENOENT) || (errno == EBADF)) { - // no such file or directory or bad file descriptor; - // let's assume the file has been closed or removed - continue; - } - else { - psutil_raise_for_pid( - pid, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO)"); - goto error; - } - } - // --- /errors checking - - // --- construct python list - py_path = PyUnicode_DecodeFSDefault(vi.pvip.vip_path); - if (! py_path) - goto error; - py_tuple = Py_BuildValue( - "(Oi)", - py_path, - (int)fdp_pointer->proc_fd); - if (!py_tuple) - goto error; - if (PyList_Append(py_retlist, py_tuple)) - goto error; - Py_DECREF(py_tuple); - py_tuple = NULL; - Py_DECREF(py_path); - py_path = NULL; - // --- /construct python list - } - } - - free(fds_pointer); - return py_retlist; - -error: - Py_XDECREF(py_tuple); - Py_XDECREF(py_path); - Py_DECREF(py_retlist); - if (fds_pointer != NULL) - free(fds_pointer); - return NULL; // exception has already been set earlier -} - - -/* - * Return process TCP and UDP connections as a list of tuples. - * Raises NSP in case of zombie process. - * References: - * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/wNrC0 - * - /usr/include/sys/proc_info.h - */ -static PyObject * -psutil_proc_connections(PyObject *self, PyObject *args) { - long pid; - int pidinfo_result; - int iterations; - int i; - unsigned long nb; - - struct proc_fdinfo *fds_pointer = NULL; - struct proc_fdinfo *fdp_pointer; - struct socket_fdinfo si; - - 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; - - 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; - } - - if (pid == 0) - return py_retlist; - pidinfo_result = psutil_proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); - if (pidinfo_result <= 0) - goto error; - - fds_pointer = malloc(pidinfo_result); - if (fds_pointer == NULL) { - PyErr_NoMemory(); - goto error; - } - - pidinfo_result = psutil_proc_pidinfo( - pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result); - if (pidinfo_result <= 0) - goto error; - - iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE); - for (i = 0; i < iterations; i++) { - py_tuple = NULL; - py_laddr = NULL; - py_raddr = NULL; - fdp_pointer = &fds_pointer[i]; - - if (fdp_pointer->proc_fdtype == PROX_FDTYPE_SOCKET) { - errno = 0; - nb = proc_pidfdinfo((pid_t)pid, fdp_pointer->proc_fd, - PROC_PIDFDSOCKETINFO, &si, sizeof(si)); - - // --- errors checking - if ((nb <= 0) || (nb < sizeof(si))) { - if (errno == EBADF) { - // let's assume socket has been closed - continue; - } - else { - psutil_raise_for_pid( - pid, "proc_pidinfo(PROC_PIDFDSOCKETINFO)"); - goto error; - } - } - // --- /errors checking - - // - int fd, family, type, lport, rport, state; - char lip[200], rip[200]; - int inseq; - PyObject *py_family; - PyObject *py_type; - - fd = (int)fdp_pointer->proc_fd; - family = si.psi.soi_family; - type = si.psi.soi_type; - - // apply filters - py_family = PyLong_FromLong((long)family); - inseq = PySequence_Contains(py_af_filter, py_family); - Py_DECREF(py_family); - if (inseq == 0) - continue; - py_type = PyLong_FromLong((long)type); - inseq = PySequence_Contains(py_type_filter, py_type); - Py_DECREF(py_type); - if (inseq == 0) - continue; - - if (errno != 0) { - PyErr_SetFromErrno(PyExc_OSError); - goto error; - } - - if ((family == AF_INET) || (family == AF_INET6)) { - if (family == AF_INET) { - inet_ntop(AF_INET, - &si.psi.soi_proto.pri_tcp.tcpsi_ini. \ - insi_laddr.ina_46.i46a_addr4, - lip, - sizeof(lip)); - inet_ntop(AF_INET, - &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr. \ - ina_46.i46a_addr4, - rip, - sizeof(rip)); - } - else { - inet_ntop(AF_INET6, - &si.psi.soi_proto.pri_tcp.tcpsi_ini. \ - insi_laddr.ina_6, - lip, sizeof(lip)); - inet_ntop(AF_INET6, - &si.psi.soi_proto.pri_tcp.tcpsi_ini. \ - insi_faddr.ina_6, - rip, sizeof(rip)); - } - - // check for inet_ntop failures - if (errno != 0) { - PyErr_SetFromErrno(PyExc_OSError); - goto error; - } - - lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport); - rport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport); - if (type == SOCK_STREAM) - state = (int)si.psi.soi_proto.pri_tcp.tcpsi_state; - else - state = PSUTIL_CONN_NONE; - - 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; - - // construct the python list - py_tuple = Py_BuildValue( - "(iiiNNi)", fd, family, type, py_laddr, py_raddr, state); - if (!py_tuple) - goto error; - if (PyList_Append(py_retlist, py_tuple)) - goto error; - Py_DECREF(py_tuple); - } - else if (family == AF_UNIX) { - py_laddr = PyUnicode_DecodeFSDefault( - si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path); - if (!py_laddr) - goto error; - py_raddr = PyUnicode_DecodeFSDefault( - si.psi.soi_proto.pri_un.unsi_caddr.ua_sun.sun_path); - if (!py_raddr) - goto error; - // construct the python list - py_tuple = Py_BuildValue( - "(iiiOOi)", - fd, family, type, - py_laddr, - py_raddr, - PSUTIL_CONN_NONE); - if (!py_tuple) - goto error; - if (PyList_Append(py_retlist, py_tuple)) - goto error; - Py_DECREF(py_tuple); - Py_DECREF(py_laddr); - Py_DECREF(py_raddr); - } - } - } - - free(fds_pointer); - return py_retlist; - -error: - Py_XDECREF(py_tuple); - Py_XDECREF(py_laddr); - Py_XDECREF(py_raddr); - Py_DECREF(py_retlist); - if (fds_pointer != NULL) - free(fds_pointer); - return NULL; -} - - -/* - * Return number of file descriptors opened by process. - * Raises NSP in case of zombie process. - */ -static PyObject * -psutil_proc_num_fds(PyObject *self, PyObject *args) { - long pid; - int pidinfo_result; - int num; - struct proc_fdinfo *fds_pointer; - - if (! PyArg_ParseTuple(args, "l", &pid)) - return NULL; - - pidinfo_result = proc_pidinfo((pid_t)pid, PROC_PIDLISTFDS, 0, NULL, 0); - if (pidinfo_result <= 0) - return PyErr_SetFromErrno(PyExc_OSError); - - fds_pointer = malloc(pidinfo_result); - if (fds_pointer == NULL) - return PyErr_NoMemory(); - pidinfo_result = proc_pidinfo((pid_t)pid, PROC_PIDLISTFDS, 0, fds_pointer, - pidinfo_result); - if (pidinfo_result <= 0) { - free(fds_pointer); - return PyErr_SetFromErrno(PyExc_OSError); - } - - num = (pidinfo_result / PROC_PIDLISTFD_SIZE); - free(fds_pointer); - return Py_BuildValue("i", num); -} - - -/* - * 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_IFLIST2; // 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; ) { - ifm = (struct if_msghdr *)next; - next += ifm->ifm_msglen; - - if (ifm->ifm_type == RTM_IFINFO2) { - py_ifc_info = NULL; - struct if_msghdr2 *if2m = (struct if_msghdr2 *)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; - - 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) { - CFDictionaryRef parent_dict; - CFDictionaryRef props_dict; - CFDictionaryRef stats_dict; - io_registry_entry_t parent; - io_registry_entry_t disk; - io_iterator_t disk_list; - PyObject *py_retdict = PyDict_New(); - PyObject *py_disk_info = NULL; - - if (py_retdict == NULL) - return NULL; - - // Get list of disks - if (IOServiceGetMatchingServices(kIOMasterPortDefault, - IOServiceMatching(kIOMediaClass), - &disk_list) != kIOReturnSuccess) { - PyErr_SetString( - PyExc_RuntimeError, "unable to get the list of disks."); - goto error; - } - - // Iterate over disks - while ((disk = IOIteratorNext(disk_list)) != 0) { - py_disk_info = NULL; - parent_dict = NULL; - props_dict = NULL; - stats_dict = NULL; - - if (IORegistryEntryGetParentEntry(disk, kIOServicePlane, &parent) - != kIOReturnSuccess) { - PyErr_SetString(PyExc_RuntimeError, - "unable to get the disk's parent."); - IOObjectRelease(disk); - goto error; - } - - if (IOObjectConformsTo(parent, "IOBlockStorageDriver")) { - if (IORegistryEntryCreateCFProperties( - disk, - (CFMutableDictionaryRef *) &parent_dict, - kCFAllocatorDefault, - kNilOptions - ) != kIOReturnSuccess) - { - PyErr_SetString(PyExc_RuntimeError, - "unable to get the parent's properties."); - IOObjectRelease(disk); - IOObjectRelease(parent); - goto error; - } - - if (IORegistryEntryCreateCFProperties( - parent, - (CFMutableDictionaryRef *) &props_dict, - kCFAllocatorDefault, - kNilOptions - ) != kIOReturnSuccess) - { - PyErr_SetString(PyExc_RuntimeError, - "unable to get the disk properties."); - CFRelease(props_dict); - IOObjectRelease(disk); - IOObjectRelease(parent); - goto error; - } - - const int kMaxDiskNameSize = 64; - CFStringRef disk_name_ref = (CFStringRef)CFDictionaryGetValue( - parent_dict, CFSTR(kIOBSDNameKey)); - char disk_name[kMaxDiskNameSize]; - - CFStringGetCString(disk_name_ref, - disk_name, - kMaxDiskNameSize, - CFStringGetSystemEncoding()); - - stats_dict = (CFDictionaryRef)CFDictionaryGetValue( - props_dict, CFSTR(kIOBlockStorageDriverStatisticsKey)); - - if (stats_dict == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "Unable to get disk stats."); - goto error; - } - - CFNumberRef number; - int64_t reads = 0; - int64_t writes = 0; - int64_t read_bytes = 0; - int64_t write_bytes = 0; - int64_t read_time = 0; - int64_t write_time = 0; - - // Get disk reads/writes - if ((number = (CFNumberRef)CFDictionaryGetValue( - stats_dict, - CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) - { - CFNumberGetValue(number, kCFNumberSInt64Type, &reads); - } - if ((number = (CFNumberRef)CFDictionaryGetValue( - stats_dict, - CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) - { - CFNumberGetValue(number, kCFNumberSInt64Type, &writes); - } - - // Get disk bytes read/written - if ((number = (CFNumberRef)CFDictionaryGetValue( - stats_dict, - CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) - { - CFNumberGetValue(number, kCFNumberSInt64Type, &read_bytes); - } - if ((number = (CFNumberRef)CFDictionaryGetValue( - stats_dict, - CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) - { - CFNumberGetValue(number, kCFNumberSInt64Type, &write_bytes); - } - - // Get disk time spent reading/writing (nanoseconds) - if ((number = (CFNumberRef)CFDictionaryGetValue( - stats_dict, - CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey)))) - { - CFNumberGetValue(number, kCFNumberSInt64Type, &read_time); - } - if ((number = (CFNumberRef)CFDictionaryGetValue( - stats_dict, - CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) - { - CFNumberGetValue(number, kCFNumberSInt64Type, &write_time); - } - - // Read/Write time on OS X comes back in nanoseconds and in psutil - // we've standardized on milliseconds so do the conversion. - py_disk_info = Py_BuildValue( - "(KKKKKK)", - reads, - writes, - read_bytes, - write_bytes, - read_time / 1000 / 1000, - write_time / 1000 / 1000); - if (!py_disk_info) - goto error; - if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info)) - goto error; - Py_DECREF(py_disk_info); - - CFRelease(parent_dict); - IOObjectRelease(parent); - CFRelease(props_dict); - IOObjectRelease(disk); - } - } - - IOObjectRelease (disk_list); - - return py_retdict; - -error: - Py_XDECREF(py_disk_info); - Py_DECREF(py_retdict); - return NULL; -} - - -/* - * Return currently connected users as a list of tuples. - */ -static PyObject * -psutil_users(PyObject *self, PyObject *args) { - struct utmpx *utx; - PyObject *py_username = NULL; - PyObject *py_tty = NULL; - PyObject *py_hostname = NULL; - PyObject *py_tuple = NULL; - PyObject *py_retlist = PyList_New(0); - - if (py_retlist == NULL) - return NULL; - 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; - py_tuple = Py_BuildValue( - "(OOOfi)", - py_username, // username - py_tty, // tty - py_hostname, // hostname - (float)utx->ut_tv.tv_sec, // start time - utx->ut_pid // process id - ); - if (!py_tuple) { - endutxent(); - goto error; - } - if (PyList_Append(py_retlist, py_tuple)) { - endutxent(); - goto error; - } - Py_DECREF(py_username); - Py_DECREF(py_tty); - Py_DECREF(py_hostname); - Py_DECREF(py_tuple); - } - - endutxent(); - return py_retlist; - -error: - Py_XDECREF(py_username); - Py_XDECREF(py_tty); - Py_XDECREF(py_hostname); - Py_XDECREF(py_tuple); - Py_DECREF(py_retlist); - return NULL; -} - - -/* - * Return CPU statistics. - */ -static PyObject * -psutil_cpu_stats(PyObject *self, PyObject *args) { - struct vmmeter vmstat; - kern_return_t ret; - mach_msg_type_number_t count = sizeof(vmstat) / sizeof(integer_t); - mach_port_t mport = mach_host_self(); - - ret = host_statistics(mport, HOST_VM_INFO, (host_info_t)&vmstat, &count); - if (ret != KERN_SUCCESS) { - PyErr_Format( - PyExc_RuntimeError, - "host_statistics(HOST_VM_INFO) failed: %s", - mach_error_string(ret)); - return NULL; - } - mach_port_deallocate(mach_task_self(), mport); - - return Py_BuildValue( - "IIIII", - vmstat.v_swtch, // ctx switches - vmstat.v_intr, // interrupts - vmstat.v_soft, // software interrupts - vmstat.v_syscall, // syscalls - vmstat.v_trap // traps - ); -} - - - -/* - * Return battery information. - */ -static PyObject * -psutil_sensors_battery(PyObject *self, PyObject *args) { - PyObject *py_tuple = NULL; - CFTypeRef power_info = NULL; - CFArrayRef power_sources_list = NULL; - CFDictionaryRef power_sources_information = NULL; - CFNumberRef capacity_ref = NULL; - CFNumberRef time_to_empty_ref = NULL; - CFStringRef ps_state_ref = NULL; - uint32_t capacity; /* units are percent */ - int time_to_empty; /* units are minutes */ - int is_power_plugged; - - power_info = IOPSCopyPowerSourcesInfo(); - - if (!power_info) { - PyErr_SetString(PyExc_RuntimeError, - "IOPSCopyPowerSourcesInfo() syscall failed"); - goto error; - } - - power_sources_list = IOPSCopyPowerSourcesList(power_info); - if (!power_sources_list) { - PyErr_SetString(PyExc_RuntimeError, - "IOPSCopyPowerSourcesList() syscall failed"); - goto error; - } - - /* Should only get one source. But in practice, check for > 0 sources */ - if (!CFArrayGetCount(power_sources_list)) { - PyErr_SetString(PyExc_NotImplementedError, "no battery"); - goto error; - } - - power_sources_information = IOPSGetPowerSourceDescription( - power_info, CFArrayGetValueAtIndex(power_sources_list, 0)); - - capacity_ref = (CFNumberRef) CFDictionaryGetValue( - power_sources_information, CFSTR(kIOPSCurrentCapacityKey)); - if (!CFNumberGetValue(capacity_ref, kCFNumberSInt32Type, &capacity)) { - PyErr_SetString(PyExc_RuntimeError, - "No battery capacity infomration in power sources info"); - goto error; - } - - ps_state_ref = (CFStringRef) CFDictionaryGetValue( - power_sources_information, CFSTR(kIOPSPowerSourceStateKey)); - is_power_plugged = CFStringCompare( - ps_state_ref, CFSTR(kIOPSACPowerValue), 0) - == kCFCompareEqualTo; - - time_to_empty_ref = (CFNumberRef) CFDictionaryGetValue( - power_sources_information, CFSTR(kIOPSTimeToEmptyKey)); - if (!CFNumberGetValue(time_to_empty_ref, - kCFNumberIntType, &time_to_empty)) { - /* This value is recommended for non-Apple power sources, so it's not - * an error if it doesn't exist. We'll return -1 for "unknown" */ - /* A value of -1 indicates "Still Calculating the Time" also for - * apple power source */ - time_to_empty = -1; - } - - py_tuple = Py_BuildValue("Iii", - capacity, time_to_empty, is_power_plugged); - if (!py_tuple) { - goto error; - } - - CFRelease(power_info); - CFRelease(power_sources_list); - /* Caller should NOT release power_sources_information */ - - return py_tuple; - -error: - if (power_info) - CFRelease(power_info); - if (power_sources_list) - CFRelease(power_sources_list); - Py_XDECREF(py_tuple); - return NULL; -} - - -/* - * define the psutil C module methods and initialize the module. - */ -static PyMethodDef -PsutilMethods[] = { - // --- per-process functions - - {"proc_kinfo_oneshot", psutil_proc_kinfo_oneshot, METH_VARARGS, - "Return multiple process info."}, - {"proc_pidtaskinfo_oneshot", psutil_proc_pidtaskinfo_oneshot, METH_VARARGS, - "Return multiple process info."}, - {"proc_name", 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_environ", psutil_proc_environ, METH_VARARGS, - "Return process environment data"}, - {"proc_exe", psutil_proc_exe, METH_VARARGS, - "Return path of the process executable"}, - {"proc_cwd", psutil_proc_cwd, METH_VARARGS, - "Return process current working directory."}, - {"proc_memory_uss", psutil_proc_memory_uss, METH_VARARGS, - "Return process USS memory"}, - {"proc_threads", psutil_proc_threads, METH_VARARGS, - "Return process threads as a list of tuples"}, - {"proc_open_files", psutil_proc_open_files, METH_VARARGS, - "Return files opened by process as a list of tuples"}, - {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS, - "Return the number of fds opened by process."}, - {"proc_connections", psutil_proc_connections, METH_VARARGS, - "Get process TCP and UDP connections as a list of tuples"}, - {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, - "Return a list of tuples for every process's memory map"}, - - // --- 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 number of physical CPUs on the system"}, - {"virtual_mem", psutil_virtual_mem, METH_VARARGS, - "Return system virtual memory stats"}, - {"swap_mem", psutil_swap_mem, METH_VARARGS, - "Return stats about swap memory, in bytes"}, - {"cpu_times", psutil_cpu_times, METH_VARARGS, - "Return system cpu times as a tuple (user, system, nice, idle, irc)"}, - {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS, - "Return system per-cpu times as a list of tuples"}, - {"cpu_freq", psutil_cpu_freq, METH_VARARGS, - "Return cpu current frequency"}, - {"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 dict of tuples of disks I/O information."}, - {"users", psutil_users, METH_VARARGS, - "Return currently connected users as a list of tuples"}, - {"cpu_stats", psutil_cpu_stats, METH_VARARGS, - "Return CPU statistics"}, - {"smc_get_temperature", psutil_smc_get_temperature, METH_VARARGS, - "Temperature of SMC key as float"}, - {"sensors_fans", psutil_sensors_fans, METH_VARARGS, - "Return the RPM of the fan with SMC key"}, - {"sensors_battery", psutil_sensors_battery, METH_VARARGS, - "Return battery information."}, - - // --- others - {"set_testing", psutil_set_testing, METH_NOARGS, - "Set psutil in testing mode"}, - - {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_osx_traverse(PyObject *m, visitproc visit, void *arg) { - Py_VISIT(GETSTATE(m)->error); - return 0; -} - -static int -psutil_osx_clear(PyObject *m) { - Py_CLEAR(GETSTATE(m)->error); - return 0; -} - - -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "psutil_osx", - NULL, - sizeof(struct module_state), - PsutilMethods, - NULL, - psutil_osx_traverse, - psutil_osx_clear, - NULL -}; - -#define INITERROR return NULL - -PyMODINIT_FUNC PyInit__psutil_osx(void) - -#else -#define INITERROR return - -void -init_psutil_osx(void) -#endif -{ -#if PY_MAJOR_VERSION >= 3 - PyObject *module = PyModule_Create(&moduledef); -#else - PyObject *module = Py_InitModule("_psutil_osx", PsutilMethods); -#endif - PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); - // process status constants, defined in: - // http://fxr.watson.org/fxr/source/bsd/sys/proc.h?v=xnu-792.6.70#L149 - 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); - // 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); - - // Exception. - ZombieProcessError = PyErr_NewException( - "_psutil_osx.ZombieProcessError", NULL, NULL); - Py_INCREF(ZombieProcessError); - PyModule_AddObject(module, "ZombieProcessError", ZombieProcessError); - - psutil_setup(); - - if (module == NULL) - INITERROR; -#if PY_MAJOR_VERSION >= 3 - return module; -#endif -} |