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"
40 * invalid input parameters → -EINVAL
42 * process does not exist → -ESRCH
43 * cgroup does not exist → -ENOENT
44 * machine, session does not exist → -ENXIO
45 * requested metadata on object is missing → -ENODATA
48 _public_ int sd_pid_get_session(pid_t pid, char **session) {
50 assert_return(pid >= 0, -EINVAL);
51 assert_return(session, -EINVAL);
53 return cg_pid_get_session(pid, session);
56 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
58 assert_return(pid >= 0, -EINVAL);
59 assert_return(unit, -EINVAL);
61 /// elogind does not support systemd units
63 return cg_pid_get_unit(pid, unit);
69 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
71 assert_return(pid >= 0, -EINVAL);
72 assert_return(unit, -EINVAL);
74 /// elogind does not support systemd units
76 return cg_pid_get_user_unit(pid, unit);
82 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
84 assert_return(pid >= 0, -EINVAL);
85 assert_return(name, -EINVAL);
87 /// elogind does not support systemd units
89 return cg_pid_get_machine_name(pid, name);
95 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
97 assert_return(pid >= 0, -EINVAL);
98 assert_return(slice, -EINVAL);
100 /// elogind does not support systemd slices
102 return cg_pid_get_slice(pid, slice);
108 _public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
110 assert_return(pid >= 0, -EINVAL);
111 assert_return(slice, -EINVAL);
113 /// elogind does not support systemd slices
115 return cg_pid_get_user_slice(pid, slice);
121 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
123 assert_return(pid >= 0, -EINVAL);
124 assert_return(uid, -EINVAL);
126 /// elogind does not support systemd slices
128 return cg_pid_get_owner_uid(pid, uid);
134 _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
138 assert_return(pid >= 0, -EINVAL);
139 assert_return(cgroup, -EINVAL);
141 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c);
145 /* The internal APIs return the empty string for the root
146 * cgroup, let's return the "/" in the public APIs instead, as
147 * that's easier and less ambigious for people to grok. */
160 _public_ int sd_peer_get_session(int fd, char **session) {
161 struct ucred ucred = {};
164 assert_return(fd >= 0, -EBADF);
165 assert_return(session, -EINVAL);
167 r = getpeercred(fd, &ucred);
171 /// elogind does not support systemd scopes
173 return cg_pid_get_session(ucred.pid, session);
179 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
183 assert_return(fd >= 0, -EBADF);
184 assert_return(uid, -EINVAL);
186 r = getpeercred(fd, &ucred);
190 /// elogind does not support systemd units
192 return cg_pid_get_owner_uid(ucred.pid, uid);
198 _public_ int sd_peer_get_unit(int fd, char **unit) {
202 assert_return(fd >= 0, -EBADF);
203 assert_return(unit, -EINVAL);
205 r = getpeercred(fd, &ucred);
209 /// elogind does not support systemd units
211 return cg_pid_get_unit(ucred.pid, unit);
217 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
221 assert_return(fd >= 0, -EBADF);
222 assert_return(unit, -EINVAL);
224 r = getpeercred(fd, &ucred);
228 /// elogind does not support systemd units
230 return cg_pid_get_user_unit(ucred.pid, unit);
236 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
240 assert_return(fd >= 0, -EBADF);
241 assert_return(machine, -EINVAL);
243 r = getpeercred(fd, &ucred);
247 /// elogind does not support systemd units
249 return cg_pid_get_machine_name(ucred.pid, machine);
255 _public_ int sd_peer_get_slice(int fd, char **slice) {
259 assert_return(fd >= 0, -EBADF);
260 assert_return(slice, -EINVAL);
262 r = getpeercred(fd, &ucred);
266 /// elogind does not support systemd slices
268 return cg_pid_get_slice(ucred.pid, slice);
274 _public_ int sd_peer_get_user_slice(int fd, char **slice) {
278 assert_return(fd >= 0, -EBADF);
279 assert_return(slice, -EINVAL);
281 r = getpeercred(fd, &ucred);
285 /// elogind does not support systemd slices
287 return cg_pid_get_user_slice(ucred.pid, slice);
293 _public_ int sd_peer_get_cgroup(int fd, char **cgroup) {
297 assert_return(fd >= 0, -EBADF);
298 assert_return(cgroup, -EINVAL);
300 r = getpeercred(fd, &ucred);
304 return sd_pid_get_cgroup(ucred.pid, cgroup);
307 static int file_of_uid(uid_t uid, char **p) {
310 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
316 _public_ int sd_uid_get_state(uid_t uid, char**state) {
317 _cleanup_free_ char *p = NULL;
321 assert_return(state, -EINVAL);
323 r = file_of_uid(uid, &p);
327 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
330 s = strdup("offline");
344 _public_ int sd_uid_get_display(uid_t uid, char **session) {
345 _cleanup_free_ char *p = NULL, *s = NULL;
348 assert_return(session, -EINVAL);
350 r = file_of_uid(uid, &p);
354 r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
369 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
370 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
373 const char *word, *variable, *state;
375 assert_return(seat, -EINVAL);
377 variable = require_active ? "ACTIVE_UID" : "UIDS";
379 p = strappend("/run/systemd/seats/", seat);
383 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
391 if (asprintf(&t, UID_FMT, uid) < 0)
394 FOREACH_WORD(word, l, s, state) {
395 if (strneq(t, word, l))
402 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
403 _cleanup_free_ char *p = NULL, *s = NULL;
407 r = file_of_uid(uid, &p);
411 r = parse_env_file(p, NEWLINE,
430 a = strv_split(s, " ");
446 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
447 return uid_get_array(
449 require_active == 0 ? "ONLINE_SESSIONS" :
450 require_active > 0 ? "ACTIVE_SESSIONS" :
455 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
456 return uid_get_array(
458 require_active == 0 ? "ONLINE_SEATS" :
459 require_active > 0 ? "ACTIVE_SEATS" :
464 static int file_of_session(const char *session, char **_p) {
471 if (!session_id_valid(session))
474 p = strappend("/run/systemd/sessions/", session);
476 _cleanup_free_ char *buf = NULL;
478 r = sd_pid_get_session(0, &buf);
482 p = strappend("/run/systemd/sessions/", buf);
492 _public_ int sd_session_is_active(const char *session) {
494 _cleanup_free_ char *p = NULL, *s = NULL;
496 r = file_of_session(session, &p);
500 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
507 return parse_boolean(s);
510 _public_ int sd_session_is_remote(const char *session) {
512 _cleanup_free_ char *p = NULL, *s = NULL;
514 r = file_of_session(session, &p);
518 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
525 return parse_boolean(s);
528 _public_ int sd_session_get_state(const char *session, char **state) {
529 _cleanup_free_ char *p = NULL, *s = NULL;
532 assert_return(state, -EINVAL);
534 r = file_of_session(session, &p);
538 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
550 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
552 _cleanup_free_ char *p = NULL, *s = NULL;
554 assert_return(uid, -EINVAL);
556 r = file_of_session(session, &p);
560 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
567 return parse_uid(s, uid);
570 static int session_get_string(const char *session, const char *field, char **value) {
571 _cleanup_free_ char *p = NULL, *s = NULL;
574 assert_return(value, -EINVAL);
576 r = file_of_session(session, &p);
580 r = parse_env_file(p, NEWLINE, field, &s, NULL);
592 _public_ int sd_session_get_seat(const char *session, char **seat) {
593 return session_get_string(session, "SEAT", seat);
596 _public_ int sd_session_get_tty(const char *session, char **tty) {
597 return session_get_string(session, "TTY", tty);
600 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
601 _cleanup_free_ char *vtnr_string = NULL;
605 r = session_get_string(session, "VTNR", &vtnr_string);
609 r = safe_atou(vtnr_string, &u);
617 _public_ int sd_session_get_service(const char *session, char **service) {
618 return session_get_string(session, "SERVICE", service);
621 _public_ int sd_session_get_type(const char *session, char **type) {
622 return session_get_string(session, "TYPE", type);
625 _public_ int sd_session_get_class(const char *session, char **class) {
626 return session_get_string(session, "CLASS", class);
629 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
630 _cleanup_free_ char *escaped = NULL;
634 assert_return(desktop, -EINVAL);
636 r = session_get_string(session, "DESKTOP", &escaped);
640 r = cunescape(escaped, 0, &t);
648 _public_ int sd_session_get_display(const char *session, char **display) {
649 return session_get_string(session, "DISPLAY", display);
652 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
653 return session_get_string(session, "REMOTE_USER", remote_user);
656 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
657 return session_get_string(session, "REMOTE_HOST", remote_host);
660 static int file_of_seat(const char *seat, char **_p) {
667 p = strappend("/run/systemd/seats/", seat);
669 _cleanup_free_ char *buf = NULL;
671 r = sd_session_get_seat(NULL, &buf);
675 p = strappend("/run/systemd/seats/", buf);
686 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
687 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
690 assert_return(session || uid, -EINVAL);
692 r = file_of_seat(seat, &p);
696 r = parse_env_file(p, NEWLINE,
710 r = parse_uid(t, uid);
723 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
724 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
725 _cleanup_strv_free_ char **a = NULL;
726 _cleanup_free_ uid_t *b = NULL;
730 r = file_of_seat(seat, &p);
734 r = parse_env_file(p, NEWLINE,
736 "ACTIVE_SESSIONS", &t,
743 a = strv_split(s, " ");
749 const char *word, *state;
752 FOREACH_WORD(word, l, t, state)
762 FOREACH_WORD(word, l, t, state) {
763 _cleanup_free_ char *k = NULL;
765 k = strndup(word, l);
769 r = parse_uid(k, b + i);
797 static int seat_get_can(const char *seat, const char *variable) {
798 _cleanup_free_ char *p = NULL, *s = NULL;
801 assert_return(variable, -EINVAL);
803 r = file_of_seat(seat, &p);
807 r = parse_env_file(p, NEWLINE,
815 return parse_boolean(s);
818 _public_ int sd_seat_can_multi_session(const char *seat) {
819 return seat_get_can(seat, "CAN_MULTI_SESSION");
822 _public_ int sd_seat_can_tty(const char *seat) {
823 return seat_get_can(seat, "CAN_TTY");
826 _public_ int sd_seat_can_graphical(const char *seat) {
827 return seat_get_can(seat, "CAN_GRAPHICAL");
830 _public_ int sd_get_seats(char ***seats) {
831 return get_files_in_directory("/run/systemd/seats/", seats);
834 _public_ int sd_get_sessions(char ***sessions) {
835 return get_files_in_directory("/run/systemd/sessions/", sessions);
838 _public_ int sd_get_uids(uid_t **users) {
839 _cleanup_closedir_ DIR *d;
842 _cleanup_free_ uid_t *l = NULL;
844 d = opendir("/run/systemd/users/");
855 if (!de && errno != 0)
861 dirent_ensure_type(d, de);
863 if (!dirent_is_file(de))
866 k = parse_uid(de->d_name, &uid);
871 if ((unsigned) r >= n) {
875 t = realloc(l, sizeof(uid_t) * n);
882 assert((unsigned) r < n);
896 _public_ int sd_get_machine_names(char ***machines) {
897 char **l = NULL, **a, **b;
900 assert_return(machines, -EINVAL);
902 r = get_files_in_directory("/run/systemd/machines/", &l);
909 /* Filter out the unit: symlinks */
910 for (a = l, b = l; *a; a++) {
911 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
927 _public_ int sd_machine_get_class(const char *machine, char **class) {
928 _cleanup_free_ char *c = NULL;
932 assert_return(machine_name_is_valid(machine), -EINVAL);
933 assert_return(class, -EINVAL);
935 p = strjoina("/run/systemd/machines/", machine);
936 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
948 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
949 _cleanup_free_ char *netif = NULL;
950 size_t l, allocated = 0, nr = 0;
952 const char *p, *word, *state;
955 assert_return(machine_name_is_valid(machine), -EINVAL);
956 assert_return(ifindices, -EINVAL);
958 p = strjoina("/run/systemd/machines/", machine);
959 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
967 FOREACH_WORD(word, l, netif, state) {
971 *(char*) (mempcpy(buf, word, l)) = 0;
973 if (safe_atoi(buf, &ifi) < 0)
978 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
990 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
991 return (int) (unsigned long) m - 1;
994 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
995 return (sd_login_monitor*) (unsigned long) (fd + 1);
998 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
1002 assert_return(m, -EINVAL);
1004 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1008 if (!category || streq(category, "seat")) {
1009 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
1018 if (!category || streq(category, "session")) {
1019 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
1028 if (!category || streq(category, "uid")) {
1029 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1038 if (!category || streq(category, "machine")) {
1039 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1053 *m = FD_TO_MONITOR(fd);
1057 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1060 assert_return(m, NULL);
1062 fd = MONITOR_TO_FD(m);
1068 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1070 assert_return(m, -EINVAL);
1072 return flush_fd(MONITOR_TO_FD(m));
1075 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1077 assert_return(m, -EINVAL);
1079 return MONITOR_TO_FD(m);
1082 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1084 assert_return(m, -EINVAL);
1086 /* For now we will only return POLLIN here, since we don't
1087 * need anything else ever for inotify. However, let's have
1088 * this API to keep our options open should we later on need
1093 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1095 assert_return(m, -EINVAL);
1096 assert_return(timeout_usec, -EINVAL);
1098 /* For now we will only return (uint64_t) -1, since we don't
1099 * need any timeout. However, let's have this API to keep our
1100 * options open should we later on need it. */
1101 *timeout_usec = (uint64_t) -1;