giampaolo / psutil

Cross-platform lib for process and system monitoring in Python
BSD 3-Clause "New" or "Revised" License
10.16k stars 1.37k forks source link

[AIX] Issue getting info on non-owned processes #1566

Open tbrownaw opened 5 years ago

tbrownaw commented 5 years ago

On the AIX 7.1 boxen I have access to, /proc/$pid/status is readable only by the process owner.

There is also data in /proc/$pid/psinfo, but the way that psutil/_psutil_aix.c reads them makes this other data less usable than it needs to be for non-owned processes.

In psutil_proc_cpu_times(), it only looks at /status. There is also partial information in /psinfo, but it doesn't try to use that.

In psutil_proc_basic_info(), it pulls many things from /psinfo, but also if the process isn't a zombie or exiting will try to pull the process status from /status. In which case it will fail for non-owned processes, and none of the other information returned by psutil_proc_basic_info() will be available either.

I have a patch I've been using, but it just swallows EACCES errors and returns partial information. Which I suspect isn't suitable.

diff --git a/psutil/_psutil_aix.c b/psutil/_psutil_aix.c
index 898da6b2..9bf07ee0 100644
--- a/psutil/_psutil_aix.c
+++ b/psutil/_psutil_aix.c
@@ -114,8 +114,16 @@ psutil_proc_basic_info(PyObject *self, PyObject *args) {
         status.pr_stat = SACTIVE;
     } else {
         sprintf(path, "%s/%i/status", procfs_path, pid);
-        if (! psutil_file_to_struct(path, (void *)&status, sizeof(status)))
-            return NULL;
+        if (! psutil_file_to_struct(path, (void *)&status, sizeof(status))) {
+            //return NULL;
+            if (errno == EACCES) {
+                errno = 0;
+                PyErr_Clear();
+                status.pr_stat = '\0';
+            } else {
+                return NULL;
+            }
+        }
     }

     return Py_BuildValue("KKKdiiiK",
@@ -277,14 +285,29 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args) {
     if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path))
         return NULL;
     sprintf(path, "%s/%i/status", procfs_path, pid);
-    if (! psutil_file_to_struct(path, (void *)&info, sizeof(info)))
-        return NULL;
-    // results are more precise than os.times()
-    return Py_BuildValue("dddd",
-                         TV2DOUBLE(info.pr_utime),
-                         TV2DOUBLE(info.pr_stime),
-                         TV2DOUBLE(info.pr_cutime),
-                         TV2DOUBLE(info.pr_cstime));
+    if (psutil_file_to_struct(path, (void *)&info, sizeof(info))) {
+        // results are more precise than os.times()
+        return Py_BuildValue("dddd",
+                            TV2DOUBLE(info.pr_utime),
+                            TV2DOUBLE(info.pr_stime),
+                            TV2DOUBLE(info.pr_cutime),
+                            TV2DOUBLE(info.pr_cstime));
+    } else if (errno == EACCES) {
+        errno = 0;
+        PyErr_Clear();
+
+        sprintf(path, "%s/%i/psinfo", procfs_path, pid);
+        psinfo_t psinfo;
+        if (psutil_file_to_struct(path, (void *)&psinfo, sizeof(psinfo))) {
+            // results are more precise than os.times()
+            return Py_BuildValue("dddd",
+                                TV2DOUBLE(psinfo.pr_time),
+                                0,
+                                0,
+                                0);
+        }
+    }
+    return NULL;
 }
ecnelises commented 5 months ago

I see the use of /proc/PID/status is to get a map of parent-child relationship. An alternative is to read and parse output of proctree PID command.