Skip to content

Commit

Permalink
Merge pull request #909 from giampaolo/osx-proc-pidinfo-refact
Browse files Browse the repository at this point in the history
OSX correct proc_pidinfo() handling
  • Loading branch information
giampaolo authored Oct 5, 2016
2 parents a084e7f + bb16715 commit f06f4a8
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 87 deletions.
2 changes: 2 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ Bug tracker at https://github.com/giampaolo/psutil/issues
- #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.
- #XXX: [OSX] Process open_files() and connections() methods may raise
OSError with no exception set if process is gone.


4.3.1 - 2016-09-01
Expand Down
100 changes: 32 additions & 68 deletions psutil/_psutil_osx.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ psutil_proc_cwd(PyObject *self, PyObject *args) {
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;

if (! psutil_proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, &pathinfo,
sizeof(pathinfo)))
if (psutil_proc_pidinfo(
pid, PROC_PIDVNODEPATHINFO, 0, &pathinfo, sizeof(pathinfo)) <= 0)
{
return NULL;
}
Expand Down Expand Up @@ -474,7 +474,7 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args) {

if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti)))
if (psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)) <= 0)
return NULL;
return Py_BuildValue("(dd)",
(float)pti.pti_total_user / 1000000000.0,
Expand Down Expand Up @@ -508,13 +508,13 @@ psutil_proc_memory_info(PyObject *self, PyObject *args) {

if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti)))
if (psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)) <= 0)
return NULL;
// Note: determining other memory stats on OSX is a mess:
// http://www.opensource.apple.com/source/top/top-67/libtop.c?txt
// I just give up...
// struct proc_regioninfo pri;
// psutil_proc_pidinfo(pid, PROC_PIDREGIONINFO, &pri, sizeof(pri))
// psutil_proc_pidinfo(pid, PROC_PIDREGIONINFO, 0, &pri, sizeof(pri))
return Py_BuildValue(
"(KKkk)",
pti.pti_resident_size, // resident memory size (rss)
Expand Down Expand Up @@ -656,7 +656,7 @@ psutil_proc_num_threads(PyObject *self, PyObject *args) {

if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti)))
if (psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)) <= 0)
return NULL;
return Py_BuildValue("k", pti.pti_threadnum);
}
Expand All @@ -672,7 +672,7 @@ psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) {

if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti)))
if (psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)) <= 0)
return NULL;
// unvoluntary value seems not to be available;
// pti.pti_csw probably refers to the sum of the two (getrusage()
Expand Down Expand Up @@ -1137,59 +1137,45 @@ psutil_proc_open_files(PyObject *self, PyObject *args) {
if (! PyArg_ParseTuple(args, "l", &pid))
goto error;

pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
if (pidinfo_result <= 0) {
// may be be ignored later if errno != 0
PyErr_Format(PyExc_RuntimeError,
"proc_pidinfo(PROC_PIDLISTFDS) failed");
pidinfo_result = psutil_proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
if (pidinfo_result <= 0)
goto error;
}

fds_pointer = malloc(pidinfo_result);
if (fds_pointer == NULL) {
PyErr_NoMemory();
goto error;
}
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer,
pidinfo_result);
if (pidinfo_result <= 0) {
// may be be ignored later if errno != 0
PyErr_Format(PyExc_RuntimeError,
"proc_pidinfo(PROC_PIDLISTFDS) failed");
pidinfo_result = psutil_proc_pidinfo(
pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result);
if (pidinfo_result <= 0)
goto error;
}

iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE);

