diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2016-01-11 06:28:34 +0000 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2016-01-11 06:28:34 +0000 |
commit | bcb0c84c9c1a173915a9d2d7aa1e8e930a3e0dfe (patch) | |
tree | 0f15fea4bb32f37b4a4bb6c87fe8c9b24637ef28 | |
parent | d7805262b79cac9c0540f37b1b47f5c36e6efeaa (diff) | |
parent | 116fc6a3436704abb71743a8dd2ef747666af6b8 (diff) | |
download | psutil-bcb0c84c9c1a173915a9d2d7aa1e8e930a3e0dfe.tar.gz |
Merge branch '0-wiz-0-master' of github.com:giampaolo/psutil into 0-wiz-0-master
-rw-r--r-- | docs/index.rst | 14 | ||||
-rw-r--r-- | psutil/__init__.py | 8 | ||||
-rw-r--r-- | psutil/_common.py | 7 | ||||
-rw-r--r-- | psutil/_psbsd.py | 132 | ||||
-rw-r--r-- | psutil/_psutil_bsd.c | 206 | ||||
-rw-r--r-- | psutil/_psutil_posix.c | 10 | ||||
-rw-r--r-- | psutil/arch/bsd/netbsd.c | 649 | ||||
-rw-r--r-- | psutil/arch/bsd/netbsd.h | 29 | ||||
-rw-r--r-- | psutil/arch/bsd/netbsd_socks.c | 515 | ||||
-rw-r--r-- | psutil/arch/bsd/netbsd_socks.h | 10 | ||||
-rw-r--r-- | psutil/arch/bsd/openbsd.c | 11 | ||||
-rw-r--r-- | setup.py | 13 | ||||
-rw-r--r-- | test/_posix.py | 6 | ||||
-rw-r--r-- | test/test_psutil.py | 7 |
14 files changed, 1498 insertions, 119 deletions
diff --git a/docs/index.rst b/docs/index.rst index 3a5f8e62..68e3e5d0 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,6 +8,7 @@ Old 1.2.1 documentation is still available `here <https://code.google.com/p/psutil/wiki/Documentation>`__. .. versionchanged:: 3.3.0 added support for OpenBSD +.. versionchanged:: 3.4.0 added support for NetBSD psutil documentation ==================== @@ -206,7 +207,7 @@ Memory * **sout**: the number of bytes the system has swapped out from disk (cumulative) - **sin** and **sout** on Windows are meaningless and are always set to ``0``. + **sin** and **sout** on Windows and OpenBSD are always set to ``0``. See `examples/meminfo.py <https://github.com/giampaolo/psutil/blob/master/examples/meminfo.py>`__ script providing an example on how to convert bytes in a human readable form. @@ -1043,7 +1044,7 @@ Process class ...] >>> - Availability: All platforms except OpenBSD. + Availability: All platforms except OpenBSD and NetBSD. .. method:: children(recursive=False) @@ -1302,13 +1303,16 @@ Constants STATUS_DEAD STATUS_WAKE_KILL STATUS_WAKING - STATUS_IDLE - STATUS_LOCKED - STATUS_WAITING + STATUS_IDLE (OSX, FreeBSD) + STATUS_LOCKED (FreeBSD) + STATUS_WAITING (FreeBSD) + STATUS_SUSPENDED (NetBSD) A set of strings representing the status of a process. Returned by :meth:`psutil.Process.status()`. + .. versionadded:: 3.4.0: STATUS_SUSPENDED (NetBSD) + .. _const-conn: .. data:: CONN_ESTABLISHED CONN_SYN_SENT diff --git a/psutil/__init__.py b/psutil/__init__.py index d825d892..f7b4b238 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -123,7 +123,9 @@ elif sys.platform.startswith("win32"): elif sys.platform.startswith("darwin"): from . import _psosx as _psplatform -elif sys.platform.startswith("freebsd") or sys.platform.startswith("openbsd"): +elif sys.platform.startswith("freebsd") or \ + sys.platform.startswith("openbsd") or \ + sys.platform.startswith("netbsd"): from . import _psbsd as _psplatform elif sys.platform.startswith("sunos"): @@ -968,7 +970,9 @@ class Process(object): except ZeroDivisionError: return 0.0 - if not _OPENBSD: + if hasattr(_psplatform.Process, "memory_maps"): + # Available everywhere except OpenBSD and NetBSD. + def memory_maps(self, grouped=True): """Return process' mapped memory regions as a list of namedtuples whose fields are variable depending on the platform. diff --git a/psutil/_common.py b/psutil/_common.py index 73ac07bc..3ff1cb88 100644 --- a/psutil/_common.py +++ b/psutil/_common.py @@ -43,9 +43,10 @@ STATUS_ZOMBIE = "zombie" STATUS_DEAD = "dead" STATUS_WAKE_KILL = "wake-kill" STATUS_WAKING = "waking" -STATUS_IDLE = "idle" # BSD -STATUS_LOCKED = "locked" # BSD -STATUS_WAITING = "waiting" # BSD +STATUS_IDLE = "idle" # FreeBSD, OSX +STATUS_LOCKED = "locked" # FreeBSD +STATUS_WAITING = "waiting" # FreeBSD +STATUS_SUSPENDED = "suspended" # NetBSD CONN_ESTABLISHED = "ESTABLISHED" CONN_SYN_SENT = "SYN_SENT" diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index a772e264..c73f7c8b 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -28,6 +28,7 @@ __extra__all__ = [] FREEBSD = sys.platform.startswith("freebsd") OPENBSD = sys.platform.startswith("openbsd") +NETBSD = sys.platform.startswith("netbsd") if FREEBSD: PROC_STATUSES = { @@ -39,7 +40,7 @@ if FREEBSD: cext.SWAIT: _common.STATUS_WAITING, cext.SLOCK: _common.STATUS_LOCKED, } -elif OPENBSD: +elif OPENBSD or NETBSD: PROC_STATUSES = { cext.SIDL: _common.STATUS_IDLE, cext.SSLEEP: _common.STATUS_SLEEPING, @@ -50,6 +51,7 @@ elif OPENBSD: # psutil.STATUS_DEAD. SDEAD really means STATUS_ZOMBIE. # cext.SZOMB: _common.STATUS_ZOMBIE, cext.SDEAD: _common.STATUS_ZOMBIE, + cext.SZOMB: _common.STATUS_ZOMBIE, # From http://www.eecs.harvard.edu/~margo/cs161/videos/proc.h.txt # OpenBSD has SRUN and SONPROC: SRUN indicates that a process # is runnable but *not* yet running, i.e. is on a run queue. @@ -61,6 +63,9 @@ elif OPENBSD: cext.SONPROC: _common.STATUS_RUNNING, } +if NETBSD: + PROC_STATUSES[cext.SSUSPENDED] = _common.STATUS_SUSPENDED + TCP_STATUSES = { cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED, cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT, @@ -76,7 +81,10 @@ TCP_STATUSES = { cext.PSUTIL_CONN_NONE: _common.CONN_NONE, } -PAGESIZE = os.sysconf("SC_PAGE_SIZE") +if NETBSD: + PAGESIZE = os.sysconf("SC_PAGESIZE") +else: + PAGESIZE = os.sysconf("SC_PAGE_SIZE") AF_LINK = cext_posix.AF_LINK # extend base mem ntuple with BSD-specific memory metrics @@ -156,9 +164,9 @@ def cpu_count_logical(): return cext.cpu_count_logical() -if OPENBSD: +if OPENBSD or NETBSD: def cpu_count_physical(): - # OpenBSD does not implement this. + # OpenBSD and NetBSD do not implement this. return 1 if cpu_count_logical() == 1 else None else: def cpu_count_physical(): @@ -273,7 +281,7 @@ def net_if_stats(): return ret -if OPENBSD: +if OPENBSD or NETBSD: def pid_exists(pid): exists = _psposix.pid_exists(pid) if not exists: @@ -333,7 +341,7 @@ class Process(object): @wrap_exceptions def exe(self): - if FREEBSD: + if FREEBSD or NETBSD: return cext.proc_exe(self.pid) else: # exe cannot be determined on OpenBSD; references: @@ -351,7 +359,19 @@ class Process(object): def cmdline(self): if OPENBSD and self.pid == 0: return None # ...else it crashes - return cext.proc_cmdline(self.pid) + elif NETBSD: + try: + return cext.proc_cmdline(self.pid) + except OSError as err: + if err.errno == errno.EINVAL: + if not pid_exists(self.pid): + raise NoSuchProcess(self.pid, self._name) + else: + raise ZombieProcess(self.pid, self._name, self._ppid) + else: + raise + else: + return cext.proc_cmdline(self.pid) @wrap_exceptions def terminal(self): @@ -426,6 +446,28 @@ class Process(object): if kind not in conn_tmap: raise ValueError("invalid %r kind argument; choose between %s" % (kind, ', '.join([repr(x) for x in conn_tmap]))) + + if NETBSD: + families, types = conn_tmap[kind] + ret = set() + rawlist = cext.proc_connections(self.pid) + for item in rawlist: + fd, fam, type, laddr, raddr, status = item + if fam in families and type in types: + try: + status = TCP_STATUSES[status] + except KeyError: + status = TCP_STATUSES[cext.PSUTIL_CONN_NONE] + fam = sockfam_to_enum(fam) + type = socktype_to_enum(type) + nt = _common.pconn(fd, fam, type, laddr, raddr, status) + ret.add(nt) + # On NetBSD the underlying C function does not raise NSP + # in case the process is gone (and the returned list may + # incomplete). + self.name() # raise NSP if the process disappeared on us + return list(ret) + families, types = conn_tmap[kind] rawlist = cext.proc_connections(self.pid, families, types) ret = [] @@ -464,59 +506,80 @@ class Process(object): @wrap_exceptions def status(self): code = cext.proc_status(self.pid) - if code in PROC_STATUSES: - return PROC_STATUSES[code] - # XXX is this legit? will we even ever get here? - return "?" + # XXX is '?' legit? (we're not supposed to return it anyway) + return PROC_STATUSES.get(code, '?') @wrap_exceptions def io_counters(self): rc, wc, rb, wb = cext.proc_io_counters(self.pid) return _common.pio(rc, wc, rb, wb) + @wrap_exceptions + def cwd(self): + """Return process current working directory.""" + # sometimes we get an empty string, in which case we turn + # it into None + if OPENBSD and self.pid == 0: + return None # ...else it would raise EINVAL + elif NETBSD: + try: + return os.readlink("/proc/%s/cwd" % self.pid) + except OSError as err: + if err.errno == errno.ENOENT: + if not pid_exists(self.pid): + raise NoSuchProcess(self.pid, self._name) + else: + raise ZombieProcess( + self.pid, self._name, self._ppid) + else: + raise + elif hasattr(cext, 'proc_open_files'): + # FreeBSD < 8 does not support functions based on + # kinfo_getfile() and kinfo_getvmmap() + return cext.proc_cwd(self.pid) or None + else: + raise NotImplementedError( + "supported only starting from FreeBSD 8" if + FREEBSD else "") + nt_mmap_grouped = namedtuple( 'mmap', 'path rss, private, ref_count, shadow_count') nt_mmap_ext = namedtuple( 'mmap', 'addr, perms path rss, private, ref_count, shadow_count') + def _not_implemented(self): + raise NotImplementedError + # FreeBSD < 8 does not support functions based on kinfo_getfile() # and kinfo_getvmmap() if hasattr(cext, 'proc_open_files'): - @wrap_exceptions def open_files(self): """Return files opened by process as a list of namedtuples.""" rawlist = cext.proc_open_files(self.pid) return [_common.popenfile(path, fd) for path, fd in rawlist] + else: + open_files = _not_implemented - @wrap_exceptions - def cwd(self): - """Return process current working directory.""" - # sometimes we get an empty string, in which case we turn - # it into None - if OPENBSD and self.pid == 0: - return None # ...else raises EINVAL - return cext.proc_cwd(self.pid) or None - - @wrap_exceptions - def memory_maps(self): - return cext.proc_memory_maps(self.pid) - + # FreeBSD < 8 does not support functions based on kinfo_getfile() + # and kinfo_getvmmap() + if hasattr(cext, 'proc_num_fds'): @wrap_exceptions def num_fds(self): """Return the number of file descriptors opened by this process.""" - return cext.proc_num_fds(self.pid) - + ret = cext.proc_num_fds(self.pid) + if NETBSD: + # On NetBSD the underlying C function does not raise NSP + # in case the process is gone. + self.name() # raise NSP if the process disappeared on us + return ret else: - def _not_implemented(self): - raise NotImplementedError("supported only starting from FreeBSD 8") - - open_files = _not_implemented - proc_cwd = _not_implemented - memory_maps = _not_implemented num_fds = _not_implemented + # --- FreeBSD only APIs + if FREEBSD: + @wrap_exceptions def cpu_affinity_get(self): return cext.proc_cpu_affinity_get(self.pid) @@ -545,3 +608,6 @@ class Process(object): "invalid CPU #%i (choose between %s)" % ( cpu, allcpus)) raise + + def memory_maps(self): + return cext.proc_memory_maps(self.pid) diff --git a/psutil/_psutil_bsd.c b/psutil/_psutil_bsd.c index 278504f8..5d22d881 100644 --- a/psutil/_psutil_bsd.c +++ b/psutil/_psutil_bsd.c @@ -9,12 +9,15 @@ * OpenBSD references: * - OpenBSD source code: http://anoncvs.spacehopper.org/openbsd-src/ * - * OpenBSD: missing compared to FreeBSD implementation: + * 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(__NetBSD__) +#define _KMEMUSER +#endif #include <Python.h> #include <assert.h> @@ -42,6 +45,7 @@ #include <netinet/in_pcb.h> #include <netinet/tcp.h> #include <netinet/tcp_timer.h> +#include <netinet/ip_var.h> #include <netinet/tcp_var.h> // for struct xtcpcb #include <netinet/tcp_fsm.h> // for TCP connection states #include <arpa/inet.h> // for inet_ntop() @@ -63,6 +67,9 @@ #include "arch/bsd/freebsd_socks.h" #elif __OpenBSD__ #include "arch/bsd/openbsd.h" +#elif __NetBSD__ + #include "arch/bsd/netbsd.h" + #include "arch/bsd/netbsd_socks.h" #endif #ifdef __FreeBSD__ @@ -85,6 +92,16 @@ #include <sys/sched.h> // for CPUSTATES & CP_* #endif +#if defined(__NetBSD__) + #include <utmpx.h> + #include <sys/vnode.h> // for VREG + #include <sys/sched.h> // for CPUSTATES & CP_* + #include <machine/vmparam.h> // for PAGE_SHIFT +#define _KERNEL + #include <uvm/uvm_extern.h> +#undef _KERNEL +#endif + // convert a timeval struct to a double #define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) @@ -95,7 +112,7 @@ (uint32_t) (bt.frac >> 32) ) >> 32 ) / 1000000) #endif -#ifdef __OpenBSD__ +#if defined(__OpenBSD__) || defined (__NetBSD__) #define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) #endif @@ -125,7 +142,7 @@ psutil_pids(PyObject *self, PyObject *args) { for (idx = 0; idx < num_processes; idx++) { #ifdef __FreeBSD__ py_pid = Py_BuildValue("i", proclist->ki_pid); -#elif __OpenBSD__ +#elif defined(__OpenBSD__) || defined(__NetBSD__) py_pid = Py_BuildValue("i", proclist->p_pid); #endif if (!py_pid) @@ -174,14 +191,14 @@ psutil_boot_time(PyObject *self, PyObject *args) { static PyObject * psutil_proc_name(PyObject *self, PyObject *args) { long pid; - struct kinfo_proc kp; + kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; #ifdef __FreeBSD__ return Py_BuildValue("s", kp.ki_comm); -#elif __OpenBSD__ +#elif defined(__OpenBSD__) || defined(__NetBSD__) return Py_BuildValue("s", kp.p_comm); #endif } @@ -213,14 +230,14 @@ psutil_proc_cmdline(PyObject *self, PyObject *args) { static PyObject * psutil_proc_ppid(PyObject *self, PyObject *args) { long pid; - struct kinfo_proc kp; + kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; #ifdef __FreeBSD__ return Py_BuildValue("l", (long)kp.ki_ppid); -#elif __OpenBSD__ +#elif defined(__OpenBSD__) || defined(__NetBSD__) return Py_BuildValue("l", (long)kp.p_ppid); #endif } @@ -232,14 +249,14 @@ psutil_proc_ppid(PyObject *self, PyObject *args) { static PyObject * psutil_proc_status(PyObject *self, PyObject *args) { long pid; - struct kinfo_proc kp; + kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; #ifdef __FreeBSD__ return Py_BuildValue("i", (int)kp.ki_stat); -#elif __OpenBSD__ +#elif defined(__OpenBSD__) || defined(__NetBSD__) return Py_BuildValue("i", (int)kp.p_stat); #endif } @@ -252,7 +269,7 @@ psutil_proc_status(PyObject *self, PyObject *args) { static PyObject * psutil_proc_uids(PyObject *self, PyObject *args) { long pid; - struct kinfo_proc kp; + kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) @@ -262,7 +279,7 @@ psutil_proc_uids(PyObject *self, PyObject *args) { (long)kp.ki_ruid, (long)kp.ki_uid, (long)kp.ki_svuid); -#elif __OpenBSD__ +#elif defined(__OpenBSD__) || defined(__NetBSD__) (long)kp.p_ruid, (long)kp.p_uid, (long)kp.p_svuid); @@ -277,7 +294,7 @@ psutil_proc_uids(PyObject *self, PyObject *args) { static PyObject * psutil_proc_gids(PyObject *self, PyObject *args) { long pid; - struct kinfo_proc kp; + kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) @@ -287,7 +304,7 @@ psutil_proc_gids(PyObject *self, PyObject *args) { (long)kp.ki_rgid, (long)kp.ki_groups[0], (long)kp.ki_svuid); -#elif __OpenBSD__ +#elif defined(__OpenBSD__) || defined(__NetBSD__) (long)kp.p_rgid, (long)kp.p_groups[0], (long)kp.p_svuid); @@ -302,14 +319,14 @@ psutil_proc_gids(PyObject *self, PyObject *args) { static PyObject * psutil_proc_tty_nr(PyObject *self, PyObject *args) { long pid; - struct kinfo_proc kp; + kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; #ifdef __FreeBSD__ return Py_BuildValue("i", kp.ki_tdev); -#elif __OpenBSD__ +#elif defined(__OpenBSD__) || defined(__NetBSD__) return Py_BuildValue("i", kp.p_tdev); #endif } @@ -321,7 +338,7 @@ psutil_proc_tty_nr(PyObject *self, PyObject *args) { static PyObject * psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) { long pid; - struct kinfo_proc kp; + kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) @@ -330,7 +347,7 @@ psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) { #ifdef __FreeBSD__ kp.ki_rusage.ru_nvcsw, kp.ki_rusage.ru_nivcsw); -#elif __OpenBSD__ +#elif defined(__OpenBSD__) || defined(__NetBSD__) kp.p_uru_nvcsw, kp.p_uru_nivcsw); #endif @@ -344,7 +361,7 @@ static PyObject * psutil_proc_cpu_times(PyObject *self, PyObject *args) { long pid; double user_t, sys_t; - struct kinfo_proc kp; + kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) @@ -353,7 +370,7 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args) { #ifdef __FreeBSD__ user_t = PSUTIL_TV2DOUBLE(kp.ki_rusage.ru_utime); sys_t = PSUTIL_TV2DOUBLE(kp.ki_rusage.ru_stime); -#elif __OpenBSD__ +#elif defined(__OpenBSD__) || defined(__NetBSD__) user_t = PSUTIL_KPT2DOUBLE(kp.p_uutime); sys_t = PSUTIL_KPT2DOUBLE(kp.p_ustime); #endif @@ -389,14 +406,14 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args) { static PyObject * psutil_proc_create_time(PyObject *self, PyObject *args) { long pid; - struct kinfo_proc kp; + kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; #ifdef __FreeBSD__ return Py_BuildValue("d", PSUTIL_TV2DOUBLE(kp.ki_start)); -#elif __OpenBSD__ +#elif defined(__OpenBSD__) || defined(__NetBSD__) return Py_BuildValue("d", PSUTIL_KPT2DOUBLE(kp.p_ustart)); #endif } @@ -409,7 +426,7 @@ psutil_proc_create_time(PyObject *self, PyObject *args) { static PyObject * psutil_proc_io_counters(PyObject *self, PyObject *args) { long pid; - struct kinfo_proc kp; + kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) @@ -419,7 +436,7 @@ psutil_proc_io_counters(PyObject *self, PyObject *args) { #ifdef __FreeBSD__ kp.ki_rusage.ru_inblock, kp.ki_rusage.ru_oublock, -#elif __OpenBSD__ +#elif defined(__OpenBSD__) || defined(__NetBSD__) kp.p_uru_inblock, kp.p_uru_oublock, #endif @@ -428,8 +445,8 @@ psutil_proc_io_counters(PyObject *self, PyObject *args) { } -#ifdef __OpenBSD__ -#define ptoa(x) ((paddr_t)(x) << PAGE_SHIFT) +#if defined(__OpenBSD__) || defined(__NetBSD__) + #define ptoa(x) ((paddr_t)(x) << PAGE_SHIFT) #endif /* @@ -438,28 +455,37 @@ psutil_proc_io_counters(PyObject *self, PyObject *args) { static PyObject * psutil_proc_memory_info(PyObject *self, PyObject *args) { long pid; - struct kinfo_proc kp; + kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; + return Py_BuildValue( "(lllll)", #ifdef __FreeBSD__ - ptoa(kp.ki_rssize), // rss - (long)kp.ki_size, // vms - ptoa(kp.ki_tsize), // text - ptoa(kp.ki_dsize), // data - ptoa(kp.ki_ssize)); // stack -#elif __OpenBSD__ - ptoa(kp.p_vm_rssize), // rss - // vms, this is how ps does it, see: + (long) ptoa(kp.ki_rssize), // rss + (long) kp.ki_size, // vms + (long) ptoa(kp.ki_tsize), // text + (long) ptoa(kp.ki_dsize), // data + (long) ptoa(kp.ki_ssize) // stack +#else + (long) ptoa(kp.p_vm_rssize), // rss + #ifdef __OpenBSD__ + // VMS, this is how ps determines it on OpenBSD: // http://anoncvs.spacehopper.org/openbsd-src/tree/bin/ps/print.c#n461 - ptoa(kp.p_vm_dsize + kp.p_vm_ssize + kp.p_vm_tsize), // vms - ptoa(kp.p_vm_tsize), // text - ptoa(kp.p_vm_dsize), // data - ptoa(kp.p_vm_ssize)); // stack + (long) ptoa(kp.p_vm_dsize + kp.p_vm_ssize + kp.p_vm_tsize), // vms + #elif __NetBSD__ + // VMS, this is how top determines it on NetBSD: + // ftp://ftp.iij.ad.jp/pub/NetBSD/NetBSD-release-6/src/external/bsd/ + // top/dist/machine/m_netbsd.c + (long) ptoa(kp.p_vm_msize), // vms + #endif + (long) ptoa(kp.p_vm_tsize), // text + (long) ptoa(kp.p_vm_dsize), // data + (long) ptoa(kp.p_vm_ssize) // stack #endif + ); } @@ -468,11 +494,15 @@ psutil_proc_memory_info(PyObject *self, PyObject *args) { */ static PyObject * psutil_cpu_times(PyObject *self, PyObject *args) { +#if defined(__NetBSD__) + u_int64_t cpu_time[CPUSTATES]; +#else long cpu_time[CPUSTATES]; +#endif size_t size = sizeof(cpu_time); int ret; -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__NetBSD__) ret = sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0); #elif __OpenBSD__ int mib[] = {CTL_KERN, KERN_CPTIME}; @@ -499,14 +529,14 @@ psutil_cpu_times(PyObject *self, PyObject *args) { * utility has the same problem see: * https://github.com/giampaolo/psutil/issues/595 */ -#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ +#if (defined(__FreeBSD_version) && __FreeBSD_version >= 800000) || __OpenBSD__ || defined(__NetBSD__) static PyObject * psutil_proc_open_files(PyObject *self, PyObject *args) { long pid; int i, cnt; struct kinfo_file *freep = NULL; struct kinfo_file *kif; - struct kinfo_proc kipp; + kinfo_proc kipp; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; @@ -530,11 +560,16 @@ psutil_proc_open_files(PyObject *self, PyObject *args) { (kif->kf_vnode_type == KF_VTYPE_VREG)) { py_tuple = Py_BuildValue("(si)", kif->kf_path, kif->kf_fd); -#else +#elif defined(__OpenBSD__) if ((kif->f_type == DTYPE_VNODE) && (kif->v_type == VREG)) { py_tuple = Py_BuildValue("(si)", "", kif->fd_fd); +#elif defined(__NetBSD__) + if ((kif->ki_ftype == DTYPE_VNODE) && + (kif->ki_vtype == VREG)) + { + py_tuple = Py_BuildValue("(si)", "", kif->ki_fd); #endif if (py_tuple == NULL) goto error; @@ -567,7 +602,11 @@ psutil_disk_partitions(PyObject *self, PyObject *args) { long len; uint64_t flags; char opts[200]; +#if defined(__NetBSD__) + struct statvfs *fs = NULL; +#else struct statfs *fs = NULL; +#endif PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; @@ -576,7 +615,11 @@ psutil_disk_partitions(PyObject *self, PyObject *args) { // get the number of mount points Py_BEGIN_ALLOW_THREADS +#if defined(__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); @@ -591,7 +634,11 @@ psutil_disk_partitions(PyObject *self, PyObject *args) { } Py_BEGIN_ALLOW_THREADS +#if defined(__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); @@ -601,24 +648,32 @@ psutil_disk_partitions(PyObject *self, PyObject *args) { for (i = 0; i < num; i++) { py_tuple = NULL; opts[0] = 0; +#if defined(__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)); -#ifdef __FreeBSD__ if (flags & MNT_SYNCHRONOUS) strlcat(opts, ",sync", sizeof(opts)); if (flags & MNT_NOEXEC) strlcat(opts, ",noexec", sizeof(opts)); if (flags & MNT_NOSUID) strlcat(opts, ",nosuid", sizeof(opts)); - if (flags & MNT_UNION) - strlcat(opts, ",union", sizeof(opts)); if (flags & MNT_ASYNC) strlcat(opts, ",async", sizeof(opts)); + if (flags & MNT_NOATIME) + strlcat(opts, ",noatime", sizeof(opts)); + if (flags & MNT_SOFTDEP) + strlcat(opts, ",softdep", sizeof(opts)); +#ifdef __FreeBSD__ + if (flags & MNT_UNION) + strlcat(opts, ",union", sizeof(opts)); if (flags & MNT_SUIDDIR) strlcat(opts, ",suiddir", sizeof(opts)); if (flags & MNT_SOFTDEP) @@ -631,27 +686,33 @@ psutil_disk_partitions(PyObject *self, PyObject *args) { strlcat(opts, ",multilabel", sizeof(opts)); if (flags & MNT_ACLS) strlcat(opts, ",acls", sizeof(opts)); - if (flags & MNT_NOATIME) - strlcat(opts, ",noatime", sizeof(opts)); if (flags & MNT_NOCLUSTERR) strlcat(opts, ",noclusterr", sizeof(opts)); if (flags & MNT_NOCLUSTERW) strlcat(opts, ",noclusterw", sizeof(opts)); if (flags & MNT_NFS4ACLS) strlcat(opts, ",nfs4acls", sizeof(opts)); -#elif __OpenBSD__ - if (flags & MNT_SYNCHRONOUS) - strlcat(opts, ",sync", sizeof(opts)); - if (flags & MNT_NOEXEC) - strlcat(opts, ",noexec", sizeof(opts)); - if (flags & MNT_NOSUID) - strlcat(opts, ",nosuid", sizeof(opts)); - if (flags & MNT_ASYNC) - strlcat(opts, ",async", sizeof(opts)); - if (flags & MNT_SOFTDEP) - strlcat(opts, ",softdep", sizeof(opts)); - if (flags & MNT_NOATIME) - strlcat(opts, ",noatime", sizeof(opts)); +#elif __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)); + if (flags & MNT_RELATIME) + strlcat(opts, ",relatime", sizeof(opts)); + if (flags & MNT_IGNORE) + strlcat(opts, ",ignore", sizeof(opts)); + if (flags & MNT_DISCARD) + strlcat(opts, ",discard", sizeof(opts)); + if (flags & MNT_EXTATTR) + strlcat(opts, ",extattr", sizeof(opts)); + 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_tuple = Py_BuildValue("(ssss)", fs[i].f_mntfromname, // device @@ -778,7 +839,7 @@ psutil_users(PyObject *self, PyObject *args) { if (py_retlist == NULL) return NULL; -#if __FreeBSD_version < 900000 || __OpenBSD__ +#if (defined(__FreeBSD_version) && (__FreeBSD_version < 900000)) || __OpenBSD__ struct utmp ut; FILE *fp; @@ -812,6 +873,7 @@ psutil_users(PyObject *self, PyObject *args) { #else struct utmpx *utx; + setutxent(); while ((utx = getutxent()) != NULL) { if (utx->ut_type != USER_PROCESS) continue; @@ -881,22 +943,25 @@ PsutilMethods[] = { "Return process IO counters"}, {"proc_tty_nr", psutil_proc_tty_nr, METH_VARARGS, "Return process tty (terminal) number"}, +#if defined(__FreeBSD__) || defined(__OpenBSD__) {"proc_cwd", psutil_proc_cwd, METH_VARARGS, "Return process current working directory."}, -#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ +#endif +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ || defined(__NetBSD__) {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS, "Return the number of file descriptors opened by this process"}, #endif -#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ || defined(__NetBSD__) {"proc_open_files", psutil_proc_open_files, METH_VARARGS, "Return files opened by process as a list of (path, fd) tuples"}, #endif -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__NetBSD__) {"proc_exe", psutil_proc_exe, METH_VARARGS, "Return process pathname executable"}, {"proc_num_threads", psutil_proc_num_threads, METH_VARARGS, "Return number of threads used by process"}, +#if defined(__FreeBSD__) {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, "Return a list of tuples for every process's memory map"}, {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS, @@ -906,6 +971,7 @@ PsutilMethods[] = { {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, "Return an XML string to determine the number physical CPUs."}, #endif +#endif // --- system-related functions @@ -932,7 +998,7 @@ PsutilMethods[] = { "Return a Python dict of tuples for disk I/O information"}, {"users", psutil_users, METH_VARARGS, "Return currently connected users as a list of tuples"}, -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__NetBSD__) {"net_connections", psutil_net_connections, METH_VARARGS, "Return system-wide open connections."}, #endif @@ -1010,6 +1076,16 @@ void init_psutil_bsd(void) PyModule_AddIntConstant(module, "SZOMB", SZOMB); // unused PyModule_AddIntConstant(module, "SDEAD", SDEAD); PyModule_AddIntConstant(module, "SONPROC", SONPROC); +#elif defined(__NetBSD__) + PyModule_AddIntConstant(module, "SIDL", LSIDL); + PyModule_AddIntConstant(module, "SRUN", LSRUN); + PyModule_AddIntConstant(module, "SSLEEP", LSSLEEP); + PyModule_AddIntConstant(module, "SSTOP", LSSTOP); + PyModule_AddIntConstant(module, "SZOMB", LSZOMB); + PyModule_AddIntConstant(module, "SDEAD", LSDEAD); + PyModule_AddIntConstant(module, "SONPROC", LSONPROC); + // unique to NetBSD + PyModule_AddIntConstant(module, "SSUSPENDED", LSSUSPENDED); #endif // connection status constants diff --git a/psutil/_psutil_posix.c b/psutil/_psutil_posix.c index 07404206..55bfec9a 100644 --- a/psutil/_psutil_posix.c +++ b/psutil/_psutil_posix.c @@ -26,7 +26,7 @@ #include <linux/if_packet.h> #endif // end linux -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) #include <netdb.h> #include <netinet/in.h> #include <net/if_dl.h> @@ -120,7 +120,7 @@ psutil_convert_ipaddr(struct sockaddr *addr, int family) { data = (const char *)lladdr->sll_addr; } #endif -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) else if (addr->sa_family == AF_LINK) { // Note: prior to Python 3.4 socket module does not expose // AF_LINK so we'll do. @@ -250,7 +250,7 @@ error: * net_if_stats() implementation. This is here because it is common * to both OSX and FreeBSD and I didn't know where else to put it. */ -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) #include <sys/sockio.h> #include <net/if_media.h> @@ -478,7 +478,7 @@ PsutilMethods[] = { "Set process priority"}, {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS, "Retrieve NICs information"}, -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) {"net_if_stats", psutil_net_if_stats, METH_VARARGS, "Return NIC stats."}, #endif @@ -537,7 +537,7 @@ void init_psutil_posix(void) PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods); #endif -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__sun) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__sun) || defined(__NetBSD__) PyModule_AddIntConstant(module, "AF_LINK", AF_LINK); #endif diff --git a/psutil/arch/bsd/netbsd.c b/psutil/arch/bsd/netbsd.c new file mode 100644 index 00000000..a8c0364c --- /dev/null +++ b/psutil/arch/bsd/netbsd.c @@ -0,0 +1,649 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil. + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Platform-specific module methods for NetBSD. + */ + +#if defined(__NetBSD__) +#define _KMEMUSER +#endif + +#include <Python.h> +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/user.h> +#include <sys/proc.h> +#include <sys/swap.h> // for swap_mem +#include <signal.h> +#include <kvm.h> +// connection stuff +#include <netdb.h> // for NI_MAXHOST +#include <sys/socket.h> +#include <sys/sched.h> // for CPUSTATES & CP_* +#define _KERNEL // for DTYPE_* +#include <sys/file.h> +#undef _KERNEL +#include <sys/disk.h> // struct diskstats +#include <netinet/in.h> +#include <arpa/inet.h> + + +#include "netbsd.h" +#include "netbsd_socks.h" +#include "../../_psutil_common.h" + +#define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) +#define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) + + +// ============================================================================ +// Utility functions +// ============================================================================ + + +int +psutil_raise_ad_or_nsp(long pid) { + // Set exception to AccessDenied if pid exists else NoSuchProcess. + if (psutil_pid_exists(pid) == 0) + NoSuchProcess(); + else + AccessDenied(); +} + + +int +psutil_kinfo_proc(pid_t pid, kinfo_proc *proc) { + // Fills a kinfo_proc struct based on process pid. + int ret; + int mib[6]; + size_t size = sizeof(kinfo_proc); + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC2; + mib[2] = KERN_PROC_PID; + mib[3] = pid; + mib[4] = size; + mib[5] = 1; + + ret = sysctl((int*)mib, 6, proc, &size, NULL, 0); + if (ret == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + // sysctl stores 0 in the size if we can't find the process information. + if (size == 0) { + NoSuchProcess(); + return -1; + } + return 0; +} + + +struct kinfo_file * +kinfo_getfile(pid_t pid, int* cnt) { + // Mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an + // int as arg and returns an array with cnt struct kinfo_file. + int mib[6]; + size_t len; + struct kinfo_file* kf; + mib[0] = CTL_KERN; + mib[1] = KERN_FILE2; + mib[2] = KERN_FILE_BYPID; + mib[3] = (int) pid; + mib[4] = sizeof(struct kinfo_file); + mib[5] = 0; + + // get the size of what would be returned + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + if ((kf = malloc(len)) == NULL) { + PyErr_NoMemory(); + return NULL; + } + mib[5] = (int)(len / sizeof(struct kinfo_file)); + if (sysctl(mib, 6, kf, &len, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + *cnt = (int)(len / sizeof(struct kinfo_file)); + return kf; +} + + +int +psutil_pid_exists(pid_t pid) { + // Return 1 if PID exists in the current process list, else 0, -1 + // on error. + // TODO: this should live in _psutil_posix.c but for some reason if I + // move it there I get a "include undefined symbol" error. + int ret; + if (pid < 0) + return 0; + ret = kill(pid , 0); + if (ret == 0) + return 1; + else { + if (ret == ESRCH) + return 0; + else if (ret == EPERM) + return 1; + else { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + } +} + +PyObject * +psutil_proc_exe(PyObject *self, PyObject *args) { +#if __NetBSD_Version__ >= 799000000 + pid_t pid; + char pathname[MAXPATHLEN]; + int error; + int mib[4]; + int ret; + size_t size; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = pid; + mib[3] = KERN_PROC_PATHNAME; + + size = sizeof(pathname); + error = sysctl(mib, 4, NULL, &size, NULL, 0); + if (error == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + error = sysctl(mib, 4, pathname, &size, NULL, 0); + if (error == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + if (size == 0 || strlen(pathname) == 0) { + ret = psutil_pid_exists(pid); + if (ret == -1) + return NULL; + else if (ret == 0) + return NoSuchProcess(); + else + strcpy(pathname, ""); + } + return Py_BuildValue("s", pathname); +#else + return Py_BuildValue("s", ""); +#endif +} + +PyObject * +psutil_proc_num_threads(PyObject *self, PyObject *args) { + // Return number of threads used by process as a Python integer. + long pid; + 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.p_nlwps); +} + +PyObject * +psutil_proc_threads(PyObject *self, PyObject *args) { + pid_t pid; + int mib[5]; + int i, nlwps; + ssize_t st; + size_t size; + struct kinfo_lwp *kl = NULL; + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + + if (py_retlist == NULL) + return NULL; + if (! PyArg_ParseTuple(args, "l", &pid)) + goto error; + + mib[0] = CTL_KERN; + mib[1] = KERN_LWP; + mib[2] = pid; + mib[3] = sizeof(struct kinfo_lwp); + mib[4] = 0; + + st = sysctl(mib, 5, NULL, &size, NULL, 0); + if (st == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + if (size == 0) { + NoSuchProcess(); + goto error; + } + + mib[4] = size / sizeof(size_t); + kl = malloc(size); + if (kl == NULL) { + PyErr_NoMemory(); + goto error; + } + + st = sysctl(mib, 5, kl, &size, NULL, 0); + if (st == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + if (size == 0) { + NoSuchProcess(); + goto error; + } + + nlwps = (int)(size / sizeof(struct kinfo_lwp)); + for (i = 0; i < nlwps; i++) { + py_tuple = Py_BuildValue("idd", + (&kl[i])->l_lid, + PSUTIL_KPT2DOUBLE((&kl[i])->l_rtime), + PSUTIL_KPT2DOUBLE((&kl[i])->l_rtime)); + if (py_tuple == NULL) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + free(kl); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (kl != NULL) + free(kl); + return NULL; +} + + +// ============================================================================ +// APIS +// ============================================================================ + +int +psutil_get_proc_list(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. + kinfo_proc *result; + int done; + static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC, 0 }; + // Declaring name as const requires us to cast it when passing it to + // sysctl because the prototype doesn't include the const modifier. + size_t length; + char errbuf[_POSIX2_LINE_MAX]; + kinfo_proc *x; + int cnt; + kvm_t *kd; + + assert( procList != NULL); + assert(*procList == NULL); + assert(procCount != NULL); + + kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); + + if (kd == NULL) { + PyErr_Format(PyExc_RuntimeError, "kvm_openfiles() failed: %s", errbuf); + return errno; + } + + result = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(kinfo_proc), &cnt); + if (result == NULL) { + PyErr_Format(PyExc_RuntimeError, "kvm_getproc2() failed"); + kvm_close(kd); + return errno; + } + + *procCount = (size_t)cnt; + + size_t mlen = cnt * sizeof(kinfo_proc); + + if ((*procList = malloc(mlen)) == NULL) { + PyErr_NoMemory(); + kvm_close(kd); + return errno; + } + + memcpy(*procList, result, mlen); + assert(*procList != NULL); + kvm_close(kd); + + return 0; +} + + +char * +psutil_get_cmd_args(pid_t pid, size_t *argsize) { + int mib[4]; + ssize_t st; + size_t argmax; + size_t size; + char *procargs = NULL; + + mib[0] = CTL_KERN; + mib[1] = KERN_ARGMAX; + + size = sizeof(argmax); + st = sysctl(mib, 2, &argmax, &size, NULL, 0); + if (st == -1) { + warn("failed to get kern.argmax"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + procargs = (char *)malloc(argmax); + if (procargs == NULL) { + PyErr_NoMemory(); + return NULL; + } + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = pid; + mib[3] = KERN_PROC_ARGV; + + st = sysctl(mib, 4, procargs, &argmax, NULL, 0); + if (st == -1) { + warn("failed to get kern.procargs"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + *argsize = argmax; + return procargs; +} + +// returns the command line as a python list object +PyObject * +psutil_get_cmdline(pid_t pid) { + char *argstr = NULL; + int pos = 0; + size_t argsize = 0; + PyObject *py_arg = NULL; + PyObject *py_retlist = PyList_New(0); + + if (py_retlist == NULL) + return 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) { + py_arg = Py_BuildValue("s", &argstr[pos]); + 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; +} + + +PyObject * +psutil_virtual_mem(PyObject *self, PyObject *args) { + unsigned int total; + size_t size = sizeof(total); + struct uvmexp_sysctl uv; + int mib[] = {CTL_VM, VM_UVMEXP2}; + long pagesize = getpagesize(); + size = sizeof(uv); + + if (sysctl(mib, 2, &uv, &size, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + return Py_BuildValue("KKKKKKKK", + (unsigned long long) uv.npages * pagesize, // total + (unsigned long long) uv.free * pagesize, // free + (unsigned long long) uv.active * pagesize, // active + (unsigned long long) uv.inactive * pagesize, // inactive + (unsigned long long) uv.wired * pagesize, // wired + // taken from: + // https://github.com/satterly/zabbix-stats/blob/master/src/libs/ + // zbxsysinfo/netbsd/memory.c + (unsigned long long) uv.filepages + uv.execpages * pagesize, // cached + (unsigned long long) 0, // buffers + (unsigned long long) 0 // shared + ); +} + + +PyObject * +psutil_swap_mem(PyObject *self, PyObject *args) { + uint64_t swap_total, swap_free; + struct swapent *swdev; + int nswap, i; + + nswap = swapctl(SWAP_NSWAP, 0, 0); + if (nswap == 0) { + // This means there's no swap partition. + return Py_BuildValue("(iiiii)", 0, 0, 0, 0, 0); + } + + swdev = calloc(nswap, sizeof(*swdev)); + if (swdev == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + if (swapctl(SWAP_STATS, swdev, nswap) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + // Total things up. + swap_total = swap_free = 0; + for (i = 0; i < nswap; i++) { + if (swdev[i].se_flags & SWF_ENABLE) { + swap_free += (swdev[i].se_nblks - swdev[i].se_inuse); + swap_total += swdev[i].se_nblks; + } + } + free(swdev); + + // Get swap in/out + unsigned int total; + size_t size = sizeof(total); + struct uvmexp_sysctl uv; + int mib[] = {CTL_VM, VM_UVMEXP2}; + long pagesize = getpagesize(); + size = sizeof(uv); + if (sysctl(mib, 2, &uv, &size, NULL, 0) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + return Py_BuildValue("(LLLll)", + swap_total * DEV_BSIZE, + (swap_total - swap_free) * DEV_BSIZE, + swap_free * DEV_BSIZE, + (long) uv.pgswapin * pagesize, // swap in + (long) uv.pgswapout * pagesize); // swap out + +error: + free(swdev); +} + + +PyObject * +psutil_proc_num_fds(PyObject *self, PyObject *args) { + long pid; + int cnt; + + struct kinfo_file *freep; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + freep = kinfo_getfile(pid, &cnt); + if (freep == NULL) { + psutil_raise_ad_or_nsp(pid); + return NULL; + } + free(freep); + + return Py_BuildValue("i", cnt); +} + + +PyObject * +psutil_per_cpu_times(PyObject *self, PyObject *args) { + static int maxcpus; + int mib[3]; + int ncpu; + size_t len; + size_t size; + int i; + PyObject *py_cputime = NULL; + PyObject *py_retlist = PyList_New(0); + + if (py_retlist == NULL) + return NULL; + // retrieve the number of cpus + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + len = sizeof(ncpu); + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + uint64_t cpu_time[CPUSTATES]; + + for (i = 0; i < ncpu; i++) { + // per-cpu info + mib[0] = CTL_KERN; + mib[1] = KERN_CP_TIME; + mib[2] = i; + size = sizeof(cpu_time); + if (sysctl(mib, 3, &cpu_time, &size, NULL, 0) == -1) { + warn("failed to get kern.cptime2"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + py_cputime = Py_BuildValue( + "(ddddd)", + (double)cpu_time[CP_USER] / CLOCKS_PER_SEC, + (double)cpu_time[CP_NICE] / CLOCKS_PER_SEC, + (double)cpu_time[CP_SYS] / CLOCKS_PER_SEC, + (double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC, + (double)cpu_time[CP_INTR] / CLOCKS_PER_SEC); + if (!py_cputime) + goto error; + if (PyList_Append(py_retlist, py_cputime)) + goto error; + Py_DECREF(py_cputime); + } + + return py_retlist; + +error: + Py_XDECREF(py_cputime); + Py_DECREF(py_retlist); + return NULL; +} + + +PyObject * +psutil_disk_io_counters(PyObject *self, PyObject *args) { + int i, dk_ndrive, mib[3]; + size_t len; + struct io_sysctl *stats; + PyObject *py_disk_info = NULL; + PyObject *py_retdict = PyDict_New(); + + if (py_retdict == NULL) + return NULL; + mib[0] = CTL_HW; + mib[1] = HW_IOSTATS; + mib[2] = sizeof(struct io_sysctl); + len = 0; + if (sysctl(mib, 3, NULL, &len, NULL, 0) < 0) { + warn("can't get HW_IOSTATS"); + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + dk_ndrive = (int)(len / sizeof(struct io_sysctl)); + + stats = malloc(len); + if (stats == NULL) { + PyErr_NoMemory(); + goto error; + } + if (sysctl(mib, 2, stats, &len, NULL, 0) < 0 ) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + + for (i = 0; i < dk_ndrive; i++) { + py_disk_info = Py_BuildValue( + "(KKKKLL)", + stats[i].rxfer, + stats[i].wxfer, + stats[i].rbytes, + stats[i].wbytes, + // assume half read - half writes. + // TODO: why? + (long long) PSUTIL_KPT2DOUBLE(stats[i].time) / 2, + (long long) PSUTIL_KPT2DOUBLE(stats[i].time) / 2); + if (!py_disk_info) + goto error; + if (PyDict_SetItemString(py_retdict, stats[i].name, py_disk_info)) + goto error; + Py_DECREF(py_disk_info); + } + + free(stats); + return py_retdict; + +error: + Py_XDECREF(py_disk_info); + Py_DECREF(py_retdict); + if (stats != NULL) + free(stats); + return NULL; +} diff --git a/psutil/arch/bsd/netbsd.h b/psutil/arch/bsd/netbsd.h new file mode 100644 index 00000000..b0b2caaf --- /dev/null +++ b/psutil/arch/bsd/netbsd.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil. + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <Python.h> + +typedef struct kinfo_proc2 kinfo_proc; + +int psutil_kinfo_proc(pid_t pid, kinfo_proc *proc); +struct kinfo_file * kinfo_getfile(pid_t pid, int* cnt); +int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount); +char *psutil_get_cmd_args(pid_t pid, size_t *argsize); +PyObject * psutil_get_cmdline(pid_t pid); +int psutil_pid_exists(pid_t pid); +int psutil_raise_ad_or_nsp(long pid); + +// +PyObject *psutil_proc_threads(PyObject *self, PyObject *args); +PyObject *psutil_virtual_mem(PyObject *self, PyObject *args); +PyObject *psutil_swap_mem(PyObject *self, PyObject *args); +PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args); +PyObject *psutil_proc_connections(PyObject *self, PyObject *args); +PyObject *psutil_per_cpu_times(PyObject *self, PyObject *args); +PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args); +PyObject* psutil_proc_exe(PyObject* self, PyObject* args); +PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args); diff --git a/psutil/arch/bsd/netbsd_socks.c b/psutil/arch/bsd/netbsd_socks.c new file mode 100644 index 00000000..0de19165 --- /dev/null +++ b/psutil/arch/bsd/netbsd_socks.c @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. + * Copyright (c) 2015, Ryo ONODERA. + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include <Python.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/sysctl.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <string.h> +#include <sys/cdefs.h> +#include <arpa/inet.h> +#include <sys/queue.h> +#include <sys/un.h> +#include <sys/file.h> + +// a signaler for connections without an actual status +int PSUTIL_CONN_NONE = 128; + +// Address family filter +enum af_filter { + INET, + INET4, + INET6, + TCP, + TCP4, + TCP6, + UDP, + UDP4, + UDP6, + UNIX, + ALL, +}; + +// kinfo_file results +struct kif { + SLIST_ENTRY(kif) kifs; + struct kinfo_file *kif; +}; + +// kinfo_file results list +SLIST_HEAD(kifhead, kif) kihead = SLIST_HEAD_INITIALIZER(kihead); + + +// kinfo_pcb results +struct kpcb { + SLIST_ENTRY(kpcb) kpcbs; + struct kinfo_pcb *kpcb; +}; + +// kinfo_pcb results list +SLIST_HEAD(kpcbhead, kpcb) kpcbhead = SLIST_HEAD_INITIALIZER(kpcbhead); + +static void kiflist_init(void); +static void kiflist_clear(void); +static void kpcblist_init(void); +static void kpcblist_clear(void); +static int get_files(void); +static int get_sockets(const char *name); +static void get_info(int aff); + +// Initialize kinfo_file results list +static void +kiflist_init(void) { + SLIST_INIT(&kihead); + return; +} + +// Clear kinfo_file results list +static void +kiflist_clear(void) { + while (!SLIST_EMPTY(&kihead)) { + SLIST_REMOVE_HEAD(&kihead, kifs); + } + + return; +} + +// Initialize kinof_pcb result list +static void +kpcblist_init(void) { + SLIST_INIT(&kpcbhead); + return; +} + +// Clear kinof_pcb result list +static void +kpcblist_clear(void) { + while (!SLIST_EMPTY(&kpcbhead)) { + SLIST_REMOVE_HEAD(&kpcbhead, kpcbs); + } + + return; +} + + +// Get all open files including socket +static int +get_files(void) { + size_t len; + int mib[6]; + char *buf; + off_t offset; + int j; + + mib[0] = CTL_KERN; + mib[1] = KERN_FILE2; + mib[2] = KERN_FILE_BYFILE; + mib[3] = 0; + mib[4] = sizeof(struct kinfo_file); + mib[5] = 0; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) + return -1; + offset = len % sizeof(off_t); + mib[5] = len / sizeof(struct kinfo_file); + if ((buf = malloc(len + offset)) == NULL) + return -1; + if (sysctl(mib, 6, buf + offset, &len, NULL, 0) == -1) { + free(buf); + return -1; + } + + len /= sizeof(struct kinfo_file); + struct kinfo_file *ki = (struct kinfo_file *)(buf + offset); + + for (j = 0; j < len; j++) { + struct kif *kif = malloc(sizeof(struct kif)); + kif->kif = &ki[j]; + SLIST_INSERT_HEAD(&kihead, kif, kifs); + } + +#if 0 + // debug + struct kif *k; + SLIST_FOREACH(k, &kihead, kifs) { + printf("%d\n", k->kif->ki_pid); + } +#endif + + return 0; +} + +// Get open sockets +static int +get_sockets(const char *name) { + size_t namelen; + int mib[8]; + int ret, j; + struct kinfo_pcb *pcb; + size_t len; + + memset(mib, 0, sizeof(mib)); + + if (sysctlnametomib(name, mib, &namelen) == -1) + return -1; + + if (sysctl(mib, __arraycount(mib), NULL, &len, NULL, 0) == -1) + return -1; + + if ((pcb = malloc(len)) == NULL) { + return -1; + } + memset(pcb, 0, len); + + mib[6] = sizeof(*pcb); + mib[7] = len / sizeof(*pcb); + + if (sysctl(mib, __arraycount(mib), pcb, &len, NULL, 0) == -1) { + free(pcb); + return -1; + } + + len /= sizeof(struct kinfo_pcb); + struct kinfo_pcb *kp = (struct kinfo_pcb *)pcb; + + for (j = 0; j < len; j++) { + struct kpcb *kpcb = malloc(sizeof(struct kpcb)); + kpcb->kpcb = &kp[j]; + SLIST_INSERT_HEAD(&kpcbhead, kpcb, kpcbs); + } + +#if 0 + // debug + struct kif *k; + struct kpcb *k; + SLIST_FOREACH(k, &kpcbhead, kpcbs) { + printf("ki_type: %d\n", k->kpcb->ki_type); + printf("ki_family: %d\n", k->kpcb->ki_family); + } +#endif + + return 0; +} + + +// Collect connections by PID +PyObject * +psutil_proc_connections(PyObject *self, PyObject *args) { + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_laddr = NULL; + PyObject *py_raddr = NULL; + pid_t pid; + + if (py_retlist == NULL) + return NULL; + + if (! PyArg_ParseTuple(args, "l", &pid)) + return NULL; + + kiflist_init(); + kpcblist_init(); + get_info(ALL); + + struct kif *k; + SLIST_FOREACH(k, &kihead, kifs) { + struct kpcb *kp; + if (k->kif->ki_pid == pid) { + SLIST_FOREACH(kp, &kpcbhead, kpcbs) { + if (k->kif->ki_fdata == kp->kpcb->ki_sockaddr) { + pid_t pid; + int32_t fd; + int32_t family; + int32_t type; + char laddr[PATH_MAX]; + int32_t lport; + char raddr[PATH_MAX]; + int32_t rport; + int32_t status; + + pid = k->kif->ki_pid; + fd = k->kif->ki_fd; + family = kp->kpcb->ki_family; + type = kp->kpcb->ki_type; + if (kp->kpcb->ki_family == AF_INET) { + struct sockaddr_in *sin_src = + (struct sockaddr_in *)&kp->kpcb->ki_src; + struct sockaddr_in *sin_dst = + (struct sockaddr_in *)&kp->kpcb->ki_dst; + if (inet_ntop(AF_INET, &sin_src->sin_addr, laddr, + sizeof(laddr)) != NULL) + lport = ntohs(sin_src->sin_port); + py_laddr = Py_BuildValue("(si)", laddr, lport); + if (!py_laddr) + goto error; + if (inet_ntop(AF_INET, &sin_dst->sin_addr, raddr, + sizeof(raddr)) != NULL) + rport = ntohs(sin_dst->sin_port); + py_raddr = Py_BuildValue("(si)", raddr, rport); + if (!py_raddr) + goto error; + if (kp->kpcb->ki_type == SOCK_STREAM) { + status = kp->kpcb->ki_tstate; + } else { + status = PSUTIL_CONN_NONE; + } + + py_tuple = Py_BuildValue("(iiiNNi)", fd, AF_INET, + type, py_laddr, py_raddr, status); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + } else if (kp->kpcb->ki_family == AF_INET6) { + struct sockaddr_in6 *sin6_src = + (struct sockaddr_in6 *)&kp->kpcb->ki_src; + struct sockaddr_in6 *sin6_dst = + (struct sockaddr_in6 *)&kp->kpcb->ki_dst; + if (inet_ntop(AF_INET6, &sin6_src->sin6_addr, laddr, + sizeof(laddr)) != NULL) + lport = ntohs(sin6_src->sin6_port); + py_laddr = Py_BuildValue("(si)", laddr, lport); + if (!py_laddr) + goto error; + if (inet_ntop(AF_INET6, &sin6_dst->sin6_addr, raddr, + sizeof(raddr)) != NULL) + rport = ntohs(sin6_dst->sin6_port); + py_raddr = Py_BuildValue("(si)", raddr, rport); + if (!py_raddr) + goto error; + if (kp->kpcb->ki_type == SOCK_STREAM) { + status = kp->kpcb->ki_tstate; + } else { + status = PSUTIL_CONN_NONE; + } + + py_tuple = Py_BuildValue("(iiiNNi)", fd, AF_INET6, + type, py_laddr, py_raddr, status); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + } else if (kp->kpcb->ki_family == AF_UNIX) { + struct sockaddr_un *sun_src = + (struct sockaddr_un *)&kp->kpcb->ki_src; + struct sockaddr_un *sun_dst = + (struct sockaddr_un *)&kp->kpcb->ki_dst; + strcpy(laddr, sun_src->sun_path); + strcpy(raddr, sun_dst->sun_path); + status = PSUTIL_CONN_NONE; + + py_tuple = Py_BuildValue("(iiissi)", fd, AF_UNIX, + type, laddr, raddr, status); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + } + + + } + }} + } + + kiflist_clear(); + kpcblist_clear(); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_XDECREF(py_laddr); + Py_XDECREF(py_raddr); + return 0; +} + + +// Collect open file and connections +static void +get_info(int aff) { + get_files(); + + switch (aff) { + case INET: + get_sockets("net.inet.tcp.pcblist"); + get_sockets("net.inet.udp.pcblist"); + get_sockets("net.inet6.tcp6.pcblist"); + get_sockets("net.inet6.udp6.pcblist"); + break; + case INET4: + get_sockets("net.inet.tcp.pcblist"); + get_sockets("net.inet.udp.pcblist"); + break; + case INET6: + get_sockets("net.inet6.tcp6.pcblist"); + get_sockets("net.inet6.udp6.pcblist"); + break; + case TCP: + get_sockets("net.inet.tcp.pcblist"); + get_sockets("net.inet6.tcp6.pcblist"); + break; + case TCP4: + get_sockets("net.inet.tcp.pcblist"); + break; + case TCP6: + get_sockets("net.inet6.tcp6.pcblist"); + break; + case UDP: + get_sockets("net.inet.udp.pcblist"); + get_sockets("net.inet6.udp6.pcblist"); + break; + case UDP4: + get_sockets("net.inet.udp.pcblist"); + break; + case UDP6: + get_sockets("net.inet6.udp6.pcblist"); + break; + case UNIX: + get_sockets("net.local.stream.pcblist"); + get_sockets("net.local.seqpacket.pcblist"); + get_sockets("net.local.dgram.pcblist"); + break; + case ALL: + get_sockets("net.inet.tcp.pcblist"); + get_sockets("net.inet.udp.pcblist"); + get_sockets("net.inet6.tcp6.pcblist"); + get_sockets("net.inet6.udp6.pcblist"); + get_sockets("net.local.stream.pcblist"); + get_sockets("net.local.seqpacket.pcblist"); + get_sockets("net.local.dgram.pcblist"); + break; + } + return; +} + +// Collect system wide connections by address family filter +PyObject * +psutil_net_connections(PyObject *self, PyObject *args) { + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_laddr = NULL; + PyObject *py_raddr = NULL; + + if (py_retlist == NULL) + return NULL; + + kiflist_init(); + kpcblist_init(); + get_info(ALL); + + struct kif *k; + SLIST_FOREACH(k, &kihead, kifs) { + struct kpcb *kp; + SLIST_FOREACH(kp, &kpcbhead, kpcbs) { + if (k->kif->ki_fdata == kp->kpcb->ki_sockaddr) { + pid_t pid; + int32_t fd; + int32_t family; + int32_t type; + char laddr[PATH_MAX]; + int32_t lport; + char raddr[PATH_MAX]; + int32_t rport; + int32_t status; + + pid = k->kif->ki_pid; + fd = k->kif->ki_fd; + family = kp->kpcb->ki_family; + type = kp->kpcb->ki_type; + if (kp->kpcb->ki_family == AF_INET) { + struct sockaddr_in *sin_src = + (struct sockaddr_in *)&kp->kpcb->ki_src; + struct sockaddr_in *sin_dst = + (struct sockaddr_in *)&kp->kpcb->ki_dst; + if (inet_ntop(AF_INET, &sin_src->sin_addr, laddr, + sizeof(laddr)) != NULL) + lport = ntohs(sin_src->sin_port); + py_laddr = Py_BuildValue("(si)", laddr, lport); + if (!py_laddr) + goto error; + if (inet_ntop(AF_INET, &sin_dst->sin_addr, raddr, + sizeof(raddr)) != NULL) + rport = ntohs(sin_dst->sin_port); + py_raddr = Py_BuildValue("(si)", raddr, rport); + if (!py_raddr) + goto error; + if (kp->kpcb->ki_type == SOCK_STREAM) { + status = kp->kpcb->ki_tstate; + } else { + status = PSUTIL_CONN_NONE; + } + + py_tuple = Py_BuildValue("(iiiNNii)", fd, AF_INET, + type, py_laddr, py_raddr, status, pid); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + } else if (kp->kpcb->ki_family == AF_INET6) { + struct sockaddr_in6 *sin6_src = + (struct sockaddr_in6 *)&kp->kpcb->ki_src; + struct sockaddr_in6 *sin6_dst = + (struct sockaddr_in6 *)&kp->kpcb->ki_dst; + if (inet_ntop(AF_INET6, &sin6_src->sin6_addr, laddr, + sizeof(laddr)) != NULL) + lport = ntohs(sin6_src->sin6_port); + py_laddr = Py_BuildValue("(si)", laddr, lport); + if (!py_laddr) + goto error; + if (inet_ntop(AF_INET6, &sin6_dst->sin6_addr, raddr, + sizeof(raddr)) != NULL) + rport = ntohs(sin6_dst->sin6_port); + py_raddr = Py_BuildValue("(si)", raddr, rport); + if (!py_raddr) + goto error; + if (kp->kpcb->ki_type == SOCK_STREAM) { + status = kp->kpcb->ki_tstate; + } else { + status = PSUTIL_CONN_NONE; + } + + py_tuple = Py_BuildValue("(iiiNNii)", fd, AF_INET6, + type, py_laddr, py_raddr, status, pid); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + } else if (kp->kpcb->ki_family == AF_UNIX) { + struct sockaddr_un *sun_src = + (struct sockaddr_un *)&kp->kpcb->ki_src; + struct sockaddr_un *sun_dst = + (struct sockaddr_un *)&kp->kpcb->ki_dst; + strcpy(laddr, sun_src->sun_path); + strcpy(raddr, sun_dst->sun_path); + status = PSUTIL_CONN_NONE; + + py_tuple = Py_BuildValue("(iiissii)", fd, AF_UNIX, + type, laddr, raddr, status, pid); + if (!py_tuple) + goto error; + if (PyList_Append(py_retlist, py_tuple)) + goto error; + } + + + } + } + } + + kiflist_clear(); + kpcblist_clear(); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_XDECREF(py_laddr); + Py_XDECREF(py_raddr); + return 0; +} diff --git a/psutil/arch/bsd/netbsd_socks.h b/psutil/arch/bsd/netbsd_socks.h new file mode 100644 index 00000000..9e6a97c0 --- /dev/null +++ b/psutil/arch/bsd/netbsd_socks.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. + * Copyright (c) 2015, Ryo ONODERA. + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +PyObject *psutil_proc_connections(PyObject *, PyObject *); +PyObject *psutil_net_connections(PyObject *, PyObject *); diff --git a/psutil/arch/bsd/openbsd.c b/psutil/arch/bsd/openbsd.c index 82a598d1..a29928ba 100644 --- a/psutil/arch/bsd/openbsd.c +++ b/psutil/arch/bsd/openbsd.c @@ -178,6 +178,7 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { result = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cnt); if (result == NULL) { + kvm_close(kd); err(1, NULL); return errno; } @@ -187,6 +188,7 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { size_t mlen = cnt * sizeof(struct kinfo_proc); if ((*procList = malloc(mlen)) == NULL) { + kvm_close(kd); err(1, NULL); return errno; } @@ -387,14 +389,13 @@ psutil_swap_mem(PyObject *self, PyObject *args) { } if ((swdev = calloc(nswap, sizeof(*swdev))) == NULL) { - PyErr_SetFromErrno(PyExc_OSError); + PyErr_NoMemory(); return NULL; } if (swapctl(SWAP_STATS, swdev, nswap) == -1) { - free(swdev); PyErr_SetFromErrno(PyExc_OSError); - return NULL; + goto error; } // Total things up. @@ -415,6 +416,10 @@ psutil_swap_mem(PyObject *self, PyObject *args) { // swapent struct does not provide any info // about it. 0, 0); + +error: + free(swdev); + return NULL; } @@ -151,6 +151,19 @@ elif sys.platform.startswith("openbsd"): define_macros=[VERSION_MACRO], libraries=["kvm"]) extensions = [ext, posix_extension] +# NetBSD +elif sys.platform.startswith("netbsd"): + ext = Extension( + 'psutil._psutil_bsd', + sources=[ + 'psutil/_psutil_bsd.c', + 'psutil/_psutil_common.c', + 'psutil/arch/bsd/netbsd.c', + 'psutil/arch/bsd/netbsd_socks.c', + ], + define_macros=[VERSION_MACRO], + libraries=["kvm"]) + extensions = [ext, posix_extension] # Linux elif sys.platform.startswith("linux"): def get_ethtool_macro(): diff --git a/test/_posix.py b/test/_posix.py index 35b498a7..10243336 100644 --- a/test/_posix.py +++ b/test/_posix.py @@ -262,6 +262,12 @@ class PosixSpecificTestCase(unittest.TestCase): if failures: self.fail('\n' + '\n'.join(failures)) + @unittest.skipUnless(os.path.islink("/proc/%s/cwd" % os.getpid()), + "/proc fs not available") + def test_cwd_proc(self): + self.assertEqual(os.readlink("/proc/%s/cwd" % os.getpid()), + psutil.Process().cwd()) + def main(): test_suite = unittest.TestSuite() diff --git a/test/test_psutil.py b/test/test_psutil.py index 5494e27b..8111068b 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -115,7 +115,8 @@ LINUX = sys.platform.startswith("linux") OSX = sys.platform.startswith("darwin") FREEBSD = sys.platform.startswith("freebsd") OPENBSD = sys.platform.startswith("openbsd") -BSD = FREEBSD or OPENBSD +NETBSD = sys.platform.startswith("netbsd") +BSD = FREEBSD or OPENBSD or NETBSD SUNOS = sys.platform.startswith("sunos") VALID_PROC_STATUSES = [getattr(psutil, x) for x in dir(psutil) if x.startswith('STATUS_')] @@ -1669,7 +1670,7 @@ class TestProcess(unittest.TestCase): # def test_memory_info_ex(self): # # tested later in fetch all test suite - @unittest.skipIf(OPENBSD, "not available on OpenBSD") + @unittest.skipIf(OPENBSD or NETBSD, "not available on this platform") def test_memory_maps(self): p = psutil.Process() maps = p.memory_maps() @@ -3121,7 +3122,7 @@ class TestExampleScripts(unittest.TestCase): def test_ifconfig(self): self.assert_stdout('ifconfig.py') - @unittest.skipIf(OPENBSD, "OpenBSD does not support memory maps") + @unittest.skipIf(OPENBSD or NETBSD, "memory maps not supported") def test_pmap(self): self.assert_stdout('pmap.py', args=str(os.getpid())) |