python/psutil/psutil/_psutil_bsd.c

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

michael@0 1 /*
michael@0 2 * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
michael@0 3 * Use of this source code is governed by a BSD-style license that can be
michael@0 4 * found in the LICENSE file.
michael@0 5 *
michael@0 6 * FreeBSD platform-specific module methods for _psutil_bsd
michael@0 7 */
michael@0 8
michael@0 9
michael@0 10 #include <Python.h>
michael@0 11 #include <assert.h>
michael@0 12 #include <errno.h>
michael@0 13 #include <stdlib.h>
michael@0 14 #include <stdio.h>
michael@0 15 #include <signal.h>
michael@0 16 #include <fcntl.h>
michael@0 17 #include <paths.h>
michael@0 18 #include <sys/types.h>
michael@0 19 #include <sys/sysctl.h>
michael@0 20 #include <sys/param.h>
michael@0 21 #include <sys/user.h>
michael@0 22 #include <sys/proc.h>
michael@0 23 #include <sys/file.h>
michael@0 24 #include <net/route.h>
michael@0 25
michael@0 26 #include <sys/socket.h>
michael@0 27 #include <sys/socketvar.h> /* for struct xsocket */
michael@0 28 /* for xinpcb struct */
michael@0 29 #include <netinet/in.h>
michael@0 30 #include <netinet/in_systm.h>
michael@0 31 #include <netinet/ip.h>
michael@0 32 #include <netinet/in_pcb.h>
michael@0 33 #include <netinet/tcp_var.h> /* for struct xtcpcb */
michael@0 34 #include <netinet/tcp_fsm.h> /* for TCP connection states */
michael@0 35 #include <arpa/inet.h> /* for inet_ntop() */
michael@0 36
michael@0 37 #if __FreeBSD_version < 900000
michael@0 38 #include <utmp.h> /* system users */
michael@0 39 #else
michael@0 40 #include <utmpx.h>
michael@0 41 #endif
michael@0 42 #include <devstat.h> /* get io counters */
michael@0 43 #include <sys/vmmeter.h> /* needed for vmtotal struct */
michael@0 44 #include <libutil.h> /* process open files, shared libs (kinfo_getvmmap) */
michael@0 45 #include <sys/mount.h>
michael@0 46
michael@0 47 #include <net/if.h> /* net io counters */
michael@0 48 #include <net/if_dl.h>
michael@0 49 #include <net/route.h>
michael@0 50
michael@0 51 #include <netinet/in.h> /* process open files/connections */
michael@0 52 #include <sys/un.h>
michael@0 53
michael@0 54 #include "_psutil_bsd.h"
michael@0 55 #include "_psutil_common.h"
michael@0 56 #include "arch/bsd/process_info.h"
michael@0 57
michael@0 58
michael@0 59 // convert a timeval struct to a double
michael@0 60 #define TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
michael@0 61
michael@0 62
michael@0 63 /*
michael@0 64 * Utility function which fills a kinfo_proc struct based on process pid
michael@0 65 */
michael@0 66 static int
michael@0 67 psutil_get_kinfo_proc(const pid_t pid, struct kinfo_proc *proc)
michael@0 68 {
michael@0 69 int mib[4];
michael@0 70 size_t size;
michael@0 71 mib[0] = CTL_KERN;
michael@0 72 mib[1] = KERN_PROC;
michael@0 73 mib[2] = KERN_PROC_PID;
michael@0 74 mib[3] = pid;
michael@0 75
michael@0 76 size = sizeof(struct kinfo_proc);
michael@0 77
michael@0 78 if (sysctl((int*)mib, 4, proc, &size, NULL, 0) == -1) {
michael@0 79 PyErr_SetFromErrno(PyExc_OSError);
michael@0 80 return -1;
michael@0 81 }
michael@0 82
michael@0 83 /*
michael@0 84 * sysctl stores 0 in the size if we can't find the process information.
michael@0 85 */
michael@0 86 if (size == 0) {
michael@0 87 NoSuchProcess();
michael@0 88 return -1;
michael@0 89 }
michael@0 90 return 0;
michael@0 91 }
michael@0 92
michael@0 93
michael@0 94 /*
michael@0 95 * Return a Python list of all the PIDs running on the system.
michael@0 96 */
michael@0 97 static PyObject*
michael@0 98 get_pid_list(PyObject* self, PyObject* args)
michael@0 99 {
michael@0 100 kinfo_proc *proclist = NULL;
michael@0 101 kinfo_proc *orig_address = NULL;
michael@0 102 size_t num_processes;
michael@0 103 size_t idx;
michael@0 104 PyObject* retlist = PyList_New(0);
michael@0 105 PyObject* pid = NULL;
michael@0 106
michael@0 107 if (retlist == NULL) {
michael@0 108 return NULL;
michael@0 109 }
michael@0 110 if (psutil_get_proc_list(&proclist, &num_processes) != 0) {
michael@0 111 PyErr_SetString(PyExc_RuntimeError, "failed to retrieve process list.");
michael@0 112 goto error;
michael@0 113 }
michael@0 114
michael@0 115 if (num_processes > 0) {
michael@0 116 orig_address = proclist; // save so we can free it after we're done
michael@0 117 for (idx=0; idx < num_processes; idx++) {
michael@0 118 pid = Py_BuildValue("i", proclist->ki_pid);
michael@0 119 if (!pid)
michael@0 120 goto error;
michael@0 121 if (PyList_Append(retlist, pid))
michael@0 122 goto error;
michael@0 123 Py_DECREF(pid);
michael@0 124 proclist++;
michael@0 125 }
michael@0 126 free(orig_address);
michael@0 127 }
michael@0 128
michael@0 129 return retlist;
michael@0 130
michael@0 131 error:
michael@0 132 Py_XDECREF(pid);
michael@0 133 Py_DECREF(retlist);
michael@0 134 if (orig_address != NULL) {
michael@0 135 free(orig_address);
michael@0 136 }
michael@0 137 return NULL;
michael@0 138 }
michael@0 139
michael@0 140
michael@0 141 /*
michael@0 142 * Return a Python float indicating the system boot time expressed in
michael@0 143 * seconds since the epoch.
michael@0 144 */
michael@0 145 static PyObject*
michael@0 146 get_system_boot_time(PyObject* self, PyObject* args)
michael@0 147 {
michael@0 148 /* fetch sysctl "kern.boottime" */
michael@0 149 static int request[2] = { CTL_KERN, KERN_BOOTTIME };
michael@0 150 struct timeval boottime;
michael@0 151 size_t len = sizeof(boottime);
michael@0 152
michael@0 153 if (sysctl(request, 2, &boottime, &len, NULL, 0) == -1) {
michael@0 154 PyErr_SetFromErrno(0);
michael@0 155 return NULL;
michael@0 156 }
michael@0 157 return Py_BuildValue("d", (double)boottime.tv_sec);
michael@0 158 }
michael@0 159
michael@0 160
michael@0 161 /*
michael@0 162 * Return process name from kinfo_proc as a Python string.
michael@0 163 */
michael@0 164 static PyObject*
michael@0 165 get_process_name(PyObject* self, PyObject* args)
michael@0 166 {
michael@0 167 long pid;
michael@0 168 struct kinfo_proc kp;
michael@0 169 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 170 return NULL;
michael@0 171 }
michael@0 172 if (psutil_get_kinfo_proc(pid, &kp) == -1) {
michael@0 173 return NULL;
michael@0 174 }
michael@0 175 return Py_BuildValue("s", kp.ki_comm);
michael@0 176 }
michael@0 177
michael@0 178
michael@0 179 /*
michael@0 180 * Return process pathname executable.
michael@0 181 * Thanks to Robert N. M. Watson:
michael@0 182 * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_bin.c?v=8-CURRENT
michael@0 183 */
michael@0 184 static PyObject*
michael@0 185 get_process_exe(PyObject* self, PyObject* args)
michael@0 186 {
michael@0 187 long pid;
michael@0 188 char pathname[PATH_MAX];
michael@0 189 int error;
michael@0 190 int mib[4];
michael@0 191 size_t size;
michael@0 192
michael@0 193 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 194 return NULL;
michael@0 195 }
michael@0 196
michael@0 197 mib[0] = CTL_KERN;
michael@0 198 mib[1] = KERN_PROC;
michael@0 199 mib[2] = KERN_PROC_PATHNAME;
michael@0 200 mib[3] = pid;
michael@0 201
michael@0 202 size = sizeof(pathname);
michael@0 203 error = sysctl(mib, 4, pathname, &size, NULL, 0);
michael@0 204 if (error == -1) {
michael@0 205 PyErr_SetFromErrno(PyExc_OSError);
michael@0 206 return NULL;
michael@0 207 }
michael@0 208 if (size == 0 || strlen(pathname) == 0) {
michael@0 209 if (psutil_pid_exists(pid) == 0) {
michael@0 210 return NoSuchProcess();
michael@0 211 }
michael@0 212 else {
michael@0 213 strcpy(pathname, "");
michael@0 214 }
michael@0 215 }
michael@0 216 return Py_BuildValue("s", pathname);
michael@0 217 }
michael@0 218
michael@0 219
michael@0 220 /*
michael@0 221 * Return process cmdline as a Python list of cmdline arguments.
michael@0 222 */
michael@0 223 static PyObject*
michael@0 224 get_process_cmdline(PyObject* self, PyObject* args)
michael@0 225 {
michael@0 226 long pid;
michael@0 227 PyObject* arglist = NULL;
michael@0 228
michael@0 229 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 230 return NULL;
michael@0 231 }
michael@0 232
michael@0 233 // get the commandline, defined in arch/bsd/process_info.c
michael@0 234 arglist = psutil_get_arg_list(pid);
michael@0 235
michael@0 236 // psutil_get_arg_list() returns NULL only if psutil_get_cmd_args failed with ESRCH
michael@0 237 // (no process with that PID)
michael@0 238 if (NULL == arglist) {
michael@0 239 return PyErr_SetFromErrno(PyExc_OSError);
michael@0 240 }
michael@0 241 return Py_BuildValue("N", arglist);
michael@0 242 }
michael@0 243
michael@0 244
michael@0 245 /*
michael@0 246 * Return process parent pid from kinfo_proc as a Python integer.
michael@0 247 */
michael@0 248 static PyObject*
michael@0 249 get_process_ppid(PyObject* self, PyObject* args)
michael@0 250 {
michael@0 251 long pid;
michael@0 252 struct kinfo_proc kp;
michael@0 253 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 254 return NULL;
michael@0 255 }
michael@0 256 if (psutil_get_kinfo_proc(pid, &kp) == -1) {
michael@0 257 return NULL;
michael@0 258 }
michael@0 259 return Py_BuildValue("l", (long)kp.ki_ppid);
michael@0 260 }
michael@0 261
michael@0 262
michael@0 263 /*
michael@0 264 * Return process status as a Python integer.
michael@0 265 */
michael@0 266 static PyObject*
michael@0 267 get_process_status(PyObject* self, PyObject* args)
michael@0 268 {
michael@0 269 long pid;
michael@0 270 struct kinfo_proc kp;
michael@0 271 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 272 return NULL;
michael@0 273 }
michael@0 274 if (psutil_get_kinfo_proc(pid, &kp) == -1) {
michael@0 275 return NULL;
michael@0 276 }
michael@0 277 return Py_BuildValue("i", (int)kp.ki_stat);
michael@0 278 }
michael@0 279
michael@0 280
michael@0 281 /*
michael@0 282 * Return process real, effective and saved user ids from kinfo_proc
michael@0 283 * as a Python tuple.
michael@0 284 */
michael@0 285 static PyObject*
michael@0 286 get_process_uids(PyObject* self, PyObject* args)
michael@0 287 {
michael@0 288 long pid;
michael@0 289 struct kinfo_proc kp;
michael@0 290 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 291 return NULL;
michael@0 292 }
michael@0 293 if (psutil_get_kinfo_proc(pid, &kp) == -1) {
michael@0 294 return NULL;
michael@0 295 }
michael@0 296 return Py_BuildValue("lll", (long)kp.ki_ruid,
michael@0 297 (long)kp.ki_uid,
michael@0 298 (long)kp.ki_svuid);
michael@0 299 }
michael@0 300
michael@0 301
michael@0 302 /*
michael@0 303 * Return process real, effective and saved group ids from kinfo_proc
michael@0 304 * as a Python tuple.
michael@0 305 */
michael@0 306 static PyObject*
michael@0 307 get_process_gids(PyObject* self, PyObject* args)
michael@0 308 {
michael@0 309 long pid;
michael@0 310 struct kinfo_proc kp;
michael@0 311 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 312 return NULL;
michael@0 313 }
michael@0 314 if (psutil_get_kinfo_proc(pid, &kp) == -1) {
michael@0 315 return NULL;
michael@0 316 }
michael@0 317 return Py_BuildValue("lll", (long)kp.ki_rgid,
michael@0 318 (long)kp.ki_groups[0],
michael@0 319 (long)kp.ki_svuid);
michael@0 320 }
michael@0 321
michael@0 322
michael@0 323 /*
michael@0 324 * Return process real, effective and saved group ids from kinfo_proc
michael@0 325 * as a Python tuple.
michael@0 326 */
michael@0 327 static PyObject*
michael@0 328 get_process_tty_nr(PyObject* self, PyObject* args)
michael@0 329 {
michael@0 330 long pid;
michael@0 331 struct kinfo_proc kp;
michael@0 332 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 333 return NULL;
michael@0 334 }
michael@0 335 if (psutil_get_kinfo_proc(pid, &kp) == -1) {
michael@0 336 return NULL;
michael@0 337 }
michael@0 338 return Py_BuildValue("i", kp.ki_tdev);
michael@0 339 }
michael@0 340
michael@0 341
michael@0 342 /*
michael@0 343 * Return the number of context switches performed by process as a tuple.
michael@0 344 */
michael@0 345 static PyObject*
michael@0 346 get_process_num_ctx_switches(PyObject* self, PyObject* args)
michael@0 347 {
michael@0 348 long pid;
michael@0 349 struct kinfo_proc kp;
michael@0 350 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 351 return NULL;
michael@0 352 }
michael@0 353 if (psutil_get_kinfo_proc(pid, &kp) == -1) {
michael@0 354 return NULL;
michael@0 355 }
michael@0 356 return Py_BuildValue("(ll)", kp.ki_rusage.ru_nvcsw,
michael@0 357 kp.ki_rusage.ru_nivcsw);
michael@0 358 }
michael@0 359
michael@0 360
michael@0 361
michael@0 362 /*
michael@0 363 * Return number of threads used by process as a Python integer.
michael@0 364 */
michael@0 365 static PyObject*
michael@0 366 get_process_num_threads(PyObject* self, PyObject* args)
michael@0 367 {
michael@0 368 long pid;
michael@0 369 struct kinfo_proc kp;
michael@0 370 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 371 return NULL;
michael@0 372 }
michael@0 373 if (psutil_get_kinfo_proc(pid, &kp) == -1) {
michael@0 374 return NULL;
michael@0 375 }
michael@0 376 return Py_BuildValue("l", (long)kp.ki_numthreads);
michael@0 377 }
michael@0 378
michael@0 379
michael@0 380 /*
michael@0 381 * Retrieves all threads used by process returning a list of tuples
michael@0 382 * including thread id, user time and system time.
michael@0 383 * Thanks to Robert N. M. Watson:
michael@0 384 * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_threads.c?v=8-CURRENT
michael@0 385 */
michael@0 386 static PyObject*
michael@0 387 get_process_threads(PyObject* self, PyObject* args)
michael@0 388 {
michael@0 389 long pid;
michael@0 390 int mib[4];
michael@0 391 struct kinfo_proc *kip = NULL;
michael@0 392 struct kinfo_proc *kipp;
michael@0 393 int error;
michael@0 394 unsigned int i;
michael@0 395 size_t size;
michael@0 396 PyObject* retList = PyList_New(0);
michael@0 397 PyObject* pyTuple = NULL;
michael@0 398
michael@0 399 if (retList == NULL)
michael@0 400 return NULL;
michael@0 401 if (! PyArg_ParseTuple(args, "l", &pid))
michael@0 402 goto error;
michael@0 403
michael@0 404 /*
michael@0 405 * We need to re-query for thread information, so don't use *kipp.
michael@0 406 */
michael@0 407 mib[0] = CTL_KERN;
michael@0 408 mib[1] = KERN_PROC;
michael@0 409 mib[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD;
michael@0 410 mib[3] = pid;
michael@0 411
michael@0 412 size = 0;
michael@0 413 error = sysctl(mib, 4, NULL, &size, NULL, 0);
michael@0 414 if (error == -1) {
michael@0 415 PyErr_SetFromErrno(PyExc_OSError);
michael@0 416 goto error;
michael@0 417 }
michael@0 418 if (size == 0) {
michael@0 419 NoSuchProcess();
michael@0 420 goto error;
michael@0 421 }
michael@0 422
michael@0 423 kip = malloc(size);
michael@0 424 if (kip == NULL) {
michael@0 425 PyErr_NoMemory();
michael@0 426 goto error;
michael@0 427 }
michael@0 428
michael@0 429 error = sysctl(mib, 4, kip, &size, NULL, 0);
michael@0 430 if (error == -1) {
michael@0 431 PyErr_SetFromErrno(PyExc_OSError);
michael@0 432 goto error;
michael@0 433 }
michael@0 434 if (size == 0) {
michael@0 435 NoSuchProcess();
michael@0 436 goto error;
michael@0 437 }
michael@0 438
michael@0 439 for (i = 0; i < size / sizeof(*kipp); i++) {
michael@0 440 kipp = &kip[i];
michael@0 441 pyTuple = Py_BuildValue("Idd", kipp->ki_tid,
michael@0 442 TV2DOUBLE(kipp->ki_rusage.ru_utime),
michael@0 443 TV2DOUBLE(kipp->ki_rusage.ru_stime)
michael@0 444 );
michael@0 445 if (pyTuple == NULL)
michael@0 446 goto error;
michael@0 447 if (PyList_Append(retList, pyTuple))
michael@0 448 goto error;
michael@0 449 Py_DECREF(pyTuple);
michael@0 450 }
michael@0 451 free(kip);
michael@0 452 return retList;
michael@0 453
michael@0 454 error:
michael@0 455 Py_XDECREF(pyTuple);
michael@0 456 Py_DECREF(retList);
michael@0 457 if (kip != NULL) {
michael@0 458 free(kip);
michael@0 459 }
michael@0 460 return NULL;
michael@0 461 }
michael@0 462
michael@0 463
michael@0 464 /*
michael@0 465 * Return a Python tuple (user_time, kernel_time)
michael@0 466 */
michael@0 467 static PyObject*
michael@0 468 get_process_cpu_times(PyObject* self, PyObject* args)
michael@0 469 {
michael@0 470 long pid;
michael@0 471 double user_t, sys_t;
michael@0 472 struct kinfo_proc kp;
michael@0 473 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 474 return NULL;
michael@0 475 }
michael@0 476 if (psutil_get_kinfo_proc(pid, &kp) == -1) {
michael@0 477 return NULL;
michael@0 478 }
michael@0 479 // convert from microseconds to seconds
michael@0 480 user_t = TV2DOUBLE(kp.ki_rusage.ru_utime);
michael@0 481 sys_t = TV2DOUBLE(kp.ki_rusage.ru_stime);
michael@0 482 return Py_BuildValue("(dd)", user_t, sys_t);
michael@0 483 }
michael@0 484
michael@0 485
michael@0 486 /*
michael@0 487 * Return a Python integer indicating the number of CPUs on the system
michael@0 488 */
michael@0 489 static PyObject*
michael@0 490 get_num_cpus(PyObject* self, PyObject* args)
michael@0 491 {
michael@0 492 int mib[2];
michael@0 493 int ncpu;
michael@0 494 size_t len;
michael@0 495
michael@0 496 mib[0] = CTL_HW;
michael@0 497 mib[1] = HW_NCPU;
michael@0 498 len = sizeof(ncpu);
michael@0 499
michael@0 500 if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) {
michael@0 501 PyErr_SetFromErrno(0);
michael@0 502 return NULL;
michael@0 503 }
michael@0 504
michael@0 505 return Py_BuildValue("i", ncpu);
michael@0 506 }
michael@0 507
michael@0 508
michael@0 509 /*
michael@0 510 * Return a Python float indicating the process create time expressed in
michael@0 511 * seconds since the epoch.
michael@0 512 */
michael@0 513 static PyObject*
michael@0 514 get_process_create_time(PyObject* self, PyObject* args)
michael@0 515 {
michael@0 516 long pid;
michael@0 517 struct kinfo_proc kp;
michael@0 518 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 519 return NULL;
michael@0 520 }
michael@0 521 if (psutil_get_kinfo_proc(pid, &kp) == -1) {
michael@0 522 return NULL;
michael@0 523 }
michael@0 524 return Py_BuildValue("d", TV2DOUBLE(kp.ki_start));
michael@0 525 }
michael@0 526
michael@0 527
michael@0 528 /*
michael@0 529 * Return a Python float indicating the process create time expressed in
michael@0 530 * seconds since the epoch.
michael@0 531 */
michael@0 532 static PyObject*
michael@0 533 get_process_io_counters(PyObject* self, PyObject* args)
michael@0 534 {
michael@0 535 long pid;
michael@0 536 struct kinfo_proc kp;
michael@0 537 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 538 return NULL;
michael@0 539 }
michael@0 540 if (psutil_get_kinfo_proc(pid, &kp) == -1) {
michael@0 541 return NULL;
michael@0 542 }
michael@0 543 // there's apparently no way to determine bytes count, hence return -1.
michael@0 544 return Py_BuildValue("(llll)", kp.ki_rusage.ru_inblock,
michael@0 545 kp.ki_rusage.ru_oublock,
michael@0 546 -1, -1);
michael@0 547 }
michael@0 548
michael@0 549
michael@0 550 /*
michael@0 551 * Return extended memory info for a process as a Python tuple.
michael@0 552 */
michael@0 553 static PyObject*
michael@0 554 get_process_memory_info(PyObject* self, PyObject* args)
michael@0 555 {
michael@0 556 long pid;
michael@0 557 struct kinfo_proc kp;
michael@0 558 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 559 return NULL;
michael@0 560 }
michael@0 561 if (psutil_get_kinfo_proc(pid, &kp) == -1) {
michael@0 562 return NULL;
michael@0 563 }
michael@0 564 return Py_BuildValue("(lllll)", ptoa(kp.ki_rssize), // rss
michael@0 565 (long)kp.ki_size, // vms
michael@0 566 ptoa(kp.ki_tsize), // text
michael@0 567 ptoa(kp.ki_dsize), // data
michael@0 568 ptoa(kp.ki_ssize)); // stack
michael@0 569 }
michael@0 570
michael@0 571
michael@0 572 /*
michael@0 573 * Return virtual memory usage statistics.
michael@0 574 */
michael@0 575 static PyObject*
michael@0 576 get_virtual_mem(PyObject* self, PyObject* args)
michael@0 577 {
michael@0 578 unsigned int total, active, inactive, wired, cached, free;
michael@0 579 size_t size = sizeof(total);
michael@0 580 struct vmtotal vm;
michael@0 581 int mib[] = {CTL_VM, VM_METER};
michael@0 582 long pagesize = getpagesize();
michael@0 583 #if __FreeBSD_version > 702101
michael@0 584 long buffers;
michael@0 585 #else
michael@0 586 int buffers;
michael@0 587 #endif
michael@0 588 size_t buffers_size = sizeof(buffers);
michael@0 589
michael@0 590 if (sysctlbyname("vm.stats.vm.v_page_count", &total, &size, NULL, 0))
michael@0 591 goto error;
michael@0 592 if (sysctlbyname("vm.stats.vm.v_active_count", &active, &size, NULL, 0))
michael@0 593 goto error;
michael@0 594 if (sysctlbyname("vm.stats.vm.v_inactive_count", &inactive, &size, NULL, 0))
michael@0 595 goto error;
michael@0 596 if (sysctlbyname("vm.stats.vm.v_wire_count", &wired, &size, NULL, 0))
michael@0 597 goto error;
michael@0 598 if (sysctlbyname("vm.stats.vm.v_cache_count", &cached, &size, NULL, 0))
michael@0 599 goto error;
michael@0 600 if (sysctlbyname("vm.stats.vm.v_free_count", &free, &size, NULL, 0))
michael@0 601 goto error;
michael@0 602 if (sysctlbyname("vfs.bufspace", &buffers, &buffers_size, NULL, 0))
michael@0 603 goto error;
michael@0 604
michael@0 605 size = sizeof(vm);
michael@0 606 if (sysctl(mib, 2, &vm, &size, NULL, 0) != 0)
michael@0 607 goto error;
michael@0 608
michael@0 609 return Py_BuildValue("KKKKKKKK",
michael@0 610 (unsigned long long) total * pagesize,
michael@0 611 (unsigned long long) free * pagesize,
michael@0 612 (unsigned long long) active * pagesize,
michael@0 613 (unsigned long long) inactive * pagesize,
michael@0 614 (unsigned long long) wired * pagesize,
michael@0 615 (unsigned long long) cached * pagesize,
michael@0 616 (unsigned long long) buffers,
michael@0 617 (unsigned long long) (vm.t_vmshr + vm.t_rmshr) * pagesize // shared
michael@0 618 );
michael@0 619
michael@0 620 error:
michael@0 621 PyErr_SetFromErrno(0);
michael@0 622 return NULL;
michael@0 623 }
michael@0 624
michael@0 625
michael@0 626 #ifndef _PATH_DEVNULL
michael@0 627 #define _PATH_DEVNULL "/dev/null"
michael@0 628 #endif
michael@0 629
michael@0 630 /*
michael@0 631 * Return swap memory stats (see 'swapinfo' cmdline tool)
michael@0 632 */
michael@0 633 static PyObject*
michael@0 634 get_swap_mem(PyObject* self, PyObject* args)
michael@0 635 {
michael@0 636 kvm_t *kd;
michael@0 637 struct kvm_swap kvmsw[1];
michael@0 638 unsigned int swapin, swapout, nodein, nodeout;
michael@0 639 size_t size = sizeof(unsigned int);
michael@0 640
michael@0 641 kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open failed");
michael@0 642 if (kd == NULL) {
michael@0 643 PyErr_SetString(PyExc_RuntimeError, "kvm_open failed");
michael@0 644 return NULL;
michael@0 645 }
michael@0 646
michael@0 647 if (kvm_getswapinfo(kd, kvmsw, 1, 0) < 0) {
michael@0 648 kvm_close(kd);
michael@0 649 PyErr_SetString(PyExc_RuntimeError, "kvm_getswapinfo failed");
michael@0 650 return NULL;
michael@0 651 }
michael@0 652
michael@0 653 kvm_close(kd);
michael@0 654
michael@0 655 if (sysctlbyname("vm.stats.vm.v_swapin", &swapin, &size, NULL, 0) == -1)
michael@0 656 goto sbn_error;
michael@0 657 if (sysctlbyname("vm.stats.vm.v_swapout", &swapout, &size, NULL, 0) == -1)
michael@0 658 goto sbn_error;
michael@0 659 if (sysctlbyname("vm.stats.vm.v_vnodein", &nodein, &size, NULL, 0) == -1)
michael@0 660 goto sbn_error;
michael@0 661 if (sysctlbyname("vm.stats.vm.v_vnodeout", &nodeout, &size, NULL, 0) == -1)
michael@0 662 goto sbn_error;
michael@0 663
michael@0 664 return Py_BuildValue("(iiiII)",
michael@0 665 kvmsw[0].ksw_total, // total
michael@0 666 kvmsw[0].ksw_used, // used
michael@0 667 kvmsw[0].ksw_total - kvmsw[0].ksw_used, // free
michael@0 668 swapin + swapout, // swap in
michael@0 669 nodein + nodeout); // swap out
michael@0 670
michael@0 671 sbn_error:
michael@0 672 PyErr_SetFromErrno(0);
michael@0 673 return NULL;
michael@0 674 }
michael@0 675
michael@0 676
michael@0 677 /*
michael@0 678 * Return a Python tuple representing user, kernel and idle CPU times
michael@0 679 */
michael@0 680 static PyObject*
michael@0 681 get_system_cpu_times(PyObject* self, PyObject* args)
michael@0 682 {
michael@0 683 long cpu_time[CPUSTATES];
michael@0 684 size_t size;
michael@0 685
michael@0 686 size = sizeof(cpu_time);
michael@0 687
michael@0 688 if (sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0) == -1) {
michael@0 689 PyErr_SetFromErrno(0);
michael@0 690 return NULL;
michael@0 691 }
michael@0 692
michael@0 693 return Py_BuildValue("(ddddd)",
michael@0 694 (double)cpu_time[CP_USER] / CLOCKS_PER_SEC,
michael@0 695 (double)cpu_time[CP_NICE] / CLOCKS_PER_SEC,
michael@0 696 (double)cpu_time[CP_SYS] / CLOCKS_PER_SEC,
michael@0 697 (double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC,
michael@0 698 (double)cpu_time[CP_INTR] / CLOCKS_PER_SEC
michael@0 699 );
michael@0 700 }
michael@0 701
michael@0 702 /*
michael@0 703 * XXX
michael@0 704 * These functions are available on FreeBSD 8 only.
michael@0 705 * In the upper python layer we do various tricks to avoid crashing
michael@0 706 * and/or to provide alternatives where possible.
michael@0 707 */
michael@0 708
michael@0 709
michael@0 710 #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
michael@0 711 /*
michael@0 712 * Return files opened by process as a list of (path, fd) tuples
michael@0 713 */
michael@0 714 static PyObject*
michael@0 715 get_process_open_files(PyObject* self, PyObject* args)
michael@0 716 {
michael@0 717 long pid;
michael@0 718 int i, cnt;
michael@0 719 struct kinfo_file *freep = NULL;
michael@0 720 struct kinfo_file *kif;
michael@0 721 struct kinfo_proc kipp;
michael@0 722 PyObject *retList = PyList_New(0);
michael@0 723 PyObject *tuple = NULL;
michael@0 724
michael@0 725 if (retList == NULL)
michael@0 726 return NULL;
michael@0 727 if (! PyArg_ParseTuple(args, "l", &pid))
michael@0 728 goto error;
michael@0 729 if (psutil_get_kinfo_proc(pid, &kipp) == -1)
michael@0 730 goto error;
michael@0 731
michael@0 732 freep = kinfo_getfile(pid, &cnt);
michael@0 733 if (freep == NULL) {
michael@0 734 psutil_raise_ad_or_nsp(pid);
michael@0 735 goto error;
michael@0 736 }
michael@0 737
michael@0 738 for (i = 0; i < cnt; i++) {
michael@0 739 kif = &freep[i];
michael@0 740 if ((kif->kf_type == KF_TYPE_VNODE) &&
michael@0 741 (kif->kf_vnode_type == KF_VTYPE_VREG))
michael@0 742 {
michael@0 743 tuple = Py_BuildValue("(si)", kif->kf_path, kif->kf_fd);
michael@0 744 if (tuple == NULL)
michael@0 745 goto error;
michael@0 746 if (PyList_Append(retList, tuple))
michael@0 747 goto error;
michael@0 748 Py_DECREF(tuple);
michael@0 749 }
michael@0 750 }
michael@0 751 free(freep);
michael@0 752 return retList;
michael@0 753
michael@0 754 error:
michael@0 755 Py_XDECREF(tuple);
michael@0 756 Py_DECREF(retList);
michael@0 757 if (freep != NULL)
michael@0 758 free(freep);
michael@0 759 return NULL;
michael@0 760 }
michael@0 761
michael@0 762
michael@0 763 /*
michael@0 764 * Return files opened by process as a list of (path, fd) tuples
michael@0 765 */
michael@0 766 static PyObject*
michael@0 767 get_process_num_fds(PyObject* self, PyObject* args)
michael@0 768 {
michael@0 769 long pid;
michael@0 770 int cnt;
michael@0 771
michael@0 772 struct kinfo_file *freep;
michael@0 773 struct kinfo_proc kipp;
michael@0 774
michael@0 775 if (! PyArg_ParseTuple(args, "l", &pid))
michael@0 776 return NULL;
michael@0 777 if (psutil_get_kinfo_proc(pid, &kipp) == -1)
michael@0 778 return NULL;
michael@0 779
michael@0 780 freep = kinfo_getfile(pid, &cnt);
michael@0 781 if (freep == NULL) {
michael@0 782 psutil_raise_ad_or_nsp(pid);
michael@0 783 return NULL;
michael@0 784 }
michael@0 785 free(freep);
michael@0 786
michael@0 787 return Py_BuildValue("i", cnt);
michael@0 788 }
michael@0 789
michael@0 790
michael@0 791 /*
michael@0 792 * Return process current working directory.
michael@0 793 */
michael@0 794 static PyObject*
michael@0 795 get_process_cwd(PyObject* self, PyObject* args)
michael@0 796 {
michael@0 797 long pid;
michael@0 798 PyObject *path = NULL;
michael@0 799 struct kinfo_file *freep = NULL;
michael@0 800 struct kinfo_file *kif;
michael@0 801 struct kinfo_proc kipp;
michael@0 802
michael@0 803 int i, cnt;
michael@0 804
michael@0 805 if (! PyArg_ParseTuple(args, "l", &pid))
michael@0 806 goto error;
michael@0 807 if (psutil_get_kinfo_proc(pid, &kipp) == -1)
michael@0 808 goto error;
michael@0 809
michael@0 810 freep = kinfo_getfile(pid, &cnt);
michael@0 811 if (freep == NULL) {
michael@0 812 psutil_raise_ad_or_nsp(pid);
michael@0 813 goto error;
michael@0 814 }
michael@0 815
michael@0 816 for (i = 0; i < cnt; i++) {
michael@0 817 kif = &freep[i];
michael@0 818 if (kif->kf_fd == KF_FD_TYPE_CWD) {
michael@0 819 path = Py_BuildValue("s", kif->kf_path);
michael@0 820 if (!path)
michael@0 821 goto error;
michael@0 822 break;
michael@0 823 }
michael@0 824 }
michael@0 825 /*
michael@0 826 * For lower pids it seems we can't retrieve any information
michael@0 827 * (lsof can't do that it either). Since this happens even
michael@0 828 * as root we return an empty string instead of AccessDenied.
michael@0 829 */
michael@0 830 if (path == NULL) {
michael@0 831 path = Py_BuildValue("s", "");
michael@0 832 }
michael@0 833 free(freep);
michael@0 834 return path;
michael@0 835
michael@0 836 error:
michael@0 837 Py_XDECREF(path);
michael@0 838 if (freep != NULL)
michael@0 839 free(freep);
michael@0 840 return NULL;
michael@0 841 }
michael@0 842
michael@0 843
michael@0 844 /*
michael@0 845 * mathes Linux net/tcp_states.h:
michael@0 846 * http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
michael@0 847 */
michael@0 848 static char *
michael@0 849 get_connection_status(int st) {
michael@0 850 switch (st) {
michael@0 851 case TCPS_CLOSED:
michael@0 852 return "CLOSE";
michael@0 853 case TCPS_CLOSING:
michael@0 854 return "CLOSING";
michael@0 855 case TCPS_CLOSE_WAIT:
michael@0 856 return "CLOSE_WAIT";
michael@0 857 case TCPS_LISTEN:
michael@0 858 return "LISTEN";
michael@0 859 case TCPS_ESTABLISHED:
michael@0 860 return "ESTABLISHED";
michael@0 861 case TCPS_SYN_SENT:
michael@0 862 return "SYN_SENT";
michael@0 863 case TCPS_SYN_RECEIVED:
michael@0 864 return "SYN_RECV";
michael@0 865 case TCPS_FIN_WAIT_1:
michael@0 866 return "FIN_WAIT_1";
michael@0 867 case TCPS_FIN_WAIT_2:
michael@0 868 return "FIN_WAIT_2";
michael@0 869 case TCPS_LAST_ACK:
michael@0 870 return "LAST_ACK";
michael@0 871 case TCPS_TIME_WAIT:
michael@0 872 return "TIME_WAIT";
michael@0 873 default:
michael@0 874 return "?";
michael@0 875 }
michael@0 876 }
michael@0 877
michael@0 878 /* The tcplist fetching and walking is borrowed from netstat/inet.c. */
michael@0 879 static char *
michael@0 880 psutil_fetch_tcplist(void)
michael@0 881 {
michael@0 882 char *buf;
michael@0 883 size_t len;
michael@0 884 int error;
michael@0 885
michael@0 886 for (;;) {
michael@0 887 if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) < 0) {
michael@0 888 PyErr_SetFromErrno(0);
michael@0 889 return NULL;
michael@0 890 }
michael@0 891 buf = malloc(len);
michael@0 892 if (buf == NULL) {
michael@0 893 PyErr_NoMemory();
michael@0 894 return NULL;
michael@0 895 }
michael@0 896 if (sysctlbyname("net.inet.tcp.pcblist", buf, &len, NULL, 0) < 0) {
michael@0 897 free(buf);
michael@0 898 PyErr_SetFromErrno(0);
michael@0 899 return NULL;
michael@0 900 }
michael@0 901 return buf;
michael@0 902 }
michael@0 903 }
michael@0 904
michael@0 905 static int
michael@0 906 psutil_sockaddr_port(int family, struct sockaddr_storage *ss)
michael@0 907 {
michael@0 908 struct sockaddr_in6 *sin6;
michael@0 909 struct sockaddr_in *sin;
michael@0 910
michael@0 911 if (family == AF_INET) {
michael@0 912 sin = (struct sockaddr_in *)ss;
michael@0 913 return (sin->sin_port);
michael@0 914 } else {
michael@0 915 sin6 = (struct sockaddr_in6 *)ss;
michael@0 916 return (sin6->sin6_port);
michael@0 917 }
michael@0 918 }
michael@0 919
michael@0 920 static void *
michael@0 921 psutil_sockaddr_addr(int family, struct sockaddr_storage *ss)
michael@0 922 {
michael@0 923 struct sockaddr_in6 *sin6;
michael@0 924 struct sockaddr_in *sin;
michael@0 925
michael@0 926 if (family == AF_INET) {
michael@0 927 sin = (struct sockaddr_in *)ss;
michael@0 928 return (&sin->sin_addr);
michael@0 929 } else {
michael@0 930 sin6 = (struct sockaddr_in6 *)ss;
michael@0 931 return (&sin6->sin6_addr);
michael@0 932 }
michael@0 933 }
michael@0 934
michael@0 935 static socklen_t
michael@0 936 psutil_sockaddr_addrlen(int family)
michael@0 937 {
michael@0 938 if (family == AF_INET)
michael@0 939 return (sizeof(struct in_addr));
michael@0 940 else
michael@0 941 return (sizeof(struct in6_addr));
michael@0 942 }
michael@0 943
michael@0 944 static int
michael@0 945 psutil_sockaddr_matches(int family, int port, void *pcb_addr,
michael@0 946 struct sockaddr_storage *ss)
michael@0 947 {
michael@0 948 if (psutil_sockaddr_port(family, ss) != port)
michael@0 949 return (0);
michael@0 950 return (memcmp(psutil_sockaddr_addr(family, ss), pcb_addr,
michael@0 951 psutil_sockaddr_addrlen(family)) == 0);
michael@0 952 }
michael@0 953
michael@0 954 static struct tcpcb *
michael@0 955 psutil_search_tcplist(char *buf, struct kinfo_file *kif)
michael@0 956 {
michael@0 957 struct tcpcb *tp;
michael@0 958 struct inpcb *inp;
michael@0 959 struct xinpgen *xig, *oxig;
michael@0 960 struct xsocket *so;
michael@0 961
michael@0 962 oxig = xig = (struct xinpgen *)buf;
michael@0 963 for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
michael@0 964 xig->xig_len > sizeof(struct xinpgen);
michael@0 965 xig = (struct xinpgen *)((char *)xig + xig->xig_len)) {
michael@0 966 tp = &((struct xtcpcb *)xig)->xt_tp;
michael@0 967 inp = &((struct xtcpcb *)xig)->xt_inp;
michael@0 968 so = &((struct xtcpcb *)xig)->xt_socket;
michael@0 969
michael@0 970 if (so->so_type != kif->kf_sock_type ||
michael@0 971 so->xso_family != kif->kf_sock_domain ||
michael@0 972 so->xso_protocol != kif->kf_sock_protocol)
michael@0 973 continue;
michael@0 974
michael@0 975 if (kif->kf_sock_domain == AF_INET) {
michael@0 976 if (!psutil_sockaddr_matches(AF_INET, inp->inp_lport, &inp->inp_laddr,
michael@0 977 &kif->kf_sa_local))
michael@0 978 continue;
michael@0 979 if (!psutil_sockaddr_matches(AF_INET, inp->inp_fport, &inp->inp_faddr,
michael@0 980 &kif->kf_sa_peer))
michael@0 981 continue;
michael@0 982 } else {
michael@0 983 if (!psutil_sockaddr_matches(AF_INET6, inp->inp_lport, &inp->in6p_laddr,
michael@0 984 &kif->kf_sa_local))
michael@0 985 continue;
michael@0 986 if (!psutil_sockaddr_matches(AF_INET6, inp->inp_fport, &inp->in6p_faddr,
michael@0 987 &kif->kf_sa_peer))
michael@0 988 continue;
michael@0 989 }
michael@0 990
michael@0 991 return (tp);
michael@0 992 }
michael@0 993 return NULL;
michael@0 994 }
michael@0 995
michael@0 996
michael@0 997 // a signaler for connections without an actual status
michael@0 998 static int PSUTIL_CONN_NONE = 128;
michael@0 999
michael@0 1000 /*
michael@0 1001 * Return connections opened by process.
michael@0 1002 */
michael@0 1003 static PyObject*
michael@0 1004 get_process_connections(PyObject* self, PyObject* args)
michael@0 1005 {
michael@0 1006 long pid;
michael@0 1007 int i, cnt;
michael@0 1008
michael@0 1009 struct kinfo_file *freep = NULL;
michael@0 1010 struct kinfo_file *kif;
michael@0 1011 struct kinfo_proc kipp;
michael@0 1012 char *tcplist = NULL;
michael@0 1013 struct tcpcb *tcp;
michael@0 1014
michael@0 1015 PyObject *retList = PyList_New(0);
michael@0 1016 PyObject *tuple = NULL;
michael@0 1017 PyObject *laddr = NULL;
michael@0 1018 PyObject *raddr = NULL;
michael@0 1019 PyObject *af_filter = NULL;
michael@0 1020 PyObject *type_filter = NULL;
michael@0 1021 PyObject* _family = NULL;
michael@0 1022 PyObject* _type = NULL;
michael@0 1023
michael@0 1024 if (retList == NULL) {
michael@0 1025 return NULL;
michael@0 1026 }
michael@0 1027 if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) {
michael@0 1028 goto error;
michael@0 1029 }
michael@0 1030 if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) {
michael@0 1031 PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
michael@0 1032 goto error;
michael@0 1033 }
michael@0 1034
michael@0 1035 if (psutil_get_kinfo_proc(pid, &kipp) == -1) {
michael@0 1036 goto error;
michael@0 1037 }
michael@0 1038
michael@0 1039 freep = kinfo_getfile(pid, &cnt);
michael@0 1040 if (freep == NULL) {
michael@0 1041 psutil_raise_ad_or_nsp(pid);
michael@0 1042 goto error;
michael@0 1043 }
michael@0 1044
michael@0 1045 tcplist = psutil_fetch_tcplist();
michael@0 1046 if (tcplist == NULL) {
michael@0 1047 PyErr_SetFromErrno(0);
michael@0 1048 goto error;
michael@0 1049 }
michael@0 1050
michael@0 1051 for (i = 0; i < cnt; i++) {
michael@0 1052 int lport, rport, state;
michael@0 1053 char lip[200], rip[200];
michael@0 1054 char path[PATH_MAX];
michael@0 1055 int inseq;
michael@0 1056 tuple = NULL;
michael@0 1057 laddr = NULL;
michael@0 1058 raddr = NULL;
michael@0 1059
michael@0 1060 kif = &freep[i];
michael@0 1061 if (kif->kf_type == KF_TYPE_SOCKET)
michael@0 1062 {
michael@0 1063 // apply filters
michael@0 1064 _family = PyLong_FromLong((long)kif->kf_sock_domain);
michael@0 1065 inseq = PySequence_Contains(af_filter, _family);
michael@0 1066 Py_DECREF(_family);
michael@0 1067 if (inseq == 0) {
michael@0 1068 continue;
michael@0 1069 }
michael@0 1070 _type = PyLong_FromLong((long)kif->kf_sock_type);
michael@0 1071 inseq = PySequence_Contains(type_filter, _type);
michael@0 1072 Py_DECREF(_type);
michael@0 1073 if (inseq == 0) {
michael@0 1074 continue;
michael@0 1075 }
michael@0 1076
michael@0 1077 // IPv4 / IPv6 socket
michael@0 1078 if ((kif->kf_sock_domain == AF_INET) ||
michael@0 1079 (kif->kf_sock_domain == AF_INET6)) {
michael@0 1080 // fill status
michael@0 1081 state = PSUTIL_CONN_NONE;
michael@0 1082 if (kif->kf_sock_type == SOCK_STREAM) {
michael@0 1083 tcp = psutil_search_tcplist(tcplist, kif);
michael@0 1084 if (tcp != NULL)
michael@0 1085 state = (int)tcp->t_state;
michael@0 1086 }
michael@0 1087
michael@0 1088 // build addr and port
michael@0 1089 inet_ntop(kif->kf_sock_domain,
michael@0 1090 psutil_sockaddr_addr(kif->kf_sock_domain, &kif->kf_sa_local),
michael@0 1091 lip, sizeof(lip));
michael@0 1092 inet_ntop(kif->kf_sock_domain,
michael@0 1093 psutil_sockaddr_addr(kif->kf_sock_domain, &kif->kf_sa_peer),
michael@0 1094 rip, sizeof(rip));
michael@0 1095 lport = htons(psutil_sockaddr_port(kif->kf_sock_domain,
michael@0 1096 &kif->kf_sa_local));
michael@0 1097 rport = htons(psutil_sockaddr_port(kif->kf_sock_domain,
michael@0 1098 &kif->kf_sa_peer));
michael@0 1099
michael@0 1100 // construct python tuple/list
michael@0 1101 laddr = Py_BuildValue("(si)", lip, lport);
michael@0 1102 if (!laddr)
michael@0 1103 goto error;
michael@0 1104 if (rport != 0) {
michael@0 1105 raddr = Py_BuildValue("(si)", rip, rport);
michael@0 1106 }
michael@0 1107 else {
michael@0 1108 raddr = Py_BuildValue("()");
michael@0 1109 }
michael@0 1110 if (!raddr)
michael@0 1111 goto error;
michael@0 1112 tuple = Py_BuildValue("(iiiNNi)", kif->kf_fd,
michael@0 1113 kif->kf_sock_domain,
michael@0 1114 kif->kf_sock_type,
michael@0 1115 laddr,
michael@0 1116 raddr,
michael@0 1117 state);
michael@0 1118 if (!tuple)
michael@0 1119 goto error;
michael@0 1120 if (PyList_Append(retList, tuple))
michael@0 1121 goto error;
michael@0 1122 Py_DECREF(tuple);
michael@0 1123 }
michael@0 1124 // UNIX socket
michael@0 1125 else if (kif->kf_sock_domain == AF_UNIX) {
michael@0 1126 struct sockaddr_un *sun;
michael@0 1127
michael@0 1128 sun = (struct sockaddr_un *)&kif->kf_sa_local;
michael@0 1129 snprintf(path, sizeof(path), "%.*s",
michael@0 1130 (sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))),
michael@0 1131 sun->sun_path);
michael@0 1132
michael@0 1133 tuple = Py_BuildValue("(iiisOi)", kif->kf_fd,
michael@0 1134 kif->kf_sock_domain,
michael@0 1135 kif->kf_sock_type,
michael@0 1136 path,
michael@0 1137 Py_None,
michael@0 1138 PSUTIL_CONN_NONE);
michael@0 1139 if (!tuple)
michael@0 1140 goto error;
michael@0 1141 if (PyList_Append(retList, tuple))
michael@0 1142 goto error;
michael@0 1143 Py_DECREF(tuple);
michael@0 1144 Py_INCREF(Py_None);
michael@0 1145 }
michael@0 1146 }
michael@0 1147 }
michael@0 1148 free(freep);
michael@0 1149 free(tcplist);
michael@0 1150 return retList;
michael@0 1151
michael@0 1152 error:
michael@0 1153 Py_XDECREF(tuple);
michael@0 1154 Py_XDECREF(laddr);
michael@0 1155 Py_XDECREF(raddr);
michael@0 1156 Py_DECREF(retList);
michael@0 1157 if (freep != NULL)
michael@0 1158 free(freep);
michael@0 1159 if (tcplist != NULL)
michael@0 1160 free(tcplist);
michael@0 1161 return NULL;
michael@0 1162 }
michael@0 1163
michael@0 1164
michael@0 1165 /*
michael@0 1166 * Return a Python list of tuple representing per-cpu times
michael@0 1167 */
michael@0 1168 static PyObject*
michael@0 1169 get_system_per_cpu_times(PyObject* self, PyObject* args)
michael@0 1170 {
michael@0 1171 static int maxcpus;
michael@0 1172 int mib[2];
michael@0 1173 int ncpu;
michael@0 1174 size_t len;
michael@0 1175 size_t size;
michael@0 1176 int i;
michael@0 1177 PyObject* py_retlist = PyList_New(0);
michael@0 1178 PyObject* py_cputime = NULL;
michael@0 1179
michael@0 1180 if (py_retlist == NULL)
michael@0 1181 return NULL;
michael@0 1182
michael@0 1183 // retrieve maxcpus value
michael@0 1184 size = sizeof(maxcpus);
michael@0 1185 if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) {
michael@0 1186 Py_DECREF(py_retlist);
michael@0 1187 PyErr_SetFromErrno(0);
michael@0 1188 return NULL;
michael@0 1189 }
michael@0 1190 long cpu_time[maxcpus][CPUSTATES];
michael@0 1191
michael@0 1192 // retrieve the number of cpus
michael@0 1193 mib[0] = CTL_HW;
michael@0 1194 mib[1] = HW_NCPU;
michael@0 1195 len = sizeof(ncpu);
michael@0 1196 if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) {
michael@0 1197 PyErr_SetFromErrno(0);
michael@0 1198 goto error;
michael@0 1199 }
michael@0 1200
michael@0 1201 // per-cpu info
michael@0 1202 size = sizeof(cpu_time);
michael@0 1203 if (sysctlbyname("kern.cp_times", &cpu_time, &size, NULL, 0) == -1) {
michael@0 1204 PyErr_SetFromErrno(0);
michael@0 1205 goto error;
michael@0 1206 }
michael@0 1207
michael@0 1208 for (i = 0; i < ncpu; i++) {
michael@0 1209 py_cputime = Py_BuildValue("(ddddd)",
michael@0 1210 (double)cpu_time[i][CP_USER] / CLOCKS_PER_SEC,
michael@0 1211 (double)cpu_time[i][CP_NICE] / CLOCKS_PER_SEC,
michael@0 1212 (double)cpu_time[i][CP_SYS] / CLOCKS_PER_SEC,
michael@0 1213 (double)cpu_time[i][CP_IDLE] / CLOCKS_PER_SEC,
michael@0 1214 (double)cpu_time[i][CP_INTR] / CLOCKS_PER_SEC
michael@0 1215 );
michael@0 1216 if (!py_cputime)
michael@0 1217 goto error;
michael@0 1218 if (PyList_Append(py_retlist, py_cputime))
michael@0 1219 goto error;
michael@0 1220 Py_DECREF(py_cputime);
michael@0 1221 }
michael@0 1222
michael@0 1223 return py_retlist;
michael@0 1224
michael@0 1225 error:
michael@0 1226 Py_XDECREF(py_cputime);
michael@0 1227 Py_DECREF(py_retlist);
michael@0 1228 return NULL;
michael@0 1229 }
michael@0 1230
michael@0 1231
michael@0 1232 // remove spaces from string
michael@0 1233 void remove_spaces(char *str) {
michael@0 1234 char *p1 = str;
michael@0 1235 char *p2 = str;
michael@0 1236 do
michael@0 1237 while (*p2 == ' ')
michael@0 1238 p2++;
michael@0 1239 while (*p1++ = *p2++);
michael@0 1240 }
michael@0 1241
michael@0 1242 /*
michael@0 1243 * Return a list of tuples for every process memory maps.
michael@0 1244 * 'procstat' cmdline utility has been used as an example.
michael@0 1245 */
michael@0 1246 static PyObject*
michael@0 1247 get_process_memory_maps(PyObject* self, PyObject* args)
michael@0 1248 {
michael@0 1249 long pid;
michael@0 1250 int ptrwidth;
michael@0 1251 int i, cnt;
michael@0 1252 char addr[30];
michael@0 1253 char perms[4];
michael@0 1254 const char *path;
michael@0 1255 struct kinfo_proc kp;
michael@0 1256 struct kinfo_vmentry *freep = NULL;
michael@0 1257 struct kinfo_vmentry *kve;
michael@0 1258 ptrwidth = 2*sizeof(void *);
michael@0 1259 PyObject* pytuple = NULL;
michael@0 1260 PyObject* retlist = PyList_New(0);
michael@0 1261
michael@0 1262 if (retlist == NULL) {
michael@0 1263 return NULL;
michael@0 1264 }
michael@0 1265 if (! PyArg_ParseTuple(args, "l", &pid)) {
michael@0 1266 goto error;
michael@0 1267 }
michael@0 1268 if (psutil_get_kinfo_proc(pid, &kp) == -1) {
michael@0 1269 goto error;
michael@0 1270 }
michael@0 1271
michael@0 1272 freep = kinfo_getvmmap(pid, &cnt);
michael@0 1273 if (freep == NULL) {
michael@0 1274 psutil_raise_ad_or_nsp(pid);
michael@0 1275 goto error;
michael@0 1276 }
michael@0 1277 for (i = 0; i < cnt; i++) {
michael@0 1278 pytuple = NULL;
michael@0 1279 kve = &freep[i];
michael@0 1280 addr[0] = '\0';
michael@0 1281 perms[0] = '\0';
michael@0 1282 sprintf(addr, "%#*jx-%#*jx", ptrwidth, (uintmax_t)kve->kve_start,
michael@0 1283 ptrwidth, (uintmax_t)kve->kve_end);
michael@0 1284 remove_spaces(addr);
michael@0 1285 strlcat(perms, kve->kve_protection & KVME_PROT_READ ? "r" : "-",
michael@0 1286 sizeof(perms));
michael@0 1287 strlcat(perms, kve->kve_protection & KVME_PROT_WRITE ? "w" : "-",
michael@0 1288 sizeof(perms));
michael@0 1289 strlcat(perms, kve->kve_protection & KVME_PROT_EXEC ? "x" : "-",
michael@0 1290 sizeof(perms));
michael@0 1291
michael@0 1292
michael@0 1293 if (strlen(kve->kve_path) == 0) {
michael@0 1294 switch (kve->kve_type) {
michael@0 1295 case KVME_TYPE_NONE:
michael@0 1296 path = "[none]";
michael@0 1297 break;
michael@0 1298 case KVME_TYPE_DEFAULT:
michael@0 1299 path = "[default]";
michael@0 1300 break;
michael@0 1301 case KVME_TYPE_VNODE:
michael@0 1302 path = "[vnode]";
michael@0 1303 break;
michael@0 1304 case KVME_TYPE_SWAP:
michael@0 1305 path = "[swap]";
michael@0 1306 break;
michael@0 1307 case KVME_TYPE_DEVICE:
michael@0 1308 path = "[device]";
michael@0 1309 break;
michael@0 1310 case KVME_TYPE_PHYS:
michael@0 1311 path = "[phys]";
michael@0 1312 break;
michael@0 1313 case KVME_TYPE_DEAD:
michael@0 1314 path = "[dead]";
michael@0 1315 break;
michael@0 1316 case KVME_TYPE_SG:
michael@0 1317 path = "[sg]";
michael@0 1318 break;
michael@0 1319 case KVME_TYPE_UNKNOWN:
michael@0 1320 path = "[unknown]";
michael@0 1321 break;
michael@0 1322 default:
michael@0 1323 path = "[?]";
michael@0 1324 break;
michael@0 1325 }
michael@0 1326 }
michael@0 1327 else {
michael@0 1328 path = kve->kve_path;
michael@0 1329 }
michael@0 1330
michael@0 1331 pytuple = Py_BuildValue("sssiiii",
michael@0 1332 addr, // "start-end" address
michael@0 1333 perms, // "rwx" permissions
michael@0 1334 path, // path
michael@0 1335 kve->kve_resident, // rss
michael@0 1336 kve->kve_private_resident, // private
michael@0 1337 kve->kve_ref_count, // ref count
michael@0 1338 kve->kve_shadow_count // shadow count
michael@0 1339 );
michael@0 1340 if (!pytuple)
michael@0 1341 goto error;
michael@0 1342 if (PyList_Append(retlist, pytuple))
michael@0 1343 goto error;
michael@0 1344 Py_DECREF(pytuple);
michael@0 1345 }
michael@0 1346 free(freep);
michael@0 1347 return retlist;
michael@0 1348
michael@0 1349 error:
michael@0 1350 Py_XDECREF(pytuple);
michael@0 1351 Py_DECREF(retlist);
michael@0 1352 if (freep != NULL)
michael@0 1353 free(freep);
michael@0 1354 return NULL;
michael@0 1355 }
michael@0 1356 #endif
michael@0 1357
michael@0 1358
michael@0 1359 /*
michael@0 1360 * Return a list of tuples including device, mount point and fs type
michael@0 1361 * for all partitions mounted on the system.
michael@0 1362 */
michael@0 1363 static PyObject*
michael@0 1364 get_disk_partitions(PyObject* self, PyObject* args)
michael@0 1365 {
michael@0 1366 int num;
michael@0 1367 int i;
michael@0 1368 long len;
michael@0 1369 uint64_t flags;
michael@0 1370 char opts[200];
michael@0 1371 struct statfs *fs = NULL;
michael@0 1372 PyObject* py_retlist = PyList_New(0);
michael@0 1373 PyObject* py_tuple = NULL;
michael@0 1374
michael@0 1375 if (py_retlist == NULL)
michael@0 1376 return NULL;
michael@0 1377
michael@0 1378 // get the number of mount points
michael@0 1379 Py_BEGIN_ALLOW_THREADS
michael@0 1380 num = getfsstat(NULL, 0, MNT_NOWAIT);
michael@0 1381 Py_END_ALLOW_THREADS
michael@0 1382 if (num == -1) {
michael@0 1383 PyErr_SetFromErrno(0);
michael@0 1384 goto error;
michael@0 1385 }
michael@0 1386
michael@0 1387 len = sizeof(*fs) * num;
michael@0 1388 fs = malloc(len);
michael@0 1389 if (fs == NULL) {
michael@0 1390 PyErr_NoMemory();
michael@0 1391 goto error;
michael@0 1392 }
michael@0 1393
michael@0 1394 Py_BEGIN_ALLOW_THREADS
michael@0 1395 num = getfsstat(fs, len, MNT_NOWAIT);
michael@0 1396 Py_END_ALLOW_THREADS
michael@0 1397 if (num == -1) {
michael@0 1398 PyErr_SetFromErrno(0);
michael@0 1399 goto error;
michael@0 1400 }
michael@0 1401
michael@0 1402 for (i = 0; i < num; i++) {
michael@0 1403 py_tuple = NULL;
michael@0 1404 opts[0] = 0;
michael@0 1405 flags = fs[i].f_flags;
michael@0 1406
michael@0 1407 // see sys/mount.h
michael@0 1408 if (flags & MNT_RDONLY)
michael@0 1409 strlcat(opts, "ro", sizeof(opts));
michael@0 1410 else
michael@0 1411 strlcat(opts, "rw", sizeof(opts));
michael@0 1412 if (flags & MNT_SYNCHRONOUS)
michael@0 1413 strlcat(opts, ",sync", sizeof(opts));
michael@0 1414 if (flags & MNT_NOEXEC)
michael@0 1415 strlcat(opts, ",noexec", sizeof(opts));
michael@0 1416 if (flags & MNT_NOSUID)
michael@0 1417 strlcat(opts, ",nosuid", sizeof(opts));
michael@0 1418 if (flags & MNT_UNION)
michael@0 1419 strlcat(opts, ",union", sizeof(opts));
michael@0 1420 if (flags & MNT_ASYNC)
michael@0 1421 strlcat(opts, ",async", sizeof(opts));
michael@0 1422 if (flags & MNT_SUIDDIR)
michael@0 1423 strlcat(opts, ",suiddir", sizeof(opts));
michael@0 1424 if (flags & MNT_SOFTDEP)
michael@0 1425 strlcat(opts, ",softdep", sizeof(opts));
michael@0 1426 if (flags & MNT_NOSYMFOLLOW)
michael@0 1427 strlcat(opts, ",nosymfollow", sizeof(opts));
michael@0 1428 if (flags & MNT_GJOURNAL)
michael@0 1429 strlcat(opts, ",gjournal", sizeof(opts));
michael@0 1430 if (flags & MNT_MULTILABEL)
michael@0 1431 strlcat(opts, ",multilabel", sizeof(opts));
michael@0 1432 if (flags & MNT_ACLS)
michael@0 1433 strlcat(opts, ",acls", sizeof(opts));
michael@0 1434 if (flags & MNT_NOATIME)
michael@0 1435 strlcat(opts, ",noatime", sizeof(opts));
michael@0 1436 if (flags & MNT_NOCLUSTERR)
michael@0 1437 strlcat(opts, ",noclusterr", sizeof(opts));
michael@0 1438 if (flags & MNT_NOCLUSTERW)
michael@0 1439 strlcat(opts, ",noclusterw", sizeof(opts));
michael@0 1440 if (flags & MNT_NFS4ACLS)
michael@0 1441 strlcat(opts, ",nfs4acls", sizeof(opts));
michael@0 1442
michael@0 1443 py_tuple = Py_BuildValue("(ssss)", fs[i].f_mntfromname, // device
michael@0 1444 fs[i].f_mntonname, // mount point
michael@0 1445 fs[i].f_fstypename, // fs type
michael@0 1446 opts); // options
michael@0 1447 if (!py_tuple)
michael@0 1448 goto error;
michael@0 1449 if (PyList_Append(py_retlist, py_tuple))
michael@0 1450 goto error;
michael@0 1451 Py_DECREF(py_tuple);
michael@0 1452 }
michael@0 1453
michael@0 1454 free(fs);
michael@0 1455 return py_retlist;
michael@0 1456
michael@0 1457 error:
michael@0 1458 Py_XDECREF(py_tuple);
michael@0 1459 Py_DECREF(py_retlist);
michael@0 1460 if (fs != NULL)
michael@0 1461 free(fs);
michael@0 1462 return NULL;
michael@0 1463 }
michael@0 1464
michael@0 1465
michael@0 1466 /*
michael@0 1467 * Return a Python list of named tuples with overall network I/O information
michael@0 1468 */
michael@0 1469 static PyObject*
michael@0 1470 get_net_io_counters(PyObject* self, PyObject* args)
michael@0 1471 {
michael@0 1472 char *buf = NULL, *lim, *next;
michael@0 1473 struct if_msghdr *ifm;
michael@0 1474 int mib[6];
michael@0 1475 size_t len;
michael@0 1476 PyObject* py_retdict = PyDict_New();
michael@0 1477 PyObject* py_ifc_info = NULL;
michael@0 1478 if (py_retdict == NULL)
michael@0 1479 return NULL;
michael@0 1480
michael@0 1481 mib[0] = CTL_NET; // networking subsystem
michael@0 1482 mib[1] = PF_ROUTE; // type of information
michael@0 1483 mib[2] = 0; // protocol (IPPROTO_xxx)
michael@0 1484 mib[3] = 0; // address family
michael@0 1485 mib[4] = NET_RT_IFLIST; // operation
michael@0 1486 mib[5] = 0;
michael@0 1487
michael@0 1488 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
michael@0 1489 PyErr_SetFromErrno(0);
michael@0 1490 goto error;
michael@0 1491 }
michael@0 1492
michael@0 1493 buf = malloc(len);
michael@0 1494 if (buf == NULL) {
michael@0 1495 PyErr_NoMemory();
michael@0 1496 goto error;
michael@0 1497 }
michael@0 1498
michael@0 1499 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
michael@0 1500 PyErr_SetFromErrno(0);
michael@0 1501 goto error;
michael@0 1502 }
michael@0 1503
michael@0 1504 lim = buf + len;
michael@0 1505
michael@0 1506 for (next = buf; next < lim; ) {
michael@0 1507 py_ifc_info = NULL;
michael@0 1508 ifm = (struct if_msghdr *)next;
michael@0 1509 next += ifm->ifm_msglen;
michael@0 1510
michael@0 1511 if (ifm->ifm_type == RTM_IFINFO) {
michael@0 1512 struct if_msghdr *if2m = (struct if_msghdr *)ifm;
michael@0 1513 struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1);
michael@0 1514 char ifc_name[32];
michael@0 1515
michael@0 1516 strncpy(ifc_name, sdl->sdl_data, sdl->sdl_nlen);
michael@0 1517 ifc_name[sdl->sdl_nlen] = 0;
michael@0 1518 // XXX: ignore usbus interfaces:
michael@0 1519 // http://lists.freebsd.org/pipermail/freebsd-current/2011-October/028752.html
michael@0 1520 // 'ifconfig -a' doesn't show them, nor do we.
michael@0 1521 if (strncmp(ifc_name, "usbus", 5) == 0) {
michael@0 1522 continue;
michael@0 1523 }
michael@0 1524
michael@0 1525 py_ifc_info = Py_BuildValue("(kkkkkkki)",
michael@0 1526 if2m->ifm_data.ifi_obytes,
michael@0 1527 if2m->ifm_data.ifi_ibytes,
michael@0 1528 if2m->ifm_data.ifi_opackets,
michael@0 1529 if2m->ifm_data.ifi_ipackets,
michael@0 1530 if2m->ifm_data.ifi_ierrors,
michael@0 1531 if2m->ifm_data.ifi_oerrors,
michael@0 1532 if2m->ifm_data.ifi_iqdrops,
michael@0 1533 0); // dropout not supported
michael@0 1534 if (!py_ifc_info)
michael@0 1535 goto error;
michael@0 1536 if (PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info))
michael@0 1537 goto error;
michael@0 1538 Py_DECREF(py_ifc_info);
michael@0 1539 }
michael@0 1540 else {
michael@0 1541 continue;
michael@0 1542 }
michael@0 1543 }
michael@0 1544
michael@0 1545 free(buf);
michael@0 1546 return py_retdict;
michael@0 1547
michael@0 1548 error:
michael@0 1549 Py_XDECREF(py_ifc_info);
michael@0 1550 Py_DECREF(py_retdict);
michael@0 1551 if (buf != NULL)
michael@0 1552 free(buf);
michael@0 1553 return NULL;
michael@0 1554 }
michael@0 1555
michael@0 1556
michael@0 1557 /*
michael@0 1558 * Return a Python dict of tuples for disk I/O information
michael@0 1559 */
michael@0 1560 static PyObject*
michael@0 1561 get_disk_io_counters(PyObject* self, PyObject* args)
michael@0 1562 {
michael@0 1563 int i;
michael@0 1564 struct statinfo stats;
michael@0 1565
michael@0 1566 PyObject* py_retdict = PyDict_New();
michael@0 1567 PyObject* py_disk_info = NULL;
michael@0 1568 if (py_retdict == NULL)
michael@0 1569 return NULL;
michael@0 1570
michael@0 1571 if (devstat_checkversion(NULL) < 0) {
michael@0 1572 PyErr_Format(PyExc_RuntimeError, "devstat_checkversion() failed");
michael@0 1573 goto error;
michael@0 1574 }
michael@0 1575
michael@0 1576 stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
michael@0 1577 if (stats.dinfo == NULL) {
michael@0 1578 PyErr_NoMemory();
michael@0 1579 goto error;
michael@0 1580 }
michael@0 1581 bzero(stats.dinfo, sizeof(struct devinfo));
michael@0 1582
michael@0 1583 if (devstat_getdevs(NULL, &stats) == -1) {
michael@0 1584 PyErr_Format(PyExc_RuntimeError, "devstat_getdevs() failed");
michael@0 1585 goto error;
michael@0 1586 }
michael@0 1587
michael@0 1588 for (i = 0; i < stats.dinfo->numdevs; i++) {
michael@0 1589 py_disk_info = NULL;
michael@0 1590 struct devstat current;
michael@0 1591 char disk_name[128];
michael@0 1592 current = stats.dinfo->devices[i];
michael@0 1593 snprintf(disk_name, sizeof(disk_name), "%s%d",
michael@0 1594 current.device_name,
michael@0 1595 current.unit_number);
michael@0 1596
michael@0 1597 py_disk_info = Py_BuildValue("(KKKKLL)",
michael@0 1598 current.operations[DEVSTAT_READ], // no reads
michael@0 1599 current.operations[DEVSTAT_WRITE], // no writes
michael@0 1600 current.bytes[DEVSTAT_READ], // bytes read
michael@0 1601 current.bytes[DEVSTAT_WRITE], // bytes written
michael@0 1602 (long long)devstat_compute_etime(
michael@0 1603 &current.duration[DEVSTAT_READ], NULL), // r time
michael@0 1604 (long long)devstat_compute_etime(
michael@0 1605 &current.duration[DEVSTAT_WRITE], NULL) // w time
michael@0 1606 );
michael@0 1607 if (!py_disk_info)
michael@0 1608 goto error;
michael@0 1609 if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info))
michael@0 1610 goto error;
michael@0 1611 Py_DECREF(py_disk_info);
michael@0 1612 }
michael@0 1613
michael@0 1614 if (stats.dinfo->mem_ptr) {
michael@0 1615 free(stats.dinfo->mem_ptr);
michael@0 1616 }
michael@0 1617 free(stats.dinfo);
michael@0 1618 return py_retdict;
michael@0 1619
michael@0 1620 error:
michael@0 1621 Py_XDECREF(py_disk_info);
michael@0 1622 Py_DECREF(py_retdict);
michael@0 1623 if (stats.dinfo != NULL)
michael@0 1624 free(stats.dinfo);
michael@0 1625 return NULL;
michael@0 1626 }
michael@0 1627
michael@0 1628
michael@0 1629 /*
michael@0 1630 * Return currently connected users as a list of tuples.
michael@0 1631 */
michael@0 1632 static PyObject*
michael@0 1633 get_system_users(PyObject* self, PyObject* args)
michael@0 1634 {
michael@0 1635 PyObject *ret_list = PyList_New(0);
michael@0 1636 PyObject *tuple = NULL;
michael@0 1637
michael@0 1638 if (ret_list == NULL)
michael@0 1639 return NULL;
michael@0 1640
michael@0 1641 #if __FreeBSD_version < 900000
michael@0 1642 struct utmp ut;
michael@0 1643 FILE *fp;
michael@0 1644
michael@0 1645 fp = fopen(_PATH_UTMP, "r");
michael@0 1646 if (fp == NULL) {
michael@0 1647 PyErr_SetFromErrno(0);
michael@0 1648 goto error;
michael@0 1649 }
michael@0 1650
michael@0 1651 while (fread(&ut, sizeof(ut), 1, fp) == 1) {
michael@0 1652 if (*ut.ut_name == '\0')
michael@0 1653 continue;
michael@0 1654 tuple = Py_BuildValue("(sssf)",
michael@0 1655 ut.ut_name, // username
michael@0 1656 ut.ut_line, // tty
michael@0 1657 ut.ut_host, // hostname
michael@0 1658 (float)ut.ut_time // start time
michael@0 1659 );
michael@0 1660 if (!tuple) {
michael@0 1661 fclose(fp);
michael@0 1662 goto error;
michael@0 1663 }
michael@0 1664 if (PyList_Append(ret_list, tuple)) {
michael@0 1665 fclose(fp);
michael@0 1666 goto error;
michael@0 1667 }
michael@0 1668 Py_DECREF(tuple);
michael@0 1669 }
michael@0 1670
michael@0 1671 fclose(fp);
michael@0 1672 #else
michael@0 1673 struct utmpx *utx;
michael@0 1674
michael@0 1675 while ((utx = getutxent()) != NULL) {
michael@0 1676 if (utx->ut_type != USER_PROCESS)
michael@0 1677 continue;
michael@0 1678 tuple = Py_BuildValue("(sssf)",
michael@0 1679 utx->ut_user, // username
michael@0 1680 utx->ut_line, // tty
michael@0 1681 utx->ut_host, // hostname
michael@0 1682 (float)utx->ut_tv.tv_sec // start time
michael@0 1683 );
michael@0 1684 if (!tuple) {
michael@0 1685 endutxent();
michael@0 1686 goto error;
michael@0 1687 }
michael@0 1688 if (PyList_Append(ret_list, tuple)) {
michael@0 1689 endutxent();
michael@0 1690 goto error;
michael@0 1691 }
michael@0 1692 Py_DECREF(tuple);
michael@0 1693 }
michael@0 1694
michael@0 1695 endutxent();
michael@0 1696 #endif
michael@0 1697 return ret_list;
michael@0 1698
michael@0 1699 error:
michael@0 1700 Py_XDECREF(tuple);
michael@0 1701 Py_DECREF(ret_list);
michael@0 1702 return NULL;
michael@0 1703 }
michael@0 1704
michael@0 1705
michael@0 1706 /*
michael@0 1707 * define the psutil C module methods and initialize the module.
michael@0 1708 */
michael@0 1709 static PyMethodDef
michael@0 1710 PsutilMethods[] =
michael@0 1711 {
michael@0 1712 // --- per-process functions
michael@0 1713
michael@0 1714 {"get_process_name", get_process_name, METH_VARARGS,
michael@0 1715 "Return process name"},
michael@0 1716 {"get_process_connections", get_process_connections, METH_VARARGS,
michael@0 1717 "Return connections opened by process"},
michael@0 1718 {"get_process_exe", get_process_exe, METH_VARARGS,
michael@0 1719 "Return process pathname executable"},
michael@0 1720 {"get_process_cmdline", get_process_cmdline, METH_VARARGS,
michael@0 1721 "Return process cmdline as a list of cmdline arguments"},
michael@0 1722 {"get_process_ppid", get_process_ppid, METH_VARARGS,
michael@0 1723 "Return process ppid as an integer"},
michael@0 1724 {"get_process_uids", get_process_uids, METH_VARARGS,
michael@0 1725 "Return process real effective and saved user ids as a Python tuple"},
michael@0 1726 {"get_process_gids", get_process_gids, METH_VARARGS,
michael@0 1727 "Return process real effective and saved group ids as a Python tuple"},
michael@0 1728 {"get_process_cpu_times", get_process_cpu_times, METH_VARARGS,
michael@0 1729 "Return tuple of user/kern time for the given PID"},
michael@0 1730 {"get_process_create_time", get_process_create_time, METH_VARARGS,
michael@0 1731 "Return a float indicating the process create time expressed in "
michael@0 1732 "seconds since the epoch"},
michael@0 1733 {"get_process_memory_info", get_process_memory_info, METH_VARARGS,
michael@0 1734 "Return extended memory info for a process as a Python tuple."},
michael@0 1735 {"get_process_num_threads", get_process_num_threads, METH_VARARGS,
michael@0 1736 "Return number of threads used by process"},
michael@0 1737 {"get_process_num_ctx_switches", get_process_num_ctx_switches, METH_VARARGS,
michael@0 1738 "Return the number of context switches performed by process"},
michael@0 1739 {"get_process_threads", get_process_threads, METH_VARARGS,
michael@0 1740 "Return process threads"},
michael@0 1741 {"get_process_status", get_process_status, METH_VARARGS,
michael@0 1742 "Return process status as an integer"},
michael@0 1743 {"get_process_io_counters", get_process_io_counters, METH_VARARGS,
michael@0 1744 "Return process IO counters"},
michael@0 1745 {"get_process_tty_nr", get_process_tty_nr, METH_VARARGS,
michael@0 1746 "Return process tty (terminal) number"},
michael@0 1747 #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
michael@0 1748 {"get_process_open_files", get_process_open_files, METH_VARARGS,
michael@0 1749 "Return files opened by process as a list of (path, fd) tuples"},
michael@0 1750 {"get_process_cwd", get_process_cwd, METH_VARARGS,
michael@0 1751 "Return process current working directory."},
michael@0 1752 {"get_process_memory_maps", get_process_memory_maps, METH_VARARGS,
michael@0 1753 "Return a list of tuples for every process's memory map"},
michael@0 1754 {"get_process_num_fds", get_process_num_fds, METH_VARARGS,
michael@0 1755 "Return the number of file descriptors opened by this process"},
michael@0 1756 #endif
michael@0 1757
michael@0 1758 // --- system-related functions
michael@0 1759
michael@0 1760 {"get_pid_list", get_pid_list, METH_VARARGS,
michael@0 1761 "Returns a list of PIDs currently running on the system"},
michael@0 1762 {"get_num_cpus", get_num_cpus, METH_VARARGS,
michael@0 1763 "Return number of CPUs on the system"},
michael@0 1764 {"get_virtual_mem", get_virtual_mem, METH_VARARGS,
michael@0 1765 "Return system virtual memory usage statistics"},
michael@0 1766 {"get_swap_mem", get_swap_mem, METH_VARARGS,
michael@0 1767 "Return swap mem stats"},
michael@0 1768 {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS,
michael@0 1769 "Return system cpu times as a tuple (user, system, nice, idle, irc)"},
michael@0 1770 #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
michael@0 1771 {"get_system_per_cpu_times", get_system_per_cpu_times, METH_VARARGS,
michael@0 1772 "Return system per-cpu times as a list of tuples"},
michael@0 1773 #endif
michael@0 1774 {"get_system_boot_time", get_system_boot_time, METH_VARARGS,
michael@0 1775 "Return the system boot time expressed in seconds since the epoch."},
michael@0 1776 {"get_disk_partitions", get_disk_partitions, METH_VARARGS,
michael@0 1777 "Return a list of tuples including device, mount point and "
michael@0 1778 "fs type for all partitions mounted on the system."},
michael@0 1779 {"get_net_io_counters", get_net_io_counters, METH_VARARGS,
michael@0 1780 "Return dict of tuples of networks I/O information."},
michael@0 1781 {"get_disk_io_counters", get_disk_io_counters, METH_VARARGS,
michael@0 1782 "Return a Python dict of tuples for disk I/O information"},
michael@0 1783 {"get_system_users", get_system_users, METH_VARARGS,
michael@0 1784 "Return currently connected users as a list of tuples"},
michael@0 1785
michael@0 1786 {NULL, NULL, 0, NULL}
michael@0 1787 };
michael@0 1788
michael@0 1789 struct module_state {
michael@0 1790 PyObject *error;
michael@0 1791 };
michael@0 1792
michael@0 1793 #if PY_MAJOR_VERSION >= 3
michael@0 1794 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
michael@0 1795 #else
michael@0 1796 #define GETSTATE(m) (&_state)
michael@0 1797 #endif
michael@0 1798
michael@0 1799 #if PY_MAJOR_VERSION >= 3
michael@0 1800
michael@0 1801 static int
michael@0 1802 psutil_bsd_traverse(PyObject *m, visitproc visit, void *arg) {
michael@0 1803 Py_VISIT(GETSTATE(m)->error);
michael@0 1804 return 0;
michael@0 1805 }
michael@0 1806
michael@0 1807 static int
michael@0 1808 psutil_bsd_clear(PyObject *m) {
michael@0 1809 Py_CLEAR(GETSTATE(m)->error);
michael@0 1810 return 0;
michael@0 1811 }
michael@0 1812
michael@0 1813 static struct PyModuleDef
michael@0 1814 moduledef = {
michael@0 1815 PyModuleDef_HEAD_INIT,
michael@0 1816 "psutil_bsd",
michael@0 1817 NULL,
michael@0 1818 sizeof(struct module_state),
michael@0 1819 PsutilMethods,
michael@0 1820 NULL,
michael@0 1821 psutil_bsd_traverse,
michael@0 1822 psutil_bsd_clear,
michael@0 1823 NULL
michael@0 1824 };
michael@0 1825
michael@0 1826 #define INITERROR return NULL
michael@0 1827
michael@0 1828 PyObject *
michael@0 1829 PyInit__psutil_bsd(void)
michael@0 1830
michael@0 1831 #else
michael@0 1832 #define INITERROR return
michael@0 1833
michael@0 1834 void init_psutil_bsd(void)
michael@0 1835 #endif
michael@0 1836 {
michael@0 1837 #if PY_MAJOR_VERSION >= 3
michael@0 1838 PyObject *module = PyModule_Create(&moduledef);
michael@0 1839 #else
michael@0 1840 PyObject *module = Py_InitModule("_psutil_bsd", PsutilMethods);
michael@0 1841 #endif
michael@0 1842 // process status constants
michael@0 1843 PyModule_AddIntConstant(module, "SSTOP", SSTOP);
michael@0 1844 PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
michael@0 1845 PyModule_AddIntConstant(module, "SRUN", SRUN);
michael@0 1846 PyModule_AddIntConstant(module, "SIDL", SIDL);
michael@0 1847 PyModule_AddIntConstant(module, "SWAIT", SWAIT);
michael@0 1848 PyModule_AddIntConstant(module, "SLOCK", SLOCK);
michael@0 1849 PyModule_AddIntConstant(module, "SZOMB", SZOMB);
michael@0 1850 // connection status constants
michael@0 1851 PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED);
michael@0 1852 PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING);
michael@0 1853 PyModule_AddIntConstant(module, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT);
michael@0 1854 PyModule_AddIntConstant(module, "TCPS_LISTEN", TCPS_LISTEN);
michael@0 1855 PyModule_AddIntConstant(module, "TCPS_ESTABLISHED", TCPS_ESTABLISHED);
michael@0 1856 PyModule_AddIntConstant(module, "TCPS_SYN_SENT", TCPS_SYN_SENT);
michael@0 1857 PyModule_AddIntConstant(module, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED);
michael@0 1858 PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1);
michael@0 1859 PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2);
michael@0 1860 PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK);
michael@0 1861 PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT);
michael@0 1862 PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE);
michael@0 1863
michael@0 1864 if (module == NULL) {
michael@0 1865 INITERROR;
michael@0 1866 }
michael@0 1867 #if PY_MAJOR_VERSION >= 3
michael@0 1868 return module;
michael@0 1869 #endif
michael@0 1870 }

mercurial