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>
30 #include "alloc-util.h"
31 #include "cgroup-util.h"
32 #include "dirent-util.h"
36 #include "formats-util.h"
38 #include "hostname-util.h"
40 #include "login-util.h"
42 #include "parse-util.h"
43 #include "path-util.h"
44 #include "socket-util.h"
45 #include "string-util.h"
47 #include "user-util.h"
52 * invalid input parameters → -EINVAL
54 * process does not exist → -ESRCH
55 * cgroup does not exist → -ENOENT
56 * machine, session does not exist → -ENXIO
57 * requested metadata on object is missing → -ENODATA
60 _public_ int sd_pid_get_session(pid_t pid, char **session) {
62 assert_return(pid >= 0, -EINVAL);
63 assert_return(session, -EINVAL);
65 return cg_pid_get_session(pid, session);
68 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
70 assert_return(pid >= 0, -EINVAL);
71 assert_return(unit, -EINVAL);
73 #if 0 /// elogind does not support systemd units
74 return cg_pid_get_unit(pid, unit);
80 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
82 assert_return(pid >= 0, -EINVAL);
83 assert_return(unit, -EINVAL);
85 #if 0 /// elogind does not support systemd units
86 return cg_pid_get_user_unit(pid, unit);
92 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
94 assert_return(pid >= 0, -EINVAL);
95 assert_return(name, -EINVAL);
97 #if 0 /// elogind does not support systemd units
98 return cg_pid_get_machine_name(pid, name);
104 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
106 assert_return(pid >= 0, -EINVAL);
107 assert_return(slice, -EINVAL);
109 #if 0 /// elogind does not support systemd slices
110 return cg_pid_get_slice(pid, slice);
116 _public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
118 assert_return(pid >= 0, -EINVAL);
119 assert_return(slice, -EINVAL);
121 #if 0 /// elogind does not support systemd slices
122 return cg_pid_get_user_slice(pid, slice);
128 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
130 assert_return(pid >= 0, -EINVAL);
131 assert_return(uid, -EINVAL);
133 #if 0 /// elogind does not support systemd slices
134 return cg_pid_get_owner_uid(pid, uid);
140 _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
144 assert_return(pid >= 0, -EINVAL);
145 assert_return(cgroup, -EINVAL);
147 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c);
151 /* The internal APIs return the empty string for the root
152 * cgroup, let's return the "/" in the public APIs instead, as
153 * that's easier and less ambigious for people to grok. */
166 _public_ int sd_peer_get_session(int fd, char **session) {
167 struct ucred ucred = {};
170 assert_return(fd >= 0, -EBADF);
171 assert_return(session, -EINVAL);
173 r = getpeercred(fd, &ucred);
177 #if 0 /// elogind does not support systemd scopes
178 return cg_pid_get_session(ucred.pid, session);
184 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
188 assert_return(fd >= 0, -EBADF);
189 assert_return(uid, -EINVAL);
191 r = getpeercred(fd, &ucred);
195 #if 0 /// elogind does not support systemd units
196 return cg_pid_get_owner_uid(ucred.pid, uid);
202 _public_ int sd_peer_get_unit(int fd, char **unit) {
206 assert_return(fd >= 0, -EBADF);
207 assert_return(unit, -EINVAL);
209 r = getpeercred(fd, &ucred);
213 #if 0 /// elogind does not support systemd units
214 return cg_pid_get_unit(ucred.pid, unit);
220 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
224 assert_return(fd >= 0, -EBADF);
225 assert_return(unit, -EINVAL);
227 r = getpeercred(fd, &ucred);
231 #if 0 /// elogind does not support systemd units
232 return cg_pid_get_user_unit(ucred.pid, unit);
238 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
242 assert_return(fd >= 0, -EBADF);
243 assert_return(machine, -EINVAL);
245 r = getpeercred(fd, &ucred);
249 #if 0 /// elogind does not support systemd units
250 return cg_pid_get_machine_name(ucred.pid, machine);
256 _public_ int sd_peer_get_slice(int fd, char **slice) {
260 assert_return(fd >= 0, -EBADF);
261 assert_return(slice, -EINVAL);
263 r = getpeercred(fd, &ucred);
267 #if 0 /// 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 #if 0 /// elogind does not support systemd slices
286 return cg_pid_get_user_slice(ucred.pid, slice);
292 _public_ int sd_peer_get_cgroup(int fd, char **cgroup) {
296 assert_return(fd >= 0, -EBADF);
297 assert_return(cgroup, -EINVAL);
299 r = getpeercred(fd, &ucred);
303 return sd_pid_get_cgroup(ucred.pid, cgroup);
306 static int file_of_uid(uid_t uid, char **p) {
308 assert_return(uid_is_valid(uid), -EINVAL);
311 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
317 _public_ int sd_uid_get_state(uid_t uid, char**state) {
318 _cleanup_free_ char *p = NULL;
322 assert_return(state, -EINVAL);
324 r = file_of_uid(uid, &p);
328 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
331 s = strdup("offline");
349 _public_ int sd_uid_get_display(uid_t uid, char **session) {
350 _cleanup_free_ char *p = NULL, *s = NULL;
353 assert_return(session, -EINVAL);
355 r = file_of_uid(uid, &p);
359 r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
373 static int file_of_seat(const char *seat, char **_p) {
380 if (!filename_is_valid(seat))
383 p = strappend("/run/systemd/seats/", seat);
385 _cleanup_free_ char *buf = NULL;
387 r = sd_session_get_seat(NULL, &buf);
391 p = strappend("/run/systemd/seats/", buf);
402 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
403 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
406 const char *word, *variable, *state;
408 assert_return(uid_is_valid(uid), -EINVAL);
410 r = file_of_seat(seat, &p);
414 variable = require_active ? "ACTIVE_UID" : "UIDS";
416 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
424 if (asprintf(&t, UID_FMT, uid) < 0)
427 FOREACH_WORD(word, l, s, state)
428 if (strneq(t, word, l))
434 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
435 _cleanup_free_ char *p = NULL, *s = NULL;
441 r = file_of_uid(uid, &p);
445 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
446 if (r == -ENOENT || (r >= 0 && isempty(s))) {
454 a = strv_split(s, " ");
469 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
470 return uid_get_array(
472 require_active == 0 ? "ONLINE_SESSIONS" :
473 require_active > 0 ? "ACTIVE_SESSIONS" :
478 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
479 return uid_get_array(
481 require_active == 0 ? "ONLINE_SEATS" :
482 require_active > 0 ? "ACTIVE_SEATS" :
487 static int file_of_session(const char *session, char **_p) {
494 if (!session_id_valid(session))
497 p = strappend("/run/systemd/sessions/", session);
499 _cleanup_free_ char *buf = NULL;
501 r = sd_pid_get_session(0, &buf);
505 p = strappend("/run/systemd/sessions/", buf);
515 _public_ int sd_session_is_active(const char *session) {
516 _cleanup_free_ char *p = NULL, *s = NULL;
519 r = file_of_session(session, &p);
523 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
531 return parse_boolean(s);
534 _public_ int sd_session_is_remote(const char *session) {
535 _cleanup_free_ char *p = NULL, *s = NULL;
538 r = file_of_session(session, &p);
542 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
550 return parse_boolean(s);
553 _public_ int sd_session_get_state(const char *session, char **state) {
554 _cleanup_free_ char *p = NULL, *s = NULL;
557 assert_return(state, -EINVAL);
559 r = file_of_session(session, &p);
563 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
577 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
579 _cleanup_free_ char *p = NULL, *s = NULL;
581 assert_return(uid, -EINVAL);
583 r = file_of_session(session, &p);
587 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
595 return parse_uid(s, uid);
598 static int session_get_string(const char *session, const char *field, char **value) {
599 _cleanup_free_ char *p = NULL, *s = NULL;
602 assert_return(value, -EINVAL);
605 r = file_of_session(session, &p);
609 r = parse_env_file(p, NEWLINE, field, &s, NULL);
622 _public_ int sd_session_get_seat(const char *session, char **seat) {
623 return session_get_string(session, "SEAT", seat);
626 _public_ int sd_session_get_tty(const char *session, char **tty) {
627 return session_get_string(session, "TTY", tty);
630 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
631 _cleanup_free_ char *vtnr_string = NULL;
635 assert_return(vtnr, -EINVAL);
637 r = session_get_string(session, "VTNR", &vtnr_string);
641 r = safe_atou(vtnr_string, &u);
649 _public_ int sd_session_get_service(const char *session, char **service) {
650 return session_get_string(session, "SERVICE", service);
653 _public_ int sd_session_get_type(const char *session, char **type) {
654 return session_get_string(session, "TYPE", type);
657 _public_ int sd_session_get_class(const char *session, char **class) {
658 return session_get_string(session, "CLASS", class);
661 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
662 _cleanup_free_ char *escaped = NULL;
666 assert_return(desktop, -EINVAL);
668 r = session_get_string(session, "DESKTOP", &escaped);
672 r = cunescape(escaped, 0, &t);
680 _public_ int sd_session_get_display(const char *session, char **display) {
681 return session_get_string(session, "DISPLAY", display);
684 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
685 return session_get_string(session, "REMOTE_USER", remote_user);
688 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
689 return session_get_string(session, "REMOTE_HOST", remote_host);
692 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
693 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
696 assert_return(session || uid, -EINVAL);
698 r = file_of_seat(seat, &p);
702 r = parse_env_file(p, NEWLINE,
718 r = parse_uid(t, uid);
731 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
732 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
733 _cleanup_strv_free_ char **a = NULL;
734 _cleanup_free_ uid_t *b = NULL;
738 r = file_of_seat(seat, &p);
742 r = parse_env_file(p, NEWLINE,
744 "ACTIVE_SESSIONS", &t,
752 a = strv_split(s, " ");
758 const char *word, *state;
761 FOREACH_WORD(word, l, t, state)
771 FOREACH_WORD(word, l, t, state) {
772 _cleanup_free_ char *k = NULL;
774 k = strndup(word, l);
778 r = parse_uid(k, b + i);
805 static int seat_get_can(const char *seat, const char *variable) {
806 _cleanup_free_ char *p = NULL, *s = NULL;
811 r = file_of_seat(seat, &p);
815 r = parse_env_file(p, NEWLINE,
825 return parse_boolean(s);
828 _public_ int sd_seat_can_multi_session(const char *seat) {
829 return seat_get_can(seat, "CAN_MULTI_SESSION");
832 _public_ int sd_seat_can_tty(const char *seat) {
833 return seat_get_can(seat, "CAN_TTY");
836 _public_ int sd_seat_can_graphical(const char *seat) {
837 return seat_get_can(seat, "CAN_GRAPHICAL");
840 _public_ int sd_get_seats(char ***seats) {
841 return get_files_in_directory("/run/systemd/seats/", seats);
844 _public_ int sd_get_sessions(char ***sessions) {
845 return get_files_in_directory("/run/systemd/sessions/", sessions);
848 _public_ int sd_get_uids(uid_t **users) {
849 _cleanup_closedir_ DIR *d;
852 _cleanup_free_ uid_t *l = NULL;
854 d = opendir("/run/systemd/users/");
865 if (!de && errno != 0)
871 dirent_ensure_type(d, de);
873 if (!dirent_is_file(de))
876 k = parse_uid(de->d_name, &uid);
881 if ((unsigned) r >= n) {
885 t = realloc(l, sizeof(uid_t) * n);
892 assert((unsigned) r < n);
906 _public_ int sd_get_machine_names(char ***machines) {
907 char **l = NULL, **a, **b;
910 assert_return(machines, -EINVAL);
912 r = get_files_in_directory("/run/systemd/machines/", &l);
919 /* Filter out the unit: symlinks */
920 for (a = l, b = l; *a; a++) {
921 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
937 _public_ int sd_machine_get_class(const char *machine, char **class) {
938 _cleanup_free_ char *c = NULL;
942 assert_return(machine_name_is_valid(machine), -EINVAL);
943 assert_return(class, -EINVAL);
945 p = strjoina("/run/systemd/machines/", machine);
946 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
960 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
961 _cleanup_free_ char *netif = NULL;
962 size_t l, allocated = 0, nr = 0;
964 const char *p, *word, *state;
967 assert_return(machine_name_is_valid(machine), -EINVAL);
968 assert_return(ifindices, -EINVAL);
970 p = strjoina("/run/systemd/machines/", machine);
971 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
981 FOREACH_WORD(word, l, netif, state) {
985 *(char*) (mempcpy(buf, word, l)) = 0;
987 if (parse_ifindex(buf, &ifi) < 0)
990 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
1002 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
1003 return (int) (unsigned long) m - 1;
1006 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
1007 return (sd_login_monitor*) (unsigned long) (fd + 1);
1010 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
1014 assert_return(m, -EINVAL);
1016 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1020 if (!category || streq(category, "seat")) {
1021 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
1030 if (!category || streq(category, "session")) {
1031 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
1040 if (!category || streq(category, "uid")) {
1041 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1050 if (!category || streq(category, "machine")) {
1051 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1065 *m = FD_TO_MONITOR(fd);
1069 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1075 fd = MONITOR_TO_FD(m);
1081 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1083 assert_return(m, -EINVAL);
1085 return flush_fd(MONITOR_TO_FD(m));
1088 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1090 assert_return(m, -EINVAL);
1092 return MONITOR_TO_FD(m);
1095 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1097 assert_return(m, -EINVAL);
1099 /* For now we will only return POLLIN here, since we don't
1100 * need anything else ever for inotify. However, let's have
1101 * this API to keep our options open should we later on need
1106 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1108 assert_return(m, -EINVAL);
1109 assert_return(timeout_usec, -EINVAL);
1111 /* For now we will only return (uint64_t) -1, since we don't
1112 * need any timeout. However, let's have this API to keep our
1113 * options open should we later on need it. */
1114 *timeout_usec = (uint64_t) -1;