From 0e8e5a983ac7e346224cfaa45856738628c1bdc5 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Mon, 27 Jan 2020 01:20:51 +0100 Subject: OpenBSD fixes (#1673) --- psutil/_psbsd.py | 2 +- psutil/_psutil_bsd.c | 14 ++----- psutil/_psutil_posix.c | 25 ++++-------- psutil/arch/freebsd/specific.c | 89 ++++++++++++------------------------------ psutil/arch/netbsd/specific.c | 6 +-- psutil/arch/openbsd/specific.c | 46 +++++++++++++--------- 6 files changed, 67 insertions(+), 115 deletions(-) (limited to 'psutil') diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index 11a2e59c..49ad1e99 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -639,7 +639,7 @@ class Process(object): # cmdline arg (may return None). cmdline = self.cmdline() if cmdline: - return which(cmdline[0]) + return which(cmdline[0]) or "" else: return "" diff --git a/psutil/_psutil_bsd.c b/psutil/_psutil_bsd.c index f58cc72f..30d9f9de 100644 --- a/psutil/_psutil_bsd.c +++ b/psutil/_psutil_bsd.c @@ -125,18 +125,8 @@ psutil_pids(PyObject *self, PyObject *args) { if (py_retlist == NULL) return NULL; - // TODO: RuntimeError is inappropriate here; we could return the - // original error instead. - 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"); - } + if (psutil_get_proc_list(&proclist, &num_processes) != 0) goto error; - } if (num_processes > 0) { orig_address = proclist; // save so we can free it after we're done @@ -475,7 +465,9 @@ psutil_proc_open_files(PyObject *self, PyObject *args) { errno = 0; freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { +#if !defined(PSUTIL_OPENBSD) psutil_raise_for_pid(pid, "kinfo_getfile()"); +#endif goto error; } diff --git a/psutil/_psutil_posix.c b/psutil/_psutil_posix.c index 7fbdcc48..88bea5ce 100644 --- a/psutil/_psutil_posix.c +++ b/psutil/_psutil_posix.c @@ -111,23 +111,14 @@ psutil_pid_exists(long pid) { * If none of this is true we giveup and raise RuntimeError(msg). * This will always set a Python exception and return NULL. */ -int -psutil_raise_for_pid(long pid, char *syscall_name) { - // Set exception to AccessDenied if pid exists else NoSuchProcess. - if (errno != 0) { - // Unlikely we get here. - PyErr_SetFromErrno(PyExc_OSError); - return 0; - } - else if (psutil_pid_exists(pid) == 0) { - psutil_debug("%s syscall failed and PID %i no longer exists; " - "assume NoSuchProcess", syscall_name, pid); - NoSuchProcess("psutil_pid_exists"); - } - else { - PyErr_Format(PyExc_RuntimeError, "%s syscall failed", syscall_name); - } - return 0; +void +psutil_raise_for_pid(long pid, char *syscall) { + if (errno != 0) // unlikely + PyErr_SetFromOSErrnoWithSyscall(syscall); + else if (psutil_pid_exists(pid) == 0) + NoSuchProcess(syscall); + else + PyErr_Format(PyExc_RuntimeError, "%s syscall failed", syscall); } diff --git a/psutil/arch/freebsd/specific.c b/psutil/arch/freebsd/specific.c index 90ea81e8..18fa51fa 100644 --- a/psutil/arch/freebsd/specific.c +++ b/psutil/arch/freebsd/specific.c @@ -88,81 +88,42 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { // Returns a list of all BSD processes on the system. This routine // allocates the list and puts it in *procList and a count of the // number of entries in *procCount. You are responsible for freeing - // this list (use "free" from System framework). - // On success, the function returns 0. - // On error, the function returns a BSD errno value. + // this list. On success returns 0, else 1 with exception set. int err; - struct kinfo_proc *result; - int done; + struct kinfo_proc *buf = NULL; int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 }; - size_t length; + size_t length = 0; - assert( procList != NULL); + assert(procList != NULL); assert(*procList == NULL); assert(procCount != NULL); - *procCount = 0; - - /* - * We start by calling sysctl with result == NULL and length == 0. - * That will succeed, and set length to the appropriate length. - * We then allocate a buffer of that size and call sysctl again - * with that buffer. If that succeeds, we're done. If that fails - * with ENOMEM, we have to throw away our buffer and loop. Note - * that the loop causes use to call sysctl with NULL again; this - * is necessary because the ENOMEM failure case sets length to - * the amount of data returned, not the amount of data that - * could have been returned. - */ - result = NULL; - done = 0; - do { - assert(result == NULL); - // Call sysctl with a NULL buffer. - length = 0; - err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, - NULL, &length, NULL, 0); - if (err == -1) - err = errno; - - // Allocate an appropriately sized buffer based on the results - // from the previous call. - if (err == 0) { - result = malloc(length); - if (result == NULL) - err = ENOMEM; - } + // Call sysctl with a NULL buffer in order to get buffer length. + err = sysctl(name, 3, NULL, &length, NULL, 0); + if (err == -1) { + PyErr_SetFromOSErrnoWithSyscall("sysctl (null buffer)"); + return 1; + } - // Call sysctl again with the new buffer. If we get an ENOMEM - // error, toss away our buffer and start again. - if (err == 0) { - err = sysctl((int *) name, (sizeof(name) / sizeof(*name)) - 1, - result, &length, NULL, 0); - if (err == -1) - err = errno; - if (err == 0) { - done = 1; - } - else if (err == ENOMEM) { - assert(result != NULL); - free(result); - result = NULL; - err = 0; - } - } - } while (err == 0 && ! done); + // Allocate an appropriately sized buffer based on the results + // from the previous call. + buf = malloc(length); + if (buf == NULL) { + PyErr_NoMemory(); + return 1; + } - // Clean up and establish post conditions. - if (err != 0 && result != NULL) { - free(result); - result = NULL; + // Call sysctl again with the new buffer. + err = sysctl(name, 3, buf, &length, NULL, 0); + if (err == -1) { + PyErr_SetFromOSErrnoWithSyscall("sysctl"); + free(buf); + return 1; } - *procList = result; + *procList = buf; *procCount = length / sizeof(struct kinfo_proc); - - assert((err == 0) == (*procList != NULL)); - return err; + return 0; } diff --git a/psutil/arch/netbsd/specific.c b/psutil/arch/netbsd/specific.c index 62e09325..04eab439 100644 --- a/psutil/arch/netbsd/specific.c +++ b/psutil/arch/netbsd/specific.c @@ -320,14 +320,14 @@ psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) { if (kd == NULL) { PyErr_Format( PyExc_RuntimeError, "kvm_openfiles() syscall failed: %s", errbuf); - return errno; + return 1; } result = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(kinfo_proc), &cnt); if (result == NULL) { PyErr_Format(PyExc_RuntimeError, "kvm_getproc2() syscall failed"); kvm_close(kd); - return errno; + return 1; } *procCount = (size_t)cnt; @@ -337,7 +337,7 @@ psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) { if ((*procList = malloc(mlen)) == NULL) { PyErr_NoMemory(); kvm_close(kd); - return errno; + return 1; } memcpy(*procList, result, mlen); diff --git a/psutil/arch/openbsd/specific.c b/psutil/arch/openbsd/specific.c index f8d3cf96..18079b89 100644 --- a/psutil/arch/openbsd/specific.c +++ b/psutil/arch/openbsd/specific.c @@ -46,6 +46,21 @@ // Utility functions // ============================================================================ + +static void +convert_kvm_err(const char *syscall, char *errbuf) { + char fullmsg[8192]; + + sprintf(fullmsg, "(originated from %s: %s)", syscall, errbuf); + if (strstr(errbuf, "Permission denied") != NULL) + AccessDenied(fullmsg); + else if (strstr(errbuf, "Operation not permitted") != NULL) + AccessDenied(fullmsg); + else + PyErr_Format(PyExc_RuntimeError, fullmsg); +} + + int psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc) { // Fills a kinfo_proc struct based on process pid. @@ -133,16 +148,16 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { assert(procCount != NULL); kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); - - if (kd == NULL) { - return errno; + if (! kd) { + convert_kvm_err("kvm_openfiles", errbuf); + return 1; } result = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cnt); if (result == NULL) { + PyErr_Format(PyExc_RuntimeError, "kvm_getprocs syscall failed"); kvm_close(kd); - err(1, NULL); - return errno; + return 1; } *procCount = (size_t)cnt; @@ -150,9 +165,9 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { size_t mlen = cnt * sizeof(struct kinfo_proc); if ((*procList = malloc(mlen)) == NULL) { + PyErr_NoMemory(); kvm_close(kd); - err(1, NULL); - return errno; + return 1; } memcpy(*procList, result, mlen); @@ -163,7 +178,7 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { } -char ** +static char ** _psutil_get_argv(long pid) { static char **argv; int argv_mib[] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV}; @@ -241,10 +256,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) { kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf); if (! kd) { - if (strstr(errbuf, "Permission denied") != NULL) - AccessDenied("kvm_openfiles"); - else - PyErr_Format(PyExc_RuntimeError, "kvm_openfiles() syscall failed"); + convert_kvm_err("kvm_openfiles()", errbuf); goto error; } @@ -398,17 +410,15 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) { if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; + if (psutil_kinfo_proc(pid, &kipp) == -1) return NULL; - errno = 0; freep = kinfo_getfile(pid, &cnt); - if (freep == NULL) { - psutil_raise_for_pid(pid, "kinfo_getfile()"); + if (freep == NULL) return NULL; - } - free(freep); + free(freep); return Py_BuildValue("i", cnt); } @@ -506,10 +516,8 @@ psutil_proc_connections(PyObject *self, PyObject *args) { goto error; } - errno = 0; freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { - psutil_raise_for_pid(pid, "kinfo_getfile()"); goto error; } -- cgit v1.2.1