Skip to content

Commit

Permalink
Implement Process.environ() on *BSD family
Browse files Browse the repository at this point in the history
Tested-on: FreeBSD-13-CURRENT (r363681), FreeBSD-12.1, FreeBSD-11.4, FreeBSD-11.3,
           FreeBSD-10.4, FreeBSD-9.3, FreeBSD-8.4, FreeBSD-7.1,
           OpenBSD-6.7, OpenBSD-5.7, NetBSD-9.0, NetBSD-8.2
  • Loading branch information
Armin Gruner committed Aug 1, 2020
1 parent 4b269a7 commit 09fc282
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 3 deletions.
5 changes: 5 additions & 0 deletions psutil/_psbsd.py
Expand Up @@ -668,6 +668,11 @@ def cmdline(self):
else:
return cext.proc_cmdline(self.pid)

if hasattr(cext, 'proc_environ'):
@wrap_exceptions
def environ(self):
return cext.proc_environ(self.pid)

@wrap_exceptions
def terminal(self):
tty_nr = self.oneshot()[kinfo_proc_map['ttynr']]
Expand Down
111 changes: 110 additions & 1 deletion psutil/_psutil_bsd.c
Expand Up @@ -57,6 +57,7 @@
#include <net/route.h>
#include <netinet/in.h> // process open files/connections
#include <sys/un.h>
#include <kvm.h>

#include "_psutil_common.h"
#include "_psutil_posix.h"
Expand All @@ -73,7 +74,11 @@
#include <utmp.h> // system users
#else
#include <utmpx.h>
#endif
#endif
#include <fcntl.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#elif PSUTIL_OPENBSD
#include "arch/openbsd/specific.h"

Expand Down Expand Up @@ -391,6 +396,106 @@ psutil_proc_cmdline(PyObject *self, PyObject *args) {
}


#if (defined(__FreeBSD_version) && __FreeBSD_version >= 701000) || defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
/*
* Return process environment as a Python dictionary
*/
PyObject *
psutil_proc_environ(PyObject *self, PyObject *args) {
unsigned int i, cnt = 0;
long pid;
char **envs;
char errbuf[_POSIX2_LINE_MAX];
kvm_t *kd;
#ifdef PSUTIL_NETBSD
struct kinfo_proc2 *p;
#else
struct kinfo_proc *p;
#endif
PyObject *py_retdict;

if (!PyArg_ParseTuple(args, "l", &pid))
return NULL;

#if defined(PSUTIL_FREEBSD)
kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf);
#else
kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
#endif
if (!kd) {
PyErr_SetString(PyExc_RuntimeError, errbuf);
return NULL;
}

#if defined(PSUTIL_FREEBSD)
p = kvm_getprocs(kd, KERN_PROC_PID, pid, (int *)&cnt);
#elif defined(PSUTIL_OPENBSD)
p = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof(*p), &cnt);
#elif defined(PSUTIL_NETBSD)
p = kvm_getproc2(kd, KERN_PROC_PID, pid, sizeof(*p), &cnt);
#endif

if (!p)
{
PyObject *ret = NoSuchProcess(kvm_geterr(kd));
kvm_close(kd);
return ret;
}

if (!cnt)
{
kvm_close(kd);
return NoSuchProcess("");
}

#if defined(PSUTIL_NETBSD)
envs = kvm_getenvv2(kd, p, 0);
#else
envs = kvm_getenvv(kd, p, 0);
#endif

if (!envs)
{
kvm_close(kd);
errno = EPERM;
return PyErr_SetFromErrno(PyExc_OSError);
}

py_retdict = PyDict_New();
if (!py_retdict)
goto error;

for (i = 0; envs[i] != NULL; i++)
{
char *p;
PyObject *py_value;

p = strchr(envs[i], '=');
if (!p)
continue;
*p++ = 0;
py_value = PyUnicode_DecodeFSDefault(p);
if (!py_value)
goto error;
if (PyDict_SetItemString(py_retdict, envs[i], py_value))
{
Py_DECREF(py_value);
goto error;
}
Py_DECREF(py_value);
}

kvm_close(kd);
return py_retdict;

error:
if (py_retdict)
Py_DECREF(py_retdict);
kvm_close(kd);
return NULL;
}
#endif

/*
* Return the number of logical CPUs in the system.
* XXX this could be shared with macOS
Expand Down Expand Up @@ -958,6 +1063,10 @@ static PyMethodDef mod_methods[] = {
{"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS,
"Return an XML string to determine the number physical CPUs."},
#endif
#if (defined(__FreeBSD_version) && __FreeBSD_version >= 701000) || defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
{"proc_environ", psutil_proc_environ, METH_VARARGS,
"Return process environment"},
#endif

// --- system-related functions

Expand Down
3 changes: 2 additions & 1 deletion psutil/tests/test_contracts.py
Expand Up @@ -137,7 +137,8 @@ class TestAvailProcessAPIs(PsutilTestCase):

def test_environ(self):
self.assertEqual(hasattr(psutil.Process, "environ"),
LINUX or MACOS or WINDOWS or AIX or SUNOS)
LINUX or MACOS or WINDOWS or AIX or SUNOS or
FREEBSD or OPENBSD or NETBSD)

def test_uids(self):
self.assertEqual(hasattr(psutil.Process, "uids"), POSIX)
Expand Down
8 changes: 7 additions & 1 deletion setup.py
Expand Up @@ -188,6 +188,12 @@ def get_winver():

elif FREEBSD:
macros.append(("PSUTIL_FREEBSD", 1))
libraries = ["devstat"]
os_major = int(platform.release().split(".")[0])
if os_major >= 9:
libraries.append("procstat")
elif os_major >= 8:
libraries.append("kvm")
ext = Extension(
'psutil._psutil_bsd',
sources=sources + [
Expand All @@ -197,7 +203,7 @@ def get_winver():
'psutil/arch/freebsd/proc_socks.c',
],
define_macros=macros,
libraries=["devstat"])
libraries=libraries)

elif OPENBSD:
macros.append(("PSUTIL_OPENBSD", 1))
Expand Down

0 comments on commit 09fc282

Please sign in to comment.