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);
358 *session = TAKE_PTR(s);
363 static int file_of_seat(const char *seat, char **_p) {
370 if (!filename_is_valid(seat))
373 p = strappend("/run/systemd/seats/", seat);
375 _cleanup_free_ char *buf = NULL;
377 r = sd_session_get_seat(NULL, &buf);
381 p = strappend("/run/systemd/seats/", buf);
391 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
392 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
395 const char *word, *variable, *state;
397 assert_return(uid_is_valid(uid), -EINVAL);
399 r = file_of_seat(seat, &p);
403 variable = require_active ? "ACTIVE_UID" : "UIDS";
405 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
413 if (asprintf(&t, UID_FMT, uid) < 0)
416 FOREACH_WORD(word, l, s, state)
417 if (strneq(t, word, l))
423 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
424 _cleanup_free_ char *p = NULL, *s = NULL;
430 r = file_of_uid(uid, &p);
434 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
435 if (r == -ENOENT || (r >= 0 && isempty(s))) {
443 a = strv_split(s, " ");
458 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
459 return uid_get_array(
461 require_active == 0 ? "ONLINE_SESSIONS" :
462 require_active > 0 ? "ACTIVE_SESSIONS" :
467 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
468 return uid_get_array(
470 require_active == 0 ? "ONLINE_SEATS" :
471 require_active > 0 ? "ACTIVE_SEATS" :
476 static int file_of_session(const char *session, char **_p) {
483 if (!session_id_valid(session))
486 p = strappend("/run/systemd/sessions/", session);
488 _cleanup_free_ char *buf = NULL;
490 r = sd_pid_get_session(0, &buf);
494 p = strappend("/run/systemd/sessions/", buf);
504 _public_ int sd_session_is_active(const char *session) {
505 _cleanup_free_ char *p = NULL, *s = NULL;
508 r = file_of_session(session, &p);
512 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
520 return parse_boolean(s);
523 _public_ int sd_session_is_remote(const char *session) {
524 _cleanup_free_ char *p = NULL, *s = NULL;
527 r = file_of_session(session, &p);
531 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
539 return parse_boolean(s);
542 _public_ int sd_session_get_state(const char *session, char **state) {
543 _cleanup_free_ char *p = NULL, *s = NULL;
546 assert_return(state, -EINVAL);
548 r = file_of_session(session, &p);
552 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
560 *state = TAKE_PTR(s);
565 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
567 _cleanup_free_ char *p = NULL, *s = NULL;
569 assert_return(uid, -EINVAL);
571 r = file_of_session(session, &p);
575 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
583 return parse_uid(s, uid);
586 static int session_get_string(const char *session, const char *field, char **value) {
587 _cleanup_free_ char *p = NULL, *s = NULL;
590 assert_return(value, -EINVAL);
593 r = file_of_session(session, &p);
597 r = parse_env_file(p, NEWLINE, field, &s, NULL);
605 *value = TAKE_PTR(s);
609 _public_ int sd_session_get_seat(const char *session, char **seat) {
610 return session_get_string(session, "SEAT", seat);
613 _public_ int sd_session_get_tty(const char *session, char **tty) {
614 return session_get_string(session, "TTY", tty);
617 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
618 _cleanup_free_ char *vtnr_string = NULL;
622 assert_return(vtnr, -EINVAL);
624 r = session_get_string(session, "VTNR", &vtnr_string);
628 r = safe_atou(vtnr_string, &u);
636 _public_ int sd_session_get_service(const char *session, char **service) {
637 return session_get_string(session, "SERVICE", service);
640 _public_ int sd_session_get_type(const char *session, char **type) {
641 return session_get_string(session, "TYPE", type);
644 _public_ int sd_session_get_class(const char *session, char **class) {
645 return session_get_string(session, "CLASS", class);
648 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
649 _cleanup_free_ char *escaped = NULL;
653 assert_return(desktop, -EINVAL);
655 r = session_get_string(session, "DESKTOP", &escaped);
659 r = cunescape(escaped, 0, &t);
667 _public_ int sd_session_get_display(const char *session, char **display) {
668 return session_get_string(session, "DISPLAY", display);
671 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
672 return session_get_string(session, "REMOTE_USER", remote_user);
675 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
676 return session_get_string(session, "REMOTE_HOST", remote_host);
679 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
680 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
683 assert_return(session || uid, -EINVAL);
685 r = file_of_seat(seat, &p);
689 r = parse_env_file(p, NEWLINE,
705 r = parse_uid(t, uid);
711 *session = TAKE_PTR(s);
716 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
717 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
718 _cleanup_strv_free_ char **a = NULL;
719 _cleanup_free_ uid_t *b = NULL;
723 r = file_of_seat(seat, &p);
727 r = parse_env_file(p, NEWLINE,
737 a = strv_split(s, " ");
743 const char *word, *state;
746 FOREACH_WORD(word, l, t, state)
756 FOREACH_WORD(word, l, t, state) {
757 _cleanup_free_ char *k = NULL;
759 k = strndup(word, l);
763 r = parse_uid(k, b + i);
775 *sessions = TAKE_PTR(a);
786 static int seat_get_can(const char *seat, const char *variable) {
787 _cleanup_free_ char *p = NULL, *s = NULL;
792 r = file_of_seat(seat, &p);
796 r = parse_env_file(p, NEWLINE,
806 return parse_boolean(s);
809 _public_ int sd_seat_can_multi_session(const char *seat) {
810 return seat_get_can(seat, "CAN_MULTI_SESSION");
813 _public_ int sd_seat_can_tty(const char *seat) {
814 return seat_get_can(seat, "CAN_TTY");
817 _public_ int sd_seat_can_graphical(const char *seat) {
818 return seat_get_can(seat, "CAN_GRAPHICAL");
821 _public_ int sd_get_seats(char ***seats) {
824 r = get_files_in_directory("/run/systemd/seats/", seats);
833 _public_ int sd_get_sessions(char ***sessions) {
836 r = get_files_in_directory("/run/systemd/sessions/", sessions);
845 _public_ int sd_get_uids(uid_t **users) {
846 _cleanup_closedir_ DIR *d;
850 _cleanup_free_ uid_t *l = NULL;
852 d = opendir("/run/systemd/users/");
854 if (errno == ENOENT) {
862 FOREACH_DIRENT_ALL(de, d, return -errno) {
866 dirent_ensure_type(d, de);
868 if (!dirent_is_file(de))
871 k = parse_uid(de->d_name, &uid);
876 if ((unsigned) r >= n) {
880 t = realloc(l, sizeof(uid_t) * n);
887 assert((unsigned) r < n);
894 *users = TAKE_PTR(l);
899 _public_ int sd_get_machine_names(char ***machines) {
900 _cleanup_strv_free_ char **l = NULL;
904 r = get_files_in_directory("/run/systemd/machines/", &l);
916 /* Filter out the unit: symlinks */
917 for (a = b = l; *a; a++) {
918 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
931 *machines = TAKE_PTR(l);
936 _public_ int sd_machine_get_class(const char *machine, char **class) {
937 _cleanup_free_ char *c = NULL;
941 assert_return(machine_name_is_valid(machine), -EINVAL);
942 assert_return(class, -EINVAL);
944 p = strjoina("/run/systemd/machines/", machine);
945 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
953 *class = TAKE_PTR(c);
958 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
959 _cleanup_free_ char *netif = NULL;
960 size_t l, allocated = 0, nr = 0;
962 const char *p, *word, *state;
965 assert_return(machine_name_is_valid(machine), -EINVAL);
966 assert_return(ifindices, -EINVAL);
968 p = strjoina("/run/systemd/machines/", machine);
969 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
979 FOREACH_WORD(word, l, netif, state) {
983 *(char*) (mempcpy(buf, word, l)) = 0;
985 if (parse_ifindex(buf, &ifi) < 0)
988 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
1000 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
1001 return (int) (unsigned long) m - 1;
1004 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
1005 return (sd_login_monitor*) (unsigned long) (fd + 1);
1008 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
1009 _cleanup_close_ int fd = -1;
1013 assert_return(m, -EINVAL);
1015 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1019 if (!category || streq(category, "seat")) {
1020 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
1027 if (!category || streq(category, "session")) {
1028 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
1035 if (!category || streq(category, "uid")) {
1036 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1043 if (!category || streq(category, "machine")) {
1044 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1054 *m = FD_TO_MONITOR(fd);
1060 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1066 fd = MONITOR_TO_FD(m);
1072 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1075 assert_return(m, -EINVAL);
1077 r = flush_fd(MONITOR_TO_FD(m));
1084 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1086 assert_return(m, -EINVAL);
1088 return MONITOR_TO_FD(m);
1091 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1093 assert_return(m, -EINVAL);
1095 /* For now we will only return POLLIN here, since we don't
1096 * need anything else ever for inotify. However, let's have
1097 * this API to keep our options open should we later on need
1102 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1104 assert_return(m, -EINVAL);
1105 assert_return(timeout_usec, -EINVAL);
1107 /* For now we will only return (uint64_t) -1, since we don't
1108 * need any timeout. However, let's have this API to keep our
1109 * options open should we later on need it. */
1110 *timeout_usec = (uint64_t) -1;