mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-06-27 02:29:35 +00:00
1390 lines
40 KiB
C
1390 lines
40 KiB
C
/*
|
|
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*
|
|
* Functions specific to Sun OS Solaris platforms.
|
|
*
|
|
* Thanks to Justin Venus who originally wrote a consistent part of
|
|
* this in Cython which I later on translated in C.
|
|
*/
|
|
|
|
|
|
#include <Python.h>
|
|
|
|
// fix for "Cannot use procfs in the large file compilation environment"
|
|
// error, see:
|
|
// http://sourceware.org/ml/gdb-patches/2010-11/msg00336.html
|
|
#undef _FILE_OFFSET_BITS
|
|
#define _STRUCTURED_PROC 1
|
|
|
|
// fix compilation issue on SunOS 5.10, see:
|
|
// https://github.com/giampaolo/psutil/issues/421
|
|
#define NEW_MIB_COMPLIANT
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/swap.h>
|
|
#include <sys/sysinfo.h>
|
|
#include <sys/mntent.h> // for MNTTAB
|
|
#include <sys/mnttab.h>
|
|
#include <sys/procfs.h>
|
|
#include <sys/sockio.h>
|
|
#include <sys/socket.h>
|
|
#include <fcntl.h>
|
|
#include <utmpx.h>
|
|
#include <kstat.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/tihdr.h>
|
|
#include <stropts.h>
|
|
#include <inet/tcp.h>
|
|
#include <arpa/inet.h>
|
|
#include <net/if.h>
|
|
|
|
#include "_psutil_sunos.h"
|
|
|
|
|
|
#define TV2DOUBLE(t) (((t).tv_nsec * 0.000000001) + (t).tv_sec)
|
|
|
|
/*
|
|
* Read a file content and fills a C structure with it.
|
|
*/
|
|
int
|
|
psutil_file_to_struct(char *path, void *fstruct, size_t size)
|
|
{
|
|
int fd;
|
|
size_t nbytes;
|
|
fd = open(path, O_RDONLY);
|
|
if (fd == -1) {
|
|
PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
|
|
return 0;
|
|
}
|
|
nbytes = read(fd, fstruct, size);
|
|
if (nbytes <= 0) {
|
|
close(fd);
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
return 0;
|
|
}
|
|
if (nbytes != size) {
|
|
close(fd);
|
|
PyErr_SetString(PyExc_RuntimeError, "structure size mismatch");
|
|
return 0;
|
|
}
|
|
close(fd);
|
|
return nbytes;
|
|
}
|
|
|
|
|
|
/*
|
|
* Return process ppid, rss, vms, ctime, nice, nthreads, status and tty
|
|
* as a Python tuple.
|
|
*/
|
|
static PyObject *
|
|
psutil_proc_basic_info(PyObject *self, PyObject *args)
|
|
{
|
|
int pid;
|
|
char path[100];
|
|
psinfo_t info;
|
|
|
|
if (! PyArg_ParseTuple(args, "i", &pid))
|
|
return NULL;
|
|
sprintf(path, "/proc/%i/psinfo", pid);
|
|
if (! psutil_file_to_struct(path, (void *)&info, sizeof(info)))
|
|
return NULL;
|
|
return Py_BuildValue("ikkdiiik",
|
|
info.pr_ppid, // parent pid
|
|
info.pr_rssize, // rss
|
|
info.pr_size, // vms
|
|
TV2DOUBLE(info.pr_start), // create time
|
|
info.pr_lwp.pr_nice, // nice
|
|
info.pr_nlwp, // no. of threads
|
|
info.pr_lwp.pr_state, // status code
|
|
info.pr_ttydev // tty nr
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* Return process name and args as a Python tuple.
|
|
*/
|
|
static PyObject *
|
|
psutil_proc_name_and_args(PyObject *self, PyObject *args)
|
|
{
|
|
int pid;
|
|
char path[100];
|
|
psinfo_t info;
|
|
|
|
if (! PyArg_ParseTuple(args, "i", &pid))
|
|
return NULL;
|
|
sprintf(path, "/proc/%i/psinfo", pid);
|
|
if (! psutil_file_to_struct(path, (void *)&info, sizeof(info)))
|
|
return NULL;
|
|
return Py_BuildValue("ss", info.pr_fname, info.pr_psargs);
|
|
}
|
|
|
|
|
|
/*
|
|
* Return process user and system CPU times as a Python tuple.
|
|
*/
|
|
static PyObject *
|
|
psutil_proc_cpu_times(PyObject *self, PyObject *args)
|
|
{
|
|
int pid;
|
|
char path[100];
|
|
pstatus_t info;
|
|
|
|
if (! PyArg_ParseTuple(args, "i", &pid))
|
|
return NULL;
|
|
sprintf(path, "/proc/%i/status", pid);
|
|
if (! psutil_file_to_struct(path, (void *)&info, sizeof(info)))
|
|
return NULL;
|
|
// results are more precise than os.times()
|
|
return Py_BuildValue("dd",
|
|
TV2DOUBLE(info.pr_utime),
|
|
TV2DOUBLE(info.pr_stime));
|
|
}
|
|
|
|
|
|
/*
|
|
* Return process uids/gids as a Python tuple.
|
|
*/
|
|
static PyObject *
|
|
psutil_proc_cred(PyObject *self, PyObject *args)
|
|
{
|
|
int pid;
|
|
char path[100];
|
|
prcred_t info;
|
|
|
|
if (! PyArg_ParseTuple(args, "i", &pid))
|
|
return NULL;
|
|
sprintf(path, "/proc/%i/cred", pid);
|
|
if (! psutil_file_to_struct(path, (void *)&info, sizeof(info)))
|
|
return NULL;
|
|
return Py_BuildValue("iiiiii",
|
|
info.pr_ruid, info.pr_euid, info.pr_suid,
|
|
info.pr_rgid, info.pr_egid, info.pr_sgid);
|
|
}
|
|
|
|
|
|
/*
|
|
* Return process uids/gids as a Python tuple.
|
|
*/
|
|
static PyObject *
|
|
psutil_proc_num_ctx_switches(PyObject *self, PyObject *args)
|
|
{
|
|
int pid;
|
|
char path[100];
|
|
prusage_t info;
|
|
|
|
if (! PyArg_ParseTuple(args, "i", &pid))
|
|
return NULL;
|
|
sprintf(path, "/proc/%i/usage", pid);
|
|
if (! psutil_file_to_struct(path, (void *)&info, sizeof(info)))
|
|
return NULL;
|
|
return Py_BuildValue("kk", info.pr_vctx, info.pr_ictx);
|
|
}
|
|
|
|
|
|
/*
|
|
* Process IO counters.
|
|
*
|
|
* Commented out and left here as a reminder. Apparently we cannot
|
|
* retrieve process IO stats because:
|
|
* - 'pr_ioch' is a sum of chars read and written, with no distinction
|
|
* - 'pr_inblk' and 'pr_oublk', which should be the number of bytes
|
|
* read and written, hardly increase and according to:
|
|
* http://www.brendangregg.com/Perf/paper_diskubyp1.pdf
|
|
* ...they should be meaningless anyway.
|
|
*
|
|
static PyObject*
|
|
proc_io_counters(PyObject* self, PyObject* args)
|
|
{
|
|
int pid;
|
|
char path[100];
|
|
prusage_t info;
|
|
|
|
if (! PyArg_ParseTuple(args, "i", &pid))
|
|
return NULL;
|
|
sprintf(path, "/proc/%i/usage", pid);
|
|
if (! psutil_file_to_struct(path, (void *)&info, sizeof(info)))
|
|
return NULL;
|
|
|
|
// On Solaris we only have 'pr_ioch' which accounts for bytes read
|
|
// *and* written.
|
|
// 'pr_inblk' and 'pr_oublk' should be expressed in blocks of
|
|
// 8KB according to:
|
|
// http://www.brendangregg.com/Perf/paper_diskubyp1.pdf (pag. 8)
|
|
return Py_BuildValue("kkkk",
|
|
info.pr_ioch,
|
|
info.pr_ioch,
|
|
info.pr_inblk,
|
|
info.pr_oublk);
|
|
}
|
|
*/
|
|
|
|
|
|
/*
|
|
* Return information about a given process thread.
|
|
*/
|
|
static PyObject *
|
|
psutil_proc_query_thread(PyObject *self, PyObject *args)
|
|
{
|
|
int pid, tid;
|
|
char path[100];
|
|
lwpstatus_t info;
|
|
|
|
if (! PyArg_ParseTuple(args, "ii", &pid, &tid))
|
|
return NULL;
|
|
sprintf(path, "/proc/%i/lwp/%i/lwpstatus", pid, tid);
|
|
if (! psutil_file_to_struct(path, (void *)&info, sizeof(info)))
|
|
return NULL;
|
|
return Py_BuildValue("dd",
|
|
TV2DOUBLE(info.pr_utime),
|
|
TV2DOUBLE(info.pr_stime));
|
|
}
|
|
|
|
|
|
/*
|
|
* Return information about system virtual memory.
|
|
*/
|
|
static PyObject *
|
|
psutil_swap_mem(PyObject *self, PyObject *args)
|
|
{
|
|
// XXX (arghhh!)
|
|
// total/free swap mem: commented out as for some reason I can't
|
|
// manage to get the same results shown by "swap -l", despite the
|
|
// code below is exactly the same as:
|
|
// http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/
|
|
// cmd/swap/swap.c
|
|
// We're going to parse "swap -l" output from Python (sigh!)
|
|
|
|
/*
|
|
struct swaptable *st;
|
|
struct swapent *swapent;
|
|
int i;
|
|
struct stat64 statbuf;
|
|
char *path;
|
|
char fullpath[MAXPATHLEN+1];
|
|
int num;
|
|
|
|
if ((num = swapctl(SC_GETNSWP, NULL)) == -1) {
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
return NULL;
|
|
}
|
|
if (num == 0) {
|
|
PyErr_SetString(PyExc_RuntimeError, "no swap devices configured");
|
|
return NULL;
|
|
}
|
|
if ((st = malloc(num * sizeof(swapent_t) + sizeof (int))) == NULL) {
|
|
PyErr_SetString(PyExc_RuntimeError, "malloc failed");
|
|
return NULL;
|
|
}
|
|
if ((path = malloc(num * MAXPATHLEN)) == NULL) {
|
|
PyErr_SetString(PyExc_RuntimeError, "malloc failed");
|
|
return NULL;
|
|
}
|
|
swapent = st->swt_ent;
|
|
for (i = 0; i < num; i++, swapent++) {
|
|
swapent->ste_path = path;
|
|
path += MAXPATHLEN;
|
|
}
|
|
st->swt_n = num;
|
|
if ((num = swapctl(SC_LIST, st)) == -1) {
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
return NULL;
|
|
}
|
|
|
|
swapent = st->swt_ent;
|
|
long t = 0, f = 0;
|
|
for (i = 0; i < num; i++, swapent++) {
|
|
int diskblks_per_page =(int)(sysconf(_SC_PAGESIZE) >> DEV_BSHIFT);
|
|
t += (long)swapent->ste_pages;
|
|
f += (long)swapent->ste_free;
|
|
}
|
|
|
|
free(st);
|
|
return Py_BuildValue("(kk)", t, f);
|
|
*/
|
|
|
|
kstat_ctl_t *kc;
|
|
kstat_t *k;
|
|
cpu_stat_t *cpu;
|
|
int cpu_count = 0;
|
|
int flag = 0;
|
|
uint_t sin = 0;
|
|
uint_t sout = 0;
|
|
|
|
kc = kstat_open();
|
|
if (kc == NULL)
|
|
return PyErr_SetFromErrno(PyExc_OSError);;
|
|
|
|
k = kc->kc_chain;
|
|
while (k != NULL) {
|
|
if ((strncmp(k->ks_name, "cpu_stat", 8) == 0) && \
|
|
(kstat_read(kc, k, NULL) != -1) )
|
|
{
|
|
flag = 1;
|
|
cpu = (cpu_stat_t *) k->ks_data;
|
|
sin += cpu->cpu_vminfo.pgswapin; // num pages swapped in
|
|
sout += cpu->cpu_vminfo.pgswapout; // num pages swapped out
|
|
}
|
|
cpu_count += 1;
|
|
k = k->ks_next;
|
|
}
|
|
kstat_close(kc);
|
|
if (!flag) {
|
|
PyErr_SetString(PyExc_RuntimeError, "no swap device was found");
|
|
return NULL;
|
|
}
|
|
return Py_BuildValue("(II)", sin, sout);
|
|
}
|
|
|
|
|
|
/*
|
|
* Return users currently connected on the system.
|
|
*/
|
|
static PyObject *
|
|
psutil_users(PyObject *self, PyObject *args)
|
|
{
|
|
struct utmpx *ut;
|
|
PyObject *ret_list = PyList_New(0);
|
|
PyObject *tuple = NULL;
|
|
PyObject *user_proc = NULL;
|
|
|
|
if (ret_list == NULL)
|
|
return NULL;
|
|
|
|
while (NULL != (ut = getutxent())) {
|
|
if (ut->ut_type == USER_PROCESS)
|
|
user_proc = Py_True;
|
|
else
|
|
user_proc = Py_False;
|
|
tuple = Py_BuildValue(
|
|
"(sssfO)",
|
|
ut->ut_user, // username
|
|
ut->ut_line, // tty
|
|
ut->ut_host, // hostname
|
|
(float)ut->ut_tv.tv_sec, // tstamp
|
|
user_proc); // (bool) user process
|
|
if (tuple == NULL)
|
|
goto error;
|
|
if (PyList_Append(ret_list, tuple))
|
|
goto error;
|
|
Py_DECREF(tuple);
|
|
}
|
|
endutent();
|
|
|
|
return ret_list;
|
|
|
|
error:
|
|
Py_XDECREF(tuple);
|
|
Py_DECREF(ret_list);
|
|
if (ut != NULL)
|
|
endutent();
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* Return disk mounted partitions as a list of tuples including device,
|
|
* mount point and filesystem type.
|
|
*/
|
|
static PyObject *
|
|
psutil_disk_partitions(PyObject *self, PyObject *args)
|
|
{
|
|
FILE *file;
|
|
struct mnttab mt;
|
|
PyObject *py_retlist = PyList_New(0);
|
|
PyObject *py_tuple = NULL;
|
|
|
|
if (py_retlist == NULL)
|
|
return NULL;
|
|
|
|
file = fopen(MNTTAB, "rb");
|
|
if (file == NULL) {
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
goto error;
|
|
}
|
|
|
|
while (getmntent(file, &mt) == 0) {
|
|
py_tuple = Py_BuildValue(
|
|
"(ssss)",
|
|
mt.mnt_special, // device
|
|
mt.mnt_mountp, // mount point
|
|
mt.mnt_fstype, // fs type
|
|
mt.mnt_mntopts); // options
|
|
if (py_tuple == NULL)
|
|
goto error;
|
|
if (PyList_Append(py_retlist, py_tuple))
|
|
goto error;
|
|
Py_DECREF(py_tuple);
|
|
|
|
}
|
|
fclose(file);
|
|
return py_retlist;
|
|
|
|
error:
|
|
Py_XDECREF(py_tuple);
|
|
Py_DECREF(py_retlist);
|
|
if (file != NULL)
|
|
fclose(file);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* Return system-wide CPU times.
|
|
*/
|
|
static PyObject *
|
|
psutil_per_cpu_times(PyObject *self, PyObject *args)
|
|
{
|
|
kstat_ctl_t *kc;
|
|
kstat_t *ksp;
|
|
cpu_stat_t cs;
|
|
PyObject *py_retlist = PyList_New(0);
|
|
PyObject *py_cputime = NULL;
|
|
|
|
if (py_retlist == NULL)
|
|
return NULL;
|
|
|
|
kc = kstat_open();
|
|
if (kc == NULL) {
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
goto error;
|
|
}
|
|
|
|
for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
|
|
if (strcmp(ksp->ks_module, "cpu_stat") == 0) {
|
|
if (kstat_read(kc, ksp, &cs) == -1) {
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
goto error;
|
|
}
|
|
py_cputime = Py_BuildValue("ffff",
|
|
(float)cs.cpu_sysinfo.cpu[CPU_USER],
|
|
(float)cs.cpu_sysinfo.cpu[CPU_KERNEL],
|
|
(float)cs.cpu_sysinfo.cpu[CPU_IDLE],
|
|
(float)cs.cpu_sysinfo.cpu[CPU_WAIT]);
|
|
if (py_cputime == NULL)
|
|
goto error;
|
|
if (PyList_Append(py_retlist, py_cputime))
|
|
goto error;
|
|
Py_DECREF(py_cputime);
|
|
py_cputime = NULL;
|
|
}
|
|
}
|
|
|
|
kstat_close(kc);
|
|
return py_retlist;
|
|
|
|
error:
|
|
Py_XDECREF(py_cputime);
|
|
Py_DECREF(py_retlist);
|
|
if (kc != NULL)
|
|
kstat_close(kc);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* Return disk IO statistics.
|
|
*/
|
|
static PyObject *
|
|
psutil_disk_io_counters(PyObject *self, PyObject *args)
|
|
{
|
|
kstat_ctl_t *kc;
|
|
kstat_t *ksp;
|
|
kstat_io_t kio;
|
|
PyObject *py_retdict = PyDict_New();
|
|
PyObject *py_disk_info = NULL;
|
|
|
|
if (py_retdict == NULL)
|
|
return NULL;
|
|
kc = kstat_open();
|
|
if (kc == NULL) {
|
|
PyErr_SetFromErrno(PyExc_OSError);;
|
|
goto error;
|
|
}
|
|
ksp = kc->kc_chain;
|
|
while (ksp != NULL) {
|
|
if (ksp->ks_type == KSTAT_TYPE_IO) {
|
|
if (strcmp(ksp->ks_class, "disk") == 0) {
|
|
if (kstat_read(kc, ksp, &kio) == -1) {
|
|
kstat_close(kc);
|
|
return PyErr_SetFromErrno(PyExc_OSError);;
|
|
}
|
|
py_disk_info = Py_BuildValue(
|
|
"(IIKKLL)",
|
|
kio.reads,
|
|
kio.writes,
|
|
kio.nread,
|
|
kio.nwritten,
|
|
kio.rtime / 1000 / 1000, // from nano to milli secs
|
|
kio.wtime / 1000 / 1000 // from nano to milli secs
|
|
);
|
|
if (!py_disk_info)
|
|
goto error;
|
|
if (PyDict_SetItemString(py_retdict, ksp->ks_name,
|
|
py_disk_info))
|
|
goto error;
|
|
Py_DECREF(py_disk_info);
|
|
}
|
|
}
|
|
ksp = ksp->ks_next;
|
|
}
|
|
kstat_close(kc);
|
|
|
|
return py_retdict;
|
|
|
|
error:
|
|
Py_XDECREF(py_disk_info);
|
|
Py_DECREF(py_retdict);
|
|
if (kc != NULL)
|
|
kstat_close(kc);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* Return process memory mappings.
|
|
*/
|
|
static PyObject *
|
|
psutil_proc_memory_maps(PyObject *self, PyObject *args)
|
|
{
|
|
int pid;
|
|
int fd = -1;
|
|
char path[100];
|
|
char perms[10];
|
|
char *name;
|
|
struct stat st;
|
|
pstatus_t status;
|
|
|
|
prxmap_t *xmap = NULL, *p;
|
|
off_t size;
|
|
size_t nread;
|
|
int nmap;
|
|
uintptr_t pr_addr_sz;
|
|
uintptr_t stk_base_sz, brk_base_sz;
|
|
|
|
PyObject *pytuple = NULL;
|
|
PyObject *py_retlist = PyList_New(0);
|
|
|
|
if (py_retlist == NULL)
|
|
return NULL;
|
|
if (! PyArg_ParseTuple(args, "i", &pid))
|
|
goto error;
|
|
|
|
sprintf(path, "/proc/%i/status", pid);
|
|
if (! psutil_file_to_struct(path, (void *)&status, sizeof(status)))
|
|
goto error;
|
|
|
|
sprintf(path, "/proc/%i/xmap", pid);
|
|
if (stat(path, &st) == -1) {
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
goto error;
|
|
}
|
|
|
|
size = st.st_size;
|
|
|
|
fd = open(path, O_RDONLY);
|
|
if (fd == -1) {
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
goto error;
|
|
}
|
|
|
|
xmap = (prxmap_t *)malloc(size);
|
|
if (xmap == NULL) {
|
|
PyErr_NoMemory();
|
|
goto error;
|
|
}
|
|
|
|
nread = pread(fd, xmap, size, 0);
|
|
nmap = nread / sizeof(prxmap_t);
|
|
p = xmap;
|
|
|
|
while (nmap) {
|
|
nmap -= 1;
|
|
if (p == NULL) {
|
|
p += 1;
|
|
continue;
|
|
}
|
|
|
|
perms[0] = '\0';
|
|
pr_addr_sz = p->pr_vaddr + p->pr_size;
|
|
|
|
// perms
|
|
sprintf(perms, "%c%c%c%c%c%c", p->pr_mflags & MA_READ ? 'r' : '-',
|
|
p->pr_mflags & MA_WRITE ? 'w' : '-',
|
|
p->pr_mflags & MA_EXEC ? 'x' : '-',
|
|
p->pr_mflags & MA_SHARED ? 's' : '-',
|
|
p->pr_mflags & MA_NORESERVE ? 'R' : '-',
|
|
p->pr_mflags & MA_RESERVED1 ? '*' : ' ');
|
|
|
|
// name
|
|
if (strlen(p->pr_mapname) > 0) {
|
|
name = p->pr_mapname;
|
|
}
|
|
else {
|
|
if ((p->pr_mflags & MA_ISM) || (p->pr_mflags & MA_SHM)) {
|
|
name = "[shmid]";
|
|
}
|
|
else {
|
|
stk_base_sz = status.pr_stkbase + status.pr_stksize;
|
|
brk_base_sz = status.pr_brkbase + status.pr_brksize;
|
|
|
|
if ((pr_addr_sz > status.pr_stkbase) &&
|
|
(p->pr_vaddr < stk_base_sz)) {
|
|
name = "[stack]";
|
|
}
|
|
else if ((p->pr_mflags & MA_ANON) && \
|
|
(pr_addr_sz > status.pr_brkbase) && \
|
|
(p->pr_vaddr < brk_base_sz)) {
|
|
name = "[heap]";
|
|
}
|
|
else {
|
|
name = "[anon]";
|
|
}
|
|
}
|
|
}
|
|
|
|
pytuple = Py_BuildValue("iisslll",
|
|
p->pr_vaddr,
|
|
pr_addr_sz,
|
|
perms,
|
|
name,
|
|
(long)p->pr_rss * p->pr_pagesize,
|
|
(long)p->pr_anon * p->pr_pagesize,
|
|
(long)p->pr_locked * p->pr_pagesize);
|
|
if (!pytuple)
|
|
goto error;
|
|
if (PyList_Append(py_retlist, pytuple))
|
|
goto error;
|
|
Py_DECREF(pytuple);
|
|
|
|
// increment pointer
|
|
p += 1;
|
|
}
|
|
|
|
close(fd);
|
|
free(xmap);
|
|
return py_retlist;
|
|
|
|
error:
|
|
if (fd != -1)
|
|
close(fd);
|
|
Py_XDECREF(pytuple);
|
|
Py_DECREF(py_retlist);
|
|
if (xmap != NULL)
|
|
free(xmap);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* Return a list of tuples for network I/O statistics.
|
|
*/
|
|
static PyObject *
|
|
psutil_net_io_counters(PyObject *self, PyObject *args)
|
|
{
|
|
kstat_ctl_t *kc = NULL;
|
|
kstat_t *ksp;
|
|
kstat_named_t *rbytes, *wbytes, *rpkts, *wpkts, *ierrs, *oerrs;
|
|
|
|
PyObject *py_retdict = PyDict_New();
|
|
PyObject *py_ifc_info = NULL;
|
|
|
|
if (py_retdict == NULL)
|
|
return NULL;
|
|
kc = kstat_open();
|
|
if (kc == NULL)
|
|
goto error;
|
|
|
|
ksp = kc->kc_chain;
|
|
while (ksp != NULL) {
|
|
if (ksp->ks_type != KSTAT_TYPE_NAMED)
|
|
goto next;
|
|
if (strcmp(ksp->ks_class, "net") != 0)
|
|
goto next;
|
|
/*
|
|
// XXX "lo" (localhost) interface makes kstat_data_lookup() fail
|
|
// (maybe because "ifconfig -a" says it's a virtual interface?).
|
|
if ((strcmp(ksp->ks_module, "link") != 0) &&
|
|
(strcmp(ksp->ks_module, "lo") != 0)) {
|
|
goto skip;
|
|
*/
|
|
if ((strcmp(ksp->ks_module, "link") != 0))
|
|
goto next;
|
|
|
|
if (kstat_read(kc, ksp, NULL) == -1) {
|
|
errno = 0;
|
|
continue;
|
|
}
|
|
|
|
rbytes = (kstat_named_t *)kstat_data_lookup(ksp, "rbytes");
|
|
wbytes = (kstat_named_t *)kstat_data_lookup(ksp, "obytes");
|
|
rpkts = (kstat_named_t *)kstat_data_lookup(ksp, "ipackets");
|
|
wpkts = (kstat_named_t *)kstat_data_lookup(ksp, "opackets");
|
|
ierrs = (kstat_named_t *)kstat_data_lookup(ksp, "ierrors");
|
|
oerrs = (kstat_named_t *)kstat_data_lookup(ksp, "oerrors");
|
|
|
|
if ((rbytes == NULL) || (wbytes == NULL) || (rpkts == NULL) ||
|
|
(wpkts == NULL) || (ierrs == NULL) || (oerrs == NULL))
|
|
{
|
|
PyErr_SetString(PyExc_RuntimeError, "kstat_data_lookup() failed");
|
|
goto error;
|
|
}
|
|
|
|
#if defined(_INT64_TYPE)
|
|
py_ifc_info = Py_BuildValue("(KKKKkkii)",
|
|
wbytes->value.ui64,
|
|
rbytes->value.ui64,
|
|
wpkts->value.ui64,
|
|
rpkts->value.ui64,
|
|
ierrs->value.ui32,
|
|
oerrs->value.ui32,
|
|
#else
|
|
py_ifc_info = Py_BuildValue("(kkkkkkii)",
|
|
wbytes->value.ui32,
|
|
rbytes->value.ui32,
|
|
wpkts->value.ui32,
|
|
rpkts->value.ui32,
|
|
ierrs->value.ui32,
|
|
oerrs->value.ui32,
|
|
#endif
|
|
0, // dropin not supported
|
|
0 // dropout not supported
|
|
);
|
|
if (!py_ifc_info)
|
|
goto error;
|
|
if (PyDict_SetItemString(py_retdict, ksp->ks_name, py_ifc_info))
|
|
goto error;
|
|
Py_DECREF(py_ifc_info);
|
|
goto next;
|
|
|
|
next:
|
|
ksp = ksp->ks_next;
|
|
}
|
|
|
|
kstat_close(kc);
|
|
return py_retdict;
|
|
|
|
error:
|
|
Py_XDECREF(py_ifc_info);
|
|
Py_DECREF(py_retdict);
|
|
if (kc != NULL)
|
|
kstat_close(kc);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
#ifndef EXPER_IP_AND_ALL_IRES
|
|
#define EXPER_IP_AND_ALL_IRES (1024+4)
|
|
#endif
|
|
|
|
// a signaler for connections without an actual status
|
|
static int PSUTIL_CONN_NONE = 128;
|
|
|
|
/*
|
|
* Return TCP and UDP connections opened by process.
|
|
* UNIX sockets are excluded.
|
|
*
|
|
* Thanks to:
|
|
* https://github.com/DavidGriffith/finx/blob/master/
|
|
* nxsensor-3.5.0-1/src/sysdeps/solaris.c
|
|
* ...and:
|
|
* https://hg.java.net/hg/solaris~on-src/file/tip/usr/src/cmd/
|
|
* cmd-inet/usr.bin/netstat/netstat.c
|
|
*/
|
|
static PyObject *
|
|
psutil_net_connections(PyObject *self, PyObject *args)
|
|
{
|
|
long pid;
|
|
int sd = 0;
|
|
mib2_tcpConnEntry_t *tp = NULL;
|
|
mib2_udpEntry_t *ude;
|
|
#if defined(AF_INET6)
|
|
mib2_tcp6ConnEntry_t *tp6;
|
|
mib2_udp6Entry_t *ude6;
|
|
#endif
|
|
char buf[512];
|
|
int i, flags, getcode, num_ent, state;
|
|
char lip[200], rip[200];
|
|
int lport, rport;
|
|
int processed_pid;
|
|
int databuf_init = 0;
|
|
struct strbuf ctlbuf, databuf;
|
|
struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf;
|
|
struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf;
|
|
struct T_error_ack *tea = (struct T_error_ack *)buf;
|
|
struct opthdr *mibhdr;
|
|
|
|
PyObject *py_retlist = PyList_New(0);
|
|
PyObject *py_tuple = NULL;
|
|
PyObject *py_laddr = NULL;
|
|
PyObject *py_raddr = NULL;
|
|
PyObject *af_filter = NULL;
|
|
PyObject *type_filter = NULL;
|
|
|
|
if (py_retlist == NULL)
|
|
return NULL;
|
|
if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter))
|
|
goto error;
|
|
if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) {
|
|
PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
|
|
goto error;
|
|
}
|
|
|
|
sd = open("/dev/arp", O_RDWR);
|
|
if (sd == -1) {
|
|
PyErr_SetFromErrnoWithFilename(PyExc_OSError, "/dev/arp");
|
|
goto error;
|
|
}
|
|
|
|
/*
|
|
XXX - These 2 are used in ifconfig.c but they seem unnecessary
|
|
ret = ioctl(sd, I_PUSH, "tcp");
|
|
if (ret == -1) {
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
goto error;
|
|
}
|
|
ret = ioctl(sd, I_PUSH, "udp");
|
|
if (ret == -1) {
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
goto error;
|
|
}
|
|
*/
|
|
|
|
// OK, this mess is basically copied and pasted from nxsensor project
|
|
// which copied and pasted it from netstat source code, mibget()
|
|
// function. Also see:
|
|
// http://stackoverflow.com/questions/8723598/
|
|
tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
|
|
tor->OPT_offset = sizeof (struct T_optmgmt_req);
|
|
tor->OPT_length = sizeof (struct opthdr);
|
|
tor->MGMT_flags = T_CURRENT;
|
|
mibhdr = (struct opthdr *)&tor[1];
|
|
mibhdr->level = EXPER_IP_AND_ALL_IRES;
|
|
mibhdr->name = 0;
|
|
mibhdr->len = 0;
|
|
|
|
ctlbuf.buf = buf;
|
|
ctlbuf.len = tor->OPT_offset + tor->OPT_length;
|
|
flags = 0; // request to be sent in non-priority
|
|
|
|
if (putmsg(sd, &ctlbuf, (struct strbuf *)0, flags) == -1) {
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
goto error;
|
|
}
|
|
|
|
mibhdr = (struct opthdr *)&toa[1];
|
|
ctlbuf.maxlen = sizeof (buf);
|
|
|
|
for (;;) {
|
|
flags = 0;
|
|
getcode = getmsg(sd, &ctlbuf, (struct strbuf *)0, &flags);
|
|
|
|
if (getcode != MOREDATA ||
|
|
ctlbuf.len < sizeof (struct T_optmgmt_ack) ||
|
|
toa->PRIM_type != T_OPTMGMT_ACK ||
|
|
toa->MGMT_flags != T_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
if (ctlbuf.len >= sizeof (struct T_error_ack) &&
|
|
tea->PRIM_type == T_ERROR_ACK)
|
|
{
|
|
PyErr_SetString(PyExc_RuntimeError, "ERROR_ACK");
|
|
goto error;
|
|
}
|
|
if (getcode == 0 &&
|
|
ctlbuf.len >= sizeof (struct T_optmgmt_ack) &&
|
|
toa->PRIM_type == T_OPTMGMT_ACK &&
|
|
toa->MGMT_flags == T_SUCCESS)
|
|
{
|
|
PyErr_SetString(PyExc_RuntimeError, "ERROR_T_OPTMGMT_ACK");
|
|
goto error;
|
|
}
|
|
|
|
databuf.maxlen = mibhdr->len;
|
|
databuf.len = 0;
|
|
databuf.buf = (char *)malloc((int)mibhdr->len);
|
|
if (!databuf.buf) {
|
|
PyErr_NoMemory();
|
|
goto error;
|
|
}
|
|
databuf_init = 1;
|
|
|
|
flags = 0;
|
|
getcode = getmsg(sd, (struct strbuf *)0, &databuf, &flags);
|
|
if (getcode < 0) {
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
goto error;
|
|
}
|
|
|
|
// TCPv4
|
|
if (mibhdr->level == MIB2_TCP && mibhdr->name == MIB2_TCP_13) {
|
|
tp = (mib2_tcpConnEntry_t *)databuf.buf;
|
|
num_ent = mibhdr->len / sizeof(mib2_tcpConnEntry_t);
|
|
for (i = 0; i < num_ent; i++, tp++) {
|
|
processed_pid = tp->tcpConnCreationProcess;
|
|
if (pid != -1 && processed_pid != pid)
|
|
continue;
|
|
// construct local/remote addresses
|
|
inet_ntop(AF_INET, &tp->tcpConnLocalAddress, lip, sizeof(lip));
|
|
inet_ntop(AF_INET, &tp->tcpConnRemAddress, rip, sizeof(rip));
|
|
lport = tp->tcpConnLocalPort;
|
|
rport = tp->tcpConnRemPort;
|
|
|
|
// contruct python tuple/list
|
|
py_laddr = Py_BuildValue("(si)", lip, lport);
|
|
if (!py_laddr)
|
|
goto error;
|
|
if (rport != 0)
|
|
py_raddr = Py_BuildValue("(si)", rip, rport);
|
|
else {
|
|
py_raddr = Py_BuildValue("()");
|
|
}
|
|
if (!py_raddr)
|
|
goto error;
|
|
state = tp->tcpConnEntryInfo.ce_state;
|
|
|
|
// add item
|
|
py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET, SOCK_STREAM,
|
|
py_laddr, py_raddr, state,
|
|
processed_pid);
|
|
if (!py_tuple)
|
|
goto error;
|
|
if (PyList_Append(py_retlist, py_tuple))
|
|
goto error;
|
|
Py_DECREF(py_tuple);
|
|
}
|
|
}
|
|
#if defined(AF_INET6)
|
|
// TCPv6
|
|
else if (mibhdr->level == MIB2_TCP6 && mibhdr->name == MIB2_TCP6_CONN)
|
|
{
|
|
tp6 = (mib2_tcp6ConnEntry_t *)databuf.buf;
|
|
num_ent = mibhdr->len / sizeof(mib2_tcp6ConnEntry_t);
|
|
|
|
for (i = 0; i < num_ent; i++, tp6++) {
|
|
processed_pid = tp6->tcp6ConnCreationProcess;
|
|
if (pid != -1 && processed_pid != pid)
|
|
continue;
|
|
// construct local/remote addresses
|
|
inet_ntop(AF_INET6, &tp6->tcp6ConnLocalAddress, lip, sizeof(lip));
|
|
inet_ntop(AF_INET6, &tp6->tcp6ConnRemAddress, rip, sizeof(rip));
|
|
lport = tp6->tcp6ConnLocalPort;
|
|
rport = tp6->tcp6ConnRemPort;
|
|
|
|
// contruct python tuple/list
|
|
py_laddr = Py_BuildValue("(si)", lip, lport);
|
|
if (!py_laddr)
|
|
goto error;
|
|
if (rport != 0)
|
|
py_raddr = Py_BuildValue("(si)", rip, rport);
|
|
else
|
|
py_raddr = Py_BuildValue("()");
|
|
if (!py_raddr)
|
|
goto error;
|
|
state = tp6->tcp6ConnEntryInfo.ce_state;
|
|
|
|
// add item
|
|
py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET6, SOCK_STREAM,
|
|
py_laddr, py_raddr, state, processed_pid);
|
|
if (!py_tuple)
|
|
goto error;
|
|
if (PyList_Append(py_retlist, py_tuple))
|
|
goto error;
|
|
Py_DECREF(py_tuple);
|
|
}
|
|
}
|
|
#endif
|
|
// UDPv4
|
|
else if (mibhdr->level == MIB2_UDP || mibhdr->level == MIB2_UDP_ENTRY) {
|
|
ude = (mib2_udpEntry_t *)databuf.buf;
|
|
num_ent = mibhdr->len / sizeof(mib2_udpEntry_t);
|
|
for (i = 0; i < num_ent; i++, ude++) {
|
|
processed_pid = ude->udpCreationProcess;
|
|
if (pid != -1 && processed_pid != pid)
|
|
continue;
|
|
// XXX Very ugly hack! It seems we get here only the first
|
|
// time we bump into a UDPv4 socket. PID is a very high
|
|
// number (clearly impossible) and the address does not
|
|
// belong to any valid interface. Not sure what else
|
|
// to do other than skipping.
|
|
if (processed_pid > 131072)
|
|
continue;
|
|
inet_ntop(AF_INET, &ude->udpLocalAddress, lip, sizeof(lip));
|
|
lport = ude->udpLocalPort;
|
|
py_laddr = Py_BuildValue("(si)", lip, lport);
|
|
if (!py_laddr)
|
|
goto error;
|
|
py_raddr = Py_BuildValue("()");
|
|
if (!py_raddr)
|
|
goto error;
|
|
py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET, SOCK_DGRAM,
|
|
py_laddr, py_raddr, PSUTIL_CONN_NONE,
|
|
processed_pid);
|
|
if (!py_tuple)
|
|
goto error;
|
|
if (PyList_Append(py_retlist, py_tuple))
|
|
goto error;
|
|
Py_DECREF(py_tuple);
|
|
}
|
|
}
|
|
#if defined(AF_INET6)
|
|
// UDPv6
|
|
else if (mibhdr->level == MIB2_UDP6 ||
|
|
mibhdr->level == MIB2_UDP6_ENTRY)
|
|
{
|
|
ude6 = (mib2_udp6Entry_t *)databuf.buf;
|
|
num_ent = mibhdr->len / sizeof(mib2_udp6Entry_t);
|
|
for (i = 0; i < num_ent; i++, ude6++) {
|
|
processed_pid = ude6->udp6CreationProcess;
|
|
if (pid != -1 && processed_pid != pid)
|
|
continue;
|
|
inet_ntop(AF_INET6, &ude6->udp6LocalAddress, lip, sizeof(lip));
|
|
lport = ude6->udp6LocalPort;
|
|
py_laddr = Py_BuildValue("(si)", lip, lport);
|
|
if (!py_laddr)
|
|
goto error;
|
|
py_raddr = Py_BuildValue("()");
|
|
if (!py_raddr)
|
|
goto error;
|
|
py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET6, SOCK_DGRAM,
|
|
py_laddr, py_raddr, PSUTIL_CONN_NONE,
|
|
processed_pid);
|
|
if (!py_tuple)
|
|
goto error;
|
|
if (PyList_Append(py_retlist, py_tuple))
|
|
goto error;
|
|
Py_DECREF(py_tuple);
|
|
}
|
|
}
|
|
#endif
|
|
free(databuf.buf);
|
|
}
|
|
|
|
close(sd);
|
|
return py_retlist;
|
|
|
|
error:
|
|
Py_XDECREF(py_tuple);
|
|
Py_XDECREF(py_laddr);
|
|
Py_XDECREF(py_raddr);
|
|
Py_DECREF(py_retlist);
|
|
if (databuf_init == 1)
|
|
free(databuf.buf);
|
|
if (sd != 0)
|
|
close(sd);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
psutil_boot_time(PyObject *self, PyObject *args)
|
|
{
|
|
float boot_time = 0.0;
|
|
struct utmpx *ut;
|
|
|
|
while (NULL != (ut = getutxent())) {
|
|
if (ut->ut_type == BOOT_TIME) {
|
|
boot_time = (float)ut->ut_tv.tv_sec;
|
|
break;
|
|
}
|
|
}
|
|
endutent();
|
|
if (boot_time != 0.0) {
|
|
return Py_BuildValue("f", boot_time);
|
|
}
|
|
else {
|
|
PyErr_SetString(PyExc_RuntimeError, "can't determine boot time");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Return the number of physical CPU cores on the system.
|
|
*/
|
|
static PyObject *
|
|
psutil_cpu_count_phys(PyObject *self, PyObject *args)
|
|
{
|
|
kstat_ctl_t *kc;
|
|
kstat_t *ksp;
|
|
int ncpus = 0;
|
|
|
|
kc = kstat_open();
|
|
if (kc == NULL)
|
|
goto error;
|
|
ksp = kstat_lookup(kc, "cpu_info", -1, NULL);
|
|
if (ksp == NULL)
|
|
goto error;
|
|
|
|
for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
|
|
if (strcmp(ksp->ks_module, "cpu_info") != 0)
|
|
continue;
|
|
if (kstat_read(kc, ksp, NULL) == -1)
|
|
goto error;
|
|
ncpus += 1;
|
|
}
|
|
|
|
kstat_close(kc);
|
|
if (ncpus > 0)
|
|
return Py_BuildValue("i", ncpus);
|
|
else
|
|
goto error;
|
|
|
|
error:
|
|
// mimic os.cpu_count()
|
|
if (kc != NULL)
|
|
kstat_close(kc);
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Return stats about a particular network
|
|
* interface. References:
|
|
* https://github.com/dpaleino/wicd/blob/master/wicd/backends/be-ioctl.py
|
|
* http://www.i-scream.org/libstatgrab/
|
|
*/
|
|
static PyObject*
|
|
psutil_net_if_stats(PyObject* self, PyObject* args)
|
|
{
|
|
kstat_ctl_t *kc = NULL;
|
|
kstat_t *ksp;
|
|
kstat_named_t *knp;
|
|
int ret;
|
|
int sock = 0;
|
|
int duplex;
|
|
int speed;
|
|
|
|
PyObject *py_retdict = PyDict_New();
|
|
PyObject *py_ifc_info = NULL;
|
|
PyObject *py_is_up = NULL;
|
|
|
|
if (py_retdict == NULL)
|
|
return NULL;
|
|
kc = kstat_open();
|
|
if (kc == NULL)
|
|
goto error;
|
|
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (sock == -1)
|
|
goto error;
|
|
|
|
for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
|
|
if (strcmp(ksp->ks_class, "net") == 0) {
|
|
struct ifreq ifr;
|
|
|
|
kstat_read(kc, ksp, NULL);
|
|
if (ksp->ks_type != KSTAT_TYPE_NAMED)
|
|
continue;
|
|
if (strcmp(ksp->ks_class, "net") != 0)
|
|
continue;
|
|
|
|
strncpy(ifr.ifr_name, ksp->ks_name, sizeof(ifr.ifr_name));
|
|
ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
|
|
if (ret == -1)
|
|
continue; // not a network interface
|
|
|
|
// is up?
|
|
if ((ifr.ifr_flags & IFF_UP) != 0) {
|
|
if ((knp = kstat_data_lookup(ksp, "link_up")) != NULL) {
|
|
if (knp->value.ui32 != 0u)
|
|
py_is_up = Py_True;
|
|
else
|
|
py_is_up = Py_False;
|
|
}
|
|
else {
|
|
py_is_up = Py_True;
|
|
}
|
|
}
|
|
else {
|
|
py_is_up = Py_False;
|
|
}
|
|
Py_INCREF(py_is_up);
|
|
|
|
// duplex
|
|
duplex = 0; // unknown
|
|
if ((knp = kstat_data_lookup(ksp, "link_duplex")) != NULL) {
|
|
if (knp->value.ui32 == 1)
|
|
duplex = 1; // half
|
|
else if (knp->value.ui32 == 2)
|
|
duplex = 2; // full
|
|
}
|
|
|
|
// speed
|
|
if ((knp = kstat_data_lookup(ksp, "ifspeed")) != NULL)
|
|
// expressed in bits per sec, we want mega bits per sec
|
|
speed = (int)knp->value.ui64 / 1000000;
|
|
else
|
|
speed = 0;
|
|
|
|
// mtu
|
|
ret = ioctl(sock, SIOCGIFMTU, &ifr);
|
|
if (ret == -1)
|
|
goto error;
|
|
|
|
py_ifc_info = Py_BuildValue("(Oiii)", py_is_up, duplex, speed,
|
|
ifr.ifr_mtu);
|
|
if (!py_ifc_info)
|
|
goto error;
|
|
if (PyDict_SetItemString(py_retdict, ksp->ks_name, py_ifc_info))
|
|
goto error;
|
|
Py_DECREF(py_ifc_info);
|
|
}
|
|
}
|
|
|
|
close(sock);
|
|
kstat_close(kc);
|
|
return py_retdict;
|
|
|
|
error:
|
|
Py_XDECREF(py_is_up);
|
|
Py_XDECREF(py_ifc_info);
|
|
Py_DECREF(py_retdict);
|
|
if (sock != 0)
|
|
close(sock);
|
|
if (kc != NULL)
|
|
kstat_close(kc);
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* define the psutil C module methods and initialize the module.
|
|
*/
|
|
static PyMethodDef
|
|
PsutilMethods[] =
|
|
{
|
|
// --- process-related functions
|
|
{"proc_basic_info", psutil_proc_basic_info, METH_VARARGS,
|
|
"Return process ppid, rss, vms, ctime, nice, nthreads, status and tty"},
|
|
{"proc_name_and_args", psutil_proc_name_and_args, METH_VARARGS,
|
|
"Return process name and args."},
|
|
{"proc_cpu_times", psutil_proc_cpu_times, METH_VARARGS,
|
|
"Return process user and system CPU times."},
|
|
{"proc_cred", psutil_proc_cred, METH_VARARGS,
|
|
"Return process uids/gids."},
|
|
{"query_process_thread", psutil_proc_query_thread, METH_VARARGS,
|
|
"Return info about a process thread"},
|
|
{"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS,
|
|
"Return process memory mappings"},
|
|
{"proc_num_ctx_switches", psutil_proc_num_ctx_switches, METH_VARARGS,
|
|
"Return the number of context switches performed by process"},
|
|
|
|
// --- system-related functions
|
|
{"swap_mem", psutil_swap_mem, METH_VARARGS,
|
|
"Return information about system swap memory."},
|
|
{"users", psutil_users, METH_VARARGS,
|
|
"Return currently connected users."},
|
|
{"disk_partitions", psutil_disk_partitions, METH_VARARGS,
|
|
"Return disk partitions."},
|
|
{"per_cpu_times", psutil_per_cpu_times, METH_VARARGS,
|
|
"Return system per-CPU times."},
|
|
{"disk_io_counters", psutil_disk_io_counters, METH_VARARGS,
|
|
"Return a Python dict of tuples for disk I/O statistics."},
|
|
{"net_io_counters", psutil_net_io_counters, METH_VARARGS,
|
|
"Return a Python dict of tuples for network I/O statistics."},
|
|
{"boot_time", psutil_boot_time, METH_VARARGS,
|
|
"Return system boot time in seconds since the EPOCH."},
|
|
{"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS,
|
|
"Return the number of physical CPUs on the system."},
|
|
{"net_connections", psutil_net_connections, METH_VARARGS,
|
|
"Return TCP and UDP syste-wide open connections."},
|
|
{"net_if_stats", psutil_net_if_stats, METH_VARARGS,
|
|
"Return NIC stats (isup, duplex, speed, mtu)"},
|
|
|
|
{NULL, NULL, 0, NULL}
|
|
};
|
|
|
|
|
|
struct module_state {
|
|
PyObject *error;
|
|
};
|
|
|
|
#if PY_MAJOR_VERSION >= 3
|
|
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
|
|
#else
|
|
#define GETSTATE(m) (&_state)
|
|
#endif
|
|
|
|
#if PY_MAJOR_VERSION >= 3
|
|
|
|
static int
|
|
psutil_sunos_traverse(PyObject *m, visitproc visit, void *arg) {
|
|
Py_VISIT(GETSTATE(m)->error);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
psutil_sunos_clear(PyObject *m) {
|
|
Py_CLEAR(GETSTATE(m)->error);
|
|
return 0;
|
|
}
|
|
|
|
static struct PyModuleDef moduledef = {
|
|
PyModuleDef_HEAD_INIT,
|
|
"psutil_sunos",
|
|
NULL,
|
|
sizeof(struct module_state),
|
|
PsutilMethods,
|
|
NULL,
|
|
psutil_sunos_traverse,
|
|
psutil_sunos_clear,
|
|
NULL
|
|
};
|
|
|
|
#define INITERROR return NULL
|
|
|
|
PyMODINIT_FUNC PyInit__psutil_sunos(void)
|
|
|
|
#else
|
|
#define INITERROR return
|
|
|
|
void init_psutil_sunos(void)
|
|
#endif
|
|
{
|
|
#if PY_MAJOR_VERSION >= 3
|
|
PyObject *module = PyModule_Create(&moduledef);
|
|
#else
|
|
PyObject *module = Py_InitModule("_psutil_sunos", PsutilMethods);
|
|
#endif
|
|
PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
|
|
|
|
PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
|
|
PyModule_AddIntConstant(module, "SRUN", SRUN);
|
|
PyModule_AddIntConstant(module, "SZOMB", SZOMB);
|
|
PyModule_AddIntConstant(module, "SSTOP", SSTOP);
|
|
PyModule_AddIntConstant(module, "SIDL", SIDL);
|
|
PyModule_AddIntConstant(module, "SONPROC", SONPROC);
|
|
PyModule_AddIntConstant(module, "SWAIT", SWAIT);
|
|
|
|
PyModule_AddIntConstant(module, "PRNODEV", PRNODEV); // for process tty
|
|
|
|
PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED);
|
|
PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING);
|
|
PyModule_AddIntConstant(module, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT);
|
|
PyModule_AddIntConstant(module, "TCPS_LISTEN", TCPS_LISTEN);
|
|
PyModule_AddIntConstant(module, "TCPS_ESTABLISHED", TCPS_ESTABLISHED);
|
|
PyModule_AddIntConstant(module, "TCPS_SYN_SENT", TCPS_SYN_SENT);
|
|
PyModule_AddIntConstant(module, "TCPS_SYN_RCVD", TCPS_SYN_RCVD);
|
|
PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1);
|
|
PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2);
|
|
PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK);
|
|
PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT);
|
|
// sunos specific
|
|
PyModule_AddIntConstant(module, "TCPS_IDLE", TCPS_IDLE);
|
|
// sunos specific
|
|
PyModule_AddIntConstant(module, "TCPS_BOUND", TCPS_BOUND);
|
|
PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE);
|
|
|
|
if (module == NULL)
|
|
INITERROR;
|
|
#if PY_MAJOR_VERSION >= 3
|
|
return module;
|
|
#endif
|
|
}
|