for (i = 0; i < iterations; i++) {
py_tuple = NULL;
fdp_pointer = &fds_pointer[i];

if (fdp_pointer->proc_fdtype == PROX_FDTYPE_VNODE)
{
if (fdp_pointer->proc_fdtype == PROX_FDTYPE_VNODE) {
errno = 0;
nb = proc_pidfdinfo(pid,
fdp_pointer->proc_fd,
PROC_PIDFDVNODEPATHINFO,
&vi,
sizeof(vi));

// --- errors checking
if (nb <= 0) {
if ((nb <= 0) || nb < sizeof(vi)) {
if ((errno == ENOENT) || (errno == EBADF)) {
// no such file or directory or bad file descriptor;
// let's assume the file has been closed or removed
continue;
}
// may be be ignored later if errno != 0
PyErr_Format(PyExc_RuntimeError,
"proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed");
goto error;
}
if (nb < sizeof(vi)) {
PyErr_Format(PyExc_RuntimeError,
"proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed "
"(buffer mismatch)");
goto error;
else {
psutil_raise_for_pid(pid, "proc_pidinfo() syscall failed");
goto error;
}
}
// --- /errors checking

Expand Down Expand Up @@ -1224,12 +1210,7 @@ psutil_proc_open_files(PyObject *self, PyObject *args) {
Py_DECREF(py_retlist);
if (fds_pointer != NULL)
free(fds_pointer);
if (errno != 0)
return PyErr_SetFromErrno(PyExc_OSError);
else if (psutil_pid_exists(pid) == 0)
return NoSuchProcess();
else
return NULL; // exception has already been set earlier
return NULL; // exception has already been set earlier
}


Expand Down Expand Up @@ -1274,7 +1255,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) {

if (pid == 0)
return py_retlist;
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
pidinfo_result = psutil_proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
if (pidinfo_result <= 0)
goto error;

Expand All @@ -1283,44 +1264,34 @@ psutil_proc_connections(PyObject *self, PyObject *args) {
PyErr_NoMemory();
goto error;
}
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer,
pidinfo_result);

pidinfo_result = psutil_proc_pidinfo(
pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result);
if (pidinfo_result <= 0)
goto error;
iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE);

iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE);
for (i = 0; i < iterations; i++) {
py_tuple = NULL;
py_laddr = NULL;
py_raddr = NULL;
errno = 0;
fdp_pointer = &fds_pointer[i];

if (fdp_pointer->proc_fdtype == PROX_FDTYPE_SOCKET)
{
if (fdp_pointer->proc_fdtype == PROX_FDTYPE_SOCKET) {
errno = 0;
nb = proc_pidfdinfo(pid, fdp_pointer->proc_fd,
PROC_PIDFDSOCKETINFO, &si, sizeof(si));

// --- errors checking
if (nb <= 0) {
if ((nb <= 0) || (nb < sizeof(si))) {
if (errno == EBADF) {
// let's assume socket has been closed
continue;
}
if (errno != 0)
PyErr_SetFromErrno(PyExc_OSError);
else
PyErr_Format(
PyExc_RuntimeError,
"proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed");
goto error;
}
if (nb < sizeof(si)) {
PyErr_Format(PyExc_RuntimeError,
"proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed "
"(buffer mismatch)");
goto error;
else {
psutil_raise_for_pid(pid, "proc_pidinfo() syscall failed");
goto error;
}
}
// --- /errors checking

Expand Down Expand Up @@ -1433,16 +1404,9 @@ psutil_proc_connections(PyObject *self, PyObject *args) {
Py_XDECREF(py_laddr);
Py_XDECREF(py_raddr);
Py_DECREF(py_retlist);

if (fds_pointer != NULL)
free(fds_pointer);
if (errno != 0)
return PyErr_SetFromErrno(PyExc_OSError);
else if (! psutil_pid_exists(pid))
return NoSuchProcess();
else
return PyErr_Format(PyExc_RuntimeError,
"proc_pidinfo(PROC_PIDLISTFDS) failed");
return NULL;
}


Expand Down
26 changes: 8 additions & 18 deletions psutil/arch/osx/process_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,26 +353,16 @@ psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp) {


/*
* A thin wrapper around proc_pidinfo()
* A wrapper around proc_pidinfo().
* Returns 0 on failure (and Python exception gets already set).
*/
int
psutil_proc_pidinfo(long pid, int flavor, void *pti, int size) {
int ret = proc_pidinfo((int)pid, flavor, 0, pti, size);
if (ret == 0) {
if (! psutil_pid_exists(pid)) {
NoSuchProcess();
return 0;
}
else {
AccessDenied();
return 0;
}
}
else if (ret != size) {
AccessDenied();
psutil_proc_pidinfo(long pid, int flavor, uint64_t arg, void *pti, int size) {
errno = 0;
int ret = proc_pidinfo((int)pid, flavor, arg, pti, size);
if ((ret <= 0) || (ret < sizeof(pti))) {
psutil_raise_for_pid(pid, "proc_pidinfo() syscall failed");
return 0;
}
else {
return 1;
}
return ret;
}
3 changes: 2 additions & 1 deletion psutil/arch/osx/process_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ typedef struct kinfo_proc kinfo_proc;
int psutil_get_argmax(void);
int psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp);
int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount);
int psutil_proc_pidinfo(long pid, int flavor, void *pti, int size);
int psutil_proc_pidinfo(
long pid, int flavor, uint64_t arg, void *pti, int size);
PyObject* psutil_get_cmdline(long pid);
PyObject* psutil_get_environ(long pid);

0 comments on commit f06f4a8

Please sign in to comment.