1 /*
2 * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil (OpenBSD).
3 * All rights reserved.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 *
7 * Platform-specific module methods for FreeBSD and OpenBSD.
8
9 * OpenBSD references:
10 * - OpenBSD source code: https://github.com/openbsd/src
11 *
12 * OpenBSD / NetBSD: missing APIs compared to FreeBSD implementation:
13 * - psutil.net_connections()
14 * - psutil.Process.get/set_cpu_affinity() (not supported natively)
15 * - psutil.Process.memory_maps()
16 */
17
18 #if defined(PSUTIL_NETBSD)
19 #define _KMEMUSER
20 #endif
21
22 #include <Python.h>
23 #include <assert.h>
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <signal.h>
28 #include <fcntl.h>
29 #include <paths.h>
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/sysctl.h>
33 #if !defined(__NetBSD__)
34 #include <sys/user.h>
35 #endif
36 #include <sys/proc.h>
37 #include <sys/file.h>
38 #include <sys/socket.h>
39 #include <net/route.h>
40 #include <sys/socketvar.h> // for struct xsocket
41 #include <sys/un.h>
42 #include <sys/unpcb.h>
43 // for xinpcb struct
44 #include <netinet/in.h>
45 #include <netinet/in_systm.h>
46 #include <netinet/ip.h>
47 #include <netinet/in_pcb.h>
48 #include <netinet/tcp.h>
49 #include <netinet/tcp_timer.h>
50 #include <netinet/ip_var.h>
51 #include <netinet/tcp_var.h> // for struct xtcpcb
52 #include <netinet/tcp_fsm.h> // for TCP connection states
53 #include <arpa/inet.h> // for inet_ntop()
54 #include <sys/mount.h>
55 #include <net/if.h> // net io counters
56 #include <net/if_dl.h>
57 #include <net/route.h>
58 #include <netinet/in.h> // process open files/connections
59 #include <sys/un.h>
60
61 #include "_psutil_common.h"
62 #include "_psutil_posix.h"
63
64 #ifdef PSUTIL_FREEBSD
65 #include "arch/freebsd/specific.h"
66 #include "arch/freebsd/sys_socks.h"
67 #include "arch/freebsd/proc_socks.h"
68
69 #include <net/if_media.h>
70 #include <devstat.h> // get io counters
71 #include <libutil.h> // process open files, shared libs (kinfo_getvmmap)
72 #if __FreeBSD_version < 900000
73 #include <utmp.h> // system users
74 #else
75 #include <utmpx.h>
76 #endif
77 #elif PSUTIL_OPENBSD
78 #include "arch/openbsd/specific.h"
79
80 #include <utmp.h>
81 #include <sys/vnode.h> // for VREG
82 #define _KERNEL // for DTYPE_VNODE
83 #include <sys/file.h>
84 #undef _KERNEL
85 #include <sys/sched.h> // for CPUSTATES & CP_*
86 #elif PSUTIL_NETBSD
87 #include "arch/netbsd/specific.h"
88 #include "arch/netbsd/socks.h"
89
90 #include <utmpx.h>
91 #include <sys/vnode.h> // for VREG
92 #include <sys/sched.h> // for CPUSTATES & CP_*
93 #ifndef DTYPE_VNODE
94 #define DTYPE_VNODE 1
95 #endif
96 #endif
97
98
99 // convert a timeval struct to a double
100 #define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
101
102 #ifdef PSUTIL_FREEBSD
103 // convert a bintime struct to milliseconds
104 #define PSUTIL_BT2MSEC(bt) (bt.sec * 1000 + (((uint64_t) 1000000000 * \
105 (uint32_t) (bt.frac >> 32) ) >> 32 ) / 1000000)
106 #endif
107
108 #if defined(PSUTIL_OPENBSD) || defined (PSUTIL_NETBSD)
109 #define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0)
110 #endif
111
112
113 /*
114 * Return a Python list of all the PIDs running on the system.
115 */
116 static PyObject *
psutil_pids(PyObject * self,PyObject * args)117 psutil_pids(PyObject *self, PyObject *args) {
118 kinfo_proc *proclist = NULL;
119 kinfo_proc *orig_address = NULL;
120 size_t num_processes;
121 size_t idx;
122 PyObject *py_retlist = PyList_New(0);
123 PyObject *py_pid = NULL;
124
125 if (py_retlist == NULL)
126 return NULL;
127
128 if (psutil_get_proc_list(&proclist, &num_processes) != 0)
129 goto error;
130
131 if (num_processes > 0) {
132 orig_address = proclist; // save so we can free it after we're done
133 for (idx = 0; idx < num_processes; idx++) {
134 #ifdef PSUTIL_FREEBSD
135 py_pid = PyLong_FromPid(proclist->ki_pid);
136 #elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
137 py_pid = PyLong_FromPid(proclist->p_pid);
138 #endif
139 if (!py_pid)
140 goto error;
141 if (PyList_Append(py_retlist, py_pid))
142 goto error;
143 Py_CLEAR(py_pid);
144 proclist++;
145 }
146 free(orig_address);
147 }
148
149 return py_retlist;
150
151 error:
152 Py_XDECREF(py_pid);
153 Py_DECREF(py_retlist);
154 if (orig_address != NULL)
155 free(orig_address);
156 return NULL;
157 }
158
159
160 /*
161 * Return a Python float indicating the system boot time expressed in
162 * seconds since the epoch.
163 */
164 static PyObject *
psutil_boot_time(PyObject * self,PyObject * args)165 psutil_boot_time(PyObject *self, PyObject *args) {
166 // fetch sysctl "kern.boottime"
167 static int request[2] = { CTL_KERN, KERN_BOOTTIME };
168 struct timeval boottime;
169 size_t len = sizeof(boottime);
170
171 if (sysctl(request, 2, &boottime, &len, NULL, 0) == -1)
172 return PyErr_SetFromErrno(PyExc_OSError);
173 return Py_BuildValue("d", (double)boottime.tv_sec);
174 }
175
176
177 /*
178 * Collect different info about a process in one shot and return
179 * them as a big Python tuple.
180 */
181 static PyObject *
psutil_proc_oneshot_info(PyObject * self,PyObject * args)182 psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
183 pid_t pid;
184 long rss;
185 long vms;
186 long memtext;
187 long memdata;
188 long memstack;
189 int oncpu;
190 kinfo_proc kp;
191 long pagesize = sysconf(_SC_PAGESIZE);
192 char str[1000];
193 PyObject *py_name;
194 PyObject *py_ppid;
195 PyObject *py_retlist;
196
197 if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
198 return NULL;
199 if (psutil_kinfo_proc(pid, &kp) == -1)
200 return NULL;
201
202 // Process
203 #ifdef PSUTIL_FREEBSD
204 sprintf(str, "%s", kp.ki_comm);
205 #elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
206 sprintf(str, "%s", kp.p_comm);
207 #endif
208 py_name = PyUnicode_DecodeFSDefault(str);
209 if (! py_name) {
210 // Likely a decoding error. We don't want to fail the whole
211 // operation. The python module may retry with proc_name().
212 PyErr_Clear();
213 py_name = Py_None;
214 }
215 // Py_INCREF(py_name);
216
217 // Calculate memory.
218 #ifdef PSUTIL_FREEBSD
219 rss = (long)kp.ki_rssize * pagesize;
220 vms = (long)kp.ki_size;
221 memtext = (long)kp.ki_tsize * pagesize;
222 memdata = (long)kp.ki_dsize * pagesize;
223 memstack = (long)kp.ki_ssize * pagesize;
224 #else
225 rss = (long)kp.p_vm_rssize * pagesize;
226 #ifdef PSUTIL_OPENBSD
227 // VMS, this is how ps determines it on OpenBSD:
228 // https://github.com/openbsd/src/blob/
229 // 588f7f8c69786211f2d16865c552afb91b1c7cba/bin/ps/print.c#L505
230 vms = (long)(kp.p_vm_dsize + kp.p_vm_ssize + kp.p_vm_tsize) * pagesize;
231 #elif PSUTIL_NETBSD
232 // VMS, this is how top determines it on NetBSD:
233 // https://github.com/IIJ-NetBSD/netbsd-src/blob/master/external/
234 // bsd/top/dist/machine/m_netbsd.c
235 vms = (long)kp.p_vm_msize * pagesize;
236 #endif
237 memtext = (long)kp.p_vm_tsize * pagesize;
238 memdata = (long)kp.p_vm_dsize * pagesize;
239 memstack = (long)kp.p_vm_ssize * pagesize;
240 #endif
241
242 #ifdef PSUTIL_FREEBSD
243 // what CPU we're on; top was used as an example:
244 // https://svnweb.freebsd.org/base/head/usr.bin/top/machine.c?
245 // view=markup&pathrev=273835
246 // XXX - note: for "intr" PID this is -1.
247 if (kp.ki_stat == SRUN && kp.ki_oncpu != NOCPU)
248 oncpu = kp.ki_oncpu;
249 else
250 oncpu = kp.ki_lastcpu;
251 #else
252 // On Net/OpenBSD we have kp.p_cpuid but it appears it's always
253 // set to KI_NOCPU. Even if it's not, ki_lastcpu does not exist
254 // so there's no way to determine where "sleeping" processes
255 // were. Not supported.
256 oncpu = -1;
257 #endif
258
259 #ifdef PSUTIL_FREEBSD
260 py_ppid = PyLong_FromPid(kp.ki_ppid);
261 #elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
262 py_ppid = PyLong_FromPid(kp.p_ppid);
263 #else
264 py_ppid = Py_BuildfValue(-1);
265 #endif
266 if (! py_ppid)
267 return NULL;
268
269 // Return a single big tuple with all process info.
270 py_retlist = Py_BuildValue(
271 #if defined(__FreeBSD_version) && __FreeBSD_version >= 1200031
272 "(OillllllLdllllddddlllllbO)",
273 #else
274 "(OillllllidllllddddlllllbO)",
275 #endif
276 #ifdef PSUTIL_FREEBSD
277 py_ppid, // (pid_t) ppid
278 (int)kp.ki_stat, // (int) status
279 // UIDs
280 (long)kp.ki_ruid, // (long) real uid
281 (long)kp.ki_uid, // (long) effective uid
282 (long)kp.ki_svuid, // (long) saved uid
283 // GIDs
284 (long)kp.ki_rgid, // (long) real gid
285 (long)kp.ki_groups[0], // (long) effective gid
286 (long)kp.ki_svuid, // (long) saved gid
287 //
288 kp.ki_tdev, // (int or long long) tty nr
289 PSUTIL_TV2DOUBLE(kp.ki_start), // (double) create time
290 // ctx switches
291 kp.ki_rusage.ru_nvcsw, // (long) ctx switches (voluntary)
292 kp.ki_rusage.ru_nivcsw, // (long) ctx switches (unvoluntary)
293 // IO count
294 kp.ki_rusage.ru_inblock, // (long) read io count
295 kp.ki_rusage.ru_oublock, // (long) write io count
296 // CPU times: convert from micro seconds to seconds.
297 PSUTIL_TV2DOUBLE(kp.ki_rusage.ru_utime), // (double) user time
298 PSUTIL_TV2DOUBLE(kp.ki_rusage.ru_stime), // (double) sys time
299 PSUTIL_TV2DOUBLE(kp.ki_rusage_ch.ru_utime), // (double) children utime
300 PSUTIL_TV2DOUBLE(kp.ki_rusage_ch.ru_stime), // (double) children stime
301 // memory
302 rss, // (long) rss
303 vms, // (long) vms
304 memtext, // (long) mem text
305 memdata, // (long) mem data
306 memstack, // (long) mem stack
307 // others
308 oncpu, // (int) the CPU we are on
309 #elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
310 py_ppid, // (pid_t) ppid
311 (int)kp.p_stat, // (int) status
312 // UIDs
313 (long)kp.p_ruid, // (long) real uid
314 (long)kp.p_uid, // (long) effective uid
315 (long)kp.p_svuid, // (long) saved uid
316 // GIDs
317 (long)kp.p_rgid, // (long) real gid
318 (long)kp.p_groups[0], // (long) effective gid
319 (long)kp.p_svuid, // (long) saved gid
320 //
321 kp.p_tdev, // (int) tty nr
322 PSUTIL_KPT2DOUBLE(kp.p_ustart), // (double) create time
323 // ctx switches
324 kp.p_uru_nvcsw, // (long) ctx switches (voluntary)
325 kp.p_uru_nivcsw, // (long) ctx switches (unvoluntary)
326 // IO count
327 kp.p_uru_inblock, // (long) read io count
328 kp.p_uru_oublock, // (long) write io count
329 // CPU times: convert from micro seconds to seconds.
330 PSUTIL_KPT2DOUBLE(kp.p_uutime), // (double) user time
331 PSUTIL_KPT2DOUBLE(kp.p_ustime), // (double) sys time
332 // OpenBSD and NetBSD provide children user + system times summed
333 // together (no distinction).
334 kp.p_uctime_sec + kp.p_uctime_usec / 1000000.0, // (double) ch utime
335 kp.p_uctime_sec + kp.p_uctime_usec / 1000000.0, // (double) ch stime
336 // memory
337 rss, // (long) rss
338 vms, // (long) vms
339 memtext, // (long) mem text
340 memdata, // (long) mem data
341 memstack, // (long) mem stack
342 // others
343 oncpu, // (int) the CPU we are on
344 #endif
345 py_name // (pystr) name
346 );
347
348 Py_DECREF(py_name);
349 Py_DECREF(py_ppid);
350 return py_retlist;
351 }
352
353
354 /*
355 * Return process name from kinfo_proc as a Python string.
356 */
357 static PyObject *
psutil_proc_name(PyObject * self,PyObject * args)358 psutil_proc_name(PyObject *self, PyObject *args) {
359 pid_t pid;
360 kinfo_proc kp;
361 char str[1000];
362
363 if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
364 return NULL;
365 if (psutil_kinfo_proc(pid, &kp) == -1)
366 return NULL;
367
368 #ifdef PSUTIL_FREEBSD
369 sprintf(str, "%s", kp.ki_comm);
370 #elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
371 sprintf(str, "%s", kp.p_comm);
372 #endif
373 return PyUnicode_DecodeFSDefault(str);
374 }
375
376
377 /*
378 * Return process cmdline as a Python list of cmdline arguments.
379 */
380 static PyObject *
psutil_proc_cmdline(PyObject * self,PyObject * args)381 psutil_proc_cmdline(PyObject *self, PyObject *args) {
382 pid_t pid;
383 PyObject *py_retlist = NULL;
384
385 if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
386 return NULL;
387 py_retlist = psutil_get_cmdline(pid);
388 if (py_retlist == NULL)
389 return NULL;
390 return Py_BuildValue("N", py_retlist);
391 }
392
393
394 /*
395 * Return the number of logical CPUs in the system.
396 * XXX this could be shared with macOS
397 */
398 static PyObject *
psutil_cpu_count_logical(PyObject * self,PyObject * args)399 psutil_cpu_count_logical(PyObject *self, PyObject *args) {
400 int mib[2];
401 int ncpu;
402 size_t len;
403
404 mib[0] = CTL_HW;
405 mib[1] = HW_NCPU;
406 len = sizeof(ncpu);
407
408 if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1)
409 Py_RETURN_NONE; // mimic os.cpu_count()
410 else
411 return Py_BuildValue("i", ncpu);
412 }
413
414
415 /*
416 * Return a Python tuple representing user, kernel and idle CPU times
417 */
418 static PyObject *
psutil_cpu_times(PyObject * self,PyObject * args)419 psutil_cpu_times(PyObject *self, PyObject *args) {
420 #ifdef PSUTIL_NETBSD
421 u_int64_t cpu_time[CPUSTATES];
422 #else
423 long cpu_time[CPUSTATES];
424 #endif
425 size_t size = sizeof(cpu_time);
426 int ret;
427
428 #if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD)
429 ret = sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0);
430 #elif PSUTIL_OPENBSD
431 int mib[] = {CTL_KERN, KERN_CPTIME};
432 ret = sysctl(mib, 2, &cpu_time, &size, NULL, 0);
433 #endif
434 if (ret == -1)
435 return PyErr_SetFromErrno(PyExc_OSError);
436 return Py_BuildValue("(ddddd)",
437 (double)cpu_time[CP_USER] / CLOCKS_PER_SEC,
438 (double)cpu_time[CP_NICE] / CLOCKS_PER_SEC,
439 (double)cpu_time[CP_SYS] / CLOCKS_PER_SEC,
440 (double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC,
441 (double)cpu_time[CP_INTR] / CLOCKS_PER_SEC
442 );
443 }
444
445
446 /*
447 * Return files opened by process as a list of (path, fd) tuples.
448 * TODO: this is broken as it may report empty paths. 'procstat'
449 * utility has the same problem see:
450 * https://github.com/giampaolo/psutil/issues/595
451 */
452 #if (defined(__FreeBSD_version) && __FreeBSD_version >= 800000) || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD)
453 static PyObject *
psutil_proc_open_files(PyObject * self,PyObject * args)454 psutil_proc_open_files(PyObject *self, PyObject *args) {
455 pid_t pid;
456 int i;
457 int cnt;
458 int regular;
459 int fd;
460 char *path;
461 struct kinfo_file *freep = NULL;
462 struct kinfo_file *kif;
463 kinfo_proc kipp;
464 PyObject *py_tuple = NULL;
465 PyObject *py_path = NULL;
466 PyObject *py_retlist = PyList_New(0);
467
468 if (py_retlist == NULL)
469 return NULL;
470 if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
471 goto error;
472 if (psutil_kinfo_proc(pid, &kipp) == -1)
473 goto error;
474
475 errno = 0;
476 freep = kinfo_getfile(pid, &cnt);
477 if (freep == NULL) {
478 #if !defined(PSUTIL_OPENBSD)
479 psutil_raise_for_pid(pid, "kinfo_getfile()");
480 #endif
481 goto error;
482 }
483
484 for (i = 0; i < cnt; i++) {
485 kif = &freep[i];
486
487 #ifdef PSUTIL_FREEBSD
488 regular = (kif->kf_type == KF_TYPE_VNODE) && \
489 (kif->kf_vnode_type == KF_VTYPE_VREG);
490 fd = kif->kf_fd;
491 path = kif->kf_path;
492 #elif PSUTIL_OPENBSD
493 regular = (kif->f_type == DTYPE_VNODE) && (kif->v_type == VREG);
494 fd = kif->fd_fd;
495 // XXX - it appears path is not exposed in the kinfo_file struct.
496 path = "";
497 #elif PSUTIL_NETBSD
498 regular = (kif->ki_ftype == DTYPE_VNODE) && (kif->ki_vtype == VREG);
499 fd = kif->ki_fd;
500 // XXX - it appears path is not exposed in the kinfo_file struct.
501 path = "";
502 #endif
503 if (regular == 1) {
504 py_path = PyUnicode_DecodeFSDefault(path);
505 if (! py_path)
506 goto error;
507 py_tuple = Py_BuildValue("(Oi)", py_path, fd);
508 if (py_tuple == NULL)
509 goto error;
510 if (PyList_Append(py_retlist, py_tuple))
511 goto error;
512 Py_CLEAR(py_path);
513 Py_CLEAR(py_tuple);
514 }
515 }
516 free(freep);
517 return py_retlist;
518
519 error:
520 Py_XDECREF(py_tuple);
521 Py_DECREF(py_retlist);
522 if (freep != NULL)
523 free(freep);
524 return NULL;
525 }
526 #endif
527
528
529 /*
530 * Return a list of tuples including device, mount point and fs type
531 * for all partitions mounted on the system.
532 */
533 static PyObject *
psutil_disk_partitions(PyObject * self,PyObject * args)534 psutil_disk_partitions(PyObject *self, PyObject *args) {
535 int num;
536 int i;
537 long len;
538 uint64_t flags;
539 char opts[200];
540 #ifdef PSUTIL_NETBSD
541 struct statvfs *fs = NULL;
542 #else
543 struct statfs *fs = NULL;
544 #endif
545 PyObject *py_retlist = PyList_New(0);
546 PyObject *py_dev = NULL;
547 PyObject *py_mountp = NULL;
548 PyObject *py_tuple = NULL;
549
550 if (py_retlist == NULL)
551 return NULL;
552
553 // get the number of mount points
554 Py_BEGIN_ALLOW_THREADS
555 #ifdef PSUTIL_NETBSD
556 num = getvfsstat(NULL, 0, MNT_NOWAIT);
557 #else
558 num = getfsstat(NULL, 0, MNT_NOWAIT);
559 #endif
560 Py_END_ALLOW_THREADS
561 if (num == -1) {
562 PyErr_SetFromErrno(PyExc_OSError);
563 goto error;
564 }
565
566 len = sizeof(*fs) * num;
567 fs = malloc(len);
568 if (fs == NULL) {
569 PyErr_NoMemory();
570 goto error;
571 }
572
573 Py_BEGIN_ALLOW_THREADS
574 #ifdef PSUTIL_NETBSD
575 num = getvfsstat(fs, len, MNT_NOWAIT);
576 #else
577 num = getfsstat(fs, len, MNT_NOWAIT);
578 #endif
579 Py_END_ALLOW_THREADS
580 if (num == -1) {
581 PyErr_SetFromErrno(PyExc_OSError);
582 goto error;
583 }
584
585 for (i = 0; i < num; i++) {
586 py_tuple = NULL;
587 opts[0] = 0;
588 #ifdef PSUTIL_NETBSD
589 flags = fs[i].f_flag;
590 #else
591 flags = fs[i].f_flags;
592 #endif
593
594 // see sys/mount.h
595 if (flags & MNT_RDONLY)
596 strlcat(opts, "ro", sizeof(opts));
597 else
598 strlcat(opts, "rw", sizeof(opts));
599 if (flags & MNT_SYNCHRONOUS)
600 strlcat(opts, ",sync", sizeof(opts));
601 if (flags & MNT_NOEXEC)
602 strlcat(opts, ",noexec", sizeof(opts));
603 if (flags & MNT_NOSUID)
604 strlcat(opts, ",nosuid", sizeof(opts));
605 if (flags & MNT_ASYNC)
606 strlcat(opts, ",async", sizeof(opts));
607 if (flags & MNT_NOATIME)
608 strlcat(opts, ",noatime", sizeof(opts));
609 if (flags & MNT_SOFTDEP)
610 strlcat(opts, ",softdep", sizeof(opts));
611 #ifdef PSUTIL_FREEBSD
612 if (flags & MNT_UNION)
613 strlcat(opts, ",union", sizeof(opts));
614 if (flags & MNT_SUIDDIR)
615 strlcat(opts, ",suiddir", sizeof(opts));
616 if (flags & MNT_SOFTDEP)
617 strlcat(opts, ",softdep", sizeof(opts));
618 if (flags & MNT_NOSYMFOLLOW)
619 strlcat(opts, ",nosymfollow", sizeof(opts));
620 if (flags & MNT_GJOURNAL)
621 strlcat(opts, ",gjournal", sizeof(opts));
622 if (flags & MNT_MULTILABEL)
623 strlcat(opts, ",multilabel", sizeof(opts));
624 if (flags & MNT_ACLS)
625 strlcat(opts, ",acls", sizeof(opts));
626 if (flags & MNT_NOCLUSTERR)
627 strlcat(opts, ",noclusterr", sizeof(opts));
628 if (flags & MNT_NOCLUSTERW)
629 strlcat(opts, ",noclusterw", sizeof(opts));
630 if (flags & MNT_NFS4ACLS)
631 strlcat(opts, ",nfs4acls", sizeof(opts));
632 #elif PSUTIL_NETBSD
633 if (flags & MNT_NODEV)
634 strlcat(opts, ",nodev", sizeof(opts));
635 if (flags & MNT_UNION)
636 strlcat(opts, ",union", sizeof(opts));
637 if (flags & MNT_NOCOREDUMP)
638 strlcat(opts, ",nocoredump", sizeof(opts));
639 #ifdef MNT_RELATIME
640 if (flags & MNT_RELATIME)
641 strlcat(opts, ",relatime", sizeof(opts));
642 #endif
643 if (flags & MNT_IGNORE)
644 strlcat(opts, ",ignore", sizeof(opts));
645 #ifdef MNT_DISCARD
646 if (flags & MNT_DISCARD)
647 strlcat(opts, ",discard", sizeof(opts));
648 #endif
649 #ifdef MNT_EXTATTR
650 if (flags & MNT_EXTATTR)
651 strlcat(opts, ",extattr", sizeof(opts));
652 #endif
653 if (flags & MNT_LOG)
654 strlcat(opts, ",log", sizeof(opts));
655 if (flags & MNT_SYMPERM)
656 strlcat(opts, ",symperm", sizeof(opts));
657 if (flags & MNT_NODEVMTIME)
658 strlcat(opts, ",nodevmtime", sizeof(opts));
659 #endif
660 py_dev = PyUnicode_DecodeFSDefault(fs[i].f_mntfromname);
661 if (! py_dev)
662 goto error;
663 py_mountp = PyUnicode_DecodeFSDefault(fs[i].f_mntonname);
664 if (! py_mountp)
665 goto error;
666 py_tuple = Py_BuildValue("(OOss)",
667 py_dev, // device
668 py_mountp, // mount point
669 fs[i].f_fstypename, // fs type
670 opts); // options
671 if (!py_tuple)
672 goto error;
673 if (PyList_Append(py_retlist, py_tuple))
674 goto error;
675 Py_CLEAR(py_dev);
676 Py_CLEAR(py_mountp);
677 Py_CLEAR(py_tuple);
678 }
679
680 free(fs);
681 return py_retlist;
682
683 error:
684 Py_XDECREF(py_dev);
685 Py_XDECREF(py_mountp);
686 Py_XDECREF(py_tuple);
687 Py_DECREF(py_retlist);
688 if (fs != NULL)
689 free(fs);
690 return NULL;
691 }
692
693
694 /*
695 * Return a Python list of named tuples with overall network I/O information
696 */
697 static PyObject *
psutil_net_io_counters(PyObject * self,PyObject * args)698 psutil_net_io_counters(PyObject *self, PyObject *args) {
699 char *buf = NULL, *lim, *next;
700 struct if_msghdr *ifm;
701 int mib[6];
702 size_t len;
703 PyObject *py_retdict = PyDict_New();
704 PyObject *py_ifc_info = NULL;
705 if (py_retdict == NULL)
706 return NULL;
707
708 mib[0] = CTL_NET; // networking subsystem
709 mib[1] = PF_ROUTE; // type of information
710 mib[2] = 0; // protocol (IPPROTO_xxx)
711 mib[3] = 0; // address family
712 mib[4] = NET_RT_IFLIST; // operation
713 mib[5] = 0;
714
715 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
716 PyErr_SetFromErrno(PyExc_OSError);
717 goto error;
718 }
719
720 buf = malloc(len);
721 if (buf == NULL) {
722 PyErr_NoMemory();
723 goto error;
724 }
725
726 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
727 PyErr_SetFromErrno(PyExc_OSError);
728 goto error;
729 }
730
731 lim = buf + len;
732
733 for (next = buf; next < lim; ) {
734 py_ifc_info = NULL;
735 ifm = (struct if_msghdr *)next;
736 next += ifm->ifm_msglen;
737
738 if (ifm->ifm_type == RTM_IFINFO) {
739 struct if_msghdr *if2m = (struct if_msghdr *)ifm;
740 struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1);
741 char ifc_name[32];
742
743 strncpy(ifc_name, sdl->sdl_data, sdl->sdl_nlen);
744 ifc_name[sdl->sdl_nlen] = 0;
745 // XXX: ignore usbus interfaces:
746 // http://lists.freebsd.org/pipermail/freebsd-current/
747 // 2011-October/028752.html
748 // 'ifconfig -a' doesn't show them, nor do we.
749 if (strncmp(ifc_name, "usbus", 5) == 0)
750 continue;
751
752 py_ifc_info = Py_BuildValue("(kkkkkkki)",
753 if2m->ifm_data.ifi_obytes,
754 if2m->ifm_data.ifi_ibytes,
755 if2m->ifm_data.ifi_opackets,
756 if2m->ifm_data.ifi_ipackets,
757 if2m->ifm_data.ifi_ierrors,
758 if2m->ifm_data.ifi_oerrors,
759 if2m->ifm_data.ifi_iqdrops,
760 #ifdef _IFI_OQDROPS
761 if2m->ifm_data.ifi_oqdrops
762 #else
763 0
764 #endif
765 );
766 if (!py_ifc_info)
767 goto error;
768 if (PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info))
769 goto error;
770 Py_CLEAR(py_ifc_info);
771 }
772 else {
773 continue;
774 }
775 }
776
777 free(buf);
778 return py_retdict;
779
780 error:
781 Py_XDECREF(py_ifc_info);
782 Py_DECREF(py_retdict);
783 if (buf != NULL)
784 free(buf);
785 return NULL;
786 }
787
788
789 /*
790 * Return currently connected users as a list of tuples.
791 */
792 static PyObject *
psutil_users(PyObject * self,PyObject * args)793 psutil_users(PyObject *self, PyObject *args) {
794 PyObject *py_retlist = PyList_New(0);
795 PyObject *py_username = NULL;
796 PyObject *py_tty = NULL;
797 PyObject *py_hostname = NULL;
798 PyObject *py_tuple = NULL;
799 PyObject *py_pid = NULL;
800
801 if (py_retlist == NULL)
802 return NULL;
803
804 #if (defined(__FreeBSD_version) && (__FreeBSD_version < 900000)) || PSUTIL_OPENBSD
805 struct utmp ut;
806 FILE *fp;
807
808 Py_BEGIN_ALLOW_THREADS
809 fp = fopen(_PATH_UTMP, "r");
810 Py_END_ALLOW_THREADS
811 if (fp == NULL) {
812 PyErr_SetFromErrnoWithFilename(PyExc_OSError, _PATH_UTMP);
813 goto error;
814 }
815
816 while (fread(&ut, sizeof(ut), 1, fp) == 1) {
817 if (*ut.ut_name == '\0')
818 continue;
819 py_username = PyUnicode_DecodeFSDefault(ut.ut_name);
820 if (! py_username)
821 goto error;
822 py_tty = PyUnicode_DecodeFSDefault(ut.ut_line);
823 if (! py_tty)
824 goto error;
825 py_hostname = PyUnicode_DecodeFSDefault(ut.ut_host);
826 if (! py_hostname)
827 goto error;
828 py_tuple = Py_BuildValue(
829 "(OOOfi)",
830 py_username, // username
831 py_tty, // tty
832 py_hostname, // hostname
833 (float)ut.ut_time, // start time
834 #ifdef PSUTIL_OPENBSD
835 -1 // process id (set to None later)
836 #else
837 ut.ut_pid // TODO: use PyLong_FromPid
838 #endif
839 );
840 if (!py_tuple) {
841 fclose(fp);
842 goto error;
843 }
844 if (PyList_Append(py_retlist, py_tuple)) {
845 fclose(fp);
846 goto error;
847 }
848 Py_CLEAR(py_username);
849 Py_CLEAR(py_tty);
850 Py_CLEAR(py_hostname);
851 Py_CLEAR(py_tuple);
852 }
853
854 fclose(fp);
855 #else
856 struct utmpx *utx;
857 setutxent();
858 while ((utx = getutxent()) != NULL) {
859 if (utx->ut_type != USER_PROCESS)
860 continue;
861 py_username = PyUnicode_DecodeFSDefault(utx->ut_user);
862 if (! py_username)
863 goto error;
864 py_tty = PyUnicode_DecodeFSDefault(utx->ut_line);
865 if (! py_tty)
866 goto error;
867 py_hostname = PyUnicode_DecodeFSDefault(utx->ut_host);
868 if (! py_hostname)
869 goto error;
870 #ifdef PSUTIL_OPENBSD
871 py_pid = Py_BuildValue("i", -1); // set to None later
872 #else
873 py_pid = PyLong_FromPid(utx->ut_pid);
874 #endif
875 if (! py_pid)
876 goto error;
877
878 py_tuple = Py_BuildValue(
879 "(OOOfO)",
880 py_username, // username
881 py_tty, // tty
882 py_hostname, // hostname
883 (float)utx->ut_tv.tv_sec, // start time
884 py_pid // process id
885 );
886
887 if (!py_tuple) {
888 endutxent();
889 goto error;
890 }
891 if (PyList_Append(py_retlist, py_tuple)) {
892 endutxent();
893 goto error;
894 }
895 Py_CLEAR(py_username);
896 Py_CLEAR(py_tty);
897 Py_CLEAR(py_hostname);
898 Py_CLEAR(py_tuple);
899 Py_CLEAR(py_pid);
900 }
901
902 endutxent();
903 #endif
904 return py_retlist;
905
906 error:
907 Py_XDECREF(py_username);
908 Py_XDECREF(py_tty);
909 Py_XDECREF(py_hostname);
910 Py_XDECREF(py_tuple);
911 Py_XDECREF(py_pid);
912 Py_DECREF(py_retlist);
913 return NULL;
914 }
915
916
917 /*
918 * define the psutil C module methods and initialize the module.
919 */
920 static PyMethodDef mod_methods[] = {
921 // --- per-process functions
922
923 {"proc_oneshot_info", psutil_proc_oneshot_info, METH_VARARGS,
924 "Return multiple info about a process"},
925 {"proc_name", psutil_proc_name, METH_VARARGS,
926 "Return process name"},
927 {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS,
928 "Return process cmdline as a list of cmdline arguments"},
929 {"proc_threads", psutil_proc_threads, METH_VARARGS,
930 "Return process threads"},
931 #if defined(PSUTIL_FREEBSD) || defined(PSUTIL_OPENBSD)
932 {"proc_connections", psutil_proc_connections, METH_VARARGS,
933 "Return connections opened by process"},
934 #endif
935 {"proc_cwd", psutil_proc_cwd, METH_VARARGS,
936 "Return process current working directory."},
937 #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD)
938 {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS,
939 "Return the number of file descriptors opened by this process"},
940 {"proc_open_files", psutil_proc_open_files, METH_VARARGS,
941 "Return files opened by process as a list of (path, fd) tuples"},
942 #endif
943 #if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD)
944 {"proc_num_threads", psutil_proc_num_threads, METH_VARARGS,
945 "Return number of threads used by process"},
946 #endif
947 #if defined(PSUTIL_FREEBSD)
948 {"proc_exe", psutil_proc_exe, METH_VARARGS,
949 "Return process pathname executable"},
950 {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS,
951 "Return a list of tuples for every process's memory map"},
952 {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS,
953 "Return process CPU affinity."},
954 {"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS,
955 "Set process CPU affinity."},
956 {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS,
957 "Return an XML string to determine the number physical CPUs."},
958 #endif
959
960 // --- system-related functions
961
962 {"pids", psutil_pids, METH_VARARGS,
963 "Returns a list of PIDs currently running on the system"},
964 {"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS,
965 "Return number of logical CPUs on the system"},
966 {"virtual_mem", psutil_virtual_mem, METH_VARARGS,
967 "Return system virtual memory usage statistics"},
968 {"swap_mem", psutil_swap_mem, METH_VARARGS,
969 "Return swap mem stats"},
970 {"cpu_times", psutil_cpu_times, METH_VARARGS,
971 "Return system cpu times as a tuple (user, system, nice, idle, irc)"},
972 {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS,
973 "Return system per-cpu times as a list of tuples"},
974 {"boot_time", psutil_boot_time, METH_VARARGS,
975 "Return the system boot time expressed in seconds since the epoch."},
976 {"disk_partitions", psutil_disk_partitions, METH_VARARGS,
977 "Return a list of tuples including device, mount point and "
978 "fs type for all partitions mounted on the system."},
979 {"net_io_counters", psutil_net_io_counters, METH_VARARGS,
980 "Return dict of tuples of networks I/O information."},
981 {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS,
982 "Return a Python dict of tuples for disk I/O information"},
983 {"users", psutil_users, METH_VARARGS,
984 "Return currently connected users as a list of tuples"},
985 {"cpu_stats", psutil_cpu_stats, METH_VARARGS,
986 "Return CPU statistics"},
987 #if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD)
988 {"net_connections", psutil_net_connections, METH_VARARGS,
989 "Return system-wide open connections."},
990 #endif
991 #if defined(PSUTIL_FREEBSD)
992 {"sensors_battery", psutil_sensors_battery, METH_VARARGS,
993 "Return battery information."},
994 {"sensors_cpu_temperature", psutil_sensors_cpu_temperature, METH_VARARGS,
995 "Return temperature information for a given CPU core number."},
996 {"cpu_frequency", psutil_cpu_freq, METH_VARARGS,
997 "Return frequency of a given CPU"},
998 #endif
999
1000 // --- others
1001 {"set_testing", psutil_set_testing, METH_NOARGS,
1002 "Set psutil in testing mode"},
1003
1004 {NULL, NULL, 0, NULL}
1005 };
1006
1007 #if PY_MAJOR_VERSION >= 3
1008 #define INITERR return NULL
1009
1010 static struct PyModuleDef moduledef = {
1011 PyModuleDef_HEAD_INIT,
1012 "_psutil_bsd",
1013 NULL,
1014 -1,
1015 mod_methods,
1016 NULL,
1017 NULL,
1018 NULL,
1019 NULL
1020 };
1021
PyInit__psutil_bsd(void)1022 PyObject *PyInit__psutil_bsd(void)
1023 #else /* PY_MAJOR_VERSION */
1024 #define INITERR return
1025
1026 void init_psutil_bsd(void)
1027 #endif /* PY_MAJOR_VERSION */
1028 {
1029 PyObject *v;
1030 #if PY_MAJOR_VERSION >= 3
1031 PyObject *mod = PyModule_Create(&moduledef);
1032 #else
1033 PyObject *mod = Py_InitModule("_psutil_bsd", mod_methods);
1034 #endif
1035 if (mod == NULL)
1036 INITERR;
1037
1038 if (PyModule_AddIntConstant(mod, "version", PSUTIL_VERSION)) INITERR;
1039 // process status constants
1040
1041 #ifdef PSUTIL_FREEBSD
1042 if (PyModule_AddIntConstant(mod, "SIDL", SIDL)) INITERR;
1043 if (PyModule_AddIntConstant(mod, "SRUN", SRUN)) INITERR;
1044 if (PyModule_AddIntConstant(mod, "SSLEEP", SSLEEP)) INITERR;
1045 if (PyModule_AddIntConstant(mod, "SSTOP", SSTOP)) INITERR;
1046 if (PyModule_AddIntConstant(mod, "SZOMB", SZOMB)) INITERR;
1047 if (PyModule_AddIntConstant(mod, "SWAIT", SWAIT)) INITERR;
1048 if (PyModule_AddIntConstant(mod, "SLOCK", SLOCK)) INITERR;
1049 #elif PSUTIL_OPENBSD
1050 if (PyModule_AddIntConstant(mod, "SIDL", SIDL)) INITERR;
1051 if (PyModule_AddIntConstant(mod, "SRUN", SRUN)) INITERR;
1052 if (PyModule_AddIntConstant(mod, "SSLEEP", SSLEEP)) INITERR;
1053 if (PyModule_AddIntConstant(mod, "SSTOP", SSTOP)) INITERR;
1054 if (PyModule_AddIntConstant(mod, "SZOMB", SZOMB)) INITERR; // unused
1055 if (PyModule_AddIntConstant(mod, "SDEAD", SDEAD)) INITERR;
1056 if (PyModule_AddIntConstant(mod, "SONPROC", SONPROC)) INITERR;
1057 #elif defined(PSUTIL_NETBSD)
1058 if (PyModule_AddIntConstant(mod, "SIDL", LSIDL)) INITERR;
1059 if (PyModule_AddIntConstant(mod, "SRUN", LSRUN)) INITERR;
1060 if (PyModule_AddIntConstant(mod, "SSLEEP", LSSLEEP)) INITERR;
1061 if (PyModule_AddIntConstant(mod, "SSTOP", LSSTOP)) INITERR;
1062 if (PyModule_AddIntConstant(mod, "SZOMB", LSZOMB)) INITERR;
1063 if (PyModule_AddIntConstant(mod, "SDEAD", LSDEAD)) INITERR;
1064 if (PyModule_AddIntConstant(mod, "SONPROC", LSONPROC)) INITERR;
1065 // unique to NetBSD
1066 if (PyModule_AddIntConstant(mod, "SSUSPENDED", LSSUSPENDED)) INITERR;
1067 #endif
1068
1069 // connection status constants
1070 if (PyModule_AddIntConstant(mod, "TCPS_CLOSED", TCPS_CLOSED))
1071 INITERR;
1072 if (PyModule_AddIntConstant(mod, "TCPS_CLOSING", TCPS_CLOSING))
1073 INITERR;
1074 if (PyModule_AddIntConstant(mod, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT))
1075 INITERR;
1076 if (PyModule_AddIntConstant(mod, "TCPS_LISTEN", TCPS_LISTEN))
1077 INITERR;
1078 if (PyModule_AddIntConstant(mod, "TCPS_ESTABLISHED", TCPS_ESTABLISHED))
1079 INITERR;
1080 if (PyModule_AddIntConstant(mod, "TCPS_SYN_SENT", TCPS_SYN_SENT))
1081 INITERR;
1082 if (PyModule_AddIntConstant(mod, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED))
1083 INITERR;
1084 if (PyModule_AddIntConstant(mod, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1))
1085 INITERR;
1086 if (PyModule_AddIntConstant(mod, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2))
1087 INITERR;
1088 if (PyModule_AddIntConstant(mod, "TCPS_LAST_ACK", TCPS_LAST_ACK))
1089 INITERR;
1090 if (PyModule_AddIntConstant(mod, "TCPS_TIME_WAIT", TCPS_TIME_WAIT))
1091 INITERR;
1092 // PSUTIL_CONN_NONE
1093 if (PyModule_AddIntConstant(mod, "PSUTIL_CONN_NONE", 128)) INITERR;
1094
1095 psutil_setup();
1096
1097 if (mod == NULL)
1098 INITERR;
1099 #if PY_MAJOR_VERSION >= 3
1100 return mod;
1101 #endif
1102 }
1103