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"
33 #include "login-shared.h"
36 _public_ int sd_pid_get_session(pid_t pid, char **session) {
38 assert_return(pid >= 0, -EINVAL);
39 assert_return(session, -EINVAL);
41 return cg_pid_get_session(pid, session);
44 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
46 assert_return(pid >= 0, -EINVAL);
47 assert_return(unit, -EINVAL);
49 return cg_pid_get_unit(pid, unit);
52 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
54 assert_return(pid >= 0, -EINVAL);
55 assert_return(unit, -EINVAL);
57 return cg_pid_get_user_unit(pid, unit);
60 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
62 assert_return(pid >= 0, -EINVAL);
63 assert_return(name, -EINVAL);
65 return cg_pid_get_machine_name(pid, name);
68 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
70 assert_return(pid >= 0, -EINVAL);
71 assert_return(slice, -EINVAL);
73 return cg_pid_get_slice(pid, slice);
76 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
78 assert_return(pid >= 0, -EINVAL);
79 assert_return(uid, -EINVAL);
81 return cg_pid_get_owner_uid(pid, uid);
84 _public_ int sd_peer_get_session(int fd, char **session) {
88 assert_return(fd >= 0, -EINVAL);
89 assert_return(session, -EINVAL);
91 r = getpeercred(fd, &ucred);
95 return cg_pid_get_session(ucred.pid, session);
98 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
102 assert_return(fd >= 0, -EINVAL);
103 assert_return(uid, -EINVAL);
105 r = getpeercred(fd, &ucred);
109 return cg_pid_get_owner_uid(ucred.pid, uid);
112 _public_ int sd_peer_get_unit(int fd, char **unit) {
116 assert_return(fd >= 0, -EINVAL);
117 assert_return(unit, -EINVAL);
119 r = getpeercred(fd, &ucred);
123 return cg_pid_get_unit(ucred.pid, unit);
126 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
130 assert_return(fd >= 0, -EINVAL);
131 assert_return(unit, -EINVAL);
133 r = getpeercred(fd, &ucred);
137 return cg_pid_get_user_unit(ucred.pid, unit);
140 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
144 assert_return(fd >= 0, -EINVAL);
145 assert_return(machine, -EINVAL);
147 r = getpeercred(fd, &ucred);
151 return cg_pid_get_machine_name(ucred.pid, machine);
154 _public_ int sd_peer_get_slice(int fd, char **slice) {
158 assert_return(fd >= 0, -EINVAL);
159 assert_return(slice, -EINVAL);
161 r = getpeercred(fd, &ucred);
165 return cg_pid_get_slice(ucred.pid, slice);
168 static int file_of_uid(uid_t uid, char **p) {
171 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
177 _public_ int sd_uid_get_state(uid_t uid, char**state) {
178 _cleanup_free_ char *p = NULL;
182 assert_return(state, -EINVAL);
184 r = file_of_uid(uid, &p);
188 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
191 s = strdup("offline");
205 _public_ int sd_uid_get_display(uid_t uid, char **session) {
206 _cleanup_free_ char *p = NULL, *s = NULL;
209 assert_return(session, -EINVAL);
211 r = file_of_uid(uid, &p);
215 r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
228 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
229 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
232 const char *word, *variable, *state;
234 assert_return(seat, -EINVAL);
236 variable = require_active ? "ACTIVE_UID" : "UIDS";
238 p = strappend("/run/systemd/seats/", seat);
242 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
250 if (asprintf(&t, UID_FMT, uid) < 0)
253 FOREACH_WORD(word, l, s, state) {
254 if (strneq(t, word, l))
261 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
262 _cleanup_free_ char *p = NULL, *s = NULL;
266 r = file_of_uid(uid, &p);
270 r = parse_env_file(p, NEWLINE,
289 a = strv_split(s, " ");
305 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
306 return uid_get_array(
308 require_active == 0 ? "ONLINE_SESSIONS" :
309 require_active > 0 ? "ACTIVE_SESSIONS" :
314 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
315 return uid_get_array(
317 require_active == 0 ? "ONLINE_SEATS" :
318 require_active > 0 ? "ACTIVE_SEATS" :
323 static int file_of_session(const char *session, char **_p) {
330 if (!session_id_valid(session))
333 p = strappend("/run/systemd/sessions/", session);
335 _cleanup_free_ char *buf = NULL;
337 r = sd_pid_get_session(0, &buf);
341 p = strappend("/run/systemd/sessions/", buf);
351 _public_ int sd_session_is_active(const char *session) {
353 _cleanup_free_ char *p = NULL, *s = NULL;
355 r = file_of_session(session, &p);
359 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
366 return parse_boolean(s);
369 _public_ int sd_session_is_remote(const char *session) {
371 _cleanup_free_ char *p = NULL, *s = NULL;
373 r = file_of_session(session, &p);
377 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
384 return parse_boolean(s);
387 _public_ int sd_session_get_state(const char *session, char **state) {
388 _cleanup_free_ char *p = NULL, *s = NULL;
391 assert_return(state, -EINVAL);
393 r = file_of_session(session, &p);
397 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
409 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
411 _cleanup_free_ char *p = NULL, *s = NULL;
413 assert_return(uid, -EINVAL);
415 r = file_of_session(session, &p);
419 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
426 return parse_uid(s, uid);
429 static int session_get_string(const char *session, const char *field, char **value) {
430 _cleanup_free_ char *p = NULL, *s = NULL;
433 assert_return(value, -EINVAL);
435 r = file_of_session(session, &p);
439 r = parse_env_file(p, NEWLINE, field, &s, NULL);
451 _public_ int sd_session_get_seat(const char *session, char **seat) {
452 return session_get_string(session, "SEAT", seat);
455 _public_ int sd_session_get_tty(const char *session, char **tty) {
456 return session_get_string(session, "TTY", tty);
459 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
460 _cleanup_free_ char *vtnr_string = NULL;
464 r = session_get_string(session, "VTNR", &vtnr_string);
468 r = safe_atou(vtnr_string, &u);
476 _public_ int sd_session_get_service(const char *session, char **service) {
477 return session_get_string(session, "SERVICE", service);
480 _public_ int sd_session_get_type(const char *session, char **type) {
481 return session_get_string(session, "TYPE", type);
484 _public_ int sd_session_get_class(const char *session, char **class) {
485 return session_get_string(session, "CLASS", class);
488 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
489 _cleanup_free_ char *escaped = NULL;
493 assert_return(desktop, -EINVAL);
495 r = session_get_string(session, "DESKTOP", &escaped);
499 t = cunescape(escaped);
507 _public_ int sd_session_get_display(const char *session, char **display) {
508 return session_get_string(session, "DISPLAY", display);
511 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
512 return session_get_string(session, "REMOTE_USER", remote_user);
515 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
516 return session_get_string(session, "REMOTE_HOST", remote_host);
519 static int file_of_seat(const char *seat, char **_p) {
526 p = strappend("/run/systemd/seats/", seat);
528 _cleanup_free_ char *buf = NULL;
530 r = sd_session_get_seat(NULL, &buf);
534 p = strappend("/run/systemd/seats/", buf);
545 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
546 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
549 assert_return(session || uid, -EINVAL);
551 r = file_of_seat(seat, &p);
555 r = parse_env_file(p, NEWLINE,
569 r = parse_uid(t, uid);
582 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
583 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
584 _cleanup_strv_free_ char **a = NULL;
585 _cleanup_free_ uid_t *b = NULL;
589 r = file_of_seat(seat, &p);
593 r = parse_env_file(p, NEWLINE,
595 "ACTIVE_SESSIONS", &t,
602 a = strv_split(s, " ");
608 const char *word, *state;
611 FOREACH_WORD(word, l, t, state)
621 FOREACH_WORD(word, l, t, state) {
622 _cleanup_free_ char *k = NULL;
624 k = strndup(word, l);
628 r = parse_uid(k, b + i);
656 static int seat_get_can(const char *seat, const char *variable) {
657 _cleanup_free_ char *p = NULL, *s = NULL;
660 assert_return(variable, -EINVAL);
662 r = file_of_seat(seat, &p);
666 r = parse_env_file(p, NEWLINE,
674 return parse_boolean(s);
677 _public_ int sd_seat_can_multi_session(const char *seat) {
678 return seat_get_can(seat, "CAN_MULTI_SESSION");
681 _public_ int sd_seat_can_tty(const char *seat) {
682 return seat_get_can(seat, "CAN_TTY");
685 _public_ int sd_seat_can_graphical(const char *seat) {
686 return seat_get_can(seat, "CAN_GRAPHICAL");
689 _public_ int sd_get_seats(char ***seats) {
690 return get_files_in_directory("/run/systemd/seats/", seats);
693 _public_ int sd_get_sessions(char ***sessions) {
694 return get_files_in_directory("/run/systemd/sessions/", sessions);
697 _public_ int sd_get_uids(uid_t **users) {
698 _cleanup_closedir_ DIR *d;
701 _cleanup_free_ uid_t *l = NULL;
703 d = opendir("/run/systemd/users/");
714 if (!de && errno != 0)
720 dirent_ensure_type(d, de);
722 if (!dirent_is_file(de))
725 k = parse_uid(de->d_name, &uid);
730 if ((unsigned) r >= n) {
734 t = realloc(l, sizeof(uid_t) * n);
741 assert((unsigned) r < n);
755 _public_ int sd_get_machine_names(char ***machines) {
756 char **l = NULL, **a, **b;
759 assert_return(machines, -EINVAL);
761 r = get_files_in_directory("/run/systemd/machines/", &l);
768 /* Filter out the unit: symlinks */
769 for (a = l, b = l; *a; a++) {
770 if (startswith(*a, "unit:"))
786 _public_ int sd_machine_get_class(const char *machine, char **class) {
787 _cleanup_free_ char *c = NULL;
791 assert_return(machine_name_is_valid(machine), -EINVAL);
792 assert_return(class, -EINVAL);
794 p = strappenda("/run/systemd/machines/", machine);
795 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
807 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
808 _cleanup_free_ char *netif = NULL;
809 size_t l, allocated = 0, nr = 0;
811 const char *p, *word, *state;
814 assert_return(machine_name_is_valid(machine), -EINVAL);
815 assert_return(ifindices, -EINVAL);
817 p = strappenda("/run/systemd/machines/", machine);
818 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
826 FOREACH_WORD(word, l, netif, state) {
830 *(char*) (mempcpy(buf, word, l)) = 0;
832 if (safe_atoi(buf, &ifi) < 0)
837 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
849 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
850 return (int) (unsigned long) m - 1;
853 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
854 return (sd_login_monitor*) (unsigned long) (fd + 1);
857 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
861 assert_return(m, -EINVAL);
863 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
867 if (!category || streq(category, "seat")) {
868 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
877 if (!category || streq(category, "session")) {
878 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
887 if (!category || streq(category, "uid")) {
888 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
897 if (!category || streq(category, "machine")) {
898 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
912 *m = FD_TO_MONITOR(fd);
916 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
919 assert_return(m, NULL);
921 fd = MONITOR_TO_FD(m);
927 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
929 assert_return(m, -EINVAL);
931 return flush_fd(MONITOR_TO_FD(m));
934 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
936 assert_return(m, -EINVAL);
938 return MONITOR_TO_FD(m);
941 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
943 assert_return(m, -EINVAL);
945 /* For now we will only return POLLIN here, since we don't
946 * need anything else ever for inotify. However, let's have
947 * this API to keep our options open should we later on need
952 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
954 assert_return(m, -EINVAL);
955 assert_return(timeout_usec, -EINVAL);
957 /* For now we will only return (uint64_t) -1, since we don't
958 * need any timeout. However, let's have this API to keep our
959 * options open should we later on need it. */
960 *timeout_usec = (uint64_t) -1;