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);
790 static int seat_get_can(const char *seat, const char *variable) {
791 _cleanup_free_ char *p = NULL, *s = NULL;
796 r = file_of_seat(seat, &p);
800 r = parse_env_file(p, NEWLINE,
810 return parse_boolean(s);
813 _public_ int sd_seat_can_multi_session(const char *seat) {
814 return seat_get_can(seat, "CAN_MULTI_SESSION");
817 _public_ int sd_seat_can_tty(const char *seat) {
818 return seat_get_can(seat, "CAN_TTY");
821 _public_ int sd_seat_can_graphical(const char *seat) {
822 return seat_get_can(seat, "CAN_GRAPHICAL");
825 _public_ int sd_get_seats(char ***seats) {
828 r = get_files_in_directory("/run/systemd/seats/", seats);
837 _public_ int sd_get_sessions(char ***sessions) {
840 r = get_files_in_directory("/run/systemd/sessions/", sessions);
849 _public_ int sd_get_uids(uid_t **users) {
850 _cleanup_closedir_ DIR *d;
854 _cleanup_free_ uid_t *l = NULL;
856 d = opendir("/run/systemd/users/");
858 if (errno == ENOENT) {
866 FOREACH_DIRENT_ALL(de, d, return -errno) {
870 dirent_ensure_type(d, de);
872 if (!dirent_is_file(de))
875 k = parse_uid(de->d_name, &uid);
880 if ((unsigned) r >= n) {
884 t = realloc(l, sizeof(uid_t) * n);
891 assert((unsigned) r < n);
905 _public_ int sd_get_machine_names(char ***machines) {
906 _cleanup_strv_free_ char **l = NULL;
910 r = get_files_in_directory("/run/systemd/machines/", &l);
922 /* Filter out the unit: symlinks */
923 for (a = b = l; *a; a++) {
924 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
937 *machines = TAKE_PTR(l);
942 _public_ int sd_machine_get_class(const char *machine, char **class) {
943 _cleanup_free_ char *c = NULL;
947 assert_return(machine_name_is_valid(machine), -EINVAL);
948 assert_return(class, -EINVAL);
950 p = strjoina("/run/systemd/machines/", machine);
951 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
959 *class = TAKE_PTR(c);
964 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
965 _cleanup_free_ char *netif = NULL;
966 size_t l, allocated = 0, nr = 0;
968 const char *p, *word, *state;
971 assert_return(machine_name_is_valid(machine), -EINVAL);
972 assert_return(ifindices, -EINVAL);
974 p = strjoina("/run/systemd/machines/", machine);
975 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
985 FOREACH_WORD(word, l, netif, state) {
989 *(char*) (mempcpy(buf, word, l)) = 0;
991 if (parse_ifindex(buf, &ifi) < 0)
994 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
1006 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
1007 return (int) (unsigned long) m - 1;
1010 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
1011 return (sd_login_monitor*) (unsigned long) (fd + 1);
1014 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
1015 _cleanup_close_ int fd = -1;
1019 assert_return(m, -EINVAL);
1021 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1025 if (!category || streq(category, "seat")) {
1026 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
1033 if (!category || streq(category, "session")) {
1034 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
1041 if (!category || streq(category, "uid")) {
1042 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1049 if (!category || streq(category, "machine")) {
1050 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1060 *m = FD_TO_MONITOR(fd);
1066 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1072 fd = MONITOR_TO_FD(m);
1078 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1081 assert_return(m, -EINVAL);
1083 r = flush_fd(MONITOR_TO_FD(m));
1090 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1092 assert_return(m, -EINVAL);
1094 return MONITOR_TO_FD(m);
1097 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1099 assert_return(m, -EINVAL);
1101 /* For now we will only return POLLIN here, since we don't
1102 * need anything else ever for inotify. However, let's have
1103 * this API to keep our options open should we later on need
1108 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1110 assert_return(m, -EINVAL);
1111 assert_return(timeout_usec, -EINVAL);
1113 /* For now we will only return (uint64_t) -1, since we don't
1114 * need any timeout. However, let's have this API to keep our
1115 * options open should we later on need it. */
1116 *timeout_usec = (uint64_t) -1;