|
14 | 14 | #include <stdlib.h>
|
15 | 15 | #include <mntent.h>
|
16 | 16 | #include <features.h>
|
| 17 | +#ifdef SYSTEMD_LINUX |
| 18 | + #include <dlfcn.h> |
| 19 | +#endif |
17 | 20 | #include <utmp.h>
|
18 | 21 | #include <sched.h>
|
19 | 22 | #include <linux/version.h>
|
@@ -357,12 +360,152 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) {
|
357 | 360 | }
|
358 | 361 | #endif /* PSUTIL_HAVE_CPU_AFFINITY */
|
359 | 362 |
|
| 363 | +#ifdef SYSTEMD_LINUX |
| 364 | + |
| 365 | +/* Systemd function signatures that will be loaded */ |
| 366 | +int (*sd_booted)(void); |
| 367 | +int (*sd_get_sessions)(char ***); |
| 368 | +int (*sd_session_get_leader)(const char *, pid_t *); |
| 369 | +int (*sd_session_get_remote_host)(const char *,char **); |
| 370 | +int (*sd_session_get_start_time)(const char *, uint64_t *); |
| 371 | +int (*sd_session_get_tty)(const char *, char **); |
| 372 | +int (*sd_session_get_username)(const char *, char **); |
| 373 | + |
| 374 | +#define dlsym_check(__h, __fn) do { \ |
| 375 | + __fn = dlsym(__h, #__fn); \ |
| 376 | + if (dlerror() != NULL || __fn == NULL) { \ |
| 377 | + dlclose(__h); \ |
| 378 | + return NULL; \ |
| 379 | + } \ |
| 380 | +} while (0) |
| 381 | + |
| 382 | +void * |
| 383 | +load_systemd() { |
| 384 | + void *handle = dlopen("libsystemd.so.0", RTLD_LAZY); |
| 385 | + if (dlerror() != NULL || handle == NULL) |
| 386 | + return NULL; |
| 387 | + |
| 388 | + dlsym_check(handle, sd_booted); |
| 389 | + dlsym_check(handle, sd_get_sessions); |
| 390 | + dlsym_check(handle, sd_session_get_leader); |
| 391 | + dlsym_check(handle, sd_session_get_remote_host); |
| 392 | + dlsym_check(handle, sd_session_get_start_time); |
| 393 | + dlsym_check(handle, sd_session_get_tty); |
| 394 | + dlsym_check(handle, sd_session_get_username); |
| 395 | + |
| 396 | + return handle; |
| 397 | +} |
| 398 | + |
| 399 | +/* |
| 400 | + * Return currently connected users as a list of tuples. |
| 401 | + */ |
| 402 | +static PyObject * |
| 403 | +psutil_users_systemd(PyObject *self, PyObject *args) { |
| 404 | + char **sessions_list = NULL; |
| 405 | + PyObject *py_retlist = PyList_New(0); |
| 406 | + PyObject *py_tuple = NULL; |
| 407 | + PyObject *py_username = NULL; |
| 408 | + PyObject *py_tty = NULL; |
| 409 | + PyObject *py_hostname = NULL; |
| 410 | + PyObject *py_user_proc = NULL; |
| 411 | + double tstamp = 0.0; |
| 412 | + pid_t pid = 0; |
| 413 | + |
| 414 | + if (py_retlist == NULL) |
| 415 | + return NULL; |
| 416 | + int sessions = sd_get_sessions(&sessions_list); |
| 417 | + for (int i = 0; i < sessions; i++) { |
| 418 | + const char *session_id = sessions_list[i]; |
| 419 | + py_tuple = NULL; |
| 420 | + py_user_proc = NULL; |
| 421 | + py_user_proc = Py_True; |
| 422 | + |
| 423 | + char *username = NULL; |
| 424 | + if (sd_session_get_username(session_id, &username) < 0) |
| 425 | + goto error; |
| 426 | + py_username = PyUnicode_DecodeFSDefault(username); |
| 427 | + free(username); |
| 428 | + if (! py_username) |
| 429 | + goto error; |
| 430 | + |
| 431 | + char *tty = NULL; |
| 432 | + if (sd_session_get_tty(session_id, &tty) < 0) { |
| 433 | + py_tty = PyUnicode_DecodeFSDefault("n/a"); |
| 434 | + } else { |
| 435 | + py_tty = PyUnicode_DecodeFSDefault(tty); |
| 436 | + free(tty); |
| 437 | + } |
| 438 | + if (! py_tty) |
| 439 | + goto error; |
| 440 | + |
| 441 | + char *hostname = NULL; |
| 442 | + if (sd_session_get_remote_host(session_id, &hostname) < 0) |
| 443 | + goto error; |
| 444 | + py_hostname = PyUnicode_DecodeFSDefault(hostname); |
| 445 | + free(hostname); |
| 446 | + if (! py_hostname) |
| 447 | + goto error; |
| 448 | + |
| 449 | + uint64_t usec = 0; |
| 450 | + if (sd_session_get_start_time(session_id, &usec) < 0) |
| 451 | + goto error; |
| 452 | + tstamp = (double)usec / 1000000.0; |
| 453 | + |
| 454 | + if (sd_session_get_leader(session_id, &pid) < 0) |
| 455 | + goto error; |
| 456 | + |
| 457 | + py_tuple = Py_BuildValue( |
| 458 | + "OOOdO" _Py_PARSE_PID, |
| 459 | + py_username, // username |
| 460 | + py_tty, // tty |
| 461 | + py_hostname, // hostname |
| 462 | + tstamp, // tstamp |
| 463 | + py_user_proc, // (bool) user process |
| 464 | + pid // process id |
| 465 | + ); |
| 466 | + if (! py_tuple) |
| 467 | + goto error; |
| 468 | + if (PyList_Append(py_retlist, py_tuple)) |
| 469 | + goto error; |
| 470 | + Py_CLEAR(py_username); |
| 471 | + Py_CLEAR(py_tty); |
| 472 | + Py_CLEAR(py_hostname); |
| 473 | + Py_CLEAR(py_tuple); |
| 474 | + free (sessions_list[i]); |
| 475 | + } |
| 476 | + free(sessions_list); |
| 477 | + return py_retlist; |
| 478 | + |
| 479 | +error: |
| 480 | + Py_XDECREF(py_username); |
| 481 | + Py_XDECREF(py_tty); |
| 482 | + Py_XDECREF(py_hostname); |
| 483 | + Py_XDECREF(py_tuple); |
| 484 | + Py_DECREF(py_retlist); |
| 485 | + free(sessions_list); |
| 486 | + return NULL; |
| 487 | +} |
| 488 | + |
| 489 | +static PyObject *psutil_users_utmp(PyObject *, PyObject *); |
| 490 | + |
| 491 | +static PyObject * |
| 492 | +psutil_users(PyObject *self, PyObject *args) { |
| 493 | + void *handle = load_systemd(); |
| 494 | + if (handle && sd_booted()) |
| 495 | + return psutil_users_systemd(self, args); |
| 496 | + else |
| 497 | + return psutil_users_utmp(self, args); |
| 498 | +} |
360 | 499 |
|
361 | 500 | /*
|
362 | 501 | * Return currently connected users as a list of tuples.
|
363 | 502 | */
|
364 | 503 | static PyObject *
|
| 504 | +psutil_users_utmp(PyObject *self, PyObject *args) { |
| 505 | +#else |
| 506 | +static PyObject * |
365 | 507 | psutil_users(PyObject *self, PyObject *args) {
|
| 508 | +#endif |
366 | 509 | struct utmp *ut;
|
367 | 510 | PyObject *py_retlist = PyList_New(0);
|
368 | 511 | PyObject *py_tuple = NULL;
|
|
0 commit comments