1 /*
2 * Copyright (c) 2009, Giampaolo Rodola'
3 * Copyright (c) 2017, Arnon Yaari
4 * All rights reserved.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 /*
10 * AIX support is experimental at this time.
11 * The following functions and methods are unsupported on the AIX platform:
12 * - psutil.Process.memory_maps
13 *
14 * Known limitations:
15 * - psutil.Process.io_counters read count is always 0
16 * - psutil.Process.io_counters may not be available on older AIX versions
17 * - psutil.Process.threads may not be available on older AIX versions
18 * - psutil.net_io_counters may not be available on older AIX versions
19 * - reading basic process info may fail or return incorrect values when
20 * process is starting (see IBM APAR IV58499 - fixed in newer AIX versions)
21 * - sockets and pipes may not be counted in num_fds (fixed in newer AIX
22 * versions)
23 *
24 * Useful resources:
25 * - proc filesystem: http://www-01.ibm.com/support/knowledgecenter/
26 * ssw_aix_72/com.ibm.aix.files/proc.htm
27 * - libperfstat: http://www-01.ibm.com/support/knowledgecenter/
28 * ssw_aix_72/com.ibm.aix.files/libperfstat.h.htm
29 */
30
31 #include <Python.h>
32 #include <sys/limits.h>
33 #include <sys/proc.h>
34 #include <sys/procfs.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <sys/sysinfo.h>
38 #include <sys/thread.h>
39 #include <sys/types.h>
40 #include <fcntl.h>
41 #include <utmp.h>
42 #include <utmpx.h>
43 #include <mntent.h>
44 #include <sys/ioctl.h>
45 #include <sys/tihdr.h>
46 #include <stropts.h>
47 #include <netinet/tcp_fsm.h>
48 #include <arpa/inet.h>
49 #include <net/if.h>
50 #include <libperfstat.h>
51 #include <unistd.h>
52
53 #include "_psutil_common.h"
54 #include "_psutil_posix.h"
55 #include "arch/aix/ifaddrs.h"
56 #include "arch/aix/net_connections.h"
57 #include "arch/aix/common.h"
58
59
60 #define TV2DOUBLE(t) (((t).tv_nsec * 0.000000001) + (t).tv_sec)
61
62 /*
63 * Read a file content and fills a C structure with it.
64 */
65 int
psutil_file_to_struct(char * path,void * fstruct,size_t size)66 psutil_file_to_struct(char *path, void *fstruct, size_t size) {
67 int fd;
68 size_t nbytes;
69 fd = open(path, O_RDONLY);
70 if (fd == -1) {
71 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
72 return 0;
73 }
74 nbytes = read(fd, fstruct, size);
75 if (nbytes <= 0) {
76 close(fd);
77 PyErr_SetFromErrno(PyExc_OSError);
78 return 0;
79 }
80 if (nbytes != size) {
81 close(fd);
82 PyErr_SetString(PyExc_RuntimeError, "structure size mismatch");
83 return 0;
84 }
85 close(fd);
86 return nbytes;
87 }
88
89
90 /*
91 * Return process ppid, rss, vms, ctime, nice, nthreads, status and tty
92 * as a Python tuple.
93 */
94 static PyObject *
psutil_proc_basic_info(PyObject * self,PyObject * args)95 psutil_proc_basic_info(PyObject *self, PyObject *args) {
96 int pid;
97 char path[100];
98 psinfo_t info;
99 pstatus_t status;
100 const char *procfs_path;
101
102 if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path))
103 return NULL;
104
105 sprintf(path, "%s/%i/psinfo", procfs_path, pid);
106 if (! psutil_file_to_struct(path, (void *)&info, sizeof(info)))
107 return NULL;
108
109 if (info.pr_nlwp == 0 && info.pr_lwp.pr_lwpid == 0) {
110 // From the /proc docs: "If the process is a zombie, the pr_nlwp
111 // and pr_lwp.pr_lwpid flags are zero."
112 status.pr_stat = SZOMB;
113 } else if (info.pr_flag & SEXIT) {
114 // "exiting" processes don't have /proc/<pid>/status
115 // There are other "exiting" processes that 'ps' shows as "active"
116 status.pr_stat = SACTIVE;
117 } else {
118 sprintf(path, "%s/%i/status", procfs_path, pid);
119 if (! psutil_file_to_struct(path, (void *)&status, sizeof(status)))
120 return NULL;
121 }
122
123 return Py_BuildValue("KKKdiiiK",
124 (unsigned long long) info.pr_ppid, // parent pid
125 (unsigned long long) info.pr_rssize, // rss
126 (unsigned long long) info.pr_size, // vms
127 TV2DOUBLE(info.pr_start), // create time
128 (int) info.pr_lwp.pr_nice, // nice
129 (int) info.pr_nlwp, // no. of threads
130 (int) status.pr_stat, // status code
131 (unsigned long long)info.pr_ttydev // tty nr
132 );
133 }
134
135
136 /*
137 * Return process name as a Python string.
138 */
139 static PyObject *
psutil_proc_name(PyObject * self,PyObject * args)140 psutil_proc_name(PyObject *self, PyObject *args) {
141 int pid;
142 char path[100];
143 psinfo_t info;
144 const char *procfs_path;
145
146 if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path))
147 return NULL;
148 sprintf(path, "%s/%i/psinfo", procfs_path, pid);
149 if (! psutil_file_to_struct(path, (void *)&info, sizeof(info)))
150 return NULL;
151
152 return PyUnicode_DecodeFSDefaultAndSize(info.pr_fname, PRFNSZ);
153 }
154
155
156 /*
157 * Return process command line arguments as a Python list
158 */
159 static PyObject *
psutil_proc_args(PyObject * self,PyObject * args)160 psutil_proc_args(PyObject *self, PyObject *args) {
161 int pid;
162 PyObject *py_retlist = PyList_New(0);
163 PyObject *py_arg = NULL;
164 struct procsinfo procbuf;
165 long arg_max;
166 char *argbuf = NULL;
167 char *curarg = NULL;
168 int ret;
169
170 if (py_retlist == NULL)
171 return NULL;
172 if (!PyArg_ParseTuple(args, "i", &pid))
173 goto error;
174 arg_max = sysconf(_SC_ARG_MAX);
175 argbuf = malloc(arg_max);
176 if (argbuf == NULL) {
177 PyErr_NoMemory();
178 goto error;
179 }
180
181 procbuf.pi_pid = pid;
182 ret = getargs(&procbuf, sizeof(procbuf), argbuf, ARG_MAX);
183 if (ret == -1) {
184 PyErr_SetFromErrno(PyExc_OSError);
185 goto error;
186 }
187
188 curarg = argbuf;
189 /* getargs will always append an extra NULL to end the arg list,
190 * even if the buffer is not big enough (even though it is supposed
191 * to be) so the following 'while' is safe */
192 while (*curarg != '\0') {
193 py_arg = PyUnicode_DecodeFSDefault(curarg);
194 if (!py_arg)
195 goto error;
196 if (PyList_Append(py_retlist, py_arg))
197 goto error;
198 Py_DECREF(py_arg);
199 curarg = strchr(curarg, '\0') + 1;
200 }
201
202 free(argbuf);
203
204 return py_retlist;
205
206 error:
207 if (argbuf != NULL)
208 free(argbuf);
209 Py_XDECREF(py_retlist);
210 Py_XDECREF(py_arg);
211 return NULL;
212 }
213
214
215 /*
216 * Return process environment variables as a Python dict
217 */
218 static PyObject *
psutil_proc_environ(PyObject * self,PyObject * args)219 psutil_proc_environ(PyObject *self, PyObject *args) {
220 int pid;
221 PyObject *py_retdict = PyDict_New();
222 PyObject *py_key = NULL;
223 PyObject *py_val = NULL;
224 struct procsinfo procbuf;
225 long env_max;
226 char *envbuf = NULL;
227 char *curvar = NULL;
228 char *separator = NULL;
229 int ret;
230
231 if (py_retdict == NULL)
232 return NULL;
233 if (!PyArg_ParseTuple(args, "i", &pid))
234 goto error;
235 env_max = sysconf(_SC_ARG_MAX);
236 envbuf = malloc(env_max);
237 if (envbuf == NULL) {
238 PyErr_NoMemory();
239 goto error;
240 }
241
242 procbuf.pi_pid = pid;
243 ret = getevars(&procbuf, sizeof(procbuf), envbuf, ARG_MAX);
244 if (ret == -1) {
245 PyErr_SetFromErrno(PyExc_OSError);
246 goto error;
247 }
248
249 curvar = envbuf;
250 /* getevars will always append an extra NULL to end the arg list,
251 * even if the buffer is not big enough (even though it is supposed
252 * to be) so the following 'while' is safe */
253 while (*curvar != '\0') {
254 separator = strchr(curvar, '=');
255 if (separator != NULL) {
256 py_key = PyUnicode_DecodeFSDefaultAndSize(
257 curvar,
258 (Py_ssize_t)(separator - curvar)
259 );
260 if (!py_key)
261 goto error;
262 py_val = PyUnicode_DecodeFSDefault(separator + 1);
263 if (!py_val)
264 goto error;
265 if (PyDict_SetItem(py_retdict, py_key, py_val))
266 goto error;
267 Py_CLEAR(py_key);
268 Py_CLEAR(py_val);
269 }
270 curvar = strchr(curvar, '\0') + 1;
271 }
272
273 free(envbuf);
274
275 return py_retdict;
276
277 error:
278 if (envbuf != NULL)
279 free(envbuf);
280 Py_XDECREF(py_retdict);
281 Py_XDECREF(py_key);
282 Py_XDECREF(py_val);
283 return NULL;
284 }
285
286
287 #ifdef CURR_VERSION_THREAD
288
289 /*
290 * Retrieves all threads used by process returning a list of tuples
291 * including thread id, user time and system time.
292 */
293 static PyObject *
psutil_proc_threads(PyObject * self,PyObject * args)294 psutil_proc_threads(PyObject *self, PyObject *args) {
295 long pid;
296 PyObject *py_retlist = PyList_New(0);
297 PyObject *py_tuple = NULL;
298 perfstat_thread_t *threadt = NULL;
299 perfstat_id_t id;
300 int i, rc, thread_count;
301
302 if (py_retlist == NULL)
303 return NULL;
304 if (! PyArg_ParseTuple(args, "l", &pid))
305 goto error;
306
307 /* Get the count of threads */
308 thread_count = perfstat_thread(NULL, NULL, sizeof(perfstat_thread_t), 0);
309 if (thread_count <= 0) {
310 PyErr_SetFromErrno(PyExc_OSError);
311 goto error;
312 }
313
314 /* Allocate enough memory */
315 threadt = (perfstat_thread_t *)calloc(thread_count,
316 sizeof(perfstat_thread_t));
317 if (threadt == NULL) {
318 PyErr_NoMemory();
319 goto error;
320 }
321
322 strcpy(id.name, "");
323 rc = perfstat_thread(&id, threadt, sizeof(perfstat_thread_t),
324 thread_count);
325 if (rc <= 0) {
326 PyErr_SetFromErrno(PyExc_OSError);
327 goto error;
328 }
329
330 for (i = 0; i < thread_count; i++) {
331 if (threadt[i].pid != pid)
332 continue;
333
334 py_tuple = Py_BuildValue("Idd",
335 threadt[i].tid,
336 threadt[i].ucpu_time,
337 threadt[i].scpu_time);
338 if (py_tuple == NULL)
339 goto error;
340 if (PyList_Append(py_retlist, py_tuple))
341 goto error;
342 Py_DECREF(py_tuple);
343 }
344 free(threadt);
345 return py_retlist;
346
347 error:
348 Py_XDECREF(py_tuple);
349 Py_DECREF(py_retlist);
350 if (threadt != NULL)
351 free(threadt);
352 return NULL;
353 }
354
355 #endif
356
357
358 #ifdef CURR_VERSION_PROCESS
359
360 static PyObject *
psutil_proc_io_counters(PyObject * self,PyObject * args)361 psutil_proc_io_counters(PyObject *self, PyObject *args) {
362 long pid;
363 int rc;
364 perfstat_process_t procinfo;
365 perfstat_id_t id;
366 if (! PyArg_ParseTuple(args, "l", &pid))
367 return NULL;
368
369 snprintf(id.name, sizeof(id.name), "%ld", pid);
370 rc = perfstat_process(&id, &procinfo, sizeof(perfstat_process_t), 1);
371 if (rc <= 0) {
372 PyErr_SetFromErrno(PyExc_OSError);
373 return NULL;
374 }
375
376 return Py_BuildValue("(KKKK)",
377 procinfo.inOps, // XXX always 0
378 procinfo.outOps,
379 procinfo.inBytes, // XXX always 0
380 procinfo.outBytes);
381 }
382
383 #endif
384
385
386 /*
387 * Return process user and system CPU times as a Python tuple.
388 */
389 static PyObject *
psutil_proc_cpu_times(PyObject * self,PyObject * args)390 psutil_proc_cpu_times(PyObject *self, PyObject *args) {
391 int pid;
392 char path[100];
393 pstatus_t info;
394 const char *procfs_path;
395
396 if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path))
397 return NULL;
398 sprintf(path, "%s/%i/status", procfs_path, pid);
399 if (! psutil_file_to_struct(path, (void *)&info, sizeof(info)))
400 return NULL;
401 // results are more precise than os.times()
402 return Py_BuildValue("dddd",
403 TV2DOUBLE(info.pr_utime),
404 TV2DOUBLE(info.pr_stime),
405 TV2DOUBLE(info.pr_cutime),
406 TV2DOUBLE(info.pr_cstime));
407 }
408
409
410 /*
411 * Return process uids/gids as a Python tuple.
412 */
413 static PyObject *
psutil_proc_cred(PyObject * self,PyObject * args)414 psutil_proc_cred(PyObject *self, PyObject *args) {
415 int pid;
416 char path[100];
417 prcred_t info;
418 const char *procfs_path;
419
420 if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path))
421 return NULL;
422 sprintf(path, "%s/%i/cred", procfs_path, pid);
423 if (! psutil_file_to_struct(path, (void *)&info, sizeof(info)))
424 return NULL;
425 return Py_BuildValue("iiiiii",
426 info.pr_ruid, info.pr_euid, info.pr_suid,
427 info.pr_rgid, info.pr_egid, info.pr_sgid);
428 }
429
430
431 /*
432 * Return process voluntary and involuntary context switches as a Python tuple.
433 */
434 static PyObject *
psutil_proc_num_ctx_switches(PyObject * self,PyObject * args)435 psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) {
436 PyObject *py_tuple = NULL;
437 pid32_t requested_pid;
438 pid32_t pid = 0;
439 int np = 0;
440 struct procentry64 *processes = (struct procentry64 *)NULL;
441 struct procentry64 *p;
442
443 if (! PyArg_ParseTuple(args, "i", &requested_pid))
444 return NULL;
445
446 processes = psutil_read_process_table(&np);
447 if (!processes)
448 return NULL;
449
450 /* Loop through processes */
451 for (p = processes; np > 0; np--, p++) {
452 pid = p->pi_pid;
453 if (requested_pid != pid)
454 continue;
455 py_tuple = Py_BuildValue("LL",
456 (long long) p->pi_ru.ru_nvcsw, /* voluntary context switches */
457 (long long) p->pi_ru.ru_nivcsw); /* involuntary */
458 free(processes);
459 return py_tuple;
460 }
461
462 /* finished iteration without finding requested pid */
463 free(processes);
464 return NoSuchProcess("psutil_read_process_table (no PID found)");
465 }
466
467
468 /*
469 * Return users currently connected on the system.
470 */
471 static PyObject *
psutil_users(PyObject * self,PyObject * args)472 psutil_users(PyObject *self, PyObject *args) {
473 struct utmpx *ut;
474 PyObject *py_retlist = PyList_New(0);
475 PyObject *py_tuple = NULL;
476 PyObject *py_username = NULL;
477 PyObject *py_tty = NULL;
478 PyObject *py_hostname = NULL;
479 PyObject *py_user_proc = NULL;
480
481 if (py_retlist == NULL)
482 return NULL;
483
484 setutxent();
485 while (NULL != (ut = getutxent())) {
486 if (ut->ut_type == USER_PROCESS)
487 py_user_proc = Py_True;
488 else
489 py_user_proc = Py_False;
490 py_username = PyUnicode_DecodeFSDefault(ut->ut_user);
491 if (! py_username)
492 goto error;
493 py_tty = PyUnicode_DecodeFSDefault(ut->ut_line);
494 if (! py_tty)
495 goto error;
496 py_hostname = PyUnicode_DecodeFSDefault(ut->ut_host);
497 if (! py_hostname)
498 goto error;
499 py_tuple = Py_BuildValue(
500 "(OOOfOi)",
501 py_username, // username
502 py_tty, // tty
503 py_hostname, // hostname
504 (float)ut->ut_tv.tv_sec, // tstamp
505 py_user_proc, // (bool) user process
506 ut->ut_pid // process id
507 );
508 if (py_tuple == NULL)
509 goto error;
510 if (PyList_Append(py_retlist, py_tuple))
511 goto error;
512 Py_CLEAR(py_username);
513 Py_CLEAR(py_tty);
514 Py_CLEAR(py_hostname);
515 Py_CLEAR(py_tuple);
516 }
517 endutxent();
518
519 return py_retlist;
520
521 error:
522 Py_XDECREF(py_username);
523 Py_XDECREF(py_tty);
524 Py_XDECREF(py_hostname);
525 Py_XDECREF(py_tuple);
526 Py_DECREF(py_retlist);
527 if (ut != NULL)
528 endutxent();
529 return NULL;
530 }
531
532
533 /*
534 * Return disk mounted partitions as a list of tuples including device,
535 * mount point and filesystem type.
536 */
537 static PyObject *
psutil_disk_partitions(PyObject * self,PyObject * args)538 psutil_disk_partitions(PyObject *self, PyObject *args) {
539 FILE *file = NULL;
540 struct mntent * mt = NULL;
541 PyObject *py_dev = NULL;
542 PyObject *py_mountp = NULL;
543 PyObject *py_tuple = NULL;
544 PyObject *py_retlist = PyList_New(0);
545
546 if (py_retlist == NULL)
547 return NULL;
548
549 file = setmntent(MNTTAB, "rb");
550 if (file == NULL) {
551 PyErr_SetFromErrno(PyExc_OSError);
552 goto error;
553 }
554 mt = getmntent(file);
555 while (mt != NULL) {
556 py_dev = PyUnicode_DecodeFSDefault(mt->mnt_fsname);
557 if (! py_dev)
558 goto error;
559 py_mountp = PyUnicode_DecodeFSDefault(mt->mnt_dir);
560 if (! py_mountp)
561 goto error;
562 py_tuple = Py_BuildValue(
563 "(OOss)",
564 py_dev, // device
565 py_mountp, // mount point
566 mt->mnt_type, // fs type
567 mt->mnt_opts); // options
568 if (py_tuple == NULL)
569 goto error;
570 if (PyList_Append(py_retlist, py_tuple))
571 goto error;
572 Py_CLEAR(py_dev);
573 Py_CLEAR(py_mountp);
574 Py_CLEAR(py_tuple);
575 mt = getmntent(file);
576 }
577 endmntent(file);
578 return py_retlist;
579
580 error:
581 Py_XDECREF(py_dev);
582 Py_XDECREF(py_mountp);
583 Py_XDECREF(py_tuple);
584 Py_DECREF(py_retlist);
585 if (file != NULL)
586 endmntent(file);
587 return NULL;
588 }
589
590
591 #if defined(CURR_VERSION_NETINTERFACE) && CURR_VERSION_NETINTERFACE >= 3
592
593 /*
594 * Return a list of tuples for network I/O statistics.
595 */
596 static PyObject *
psutil_net_io_counters(PyObject * self,PyObject * args)597 psutil_net_io_counters(PyObject *self, PyObject *args) {
598 perfstat_netinterface_t *statp = NULL;
599 int tot, i;
600 perfstat_id_t first;
601
602 PyObject *py_retdict = PyDict_New();
603 PyObject *py_ifc_info = NULL;
604
605 if (py_retdict == NULL)
606 return NULL;
607
608 /* check how many perfstat_netinterface_t structures are available */
609 tot = perfstat_netinterface(
610 NULL, NULL, sizeof(perfstat_netinterface_t), 0);
611 if (tot == 0) {
612 // no network interfaces - return empty dict
613 return py_retdict;
614 }
615 if (tot < 0) {
616 PyErr_SetFromErrno(PyExc_OSError);
617 goto error;
618 }
619 statp = (perfstat_netinterface_t *)
620 malloc(tot * sizeof(perfstat_netinterface_t));
621 if (statp == NULL) {
622 PyErr_NoMemory();
623 goto error;
624 }
625 strcpy(first.name, FIRST_NETINTERFACE);
626 tot = perfstat_netinterface(&first, statp,
627 sizeof(perfstat_netinterface_t), tot);
628 if (tot < 0) {
629 PyErr_SetFromErrno(PyExc_OSError);
630 goto error;
631 }
632
633 for (i = 0; i < tot; i++) {
634 py_ifc_info = Py_BuildValue("(KKKKKKKK)",
635 statp[i].obytes, /* number of bytes sent on interface */
636 statp[i].ibytes, /* number of bytes received on interface */
637 statp[i].opackets, /* number of packets sent on interface */
638 statp[i].ipackets, /* number of packets received on interface */
639 statp[i].ierrors, /* number of input errors on interface */
640 statp[i].oerrors, /* number of output errors on interface */
641 statp[i].if_iqdrops, /* Dropped on input, this interface */
642 statp[i].xmitdrops /* number of packets not transmitted */
643 );
644 if (!py_ifc_info)
645 goto error;
646 if (PyDict_SetItemString(py_retdict, statp[i].name, py_ifc_info))
647 goto error;
648 Py_DECREF(py_ifc_info);
649 }
650
651 free(statp);
652 return py_retdict;
653
654 error:
655 if (statp != NULL)
656 free(statp);
657 Py_XDECREF(py_ifc_info);
658 Py_DECREF(py_retdict);
659 return NULL;
660 }
661
662 #endif
663
664
665 static PyObject*
psutil_net_if_stats(PyObject * self,PyObject * args)666 psutil_net_if_stats(PyObject* self, PyObject* args) {
667 char *nic_name;
668 int sock = 0;
669 int ret;
670 int mtu;
671 struct ifreq ifr;
672 PyObject *py_is_up = NULL;
673 PyObject *py_retlist = NULL;
674
675 if (! PyArg_ParseTuple(args, "s", &nic_name))
676 return NULL;
677
678 sock = socket(AF_INET, SOCK_DGRAM, 0);
679 if (sock == -1)
680 goto error;
681
682 PSUTIL_STRNCPY(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
683
684 // is up?
685 ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
686 if (ret == -1)
687 goto error;
688 if ((ifr.ifr_flags & IFF_UP) != 0)
689 py_is_up = Py_True;
690 else
691 py_is_up = Py_False;
692 Py_INCREF(py_is_up);
693
694 // MTU
695 ret = ioctl(sock, SIOCGIFMTU, &ifr);
696 if (ret == -1)
697 goto error;
698 mtu = ifr.ifr_mtu;
699
700 close(sock);
701 py_retlist = Py_BuildValue("[Oi]", py_is_up, mtu);
702 if (!py_retlist)
703 goto error;
704 Py_DECREF(py_is_up);
705 return py_retlist;
706
707 error:
708 Py_XDECREF(py_is_up);
709 if (sock != 0)
710 close(sock);
711 PyErr_SetFromErrno(PyExc_OSError);
712 return NULL;
713 }
714
715
716 static PyObject *
psutil_boot_time(PyObject * self,PyObject * args)717 psutil_boot_time(PyObject *self, PyObject *args) {
718 float boot_time = 0.0;
719 struct utmpx *ut;
720
721 setutxent();
722 while (NULL != (ut = getutxent())) {
723 if (ut->ut_type == BOOT_TIME) {
724 boot_time = (float)ut->ut_tv.tv_sec;
725 break;
726 }
727 }
728 endutxent();
729 if (boot_time == 0.0) {
730 /* could not find BOOT_TIME in getutxent loop */
731 PyErr_SetString(PyExc_RuntimeError, "can't determine boot time");
732 return NULL;
733 }
734 return Py_BuildValue("f", boot_time);
735 }
736
737
738 /*
739 * Return a Python list of tuple representing per-cpu times
740 */
741 static PyObject *
psutil_per_cpu_times(PyObject * self,PyObject * args)742 psutil_per_cpu_times(PyObject *self, PyObject *args) {
743 int ncpu, rc, i;
744 long ticks;
745 perfstat_cpu_t *cpu = NULL;
746 perfstat_id_t id;
747 PyObject *py_retlist = PyList_New(0);
748 PyObject *py_cputime = NULL;
749
750 if (py_retlist == NULL)
751 return NULL;
752
753 /* get the number of ticks per second */
754 ticks = sysconf(_SC_CLK_TCK);
755 if (ticks < 0) {
756 PyErr_SetFromErrno(PyExc_OSError);
757 goto error;
758 }
759
760 /* get the number of cpus in ncpu */
761 ncpu = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
762 if (ncpu <= 0){
763 PyErr_SetFromErrno(PyExc_OSError);
764 goto error;
765 }
766
767 /* allocate enough memory to hold the ncpu structures */
768 cpu = (perfstat_cpu_t *) malloc(ncpu * sizeof(perfstat_cpu_t));
769 if (cpu == NULL) {
770 PyErr_NoMemory();
771 goto error;
772 }
773
774 strcpy(id.name, "");
775 rc = perfstat_cpu(&id, cpu, sizeof(perfstat_cpu_t), ncpu);
776
777 if (rc <= 0) {
778 PyErr_SetFromErrno(PyExc_OSError);
779 goto error;
780 }
781
782 for (i = 0; i < ncpu; i++) {
783 py_cputime = Py_BuildValue(
784 "(dddd)",
785 (double)cpu[i].user / ticks,
786 (double)cpu[i].sys / ticks,
787 (double)cpu[i].idle / ticks,
788 (double)cpu[i].wait / ticks);
789 if (!py_cputime)
790 goto error;
791 if (PyList_Append(py_retlist, py_cputime))
792 goto error;
793 Py_DECREF(py_cputime);
794 }
795 free(cpu);
796 return py_retlist;
797
798 error:
799 Py_XDECREF(py_cputime);
800 Py_DECREF(py_retlist);
801 if (cpu != NULL)
802 free(cpu);
803 return NULL;
804 }
805
806
807 /*
808 * Return disk IO statistics.
809 */
810 static PyObject *
psutil_disk_io_counters(PyObject * self,PyObject * args)811 psutil_disk_io_counters(PyObject *self, PyObject *args) {
812 PyObject *py_retdict = PyDict_New();
813 PyObject *py_disk_info = NULL;
814 perfstat_disk_t *diskt = NULL;
815 perfstat_id_t id;
816 int i, rc, disk_count;
817
818 if (py_retdict == NULL)
819 return NULL;
820
821 /* Get the count of disks */
822 disk_count = perfstat_disk(NULL, NULL, sizeof(perfstat_disk_t), 0);
823 if (disk_count <= 0) {
824 PyErr_SetFromErrno(PyExc_OSError);
825 goto error;
826 }
827
828 /* Allocate enough memory */
829 diskt = (perfstat_disk_t *)calloc(disk_count,
830 sizeof(perfstat_disk_t));
831 if (diskt == NULL) {
832 PyErr_NoMemory();
833 goto error;
834 }
835
836 strcpy(id.name, FIRST_DISK);
837 rc = perfstat_disk(&id, diskt, sizeof(perfstat_disk_t),
838 disk_count);
839 if (rc <= 0) {
840 PyErr_SetFromErrno(PyExc_OSError);
841 goto error;
842 }
843
844 for (i = 0; i < disk_count; i++) {
845 py_disk_info = Py_BuildValue(
846 "KKKKKK",
847 diskt[i].__rxfers,
848 diskt[i].xfers - diskt[i].__rxfers,
849 diskt[i].rblks * diskt[i].bsize,
850 diskt[i].wblks * diskt[i].bsize,
851 diskt[i].rserv / 1000 / 1000, // from nano to milli secs
852 diskt[i].wserv / 1000 / 1000 // from nano to milli secs
853 );
854 if (py_disk_info == NULL)
855 goto error;
856 if (PyDict_SetItemString(py_retdict, diskt[i].name,
857 py_disk_info))
858 goto error;
859 Py_DECREF(py_disk_info);
860 }
861 free(diskt);
862 return py_retdict;
863
864 error:
865 Py_XDECREF(py_disk_info);
866 Py_DECREF(py_retdict);
867 if (diskt != NULL)
868 free(diskt);
869 return NULL;
870 }
871
872
873 /*
874 * Return virtual memory usage statistics.
875 */
876 static PyObject *
psutil_virtual_mem(PyObject * self,PyObject * args)877 psutil_virtual_mem(PyObject *self, PyObject *args) {
878 int rc;
879 long pagesize = psutil_getpagesize();
880 perfstat_memory_total_t memory;
881
882 rc = perfstat_memory_total(
883 NULL, &memory, sizeof(perfstat_memory_total_t), 1);
884 if (rc <= 0){
885 PyErr_SetFromErrno(PyExc_OSError);
886 return NULL;
887 }
888
889 return Py_BuildValue("KKKKK",
890 (unsigned long long) memory.real_total * pagesize,
891 (unsigned long long) memory.real_avail * pagesize,
892 (unsigned long long) memory.real_free * pagesize,
893 (unsigned long long) memory.real_pinned * pagesize,
894 (unsigned long long) memory.real_inuse * pagesize
895 );
896 }
897
898
899 /*
900 * Return stats about swap memory.
901 */
902 static PyObject *
psutil_swap_mem(PyObject * self,PyObject * args)903 psutil_swap_mem(PyObject *self, PyObject *args) {
904 int rc;
905 long pagesize = psutil_getpagesize();
906 perfstat_memory_total_t memory;
907
908 rc = perfstat_memory_total(
909 NULL, &memory, sizeof(perfstat_memory_total_t), 1);
910 if (rc <= 0){
911 PyErr_SetFromErrno(PyExc_OSError);
912 return NULL;
913 }
914
915 return Py_BuildValue("KKKK",
916 (unsigned long long) memory.pgsp_total * pagesize,
917 (unsigned long long) memory.pgsp_free * pagesize,
918 (unsigned long long) memory.pgins * pagesize,
919 (unsigned long long) memory.pgouts * pagesize
920 );
921 }
922
923
924 /*
925 * Return CPU statistics.
926 */
927 static PyObject *
psutil_cpu_stats(PyObject * self,PyObject * args)928 psutil_cpu_stats(PyObject *self, PyObject *args) {
929 int ncpu, rc, i;
930 // perfstat_cpu_total_t doesn't have invol/vol cswitch, only pswitch
931 // which is apparently something else. We have to sum over all cpus
932 perfstat_cpu_t *cpu = NULL;
933 perfstat_id_t id;
934 u_longlong_t cswitches = 0;
935 u_longlong_t devintrs = 0;
936 u_longlong_t softintrs = 0;
937 u_longlong_t syscall = 0;
938
939 /* get the number of cpus in ncpu */
940 ncpu = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
941 if (ncpu <= 0){
942 PyErr_SetFromErrno(PyExc_OSError);
943 goto error;
944 }
945
946 /* allocate enough memory to hold the ncpu structures */
947 cpu = (perfstat_cpu_t *) malloc(ncpu * sizeof(perfstat_cpu_t));
948 if (cpu == NULL) {
949 PyErr_NoMemory();
950 goto error;
951 }
952
953 strcpy(id.name, "");
954 rc = perfstat_cpu(&id, cpu, sizeof(perfstat_cpu_t), ncpu);
955
956 if (rc <= 0) {
957 PyErr_SetFromErrno(PyExc_OSError);
958 goto error;
959 }
960
961 for (i = 0; i < ncpu; i++) {
962 cswitches += cpu[i].invol_cswitch + cpu[i].vol_cswitch;
963 devintrs += cpu[i].devintrs;
964 softintrs += cpu[i].softintrs;
965 syscall += cpu[i].syscall;
966 }
967
968 free(cpu);
969
970 return Py_BuildValue(
971 "KKKK",
972 cswitches,
973 devintrs,
974 softintrs,
975 syscall
976 );
977
978 error:
979 if (cpu != NULL)
980 free(cpu);
981 return NULL;
982 }
983
984
985 /*
986 * define the psutil C module methods and initialize the module.
987 */
988 static PyMethodDef
989 PsutilMethods[] =
990 {
991 // --- process-related functions
992 {"proc_basic_info", psutil_proc_basic_info, METH_VARARGS,
993 "Return process ppid, rss, vms, ctime, nice, nthreads, status and tty"},
994 {"proc_name", psutil_proc_name, METH_VARARGS,
995 "Return process name."},
996 {"proc_args", psutil_proc_args, METH_VARARGS,
997 "Return process command line arguments."},
998 {"proc_environ", psutil_proc_environ, METH_VARARGS,
999 "Return process environment variables."},
1000 {"proc_cpu_times", psutil_proc_cpu_times, METH_VARARGS,
1001 "Return process user and system CPU times."},
1002 {"proc_cred", psutil_proc_cred, METH_VARARGS,
1003 "Return process uids/gids."},
1004 #ifdef CURR_VERSION_THREAD
1005 {"proc_threads", psutil_proc_threads, METH_VARARGS,
1006 "Return process threads"},
1007 #endif
1008 #ifdef CURR_VERSION_PROCESS
1009 {"proc_io_counters", psutil_proc_io_counters, METH_VARARGS,
1010 "Get process I/O counters."},
1011 #endif
1012 {"proc_num_ctx_switches", psutil_proc_num_ctx_switches, METH_VARARGS,
1013 "Get process I/O counters."},
1014
1015 // --- system-related functions
1016 {"users", psutil_users, METH_VARARGS,
1017 "Return currently connected users."},
1018 {"disk_partitions", psutil_disk_partitions, METH_VARARGS,
1019 "Return disk partitions."},
1020 {"boot_time", psutil_boot_time, METH_VARARGS,
1021 "Return system boot time in seconds since the EPOCH."},
1022 {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS,
1023 "Return system per-cpu times as a list of tuples"},
1024 {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS,
1025 "Return a Python dict of tuples for disk I/O statistics."},
1026 {"virtual_mem", psutil_virtual_mem, METH_VARARGS,
1027 "Return system virtual memory usage statistics"},
1028 {"swap_mem", psutil_swap_mem, METH_VARARGS,
1029 "Return stats about swap memory, in bytes"},
1030 #if defined(CURR_VERSION_NETINTERFACE) && CURR_VERSION_NETINTERFACE >= 3
1031 {"net_io_counters", psutil_net_io_counters, METH_VARARGS,
1032 "Return a Python dict of tuples for network I/O statistics."},
1033 #endif
1034 {"net_connections", psutil_net_connections, METH_VARARGS,
1035 "Return system-wide connections"},
1036 {"net_if_stats", psutil_net_if_stats, METH_VARARGS,
1037 "Return NIC stats (isup, mtu)"},
1038 {"cpu_stats", psutil_cpu_stats, METH_VARARGS,
1039 "Return CPU statistics"},
1040
1041 // --- others
1042 {"set_testing", psutil_set_testing, METH_NOARGS,
1043 "Set psutil in testing mode"},
1044
1045 {NULL, NULL, 0, NULL}
1046 };
1047
1048
1049 struct module_state {
1050 PyObject *error;
1051 };
1052
1053 #if PY_MAJOR_VERSION >= 3
1054 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
1055 #else
1056 #define GETSTATE(m) (&_state)
1057 #endif
1058
1059 #ifdef __cplusplus
1060 extern "C" {
1061 #endif
1062
1063 #if PY_MAJOR_VERSION >= 3
1064
1065 static int
psutil_aix_traverse(PyObject * m,visitproc visit,void * arg)1066 psutil_aix_traverse(PyObject *m, visitproc visit, void *arg) {
1067 Py_VISIT(GETSTATE(m)->error);
1068 return 0;
1069 }
1070
1071 static int
psutil_aix_clear(PyObject * m)1072 psutil_aix_clear(PyObject *m) {
1073 Py_CLEAR(GETSTATE(m)->error);
1074 return 0;
1075 }
1076
1077 static struct PyModuleDef moduledef = {
1078 PyModuleDef_HEAD_INIT,
1079 "psutil_aix",
1080 NULL,
1081 sizeof(struct module_state),
1082 PsutilMethods,
1083 NULL,
1084 psutil_aix_traverse,
1085 psutil_aix_clear,
1086 NULL
1087 };
1088
1089 #define INITERROR return NULL
1090
PyInit__psutil_aix(void)1091 PyMODINIT_FUNC PyInit__psutil_aix(void)
1092
1093 #else
1094 #define INITERROR return
1095
1096 void init_psutil_aix(void)
1097 #endif
1098 {
1099 #if PY_MAJOR_VERSION >= 3
1100 PyObject *module = PyModule_Create(&moduledef);
1101 #else
1102 PyObject *module = Py_InitModule("_psutil_aix", PsutilMethods);
1103 #endif
1104 PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
1105
1106 PyModule_AddIntConstant(module, "SIDL", SIDL);
1107 PyModule_AddIntConstant(module, "SZOMB", SZOMB);
1108 PyModule_AddIntConstant(module, "SACTIVE", SACTIVE);
1109 PyModule_AddIntConstant(module, "SSWAP", SSWAP);
1110 PyModule_AddIntConstant(module, "SSTOP", SSTOP);
1111
1112 PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED);
1113 PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING);
1114 PyModule_AddIntConstant(module, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT);
1115 PyModule_AddIntConstant(module, "TCPS_LISTEN", TCPS_LISTEN);
1116 PyModule_AddIntConstant(module, "TCPS_ESTABLISHED", TCPS_ESTABLISHED);
1117 PyModule_AddIntConstant(module, "TCPS_SYN_SENT", TCPS_SYN_SENT);
1118 PyModule_AddIntConstant(module, "TCPS_SYN_RCVD", TCPS_SYN_RECEIVED);
1119 PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1);
1120 PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2);
1121 PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK);
1122 PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT);
1123 PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE);
1124
1125 psutil_setup();
1126
1127 if (module == NULL)
1128 INITERROR;
1129 #if PY_MAJOR_VERSION >= 3
1130 return module;
1131 #endif
1132 }
1133
1134 #ifdef __cplusplus
1135 }
1136 #endif
1137