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_user_unit(pid_t pid, char **unit) {
95 return cg_pid_get_user_unit(pid, unit);
98 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
100 char *root, *cgroup, *p, *cc;
109 r = cg_pid_get_cgroup(pid, &root, &cgroup);
113 if (!startswith(cgroup, "/user/")) {
119 p = strchr(cgroup + 6, '/');
126 p += strcspn(p, "/");
129 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, cgroup, &cc);
142 if (!S_ISDIR(st.st_mode))
149 _public_ int sd_uid_get_state(uid_t uid, char**state) {
156 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
159 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
164 s = strdup("offline");
180 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
181 char *p, *w, *t, *state, *s = NULL;
184 const char *variable;
189 variable = require_active ? "ACTIVE_UID" : "UIDS";
191 p = strappend("/run/systemd/seats/", seat);
195 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
206 if (asprintf(&t, "%lu", (unsigned long) uid) < 0) {
211 FOREACH_WORD(w, l, s, state) {
212 if (strneq(t, w, l)) {
226 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
231 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
234 r = parse_env_file(p, NEWLINE,
257 a = strv_split(s, " ");
274 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
275 return uid_get_array(
277 require_active == 0 ? "ONLINE_SESSIONS" :
278 require_active > 0 ? "ACTIVE_SESSIONS" :
283 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
284 return uid_get_array(
286 require_active == 0 ? "ONLINE_SEATS" :
287 require_active > 0 ? "ACTIVE_SEATS" :
292 static int file_of_session(const char *session, char **_p) {
299 p = strappend("/run/systemd/sessions/", session);
303 r = sd_pid_get_session(0, &buf);
307 p = strappend("/run/systemd/sessions/", buf);
318 _public_ int sd_session_is_active(const char *session) {
322 r = file_of_session(session, &p);
326 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
337 r = parse_boolean(s);
343 _public_ int sd_session_get_state(const char *session, char **state) {
350 r = file_of_session(session, &p);
354 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
367 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
374 r = file_of_session(session, &p);
378 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
389 r = parse_uid(s, uid);
395 static int session_get_string(const char *session, const char *field, char **value) {
402 r = file_of_session(session, &p);
406 r = parse_env_file(p, NEWLINE, field, &s, NULL);
421 _public_ int sd_session_get_seat(const char *session, char **seat) {
422 return session_get_string(session, "SEAT", seat);
425 _public_ int sd_session_get_tty(const char *session, char **tty) {
426 return session_get_string(session, "TTY", tty);
429 _public_ int sd_session_get_service(const char *session, char **service) {
430 return session_get_string(session, "SERVICE", service);
433 _public_ int sd_session_get_type(const char *session, char **type) {
434 return session_get_string(session, "TYPE", type);
437 _public_ int sd_session_get_class(const char *session, char **class) {
438 return session_get_string(session, "CLASS", class);
441 _public_ int sd_session_get_display(const char *session, char **display) {
442 return session_get_string(session, "DISPLAY", display);
445 static int file_of_seat(const char *seat, char **_p) {
452 p = strappend("/run/systemd/seats/", seat);
456 r = sd_session_get_seat(NULL, &buf);
460 p = strappend("/run/systemd/seats/", buf);
471 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
472 char *p, *s = NULL, *t = NULL;
475 if (!session && !uid)
478 r = file_of_seat(seat, &p);
482 r = parse_env_file(p, NEWLINE,
505 r = parse_uid(t, uid);
523 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
524 char *p, *s = NULL, *t = NULL, **a = NULL;
529 r = file_of_seat(seat, &p);
533 r = parse_env_file(p, NEWLINE,
535 "ACTIVE_SESSIONS", &t,
546 a = strv_split(s, " ");
560 FOREACH_WORD(w, l, t, state)
574 FOREACH_WORD(w, l, t, state) {
585 r = parse_uid(k, b + i);
613 static int seat_get_can(const char *seat, const char *variable) {
617 r = file_of_seat(seat, &p);
621 r = parse_env_file(p, NEWLINE,
632 r = parse_boolean(s);
640 _public_ int sd_seat_can_multi_session(const char *seat) {
641 return seat_get_can(seat, "CAN_MULTI_SESSION");
644 _public_ int sd_seat_can_tty(const char *seat) {
645 return seat_get_can(seat, "CAN_TTY");
648 _public_ int sd_seat_can_graphical(const char *seat) {
649 return seat_get_can(seat, "CAN_GRAPHICAL");
652 _public_ int sd_get_seats(char ***seats) {
653 return get_files_in_directory("/run/systemd/seats/", seats);
656 _public_ int sd_get_sessions(char ***sessions) {
657 return get_files_in_directory("/run/systemd/sessions/", sessions);
660 _public_ int sd_get_uids(uid_t **users) {
666 d = opendir("/run/systemd/users/");
672 union dirent_storage buf;
676 k = readdir_r(d, &buf.de, &de);
685 dirent_ensure_type(d, de);
687 if (!dirent_is_file(de))
690 k = parse_uid(de->d_name, &uid);
695 if ((unsigned) r >= n) {
699 t = realloc(l, sizeof(uid_t) * n);
708 assert((unsigned) r < n);
727 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
728 return (int) (unsigned long) m - 1;
731 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
732 return (sd_login_monitor*) (unsigned long) (fd + 1);
735 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
742 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
746 if (!category || streq(category, "seat")) {
747 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
749 close_nointr_nofail(fd);
756 if (!category || streq(category, "session")) {
757 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
759 close_nointr_nofail(fd);
766 if (!category || streq(category, "uid")) {
767 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
769 close_nointr_nofail(fd);
781 *m = FD_TO_MONITOR(fd);
785 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
791 fd = MONITOR_TO_FD(m);
797 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
802 return flush_fd(MONITOR_TO_FD(m));
805 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
810 return MONITOR_TO_FD(m);
813 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
818 /* For now we will only return POLLIN here, since we don't
819 * need anything else ever for inotify. However, let's have
820 * this API to keep our options open should we later on need
825 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
832 /* For now we will only return (uint64_t) -1, since we don't
833 * need any timeout. However, let's have this API to keep our
834 * options open should we later on need it. */
835 *timeout_usec = (uint64_t) -1;