summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2020-01-27 01:20:51 +0100
committerGitHub <noreply@github.com>2020-01-27 01:20:51 +0100
commit0e8e5a983ac7e346224cfaa45856738628c1bdc5 (patch)
tree9df6219ba109aabd0ec5ecc56db4d8ce45b3a149
parentb178279e908476fa8501008d9cef20c8f362dad1 (diff)
downloadpsutil-0e8e5a983ac7e346224cfaa45856738628c1bdc5.tar.gz
OpenBSD fixes (#1673)
-rw-r--r--HISTORY.rst2
-rw-r--r--psutil/_psbsd.py2
-rw-r--r--psutil/_psutil_bsd.c14
-rw-r--r--psutil/_psutil_posix.c25
-rw-r--r--psutil/arch/freebsd/specific.c89
-rw-r--r--psutil/arch/netbsd/specific.c6
-rw-r--r--psutil/arch/openbsd/specific.c46
7 files changed, 69 insertions, 115 deletions
diff --git a/HISTORY.rst b/HISTORY.rst
index 754c15a0..3f2a81b0 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -26,6 +26,8 @@ XXXX-XX-XX
- 1662_: [Windows] process exe() may raise WinError 0.
- 1665_: [Linux] disk_io_counters() does not take into account extra fields
added to recent kernels. (patch by Mike Hommey)
+- 1673_: [OpenBSD] Process connections(), num_fds() and threads() returned
+ improper exception if process is gone.
5.6.7
=====
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;
}