Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor C psutil_pid_exists(), fixes #783 and #855 #908

Merged
merged 9 commits into from
Oct 5, 2016
5 changes: 5 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Bug tracker at https://github.com/giampaolo/psutil/issues

**Bug fixes**

- #783: [OSX] Process.status() may erroneously return "running" for zombie
processes.
- #798: [Windows] Process.open_files() returns and empty list on Windows 10.
- #825: [Linux] cpu_affinity; fix possible double close and use of unopened
socket.
Expand All @@ -25,6 +27,9 @@ Bug tracker at https://github.com/giampaolo/psutil/issues
- #906: [BSD] disk_partitions(all=False) returned an empty list. Now the
argument is ignored and all partitions are always returned.
- #907: [FreeBSD] Process.exe() may fail with OSError(ENOENT).
- #908: [OSX, BSD] different process methods could errounesuly mask the real
error for high-privileged PIDs and raise NoSuchProcess and AccessDenied
instead of OSError and RuntimeError.


4.3.1 - 2016-09-01
Expand Down
5 changes: 4 additions & 1 deletion psutil/_psutil_bsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
#include <netinet/in.h> // process open files/connections
#include <sys/un.h>

#include "_psutil_common.h"

#ifdef __FreeBSD__
#include "arch/bsd/freebsd.h"
#include "arch/bsd/freebsd_socks.h"
Expand Down Expand Up @@ -557,9 +559,10 @@ psutil_proc_open_files(PyObject *self, PyObject *args) {
if (psutil_kinfo_proc(pid, &kipp) == -1)
goto error;

errno = 0;
freep = kinfo_getfile(pid, &cnt);
if (freep == NULL) {
psutil_raise_ad_or_nsp(pid);
psutil_raise_for_pid(pid, "kinfo_getfile() failed");
goto error;
}

Expand Down
75 changes: 75 additions & 0 deletions psutil/_psutil_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
* Routines common to all platforms.
*/

#ifdef PSUTIL_POSIX
#include <sys/types.h>
#include <signal.h>
#endif

#include <Python.h>


Expand Down Expand Up @@ -35,3 +40,73 @@ AccessDenied(void) {
Py_XDECREF(exc);
return NULL;
}


#ifdef PSUTIL_POSIX
/*
* Check if PID exists. Return values:
* 1: exists
* 0: does not exist
* -1: error (Python exception is set)
*/
int
psutil_pid_exists(long pid) {
int ret;

// No negative PID exists, plus -1 is an alias for sending signal
// too all processes except system ones. Not what we want.
if (pid < 0)
return 0;

// As per "man 2 kill" PID 0 is an alias for sending the seignal to
// every process in the process group of the calling process.
// Not what we want.
if (pid == 0) {
#if defined(PSUTIL_LINUX) || defined(PSUTIL_FREEBSD)
// PID 0 does not exist on these platforms.
return 0;
#else
return 1;
#endif
}

ret = kill(pid , 0);
if (ret == 0)
return 1;
else {
if (errno == ESRCH)
return 0;
else if (errno == EPERM)
return 1;
else {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
}
}


/*
* Utility used for those syscalls which do not return a meaningful
* error that we can translate into an exception which makes sense.
* As such, we'll have to guess.
* On UNIX, if errno is set, we return that one (OSError).
* Else, if PID does not exist we assume the syscall failed because
* of that so we raise NoSuchProcess.
* 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 *msg) {
// Set exception to AccessDenied if pid exists else NoSuchProcess.
if (errno != 0) {
PyErr_SetFromErrno(PyExc_OSError);
return 0;
}
if (psutil_pid_exists(pid) == 0)
NoSuchProcess();
else
PyErr_SetString(PyExc_RuntimeError, msg);
return 0;
}
#endif
5 changes: 5 additions & 0 deletions psutil/_psutil_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@

PyObject* AccessDenied(void);
PyObject* NoSuchProcess(void);

#ifdef PSUTIL_POSIX
int psutil_pid_exists(long pid);
void psutil_raise_for_pid(long pid, char *msg);
#endif
33 changes: 14 additions & 19 deletions psutil/_psutil_osx.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,6 @@ psutil_sys_vminfo(vm_statistics_data_t *vmstat) {
}


/*
* Set exception to AccessDenied if pid exists else NoSuchProcess.
*/
void
psutil_raise_ad_or_nsp(long pid) {
int ret;
ret = psutil_pid_exists(pid);
if (ret == 0)
NoSuchProcess();
else
AccessDenied();
}


/*
* Return a Python list of all the PIDs running on the system.
*/
Expand Down Expand Up @@ -183,9 +169,10 @@ psutil_proc_exe(PyObject *self, PyObject *args) {

if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
errno = 0;
ret = proc_pidpath(pid, &buf, sizeof(buf));
if (ret == 0) {
psutil_raise_ad_or_nsp(pid);
psutil_raise_for_pid(pid, "proc_pidpath() syscall failed");
return NULL;
}
#if PY_MAJOR_VERSION >= 3
Expand Down Expand Up @@ -323,9 +310,11 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) {
goto error;

err = task_for_pid(mach_task_self(), pid, &task);

if (err != KERN_SUCCESS) {
psutil_raise_ad_or_nsp(pid);
if (psutil_pid_exists(pid) == 0)
NoSuchProcess();
else
AccessDenied();
goto error;
}

Expand Down Expand Up @@ -592,7 +581,10 @@ psutil_proc_memory_uss(PyObject *self, PyObject *args) {

err = task_for_pid(mach_task_self(), pid, &task);
if (err != KERN_SUCCESS) {
psutil_raise_ad_or_nsp(pid);
if (psutil_pid_exists(pid) == 0)
NoSuchProcess();
else
AccessDenied();
return NULL;
}

Expand Down Expand Up @@ -1039,7 +1031,10 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
// task_for_pid() requires special privileges
err = task_for_pid(mach_task_self(), pid, &task);
if (err != KERN_SUCCESS) {
psutil_raise_ad_or_nsp(pid);
if (psutil_pid_exists(pid) == 0)
NoSuchProcess();
else
AccessDenied();
goto error;
}

Expand Down
54 changes: 6 additions & 48 deletions psutil/arch/bsd/freebsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,51 +66,6 @@ psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) {
}


/*
* 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
psutil_pid_exists(long pid) {
int ret;

if (pid < 0)
return 0;
if (pid == 0)
return 1;

ret = kill(pid , 0);
if (ret == 0)
return 1;
else {
if (errno == ESRCH)
return 0;
else if (errno == EPERM)
return 1;
else {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
}
}



int
psutil_raise_ad_or_nsp(long pid) {
// Set exception to AccessDenied if pid exists else NoSuchProcess.
int ret;
ret = psutil_pid_exists(pid);
if (ret == 0)
NoSuchProcess();
else if (ret == 1)
AccessDenied();
return ret;
}


// remove spaces from string
static void psutil_remove_spaces(char *str) {
char *p1 = str;
Expand Down Expand Up @@ -604,9 +559,10 @@ psutil_proc_cwd(PyObject *self, PyObject *args) {
if (psutil_kinfo_proc(pid, &kipp) == -1)
goto error;

errno = 0;
freep = kinfo_getfile(pid, &cnt);
if (freep == NULL) {
psutil_raise_ad_or_nsp(pid);
psutil_raise_for_pid(pid, "kinfo_getfile() failed");
goto error;
}

Expand Down Expand Up @@ -656,9 +612,10 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) {
if (psutil_kinfo_proc(pid, &kipp) == -1)
return NULL;

errno = 0;
freep = kinfo_getfile(pid, &cnt);
if (freep == NULL) {
psutil_raise_ad_or_nsp(pid);
psutil_raise_for_pid(pid, "kinfo_getfile() failed");
return NULL;
}
free(freep);
Expand Down Expand Up @@ -822,9 +779,10 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) {
if (psutil_kinfo_proc(pid, &kp) == -1)
goto error;

errno = 0;
freep = kinfo_getvmmap(pid, &cnt);
if (freep == NULL) {
psutil_raise_ad_or_nsp(pid);
psutil_raise_for_pid(pid, "kinfo_getvmmap() failed");
goto error;
}
for (i = 0; i < cnt; i++) {
Expand Down
2 changes: 0 additions & 2 deletions psutil/arch/bsd/freebsd.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ typedef struct kinfo_proc kinfo_proc;

int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount);
int psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc);
int psutil_pid_exists(long pid);
int psutil_raise_ad_or_nsp(long pid);

//
PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args);
Expand Down
5 changes: 3 additions & 2 deletions psutil/arch/bsd/freebsd_socks.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include <net/if_media.h>
#include <libutil.h>

#include "freebsd.h"
#include "../../_psutil_common.h"


#define HASHSIZE 1009
Expand Down Expand Up @@ -497,9 +497,10 @@ psutil_proc_connections(PyObject *self, PyObject *args) {
goto error;
}

errno = 0;
freep = kinfo_getfile(pid, &cnt);
if (freep == NULL) {
psutil_raise_ad_or_nsp(pid);
psutil_raise_for_pid(pid, "kinfo_getfile() failed");
goto error;
}

Expand Down
39 changes: 2 additions & 37 deletions psutil/arch/bsd/netbsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
#include <arpa/inet.h>


#include "netbsd.h"
#include "netbsd_socks.h"
#include "../../_psutil_common.h"

Expand All @@ -52,16 +51,6 @@
// ============================================================================


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.
Expand Down Expand Up @@ -124,31 +113,6 @@ kinfo_getfile(pid_t pid, int* cnt) {
}


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;
}
}
}


// XXX: This is no longer used as per
// https://github.com/giampaolo/psutil/pull/557#issuecomment-171912820
// Current implementation uses /proc instead.
Expand Down Expand Up @@ -549,9 +513,10 @@ psutil_proc_num_fds(PyObject *self, PyObject *args) {
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;

errno = 0;
freep = kinfo_getfile(pid, &cnt);
if (freep == NULL) {
psutil_raise_ad_or_nsp(pid);
psutil_raise_for_pid(pid, "kinfo_getfile() failed");
return NULL;
}
free(freep);
Expand Down
Loading