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 /// elogind does not support systemd units
75 return cg_pid_get_unit(pid, unit);
81 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
83 assert_return(pid >= 0, -EINVAL);
84 assert_return(unit, -EINVAL);
86 /// elogind does not support systemd units
88 return cg_pid_get_user_unit(pid, unit);
94 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
96 assert_return(pid >= 0, -EINVAL);
97 assert_return(name, -EINVAL);
99 /// elogind does not support systemd units
101 return cg_pid_get_machine_name(pid, name);
107 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
109 assert_return(pid >= 0, -EINVAL);
110 assert_return(slice, -EINVAL);
112 /// elogind does not support systemd slices
114 return cg_pid_get_slice(pid, slice);
120 _public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
122 assert_return(pid >= 0, -EINVAL);
123 assert_return(slice, -EINVAL);
125 /// elogind does not support systemd slices
127 return cg_pid_get_user_slice(pid, slice);
133 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
135 assert_return(pid >= 0, -EINVAL);
136 assert_return(uid, -EINVAL);
138 /// elogind does not support systemd slices
140 return cg_pid_get_owner_uid(pid, uid);
146 _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
150 assert_return(pid >= 0, -EINVAL);
151 assert_return(cgroup, -EINVAL);
153 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c);
157 /* The internal APIs return the empty string for the root
158 * cgroup, let's return the "/" in the public APIs instead, as
159 * that's easier and less ambigious for people to grok. */
172 _public_ int sd_peer_get_session(int fd, char **session) {
173 struct ucred ucred = {};
176 assert_return(fd >= 0, -EBADF);
177 assert_return(session, -EINVAL);
179 r = getpeercred(fd, &ucred);
183 /// elogind does not support systemd scopes
185 return cg_pid_get_session(ucred.pid, session);
191 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
195 assert_return(fd >= 0, -EBADF);
196 assert_return(uid, -EINVAL);
198 r = getpeercred(fd, &ucred);
202 /// elogind does not support systemd units
204 return cg_pid_get_owner_uid(ucred.pid, uid);
210 _public_ int sd_peer_get_unit(int fd, char **unit) {
214 assert_return(fd >= 0, -EBADF);
215 assert_return(unit, -EINVAL);
217 r = getpeercred(fd, &ucred);
221 /// elogind does not support systemd units
223 return cg_pid_get_unit(ucred.pid, unit);
229 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
233 assert_return(fd >= 0, -EBADF);
234 assert_return(unit, -EINVAL);
236 r = getpeercred(fd, &ucred);
240 /// elogind does not support systemd units
242 return cg_pid_get_user_unit(ucred.pid, unit);
248 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
252 assert_return(fd >= 0, -EBADF);
253 assert_return(machine, -EINVAL);
255 r = getpeercred(fd, &ucred);
259 /// elogind does not support systemd units
261 return cg_pid_get_machine_name(ucred.pid, machine);
267 _public_ int sd_peer_get_slice(int fd, char **slice) {
271 assert_return(fd >= 0, -EBADF);
272 assert_return(slice, -EINVAL);
274 r = getpeercred(fd, &ucred);
278 /// elogind does not support systemd slices
280 return cg_pid_get_slice(ucred.pid, slice);
286 _public_ int sd_peer_get_user_slice(int fd, char **slice) {
290 assert_return(fd >= 0, -EBADF);
291 assert_return(slice, -EINVAL);
293 r = getpeercred(fd, &ucred);
297 /// elogind does not support systemd slices
299 return cg_pid_get_user_slice(ucred.pid, slice);
305 _public_ int sd_peer_get_cgroup(int fd, char **cgroup) {
309 assert_return(fd >= 0, -EBADF);
310 assert_return(cgroup, -EINVAL);
312 r = getpeercred(fd, &ucred);
316 return sd_pid_get_cgroup(ucred.pid, cgroup);
319 static int file_of_uid(uid_t uid, char **p) {
321 assert_return(uid_is_valid(uid), -EINVAL);
324 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
330 _public_ int sd_uid_get_state(uid_t uid, char**state) {
331 _cleanup_free_ char *p = NULL;
335 assert_return(state, -EINVAL);
337 r = file_of_uid(uid, &p);
341 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
344 s = strdup("offline");
362 _public_ int sd_uid_get_display(uid_t uid, char **session) {
363 _cleanup_free_ char *p = NULL, *s = NULL;
366 assert_return(session, -EINVAL);
368 r = file_of_uid(uid, &p);
372 r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
386 static int file_of_seat(const char *seat, char **_p) {
393 if (!filename_is_valid(seat))
396 p = strappend("/run/systemd/seats/", seat);
398 _cleanup_free_ char *buf = NULL;
400 r = sd_session_get_seat(NULL, &buf);
404 p = strappend("/run/systemd/seats/", buf);
415 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
416 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
419 const char *word, *variable, *state;
421 assert_return(uid_is_valid(uid), -EINVAL);
423 r = file_of_seat(seat, &p);
427 variable = require_active ? "ACTIVE_UID" : "UIDS";
429 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
437 if (asprintf(&t, UID_FMT, uid) < 0)
440 FOREACH_WORD(word, l, s, state)
441 if (strneq(t, word, l))
447 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
448 _cleanup_free_ char *p = NULL, *s = NULL;
454 r = file_of_uid(uid, &p);
458 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
459 if (r == -ENOENT || (r >= 0 && isempty(s))) {
467 a = strv_split(s, " ");
482 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
483 return uid_get_array(
485 require_active == 0 ? "ONLINE_SESSIONS" :
486 require_active > 0 ? "ACTIVE_SESSIONS" :
491 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
492 return uid_get_array(
494 require_active == 0 ? "ONLINE_SEATS" :
495 require_active > 0 ? "ACTIVE_SEATS" :
500 static int file_of_session(const char *session, char **_p) {
507 if (!session_id_valid(session))
510 p = strappend("/run/systemd/sessions/", session);
512 _cleanup_free_ char *buf = NULL;
514 r = sd_pid_get_session(0, &buf);
518 p = strappend("/run/systemd/sessions/", buf);
528 _public_ int sd_session_is_active(const char *session) {
529 _cleanup_free_ char *p = NULL, *s = NULL;
532 r = file_of_session(session, &p);
536 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
544 return parse_boolean(s);
547 _public_ int sd_session_is_remote(const char *session) {
548 _cleanup_free_ char *p = NULL, *s = NULL;
551 r = file_of_session(session, &p);
555 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
563 return parse_boolean(s);
566 _public_ int sd_session_get_state(const char *session, char **state) {
567 _cleanup_free_ char *p = NULL, *s = NULL;
570 assert_return(state, -EINVAL);
572 r = file_of_session(session, &p);
576 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
590 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
592 _cleanup_free_ char *p = NULL, *s = NULL;
594 assert_return(uid, -EINVAL);
596 r = file_of_session(session, &p);
600 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
608 return parse_uid(s, uid);
611 static int session_get_string(const char *session, const char *field, char **value) {
612 _cleanup_free_ char *p = NULL, *s = NULL;
615 assert_return(value, -EINVAL);
618 r = file_of_session(session, &p);
622 r = parse_env_file(p, NEWLINE, field, &s, NULL);
635 _public_ int sd_session_get_seat(const char *session, char **seat) {
636 return session_get_string(session, "SEAT", seat);
639 _public_ int sd_session_get_tty(const char *session, char **tty) {
640 return session_get_string(session, "TTY", tty);
643 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
644 _cleanup_free_ char *vtnr_string = NULL;
648 assert_return(vtnr, -EINVAL);
650 r = session_get_string(session, "VTNR", &vtnr_string);
654 r = safe_atou(vtnr_string, &u);
662 _public_ int sd_session_get_service(const char *session, char **service) {
663 return session_get_string(session, "SERVICE", service);
666 _public_ int sd_session_get_type(const char *session, char **type) {
667 return session_get_string(session, "TYPE", type);
670 _public_ int sd_session_get_class(const char *session, char **class) {
671 return session_get_string(session, "CLASS", class);
674 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
675 _cleanup_free_ char *escaped = NULL;
679 assert_return(desktop, -EINVAL);
681 r = session_get_string(session, "DESKTOP", &escaped);
685 r = cunescape(escaped, 0, &t);
693 _public_ int sd_session_get_display(const char *session, char **display) {
694 return session_get_string(session, "DISPLAY", display);
697 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
698 return session_get_string(session, "REMOTE_USER", remote_user);
701 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
702 return session_get_string(session, "REMOTE_HOST", remote_host);
705 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
706 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
709 assert_return(session || uid, -EINVAL);
711 r = file_of_seat(seat, &p);
715 r = parse_env_file(p, NEWLINE,
731 r = parse_uid(t, uid);
744 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
745 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
746 _cleanup_strv_free_ char **a = NULL;
747 _cleanup_free_ uid_t *b = NULL;
751 r = file_of_seat(seat, &p);
755 r = parse_env_file(p, NEWLINE,
757 "ACTIVE_SESSIONS", &t,
765 a = strv_split(s, " ");
771 const char *word, *state;
774 FOREACH_WORD(word, l, t, state)
784 FOREACH_WORD(word, l, t, state) {
785 _cleanup_free_ char *k = NULL;
787 k = strndup(word, l);
791 r = parse_uid(k, b + i);
818 static int seat_get_can(const char *seat, const char *variable) {
819 _cleanup_free_ char *p = NULL, *s = NULL;
824 r = file_of_seat(seat, &p);
828 r = parse_env_file(p, NEWLINE,
838 return parse_boolean(s);
841 _public_ int sd_seat_can_multi_session(const char *seat) {
842 return seat_get_can(seat, "CAN_MULTI_SESSION");
845 _public_ int sd_seat_can_tty(const char *seat) {
846 return seat_get_can(seat, "CAN_TTY");
849 _public_ int sd_seat_can_graphical(const char *seat) {
850 return seat_get_can(seat, "CAN_GRAPHICAL");
853 _public_ int sd_get_seats(char ***seats) {
854 return get_files_in_directory("/run/systemd/seats/", seats);
857 _public_ int sd_get_sessions(char ***sessions) {
858 return get_files_in_directory("/run/systemd/sessions/", sessions);
861 _public_ int sd_get_uids(uid_t **users) {
862 _cleanup_closedir_ DIR *d;
865 _cleanup_free_ uid_t *l = NULL;
867 d = opendir("/run/systemd/users/");
878 if (!de && errno != 0)
884 dirent_ensure_type(d, de);
886 if (!dirent_is_file(de))
889 k = parse_uid(de->d_name, &uid);
894 if ((unsigned) r >= n) {
898 t = realloc(l, sizeof(uid_t) * n);
905 assert((unsigned) r < n);
919 _public_ int sd_get_machine_names(char ***machines) {
920 char **l = NULL, **a, **b;
923 assert_return(machines, -EINVAL);
925 r = get_files_in_directory("/run/systemd/machines/", &l);
932 /* Filter out the unit: symlinks */
933 for (a = l, b = l; *a; a++) {
934 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
950 _public_ int sd_machine_get_class(const char *machine, char **class) {
951 _cleanup_free_ char *c = NULL;
955 assert_return(machine_name_is_valid(machine), -EINVAL);
956 assert_return(class, -EINVAL);
958 p = strjoina("/run/systemd/machines/", machine);
959 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
973 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
974 _cleanup_free_ char *netif = NULL;
975 size_t l, allocated = 0, nr = 0;
977 const char *p, *word, *state;
980 assert_return(machine_name_is_valid(machine), -EINVAL);
981 assert_return(ifindices, -EINVAL);
983 p = strjoina("/run/systemd/machines/", machine);
984 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
994 FOREACH_WORD(word, l, netif, state) {
998 *(char*) (mempcpy(buf, word, l)) = 0;
1000 if (parse_ifindex(buf, &ifi) < 0)
1003 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
1015 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
1016 return (int) (unsigned long) m - 1;
1019 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
1020 return (sd_login_monitor*) (unsigned long) (fd + 1);
1023 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
1027 assert_return(m, -EINVAL);
1029 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1033 if (!category || streq(category, "seat")) {
1034 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
1043 if (!category || streq(category, "session")) {
1044 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
1053 if (!category || streq(category, "uid")) {
1054 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1063 if (!category || streq(category, "machine")) {
1064 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1078 *m = FD_TO_MONITOR(fd);
1082 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1085 assert_return(m, NULL);
1087 fd = MONITOR_TO_FD(m);
1093 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1095 assert_return(m, -EINVAL);
1097 return flush_fd(MONITOR_TO_FD(m));
1100 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1102 assert_return(m, -EINVAL);
1104 return MONITOR_TO_FD(m);
1107 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1109 assert_return(m, -EINVAL);
1111 /* For now we will only return POLLIN here, since we don't
1112 * need anything else ever for inotify. However, let's have
1113 * this API to keep our options open should we later on need
1118 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1120 assert_return(m, -EINVAL);
1121 assert_return(timeout_usec, -EINVAL);
1123 /* For now we will only return (uint64_t) -1, since we don't
1124 * need any timeout. However, let's have this API to keep our
1125 * options open should we later on need it. */
1126 *timeout_usec = (uint64_t) -1;