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-util.h"
34 #include "formats-util.h"
35 #include "hostname-util.h"
38 _public_ int sd_pid_get_session(pid_t pid, char **session) {
40 assert_return(pid >= 0, -EINVAL);
41 assert_return(session, -EINVAL);
43 return cg_pid_get_session(pid, session);
46 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
48 assert_return(pid >= 0, -EINVAL);
49 assert_return(unit, -EINVAL);
51 return cg_pid_get_unit(pid, unit);
54 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
56 assert_return(pid >= 0, -EINVAL);
57 assert_return(unit, -EINVAL);
59 return cg_pid_get_user_unit(pid, unit);
62 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
64 assert_return(pid >= 0, -EINVAL);
65 assert_return(name, -EINVAL);
67 return cg_pid_get_machine_name(pid, name);
70 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
72 assert_return(pid >= 0, -EINVAL);
73 assert_return(slice, -EINVAL);
75 return cg_pid_get_slice(pid, slice);
78 _public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
80 assert_return(pid >= 0, -EINVAL);
81 assert_return(slice, -EINVAL);
83 return cg_pid_get_user_slice(pid, slice);
86 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
88 assert_return(pid >= 0, -EINVAL);
89 assert_return(uid, -EINVAL);
91 return cg_pid_get_owner_uid(pid, uid);
94 _public_ int sd_peer_get_session(int fd, char **session) {
95 struct ucred ucred = {};
98 assert_return(fd >= 0, -EBADF);
99 assert_return(session, -EINVAL);
101 r = getpeercred(fd, &ucred);
105 return cg_pid_get_session(ucred.pid, session);
108 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
112 assert_return(fd >= 0, -EBADF);
113 assert_return(uid, -EINVAL);
115 r = getpeercred(fd, &ucred);
119 return cg_pid_get_owner_uid(ucred.pid, uid);
122 _public_ int sd_peer_get_unit(int fd, char **unit) {
126 assert_return(fd >= 0, -EBADF);
127 assert_return(unit, -EINVAL);
129 r = getpeercred(fd, &ucred);
133 return cg_pid_get_unit(ucred.pid, unit);
136 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
140 assert_return(fd >= 0, -EBADF);
141 assert_return(unit, -EINVAL);
143 r = getpeercred(fd, &ucred);
147 return cg_pid_get_user_unit(ucred.pid, unit);
150 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
154 assert_return(fd >= 0, -EBADF);
155 assert_return(machine, -EINVAL);
157 r = getpeercred(fd, &ucred);
161 return cg_pid_get_machine_name(ucred.pid, machine);
164 _public_ int sd_peer_get_slice(int fd, char **slice) {
168 assert_return(fd >= 0, -EBADF);
169 assert_return(slice, -EINVAL);
171 r = getpeercred(fd, &ucred);
175 return cg_pid_get_slice(ucred.pid, slice);
178 _public_ int sd_peer_get_user_slice(int fd, char **slice) {
182 assert_return(fd >= 0, -EBADF);
183 assert_return(slice, -EINVAL);
185 r = getpeercred(fd, &ucred);
189 return cg_pid_get_user_slice(ucred.pid, slice);
192 static int file_of_uid(uid_t uid, char **p) {
195 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
201 _public_ int sd_uid_get_state(uid_t uid, char**state) {
202 _cleanup_free_ char *p = NULL;
206 assert_return(uid_is_valid(uid), -EINVAL);
207 assert_return(state, -EINVAL);
209 r = file_of_uid(uid, &p);
213 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
216 s = strdup("offline");
230 _public_ int sd_uid_get_display(uid_t uid, char **session) {
231 _cleanup_free_ char *p = NULL, *s = NULL;
234 assert_return(uid_is_valid(uid), -EINVAL);
235 assert_return(session, -EINVAL);
237 r = file_of_uid(uid, &p);
241 r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
256 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
257 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
260 const char *word, *variable, *state;
262 assert_return(uid_is_valid(uid), -EINVAL);
263 assert_return(seat, -EINVAL);
265 variable = require_active ? "ACTIVE_UID" : "UIDS";
267 p = strappend("/run/systemd/seats/", seat);
271 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
279 if (asprintf(&t, UID_FMT, uid) < 0)
282 FOREACH_WORD(word, l, s, state) {
283 if (strneq(t, word, l))
290 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
291 _cleanup_free_ char *p = NULL, *s = NULL;
295 assert_return(uid_is_valid(uid), -EINVAL);
297 r = file_of_uid(uid, &p);
301 r = parse_env_file(p, NEWLINE,
320 a = strv_split(s, " ");
336 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
337 return uid_get_array(
339 require_active == 0 ? "ONLINE_SESSIONS" :
340 require_active > 0 ? "ACTIVE_SESSIONS" :
345 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
346 return uid_get_array(
348 require_active == 0 ? "ONLINE_SEATS" :
349 require_active > 0 ? "ACTIVE_SEATS" :
354 static int file_of_session(const char *session, char **_p) {
361 if (!session_id_valid(session))
364 p = strappend("/run/systemd/sessions/", session);
366 _cleanup_free_ char *buf = NULL;
368 r = sd_pid_get_session(0, &buf);
372 p = strappend("/run/systemd/sessions/", buf);
382 _public_ int sd_session_is_active(const char *session) {
384 _cleanup_free_ char *p = NULL, *s = NULL;
386 r = file_of_session(session, &p);
390 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
397 return parse_boolean(s);
400 _public_ int sd_session_is_remote(const char *session) {
402 _cleanup_free_ char *p = NULL, *s = NULL;
404 r = file_of_session(session, &p);
408 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
415 return parse_boolean(s);
418 _public_ int sd_session_get_state(const char *session, char **state) {
419 _cleanup_free_ char *p = NULL, *s = NULL;
422 assert_return(state, -EINVAL);
424 r = file_of_session(session, &p);
428 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
440 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
442 _cleanup_free_ char *p = NULL, *s = NULL;
444 assert_return(uid, -EINVAL);
446 r = file_of_session(session, &p);
450 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
457 return parse_uid(s, uid);
460 static int session_get_string(const char *session, const char *field, char **value) {
461 _cleanup_free_ char *p = NULL, *s = NULL;
464 assert_return(value, -EINVAL);
466 r = file_of_session(session, &p);
470 r = parse_env_file(p, NEWLINE, field, &s, NULL);
482 _public_ int sd_session_get_seat(const char *session, char **seat) {
483 return session_get_string(session, "SEAT", seat);
486 _public_ int sd_session_get_tty(const char *session, char **tty) {
487 return session_get_string(session, "TTY", tty);
490 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
491 _cleanup_free_ char *vtnr_string = NULL;
495 r = session_get_string(session, "VTNR", &vtnr_string);
499 r = safe_atou(vtnr_string, &u);
507 _public_ int sd_session_get_service(const char *session, char **service) {
508 return session_get_string(session, "SERVICE", service);
511 _public_ int sd_session_get_type(const char *session, char **type) {
512 return session_get_string(session, "TYPE", type);
515 _public_ int sd_session_get_class(const char *session, char **class) {
516 return session_get_string(session, "CLASS", class);
519 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
520 _cleanup_free_ char *escaped = NULL;
524 assert_return(desktop, -EINVAL);
526 r = session_get_string(session, "DESKTOP", &escaped);
530 r = cunescape(escaped, 0, &t);
538 _public_ int sd_session_get_display(const char *session, char **display) {
539 return session_get_string(session, "DISPLAY", display);
542 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
543 return session_get_string(session, "REMOTE_USER", remote_user);
546 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
547 return session_get_string(session, "REMOTE_HOST", remote_host);
550 static int file_of_seat(const char *seat, char **_p) {
557 p = strappend("/run/systemd/seats/", seat);
559 _cleanup_free_ char *buf = NULL;
561 r = sd_session_get_seat(NULL, &buf);
565 p = strappend("/run/systemd/seats/", buf);
576 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
577 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
580 assert_return(session || uid, -EINVAL);
582 r = file_of_seat(seat, &p);
586 r = parse_env_file(p, NEWLINE,
600 r = parse_uid(t, uid);
613 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
614 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
615 _cleanup_strv_free_ char **a = NULL;
616 _cleanup_free_ uid_t *b = NULL;
620 r = file_of_seat(seat, &p);
624 r = parse_env_file(p, NEWLINE,
626 "ACTIVE_SESSIONS", &t,
633 a = strv_split(s, " ");
639 const char *word, *state;
642 FOREACH_WORD(word, l, t, state)
652 FOREACH_WORD(word, l, t, state) {
653 _cleanup_free_ char *k = NULL;
655 k = strndup(word, l);
659 r = parse_uid(k, b + i);
687 static int seat_get_can(const char *seat, const char *variable) {
688 _cleanup_free_ char *p = NULL, *s = NULL;
691 assert_return(variable, -EINVAL);
693 r = file_of_seat(seat, &p);
697 r = parse_env_file(p, NEWLINE,
705 return parse_boolean(s);
708 _public_ int sd_seat_can_multi_session(const char *seat) {
709 return seat_get_can(seat, "CAN_MULTI_SESSION");
712 _public_ int sd_seat_can_tty(const char *seat) {
713 return seat_get_can(seat, "CAN_TTY");
716 _public_ int sd_seat_can_graphical(const char *seat) {
717 return seat_get_can(seat, "CAN_GRAPHICAL");
720 _public_ int sd_get_seats(char ***seats) {
721 return get_files_in_directory("/run/systemd/seats/", seats);
724 _public_ int sd_get_sessions(char ***sessions) {
725 return get_files_in_directory("/run/systemd/sessions/", sessions);
728 _public_ int sd_get_uids(uid_t **users) {
729 _cleanup_closedir_ DIR *d;
732 _cleanup_free_ uid_t *l = NULL;
734 d = opendir("/run/systemd/users/");
745 if (!de && errno != 0)
751 dirent_ensure_type(d, de);
753 if (!dirent_is_file(de))
756 k = parse_uid(de->d_name, &uid);
761 if ((unsigned) r >= n) {
765 t = realloc(l, sizeof(uid_t) * n);
772 assert((unsigned) r < n);
786 _public_ int sd_get_machine_names(char ***machines) {
787 char **l = NULL, **a, **b;
790 assert_return(machines, -EINVAL);
792 r = get_files_in_directory("/run/systemd/machines/", &l);
799 /* Filter out the unit: symlinks */
800 for (a = l, b = l; *a; a++) {
801 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
817 _public_ int sd_machine_get_class(const char *machine, char **class) {
818 _cleanup_free_ char *c = NULL;
822 assert_return(machine_name_is_valid(machine), -EINVAL);
823 assert_return(class, -EINVAL);
825 p = strjoina("/run/systemd/machines/", machine);
826 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
838 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
839 _cleanup_free_ char *netif = NULL;
840 size_t l, allocated = 0, nr = 0;
842 const char *p, *word, *state;
845 assert_return(machine_name_is_valid(machine), -EINVAL);
846 assert_return(ifindices, -EINVAL);
848 p = strjoina("/run/systemd/machines/", machine);
849 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
857 FOREACH_WORD(word, l, netif, state) {
861 *(char*) (mempcpy(buf, word, l)) = 0;
863 if (safe_atoi(buf, &ifi) < 0)
868 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
880 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
881 return (int) (unsigned long) m - 1;
884 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
885 return (sd_login_monitor*) (unsigned long) (fd + 1);
888 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
892 assert_return(m, -EINVAL);
894 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
898 if (!category || streq(category, "seat")) {
899 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
908 if (!category || streq(category, "session")) {
909 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
918 if (!category || streq(category, "uid")) {
919 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
928 if (!category || streq(category, "machine")) {
929 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
943 *m = FD_TO_MONITOR(fd);
947 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
950 assert_return(m, NULL);
952 fd = MONITOR_TO_FD(m);
958 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
960 assert_return(m, -EINVAL);
962 return flush_fd(MONITOR_TO_FD(m));
965 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
967 assert_return(m, -EINVAL);
969 return MONITOR_TO_FD(m);
972 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
974 assert_return(m, -EINVAL);
976 /* For now we will only return POLLIN here, since we don't
977 * need anything else ever for inotify. However, let's have
978 * this API to keep our options open should we later on need
983 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
985 assert_return(m, -EINVAL);
986 assert_return(timeout_usec, -EINVAL);
988 /* For now we will only return (uint64_t) -1, since we don't
989 * need any timeout. However, let's have this API to keep our
990 * options open should we later on need it. */
991 *timeout_usec = (uint64_t) -1;