diff --git a/docs/index.rst b/docs/index.rst index 3a5f8e621..fc43d70af 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,6 +8,7 @@ Old 1.2.1 documentation is still available `here `__. .. 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, OpenBSD and NetBSD are always set to ``0``. See `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) diff --git a/psutil/__init__.py b/psutil/__init__.py index 2ab1b7f2b..e5f06a878 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -123,8 +123,9 @@ elif sys.platform.startswith("darwin"): from . import _psosx as _psplatform -elif sys.platform.startswith("freebsd") or sys.platform.startswith("openbsd") \ - or sys.platform.startswith("netbsd"): +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"): @@ -969,7 +970,9 @@ def memory_percent(self): 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/_psbsd.py b/psutil/_psbsd.py index 3304cece7..032b87c0f 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -521,66 +521,67 @@ 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 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 - else: - return cext.proc_cwd(self.pid) or None - - @wrap_exceptions - def memory_maps(self): - if FREEBSD: - return cext.proc_memory_maps(self.pid) - else: - # TODO - raise NotImplementedError - + # 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) - 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) @@ -609,3 +610,6 @@ def cpu_affinity_set(self, cpus): "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 888cf7b7d..a621afc21 100644 --- a/psutil/_psutil_bsd.c +++ b/psutil/_psutil_bsd.c @@ -9,7 +9,7 @@ * 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() diff --git a/psutil/arch/bsd/netbsd.c b/psutil/arch/bsd/netbsd.c index 5491c0fef..48373c725 100644 --- a/psutil/arch/bsd/netbsd.c +++ b/psutil/arch/bsd/netbsd.c @@ -461,7 +461,8 @@ psutil_swap_mem(PyObject *self, PyObject *args) { return Py_BuildValue("(iiiii)", 0, 0, 0, 0, 0); } - if ((swdev = calloc(nswap, sizeof(*swdev))) == NULL) { + swdev = calloc(nswap, sizeof(*swdev)); + if (swdev == NULL) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -511,40 +512,6 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) { } -// see sys/kern/kern_sysctl.c lines 1100 and -// usr.bin/fstat/fstat.c print_inet_details() -static char * -psutil_convert_ipv4(int family, uint32_t addr[4]) { - struct in_addr a; - memcpy(&a, addr, sizeof(a)); - return inet_ntoa(a); -} - - -static char * -psutil_inet6_addrstr(struct in6_addr *p) { - struct sockaddr_in6 sin6; - static char hbuf[NI_MAXHOST]; - const int niflags = NI_NUMERICHOST; - - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_addr = *p; - if (IN6_IS_ADDR_LINKLOCAL(p) && - *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) { - sin6.sin6_scope_id = - ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); - sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0; - } - - if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, - hbuf, sizeof(hbuf), NULL, 0, niflags)) - return "invalid"; - - return hbuf; -} - PyObject * psutil_per_cpu_times(PyObject *self, PyObject *args) { static int maxcpus; @@ -553,13 +520,11 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) { size_t len; size_t size; int i; - PyObject *py_retlist = PyList_New(0); 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; @@ -610,12 +575,11 @@ psutil_disk_io_counters(PyObject *self, PyObject *args) { int i, dk_ndrive, mib[3]; size_t len; struct io_sysctl *stats; - - PyObject *py_retdict = PyDict_New(); 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); @@ -629,12 +593,10 @@ psutil_disk_io_counters(PyObject *self, PyObject *args) { stats = malloc(len); if (stats == NULL) { - warn("can't malloc"); PyErr_NoMemory(); goto error; } if (sysctl(mib, 2, stats, &len, NULL, 0) < 0 ) { - warn("could not read HW_IOSTATS"); PyErr_SetFromErrno(PyExc_OSError); goto error; } @@ -667,4 +629,3 @@ psutil_disk_io_counters(PyObject *self, PyObject *args) { free(stats); return NULL; } - diff --git a/test/test_psutil.py b/test/test_psutil.py index fba71d200..d1039fc17 100644 --- a/test/test_psutil.py +++ b/test/test_psutil.py @@ -1670,7 +1670,7 @@ def test_memory_info(self): # def test_memory_info_ex(self): # # tested later in fetch all test suite - @unittest.skipIf(OPENBSD, "not available on OpenBSD") + @unittest.skipIf(OPENBSD or NETBSD, "not available on this platform") def test_memory_maps(self): p = psutil.Process() maps = p.memory_maps() @@ -3122,7 +3122,7 @@ def test_netstat(self): 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()))