1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <sys/inotify.h>
29 #include "cgroup-util.h"
35 _public_ int sd_pid_get_session(pid_t pid, char **session) {
42 return cg_pid_get_session(pid, session);
45 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
52 return cg_pid_get_unit(pid, unit);
55 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
62 return cg_pid_get_user_unit(pid, unit);
65 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
72 return cg_pid_get_machine_name(pid, name);
75 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
77 char *root, *cgroup, *p, *cc;
86 r = cg_pid_get_path_shifted(pid, &root, &cgroup);
90 if (!startswith(cgroup, "/user/")) {
96 p = strchr(cgroup + 6, '/');
103 p += strcspn(p, "/");
106 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, cgroup, &cc);
119 if (!S_ISDIR(st.st_mode))
126 _public_ int sd_uid_get_state(uid_t uid, char**state) {
133 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
136 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
141 s = strdup("offline");
157 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
158 char *p, *w, *t, *state, *s = NULL;
161 const char *variable;
166 variable = require_active ? "ACTIVE_UID" : "UIDS";
168 p = strappend("/run/systemd/seats/", seat);
172 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
183 if (asprintf(&t, "%lu", (unsigned long) uid) < 0) {
188 FOREACH_WORD(w, l, s, state) {
189 if (strneq(t, w, l)) {
203 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
208 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
211 r = parse_env_file(p, NEWLINE,
234 a = strv_split(s, " ");
251 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
252 return uid_get_array(
254 require_active == 0 ? "ONLINE_SESSIONS" :
255 require_active > 0 ? "ACTIVE_SESSIONS" :
260 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
261 return uid_get_array(
263 require_active == 0 ? "ONLINE_SEATS" :
264 require_active > 0 ? "ACTIVE_SEATS" :
269 static int file_of_session(const char *session, char **_p) {
276 p = strappend("/run/systemd/sessions/", session);
280 r = sd_pid_get_session(0, &buf);
284 p = strappend("/run/systemd/sessions/", buf);
295 _public_ int sd_session_is_active(const char *session) {
299 r = file_of_session(session, &p);
303 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
314 r = parse_boolean(s);
320 _public_ int sd_session_get_state(const char *session, char **state) {
327 r = file_of_session(session, &p);
331 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
344 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
351 r = file_of_session(session, &p);
355 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
366 r = parse_uid(s, uid);
372 static int session_get_string(const char *session, const char *field, char **value) {
379 r = file_of_session(session, &p);
383 r = parse_env_file(p, NEWLINE, field, &s, NULL);
398 _public_ int sd_session_get_seat(const char *session, char **seat) {
399 return session_get_string(session, "SEAT", seat);
402 _public_ int sd_session_get_tty(const char *session, char **tty) {
403 return session_get_string(session, "TTY", tty);
406 _public_ int sd_session_get_service(const char *session, char **service) {
407 return session_get_string(session, "SERVICE", service);
410 _public_ int sd_session_get_type(const char *session, char **type) {
411 return session_get_string(session, "TYPE", type);
414 _public_ int sd_session_get_class(const char *session, char **class) {
415 return session_get_string(session, "CLASS", class);
418 _public_ int sd_session_get_display(const char *session, char **display) {
419 return session_get_string(session, "DISPLAY", display);
422 static int file_of_seat(const char *seat, char **_p) {
429 p = strappend("/run/systemd/seats/", seat);
433 r = sd_session_get_seat(NULL, &buf);
437 p = strappend("/run/systemd/seats/", buf);
448 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
449 char *p, *s = NULL, *t = NULL;
452 if (!session && !uid)
455 r = file_of_seat(seat, &p);
459 r = parse_env_file(p, NEWLINE,
482 r = parse_uid(t, uid);
500 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
501 char *p, *s = NULL, *t = NULL, **a = NULL;
506 r = file_of_seat(seat, &p);
510 r = parse_env_file(p, NEWLINE,
512 "ACTIVE_SESSIONS", &t,
523 a = strv_split(s, " ");
537 FOREACH_WORD(w, l, t, state)
551 FOREACH_WORD(w, l, t, state) {
562 r = parse_uid(k, b + i);
590 static int seat_get_can(const char *seat, const char *variable) {
594 r = file_of_seat(seat, &p);
598 r = parse_env_file(p, NEWLINE,
609 r = parse_boolean(s);
617 _public_ int sd_seat_can_multi_session(const char *seat) {
618 return seat_get_can(seat, "CAN_MULTI_SESSION");
621 _public_ int sd_seat_can_tty(const char *seat) {
622 return seat_get_can(seat, "CAN_TTY");
625 _public_ int sd_seat_can_graphical(const char *seat) {
626 return seat_get_can(seat, "CAN_GRAPHICAL");
629 _public_ int sd_get_seats(char ***seats) {
630 return get_files_in_directory("/run/systemd/seats/", seats);
633 _public_ int sd_get_sessions(char ***sessions) {
634 return get_files_in_directory("/run/systemd/sessions/", sessions);
637 _public_ int sd_get_uids(uid_t **users) {
643 d = opendir("/run/systemd/users/");
649 union dirent_storage buf;
653 k = readdir_r(d, &buf.de, &de);
662 dirent_ensure_type(d, de);
664 if (!dirent_is_file(de))
667 k = parse_uid(de->d_name, &uid);
672 if ((unsigned) r >= n) {
676 t = realloc(l, sizeof(uid_t) * n);
685 assert((unsigned) r < n);
704 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
705 return (int) (unsigned long) m - 1;
708 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
709 return (sd_login_monitor*) (unsigned long) (fd + 1);
712 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
719 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
723 if (!category || streq(category, "seat")) {
724 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
726 close_nointr_nofail(fd);
733 if (!category || streq(category, "session")) {
734 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
736 close_nointr_nofail(fd);
743 if (!category || streq(category, "uid")) {
744 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
746 close_nointr_nofail(fd);
758 *m = FD_TO_MONITOR(fd);
762 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
768 fd = MONITOR_TO_FD(m);
774 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
779 return flush_fd(MONITOR_TO_FD(m));
782 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
787 return MONITOR_TO_FD(m);
790 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
795 /* For now we will only return POLLIN here, since we don't
796 * need anything else ever for inotify. However, let's have
797 * this API to keep our options open should we later on need
802 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
809 /* For now we will only return (uint64_t) -1, since we don't
810 * need any timeout. However, let's have this API to keep our
811 * options open should we later on need it. */
812 *timeout_usec = (uint64_t) -1;