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) {
45 r = cg_pid_get_cgroup(pid, NULL, &cgroup);
49 if (!startswith(cgroup, "/user/")) {
54 p = strchr(cgroup + 6, '/');
61 if (startswith(p, "shared/") || streq(p, "shared")) {
66 p = strndup(p, strcspn(p, "/"));
76 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
84 return cg_pid_get_unit(pid, unit);
87 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
89 char *root, *cgroup, *p, *cc;
98 r = cg_pid_get_cgroup(pid, &root, &cgroup);
102 if (!startswith(cgroup, "/user/")) {
108 p = strchr(cgroup + 6, '/');
115 p += strcspn(p, "/");
118 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, cgroup, &cc);
131 if (!S_ISDIR(st.st_mode))
138 _public_ int sd_uid_get_state(uid_t uid, char**state) {
145 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
148 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
153 s = strdup("offline");
169 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
170 char *p, *w, *t, *state, *s = NULL;
173 const char *variable;
178 variable = require_active ? "ACTIVE_UID" : "UIDS";
180 p = strappend("/run/systemd/seats/", seat);
184 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
195 if (asprintf(&t, "%lu", (unsigned long) uid) < 0) {
200 FOREACH_WORD(w, l, s, state) {
201 if (strneq(t, w, l)) {
215 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
220 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
223 r = parse_env_file(p, NEWLINE,
246 a = strv_split(s, " ");
263 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
264 return uid_get_array(
266 require_active == 0 ? "ONLINE_SESSIONS" :
267 require_active > 0 ? "ACTIVE_SESSIONS" :
272 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
273 return uid_get_array(
275 require_active == 0 ? "ONLINE_SEATS" :
276 require_active > 0 ? "ACTIVE_SEATS" :
281 static int file_of_session(const char *session, char **_p) {
288 p = strappend("/run/systemd/sessions/", session);
292 r = sd_pid_get_session(0, &buf);
296 p = strappend("/run/systemd/sessions/", buf);
307 _public_ int sd_session_is_active(const char *session) {
311 r = file_of_session(session, &p);
315 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
326 r = parse_boolean(s);
332 _public_ int sd_session_get_state(const char *session, char **state) {
339 r = file_of_session(session, &p);
343 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
356 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
363 r = file_of_session(session, &p);
367 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
378 r = parse_uid(s, uid);
384 static int session_get_string(const char *session, const char *field, char **value) {
391 r = file_of_session(session, &p);
395 r = parse_env_file(p, NEWLINE, field, &s, NULL);
410 _public_ int sd_session_get_seat(const char *session, char **seat) {
411 return session_get_string(session, "SEAT", seat);
414 _public_ int sd_session_get_tty(const char *session, char **tty) {
415 return session_get_string(session, "TTY", tty);
418 _public_ int sd_session_get_service(const char *session, char **service) {
419 return session_get_string(session, "SERVICE", service);
422 _public_ int sd_session_get_type(const char *session, char **type) {
423 return session_get_string(session, "TYPE", type);
426 _public_ int sd_session_get_class(const char *session, char **class) {
427 return session_get_string(session, "CLASS", class);
430 _public_ int sd_session_get_display(const char *session, char **display) {
431 return session_get_string(session, "DISPLAY", display);
434 static int file_of_seat(const char *seat, char **_p) {
441 p = strappend("/run/systemd/seats/", seat);
445 r = sd_session_get_seat(NULL, &buf);
449 p = strappend("/run/systemd/seats/", buf);
460 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
461 char *p, *s = NULL, *t = NULL;
464 if (!session && !uid)
467 r = file_of_seat(seat, &p);
471 r = parse_env_file(p, NEWLINE,
494 r = parse_uid(t, uid);
512 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
513 char *p, *s = NULL, *t = NULL, **a = NULL;
518 r = file_of_seat(seat, &p);
522 r = parse_env_file(p, NEWLINE,
524 "ACTIVE_SESSIONS", &t,
535 a = strv_split(s, " ");
549 FOREACH_WORD(w, l, t, state)
563 FOREACH_WORD(w, l, t, state) {
574 r = parse_uid(k, b + i);
602 static int seat_get_can(const char *seat, const char *variable) {
606 r = file_of_seat(seat, &p);
610 r = parse_env_file(p, NEWLINE,
621 r = parse_boolean(s);
629 _public_ int sd_seat_can_multi_session(const char *seat) {
630 return seat_get_can(seat, "CAN_MULTI_SESSION");
633 _public_ int sd_seat_can_tty(const char *seat) {
634 return seat_get_can(seat, "CAN_TTY");
637 _public_ int sd_seat_can_graphical(const char *seat) {
638 return seat_get_can(seat, "CAN_GRAPHICAL");
641 _public_ int sd_get_seats(char ***seats) {
642 return get_files_in_directory("/run/systemd/seats/", seats);
645 _public_ int sd_get_sessions(char ***sessions) {
646 return get_files_in_directory("/run/systemd/sessions/", sessions);
649 _public_ int sd_get_uids(uid_t **users) {
655 d = opendir("/run/systemd/users/");
661 union dirent_storage buf;
665 k = readdir_r(d, &buf.de, &de);
674 dirent_ensure_type(d, de);
676 if (!dirent_is_file(de))
679 k = parse_uid(de->d_name, &uid);
684 if ((unsigned) r >= n) {
688 t = realloc(l, sizeof(uid_t) * n);
697 assert((unsigned) r < n);
716 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
717 return (int) (unsigned long) m - 1;
720 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
721 return (sd_login_monitor*) (unsigned long) (fd + 1);
724 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
731 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
735 if (!category || streq(category, "seat")) {
736 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
738 close_nointr_nofail(fd);
745 if (!category || streq(category, "session")) {
746 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
748 close_nointr_nofail(fd);
755 if (!category || streq(category, "uid")) {
756 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
758 close_nointr_nofail(fd);
770 *m = FD_TO_MONITOR(fd);
774 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
780 fd = MONITOR_TO_FD(m);
786 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
791 return flush_fd(MONITOR_TO_FD(m));
794 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
799 return MONITOR_TO_FD(m);
802 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
807 /* For now we will only return POLLIN here, since we don't
808 * need anything else ever for inotify. However, let's have
809 * this API to keep our options open should we later on need
814 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
821 /* For now we will only return (uint64_t) -1, since we don't
822 * need any timeout. However, let's have this API to keep our
823 * options open should we later on need it. */
824 *timeout_usec = (uint64_t) -1;