1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <sys/inotify.h>
29 #include "alloc-util.h"
30 #include "cgroup-util.h"
31 #include "dirent-util.h"
35 #include "format-util.h"
37 #include "hostname-util.h"
39 #include "login-util.h"
41 #include "parse-util.h"
42 #include "path-util.h"
43 #include "socket-util.h"
44 #include "string-util.h"
46 #include "user-util.h"
51 * invalid input parameters → -EINVAL
53 * process does not exist → -ESRCH
54 * cgroup does not exist → -ENOENT
55 * machine, session does not exist → -ENXIO
56 * requested metadata on object is missing → -ENODATA
59 _public_ int sd_pid_get_session(pid_t pid, char **session) {
62 assert_return(pid >= 0, -EINVAL);
63 assert_return(session, -EINVAL);
65 r = cg_pid_get_session(pid, session);
66 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
69 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
70 #if 0 /// UNNEEDED by elogind
74 assert_return(pid >= 0, -EINVAL);
75 assert_return(unit, -EINVAL);
77 #if 0 /// elogind does not support systemd units
78 r = cg_pid_get_unit(pid, unit);
79 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
85 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
86 #if 0 /// UNNEEDED by elogind
90 assert_return(pid >= 0, -EINVAL);
91 assert_return(unit, -EINVAL);
93 #if 0 /// elogind does not support systemd units
94 r = cg_pid_get_user_unit(pid, unit);
95 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
101 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
102 #if 0 /// UNNEEDED by elogind
106 assert_return(pid >= 0, -EINVAL);
107 assert_return(name, -EINVAL);
109 #if 0 /// elogind does not support systemd units
110 r = cg_pid_get_machine_name(pid, name);
111 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
117 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
120 assert_return(pid >= 0, -EINVAL);
121 assert_return(slice, -EINVAL);
123 r = cg_pid_get_slice(pid, slice);
124 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
127 _public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
130 assert_return(pid >= 0, -EINVAL);
131 assert_return(slice, -EINVAL);
133 r = cg_pid_get_user_slice(pid, slice);
134 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
137 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
140 assert_return(pid >= 0, -EINVAL);
141 assert_return(uid, -EINVAL);
143 r = cg_pid_get_owner_uid(pid, uid);
144 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
147 _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
151 assert_return(pid >= 0, -EINVAL);
152 assert_return(cgroup, -EINVAL);
154 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c);
158 /* The internal APIs return the empty string for the root
159 * cgroup, let's return the "/" in the public APIs instead, as
160 * that's easier and less ambiguous for people to grok. */
173 _public_ int sd_peer_get_session(int fd, char **session) {
174 struct ucred ucred = {};
177 assert_return(fd >= 0, -EBADF);
178 assert_return(session, -EINVAL);
180 r = getpeercred(fd, &ucred);
184 return cg_pid_get_session(ucred.pid, session);
187 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
191 assert_return(fd >= 0, -EBADF);
192 assert_return(uid, -EINVAL);
194 r = getpeercred(fd, &ucred);
198 return cg_pid_get_owner_uid(ucred.pid, uid);
201 _public_ int sd_peer_get_unit(int fd, char **unit) {
205 assert_return(fd >= 0, -EBADF);
206 assert_return(unit, -EINVAL);
208 r = getpeercred(fd, &ucred);
212 #if 0 /// elogind does not support systemd units
213 return cg_pid_get_unit(ucred.pid, unit);
219 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
223 assert_return(fd >= 0, -EBADF);
224 assert_return(unit, -EINVAL);
226 r = getpeercred(fd, &ucred);
230 #if 0 /// elogind does not support systemd units
231 return cg_pid_get_user_unit(ucred.pid, unit);
237 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
241 assert_return(fd >= 0, -EBADF);
242 assert_return(machine, -EINVAL);
244 r = getpeercred(fd, &ucred);
248 #if 0 /// 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 return cg_pid_get_slice(ucred.pid, slice);
269 _public_ int sd_peer_get_user_slice(int fd, char **slice) {
273 assert_return(fd >= 0, -EBADF);
274 assert_return(slice, -EINVAL);
276 r = getpeercred(fd, &ucred);
280 return cg_pid_get_user_slice(ucred.pid, slice);
283 _public_ int sd_peer_get_cgroup(int fd, char **cgroup) {
287 assert_return(fd >= 0, -EBADF);
288 assert_return(cgroup, -EINVAL);
290 r = getpeercred(fd, &ucred);
294 return sd_pid_get_cgroup(ucred.pid, cgroup);
297 static int file_of_uid(uid_t uid, char **p) {
299 assert_return(uid_is_valid(uid), -EINVAL);
302 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
308 _public_ int sd_uid_get_state(uid_t uid, char**state) {
309 _cleanup_free_ char *p = NULL;
313 assert_return(state, -EINVAL);
315 r = file_of_uid(uid, &p);
319 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
322 s = strdup("offline");
340 _public_ int sd_uid_get_display(uid_t uid, char **session) {
341 _cleanup_free_ char *p = NULL, *s = NULL;
344 assert_return(session, -EINVAL);
346 r = file_of_uid(uid, &p);
350 r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
364 static int file_of_seat(const char *seat, char **_p) {
371 if (!filename_is_valid(seat))
374 p = strappend("/run/systemd/seats/", seat);
376 _cleanup_free_ char *buf = NULL;
378 r = sd_session_get_seat(NULL, &buf);
382 p = strappend("/run/systemd/seats/", buf);
393 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
394 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
397 const char *word, *variable, *state;
399 assert_return(uid_is_valid(uid), -EINVAL);
401 r = file_of_seat(seat, &p);
405 variable = require_active ? "ACTIVE_UID" : "UIDS";
407 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
415 if (asprintf(&t, UID_FMT, uid) < 0)
418 FOREACH_WORD(word, l, s, state)
419 if (strneq(t, word, l))
425 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
426 _cleanup_free_ char *p = NULL, *s = NULL;
432 r = file_of_uid(uid, &p);
436 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
437 if (r == -ENOENT || (r >= 0 && isempty(s))) {
445 a = strv_split(s, " ");
460 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
461 return uid_get_array(
463 require_active == 0 ? "ONLINE_SESSIONS" :
464 require_active > 0 ? "ACTIVE_SESSIONS" :
469 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
470 return uid_get_array(
472 require_active == 0 ? "ONLINE_SEATS" :
473 require_active > 0 ? "ACTIVE_SEATS" :
478 static int file_of_session(const char *session, char **_p) {
485 if (!session_id_valid(session))
488 p = strappend("/run/systemd/sessions/", session);
490 _cleanup_free_ char *buf = NULL;
492 r = sd_pid_get_session(0, &buf);
496 p = strappend("/run/systemd/sessions/", buf);
506 _public_ int sd_session_is_active(const char *session) {
507 _cleanup_free_ char *p = NULL, *s = NULL;
510 r = file_of_session(session, &p);
514 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
522 return parse_boolean(s);
525 _public_ int sd_session_is_remote(const char *session) {
526 _cleanup_free_ char *p = NULL, *s = NULL;
529 r = file_of_session(session, &p);
533 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
541 return parse_boolean(s);
544 _public_ int sd_session_get_state(const char *session, char **state) {
545 _cleanup_free_ char *p = NULL, *s = NULL;
548 assert_return(state, -EINVAL);
550 r = file_of_session(session, &p);
554 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
568 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
570 _cleanup_free_ char *p = NULL, *s = NULL;
572 assert_return(uid, -EINVAL);
574 r = file_of_session(session, &p);
578 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
586 return parse_uid(s, uid);
589 static int session_get_string(const char *session, const char *field, char **value) {
590 _cleanup_free_ char *p = NULL, *s = NULL;
593 assert_return(value, -EINVAL);
596 r = file_of_session(session, &p);
600 r = parse_env_file(p, NEWLINE, field, &s, NULL);
613 _public_ int sd_session_get_seat(const char *session, char **seat) {
614 return session_get_string(session, "SEAT", seat);
617 _public_ int sd_session_get_tty(const char *session, char **tty) {
618 return session_get_string(session, "TTY", tty);
621 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
622 _cleanup_free_ char *vtnr_string = NULL;
626 assert_return(vtnr, -EINVAL);
628 r = session_get_string(session, "VTNR", &vtnr_string);
632 r = safe_atou(vtnr_string, &u);
640 _public_ int sd_session_get_service(const char *session, char **service) {
641 return session_get_string(session, "SERVICE", service);
644 _public_ int sd_session_get_type(const char *session, char **type) {
645 return session_get_string(session, "TYPE", type);
648 _public_ int sd_session_get_class(const char *session, char **class) {
649 return session_get_string(session, "CLASS", class);
652 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
653 _cleanup_free_ char *escaped = NULL;
657 assert_return(desktop, -EINVAL);
659 r = session_get_string(session, "DESKTOP", &escaped);
663 r = cunescape(escaped, 0, &t);
671 _public_ int sd_session_get_display(const char *session, char **display) {
672 return session_get_string(session, "DISPLAY", display);
675 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
676 return session_get_string(session, "REMOTE_USER", remote_user);
679 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
680 return session_get_string(session, "REMOTE_HOST", remote_host);
683 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
684 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
687 assert_return(session || uid, -EINVAL);
689 r = file_of_seat(seat, &p);
693 r = parse_env_file(p, NEWLINE,
709 r = parse_uid(t, uid);
722 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
723 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
724 _cleanup_strv_free_ char **a = NULL;
725 _cleanup_free_ uid_t *b = NULL;
729 r = file_of_seat(seat, &p);
733 r = parse_env_file(p, NEWLINE,
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);
796 static int seat_get_can(const char *seat, const char *variable) {
797 _cleanup_free_ char *p = NULL, *s = NULL;
802 r = file_of_seat(seat, &p);
806 r = parse_env_file(p, NEWLINE,
816 return parse_boolean(s);
819 _public_ int sd_seat_can_multi_session(const char *seat) {
820 return seat_get_can(seat, "CAN_MULTI_SESSION");
823 _public_ int sd_seat_can_tty(const char *seat) {
824 return seat_get_can(seat, "CAN_TTY");
827 _public_ int sd_seat_can_graphical(const char *seat) {
828 return seat_get_can(seat, "CAN_GRAPHICAL");
831 _public_ int sd_get_seats(char ***seats) {
834 r = get_files_in_directory("/run/systemd/seats/", seats);
843 _public_ int sd_get_sessions(char ***sessions) {
846 r = get_files_in_directory("/run/systemd/sessions/", sessions);
855 _public_ int sd_get_uids(uid_t **users) {
856 _cleanup_closedir_ DIR *d;
860 _cleanup_free_ uid_t *l = NULL;
862 d = opendir("/run/systemd/users/");
864 if (errno == ENOENT) {
872 FOREACH_DIRENT_ALL(de, d, return -errno) {
876 dirent_ensure_type(d, de);
878 if (!dirent_is_file(de))
881 k = parse_uid(de->d_name, &uid);
886 if ((unsigned) r >= n) {
890 t = realloc(l, sizeof(uid_t) * n);
897 assert((unsigned) r < n);
911 _public_ int sd_get_machine_names(char ***machines) {
912 _cleanup_strv_free_ char **l = NULL;
916 r = get_files_in_directory("/run/systemd/machines/", &l);
928 /* Filter out the unit: symlinks */
929 for (a = b = l; *a; a++) {
930 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
949 _public_ int sd_machine_get_class(const char *machine, char **class) {
950 _cleanup_free_ char *c = NULL;
954 assert_return(machine_name_is_valid(machine), -EINVAL);
955 assert_return(class, -EINVAL);
957 p = strjoina("/run/systemd/machines/", machine);
958 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
972 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
973 _cleanup_free_ char *netif = NULL;
974 size_t l, allocated = 0, nr = 0;
976 const char *p, *word, *state;
979 assert_return(machine_name_is_valid(machine), -EINVAL);
980 assert_return(ifindices, -EINVAL);
982 p = strjoina("/run/systemd/machines/", machine);
983 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
993 FOREACH_WORD(word, l, netif, state) {
997 *(char*) (mempcpy(buf, word, l)) = 0;
999 if (parse_ifindex(buf, &ifi) < 0)
1002 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
1014 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
1015 return (int) (unsigned long) m - 1;
1018 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
1019 return (sd_login_monitor*) (unsigned long) (fd + 1);
1022 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
1026 assert_return(m, -EINVAL);
1028 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1032 if (!category || streq(category, "seat")) {
1033 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
1042 if (!category || streq(category, "session")) {
1043 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
1052 if (!category || streq(category, "uid")) {
1053 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1062 if (!category || streq(category, "machine")) {
1063 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1077 *m = FD_TO_MONITOR(fd);
1081 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1087 fd = MONITOR_TO_FD(m);
1093 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1096 assert_return(m, -EINVAL);
1098 r = flush_fd(MONITOR_TO_FD(m));
1105 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1107 assert_return(m, -EINVAL);
1109 return MONITOR_TO_FD(m);
1112 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1114 assert_return(m, -EINVAL);
1116 /* For now we will only return POLLIN here, since we don't
1117 * need anything else ever for inotify. However, let's have
1118 * this API to keep our options open should we later on need
1123 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1125 assert_return(m, -EINVAL);
1126 assert_return(timeout_usec, -EINVAL);
1128 /* For now we will only return (uint64_t) -1, since we don't
1129 * need any timeout. However, let's have this API to keep our
1130 * options open should we later on need it. */
1131 *timeout_usec = (uint64_t) -1;