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) {
309 assert_return(uid_is_valid(uid), -EINVAL);
312 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
318 _public_ int sd_uid_get_state(uid_t uid, char**state) {
319 _cleanup_free_ char *p = NULL;
323 assert_return(state, -EINVAL);
325 r = file_of_uid(uid, &p);
329 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
332 s = strdup("offline");
350 _public_ int sd_uid_get_display(uid_t uid, char **session) {
351 _cleanup_free_ char *p = NULL, *s = NULL;
354 assert_return(session, -EINVAL);
356 r = file_of_uid(uid, &p);
360 r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
374 static int file_of_seat(const char *seat, char **_p) {
381 if (!filename_is_valid(seat))
384 p = strappend("/run/systemd/seats/", seat);
386 _cleanup_free_ char *buf = NULL;
388 r = sd_session_get_seat(NULL, &buf);
392 p = strappend("/run/systemd/seats/", buf);
403 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
404 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
407 const char *word, *variable, *state;
409 assert_return(uid_is_valid(uid), -EINVAL);
411 r = file_of_seat(seat, &p);
415 variable = require_active ? "ACTIVE_UID" : "UIDS";
417 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
425 if (asprintf(&t, UID_FMT, uid) < 0)
428 FOREACH_WORD(word, l, s, state)
429 if (strneq(t, word, l))
435 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
436 _cleanup_free_ char *p = NULL, *s = NULL;
442 r = file_of_uid(uid, &p);
446 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
447 if (r == -ENOENT || (r >= 0 && isempty(s))) {
455 a = strv_split(s, " ");
470 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
471 return uid_get_array(
473 require_active == 0 ? "ONLINE_SESSIONS" :
474 require_active > 0 ? "ACTIVE_SESSIONS" :
479 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
480 return uid_get_array(
482 require_active == 0 ? "ONLINE_SEATS" :
483 require_active > 0 ? "ACTIVE_SEATS" :
488 static int file_of_session(const char *session, char **_p) {
495 if (!session_id_valid(session))
498 p = strappend("/run/systemd/sessions/", session);
500 _cleanup_free_ char *buf = NULL;
502 r = sd_pid_get_session(0, &buf);
506 p = strappend("/run/systemd/sessions/", buf);
516 _public_ int sd_session_is_active(const char *session) {
517 _cleanup_free_ char *p = NULL, *s = NULL;
520 r = file_of_session(session, &p);
524 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
532 return parse_boolean(s);
535 _public_ int sd_session_is_remote(const char *session) {
536 _cleanup_free_ char *p = NULL, *s = NULL;
539 r = file_of_session(session, &p);
543 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
551 return parse_boolean(s);
554 _public_ int sd_session_get_state(const char *session, char **state) {
555 _cleanup_free_ char *p = NULL, *s = NULL;
558 assert_return(state, -EINVAL);
560 r = file_of_session(session, &p);
564 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
578 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
580 _cleanup_free_ char *p = NULL, *s = NULL;
582 assert_return(uid, -EINVAL);
584 r = file_of_session(session, &p);
588 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
596 return parse_uid(s, uid);
599 static int session_get_string(const char *session, const char *field, char **value) {
600 _cleanup_free_ char *p = NULL, *s = NULL;
603 assert_return(value, -EINVAL);
606 r = file_of_session(session, &p);
610 r = parse_env_file(p, NEWLINE, field, &s, NULL);
623 _public_ int sd_session_get_seat(const char *session, char **seat) {
624 return session_get_string(session, "SEAT", seat);
627 _public_ int sd_session_get_tty(const char *session, char **tty) {
628 return session_get_string(session, "TTY", tty);
631 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
632 _cleanup_free_ char *vtnr_string = NULL;
636 assert_return(vtnr, -EINVAL);
638 r = session_get_string(session, "VTNR", &vtnr_string);
642 r = safe_atou(vtnr_string, &u);
650 _public_ int sd_session_get_service(const char *session, char **service) {
651 return session_get_string(session, "SERVICE", service);
654 _public_ int sd_session_get_type(const char *session, char **type) {
655 return session_get_string(session, "TYPE", type);
658 _public_ int sd_session_get_class(const char *session, char **class) {
659 return session_get_string(session, "CLASS", class);
662 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
663 _cleanup_free_ char *escaped = NULL;
667 assert_return(desktop, -EINVAL);
669 r = session_get_string(session, "DESKTOP", &escaped);
673 r = cunescape(escaped, 0, &t);
681 _public_ int sd_session_get_display(const char *session, char **display) {
682 return session_get_string(session, "DISPLAY", display);
685 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
686 return session_get_string(session, "REMOTE_USER", remote_user);
689 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
690 return session_get_string(session, "REMOTE_HOST", remote_host);
693 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
694 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
697 assert_return(session || uid, -EINVAL);
699 r = file_of_seat(seat, &p);
703 r = parse_env_file(p, NEWLINE,
719 r = parse_uid(t, uid);
732 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
733 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
734 _cleanup_strv_free_ char **a = NULL;
735 _cleanup_free_ uid_t *b = NULL;
739 r = file_of_seat(seat, &p);
743 r = parse_env_file(p, NEWLINE,
745 "ACTIVE_SESSIONS", &t,
753 a = strv_split(s, " ");
759 const char *word, *state;
762 FOREACH_WORD(word, l, t, state)
772 FOREACH_WORD(word, l, t, state) {
773 _cleanup_free_ char *k = NULL;
775 k = strndup(word, l);
779 r = parse_uid(k, b + i);
806 static int seat_get_can(const char *seat, const char *variable) {
807 _cleanup_free_ char *p = NULL, *s = NULL;
812 r = file_of_seat(seat, &p);
816 r = parse_env_file(p, NEWLINE,
826 return parse_boolean(s);
829 _public_ int sd_seat_can_multi_session(const char *seat) {
830 return seat_get_can(seat, "CAN_MULTI_SESSION");
833 _public_ int sd_seat_can_tty(const char *seat) {
834 return seat_get_can(seat, "CAN_TTY");
837 _public_ int sd_seat_can_graphical(const char *seat) {
838 return seat_get_can(seat, "CAN_GRAPHICAL");
841 _public_ int sd_get_seats(char ***seats) {
842 return get_files_in_directory("/run/systemd/seats/", seats);
845 _public_ int sd_get_sessions(char ***sessions) {
846 return get_files_in_directory("/run/systemd/sessions/", sessions);
849 _public_ int sd_get_uids(uid_t **users) {
850 _cleanup_closedir_ DIR *d;
853 _cleanup_free_ uid_t *l = NULL;
855 d = opendir("/run/systemd/users/");
866 if (!de && errno != 0)
872 dirent_ensure_type(d, de);
874 if (!dirent_is_file(de))
877 k = parse_uid(de->d_name, &uid);
882 if ((unsigned) r >= n) {
886 t = realloc(l, sizeof(uid_t) * n);
893 assert((unsigned) r < n);
907 _public_ int sd_get_machine_names(char ***machines) {
908 char **l = NULL, **a, **b;
911 assert_return(machines, -EINVAL);
913 r = get_files_in_directory("/run/systemd/machines/", &l);
920 /* Filter out the unit: symlinks */
921 for (a = l, b = l; *a; a++) {
922 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
938 _public_ int sd_machine_get_class(const char *machine, char **class) {
939 _cleanup_free_ char *c = NULL;
943 assert_return(machine_name_is_valid(machine), -EINVAL);
944 assert_return(class, -EINVAL);
946 p = strjoina("/run/systemd/machines/", machine);
947 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
961 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
962 _cleanup_free_ char *netif = NULL;
963 size_t l, allocated = 0, nr = 0;
965 const char *p, *word, *state;
968 assert_return(machine_name_is_valid(machine), -EINVAL);
969 assert_return(ifindices, -EINVAL);
971 p = strjoina("/run/systemd/machines/", machine);
972 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
982 FOREACH_WORD(word, l, netif, state) {
986 *(char*) (mempcpy(buf, word, l)) = 0;
988 if (safe_atoi(buf, &ifi) < 0)
993 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
1005 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
1006 return (int) (unsigned long) m - 1;
1009 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
1010 return (sd_login_monitor*) (unsigned long) (fd + 1);
1013 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
1017 assert_return(m, -EINVAL);
1019 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1023 if (!category || streq(category, "seat")) {
1024 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);
1043 if (!category || streq(category, "uid")) {
1044 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1053 if (!category || streq(category, "machine")) {
1054 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1068 *m = FD_TO_MONITOR(fd);
1072 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1075 assert_return(m, NULL);
1077 fd = MONITOR_TO_FD(m);
1083 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1085 assert_return(m, -EINVAL);
1087 return 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;