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 return cg_pid_get_unit(pid, unit);
64 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
66 assert_return(pid >= 0, -EINVAL);
67 assert_return(unit, -EINVAL);
69 return cg_pid_get_user_unit(pid, unit);
72 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
74 assert_return(pid >= 0, -EINVAL);
75 assert_return(name, -EINVAL);
77 return cg_pid_get_machine_name(pid, name);
80 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
82 assert_return(pid >= 0, -EINVAL);
83 assert_return(slice, -EINVAL);
85 return cg_pid_get_slice(pid, slice);
88 _public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
90 assert_return(pid >= 0, -EINVAL);
91 assert_return(slice, -EINVAL);
93 return cg_pid_get_user_slice(pid, slice);
96 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
98 assert_return(pid >= 0, -EINVAL);
99 assert_return(uid, -EINVAL);
101 return cg_pid_get_owner_uid(pid, uid);
104 _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
108 assert_return(pid >= 0, -EINVAL);
109 assert_return(cgroup, -EINVAL);
111 r = cg_pid_get_path(ELOGIND_CGROUP_CONTROLLER, pid, &c);
115 /* The internal APIs return the empty string for the root
116 * cgroup, let's return the "/" in the public APIs instead, as
117 * that's easier and less ambigious for people to grok. */
130 _public_ int sd_peer_get_session(int fd, char **session) {
131 struct ucred ucred = {};
134 assert_return(fd >= 0, -EBADF);
135 assert_return(session, -EINVAL);
137 r = getpeercred(fd, &ucred);
141 return cg_pid_get_session(ucred.pid, session);
144 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
148 assert_return(fd >= 0, -EBADF);
149 assert_return(uid, -EINVAL);
151 r = getpeercred(fd, &ucred);
155 return cg_pid_get_owner_uid(ucred.pid, uid);
158 _public_ int sd_peer_get_unit(int fd, char **unit) {
162 assert_return(fd >= 0, -EBADF);
163 assert_return(unit, -EINVAL);
165 r = getpeercred(fd, &ucred);
169 return cg_pid_get_unit(ucred.pid, unit);
172 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
176 assert_return(fd >= 0, -EBADF);
177 assert_return(unit, -EINVAL);
179 r = getpeercred(fd, &ucred);
183 return cg_pid_get_user_unit(ucred.pid, unit);
186 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
190 assert_return(fd >= 0, -EBADF);
191 assert_return(machine, -EINVAL);
193 r = getpeercred(fd, &ucred);
197 return cg_pid_get_machine_name(ucred.pid, machine);
200 _public_ int sd_peer_get_slice(int fd, char **slice) {
204 assert_return(fd >= 0, -EBADF);
205 assert_return(slice, -EINVAL);
207 r = getpeercred(fd, &ucred);
211 return cg_pid_get_slice(ucred.pid, slice);
214 _public_ int sd_peer_get_user_slice(int fd, char **slice) {
218 assert_return(fd >= 0, -EBADF);
219 assert_return(slice, -EINVAL);
221 r = getpeercred(fd, &ucred);
225 return cg_pid_get_user_slice(ucred.pid, slice);
228 _public_ int sd_peer_get_cgroup(int fd, char **cgroup) {
232 assert_return(fd >= 0, -EBADF);
233 assert_return(cgroup, -EINVAL);
235 r = getpeercred(fd, &ucred);
239 return sd_pid_get_cgroup(ucred.pid, cgroup);
242 static int file_of_uid(uid_t uid, char **p) {
244 assert_return(uid_is_valid(uid), -EINVAL);
247 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
253 _public_ int sd_uid_get_state(uid_t uid, char**state) {
254 _cleanup_free_ char *p = NULL;
258 assert_return(state, -EINVAL);
260 r = file_of_uid(uid, &p);
264 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
267 s = strdup("offline");
285 _public_ int sd_uid_get_display(uid_t uid, char **session) {
286 _cleanup_free_ char *p = NULL, *s = NULL;
289 assert_return(session, -EINVAL);
291 r = file_of_uid(uid, &p);
295 r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
309 static int file_of_seat(const char *seat, char **_p) {
316 if (!filename_is_valid(seat))
319 p = strappend("/run/systemd/seats/", seat);
321 _cleanup_free_ char *buf = NULL;
323 r = sd_session_get_seat(NULL, &buf);
327 p = strappend("/run/systemd/seats/", buf);
338 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
339 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
342 const char *word, *variable, *state;
344 assert_return(uid_is_valid(uid), -EINVAL);
346 r = file_of_seat(seat, &p);
350 variable = require_active ? "ACTIVE_UID" : "UIDS";
352 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
360 if (asprintf(&t, UID_FMT, uid) < 0)
363 FOREACH_WORD(word, l, s, state)
364 if (strneq(t, word, l))
370 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
371 _cleanup_free_ char *p = NULL, *s = NULL;
377 r = file_of_uid(uid, &p);
381 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
382 if (r == -ENOENT || (r >= 0 && isempty(s))) {
390 a = strv_split(s, " ");
405 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
406 return uid_get_array(
408 require_active == 0 ? "ONLINE_SESSIONS" :
409 require_active > 0 ? "ACTIVE_SESSIONS" :
414 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
415 return uid_get_array(
417 require_active == 0 ? "ONLINE_SEATS" :
418 require_active > 0 ? "ACTIVE_SEATS" :
423 static int file_of_session(const char *session, char **_p) {
430 if (!session_id_valid(session))
433 p = strappend("/run/systemd/sessions/", session);
435 _cleanup_free_ char *buf = NULL;
437 r = sd_pid_get_session(0, &buf);
441 p = strappend("/run/systemd/sessions/", buf);
451 _public_ int sd_session_is_active(const char *session) {
452 _cleanup_free_ char *p = NULL, *s = NULL;
455 r = file_of_session(session, &p);
459 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
467 return parse_boolean(s);
470 _public_ int sd_session_is_remote(const char *session) {
471 _cleanup_free_ char *p = NULL, *s = NULL;
474 r = file_of_session(session, &p);
478 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
486 return parse_boolean(s);
489 _public_ int sd_session_get_state(const char *session, char **state) {
490 _cleanup_free_ char *p = NULL, *s = NULL;
493 assert_return(state, -EINVAL);
495 r = file_of_session(session, &p);
499 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
513 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
515 _cleanup_free_ char *p = NULL, *s = NULL;
517 assert_return(uid, -EINVAL);
519 r = file_of_session(session, &p);
523 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
531 return parse_uid(s, uid);
534 static int session_get_string(const char *session, const char *field, char **value) {
535 _cleanup_free_ char *p = NULL, *s = NULL;
538 assert_return(value, -EINVAL);
541 r = file_of_session(session, &p);
545 r = parse_env_file(p, NEWLINE, field, &s, NULL);
558 _public_ int sd_session_get_seat(const char *session, char **seat) {
559 return session_get_string(session, "SEAT", seat);
562 _public_ int sd_session_get_tty(const char *session, char **tty) {
563 return session_get_string(session, "TTY", tty);
566 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
567 _cleanup_free_ char *vtnr_string = NULL;
571 assert_return(vtnr, -EINVAL);
573 r = session_get_string(session, "VTNR", &vtnr_string);
577 r = safe_atou(vtnr_string, &u);
585 _public_ int sd_session_get_service(const char *session, char **service) {
586 return session_get_string(session, "SERVICE", service);
589 _public_ int sd_session_get_type(const char *session, char **type) {
590 return session_get_string(session, "TYPE", type);
593 _public_ int sd_session_get_class(const char *session, char **class) {
594 return session_get_string(session, "CLASS", class);
597 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
598 _cleanup_free_ char *escaped = NULL;
602 assert_return(desktop, -EINVAL);
604 r = session_get_string(session, "DESKTOP", &escaped);
608 r = cunescape(escaped, 0, &t);
616 _public_ int sd_session_get_display(const char *session, char **display) {
617 return session_get_string(session, "DISPLAY", display);
620 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
621 return session_get_string(session, "REMOTE_USER", remote_user);
624 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
625 return session_get_string(session, "REMOTE_HOST", remote_host);
628 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
629 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
632 assert_return(session || uid, -EINVAL);
634 r = file_of_seat(seat, &p);
638 r = parse_env_file(p, NEWLINE,
654 r = parse_uid(t, uid);
667 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
668 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
669 _cleanup_strv_free_ char **a = NULL;
670 _cleanup_free_ uid_t *b = NULL;
674 r = file_of_seat(seat, &p);
678 r = parse_env_file(p, NEWLINE,
680 "ACTIVE_SESSIONS", &t,
688 a = strv_split(s, " ");
694 const char *word, *state;
697 FOREACH_WORD(word, l, t, state)
707 FOREACH_WORD(word, l, t, state) {
708 _cleanup_free_ char *k = NULL;
710 k = strndup(word, l);
714 r = parse_uid(k, b + i);
741 static int seat_get_can(const char *seat, const char *variable) {
742 _cleanup_free_ char *p = NULL, *s = NULL;
747 r = file_of_seat(seat, &p);
751 r = parse_env_file(p, NEWLINE,
761 return parse_boolean(s);
764 _public_ int sd_seat_can_multi_session(const char *seat) {
765 return seat_get_can(seat, "CAN_MULTI_SESSION");
768 _public_ int sd_seat_can_tty(const char *seat) {
769 return seat_get_can(seat, "CAN_TTY");
772 _public_ int sd_seat_can_graphical(const char *seat) {
773 return seat_get_can(seat, "CAN_GRAPHICAL");
776 _public_ int sd_get_seats(char ***seats) {
777 return get_files_in_directory("/run/systemd/seats/", seats);
780 _public_ int sd_get_sessions(char ***sessions) {
781 return get_files_in_directory("/run/systemd/sessions/", sessions);
784 _public_ int sd_get_uids(uid_t **users) {
785 _cleanup_closedir_ DIR *d;
788 _cleanup_free_ uid_t *l = NULL;
790 d = opendir("/run/systemd/users/");
801 if (!de && errno != 0)
807 dirent_ensure_type(d, de);
809 if (!dirent_is_file(de))
812 k = parse_uid(de->d_name, &uid);
817 if ((unsigned) r >= n) {
821 t = realloc(l, sizeof(uid_t) * n);
828 assert((unsigned) r < n);
842 _public_ int sd_get_machine_names(char ***machines) {
843 char **l = NULL, **a, **b;
846 assert_return(machines, -EINVAL);
848 r = get_files_in_directory("/run/systemd/machines/", &l);
855 /* Filter out the unit: symlinks */
856 for (a = l, b = l; *a; a++) {
857 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
873 _public_ int sd_machine_get_class(const char *machine, char **class) {
874 _cleanup_free_ char *c = NULL;
878 assert_return(machine_name_is_valid(machine), -EINVAL);
879 assert_return(class, -EINVAL);
881 p = strjoina("/run/systemd/machines/", machine);
882 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
896 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
897 _cleanup_free_ char *netif = NULL;
898 size_t l, allocated = 0, nr = 0;
900 const char *p, *word, *state;
903 assert_return(machine_name_is_valid(machine), -EINVAL);
904 assert_return(ifindices, -EINVAL);
906 p = strjoina("/run/systemd/machines/", machine);
907 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
917 FOREACH_WORD(word, l, netif, state) {
921 *(char*) (mempcpy(buf, word, l)) = 0;
923 if (safe_atoi(buf, &ifi) < 0)
928 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
940 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
941 return (int) (unsigned long) m - 1;
944 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
945 return (sd_login_monitor*) (unsigned long) (fd + 1);
948 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
952 assert_return(m, -EINVAL);
954 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
958 if (!category || streq(category, "seat")) {
959 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
968 if (!category || streq(category, "session")) {
969 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
978 if (!category || streq(category, "uid")) {
979 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
988 if (!category || streq(category, "machine")) {
989 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1003 *m = FD_TO_MONITOR(fd);
1007 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1010 assert_return(m, NULL);
1012 fd = MONITOR_TO_FD(m);
1018 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1020 assert_return(m, -EINVAL);
1022 return flush_fd(MONITOR_TO_FD(m));
1025 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1027 assert_return(m, -EINVAL);
1029 return MONITOR_TO_FD(m);
1032 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1034 assert_return(m, -EINVAL);
1036 /* For now we will only return POLLIN here, since we don't
1037 * need anything else ever for inotify. However, let's have
1038 * this API to keep our options open should we later on need
1043 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1045 assert_return(m, -EINVAL);
1046 assert_return(timeout_usec, -EINVAL);
1048 /* For now we will only return (uint64_t) -1, since we don't
1049 * need any timeout. However, let's have this API to keep our
1050 * options open should we later on need it. */
1051 *timeout_usec = (uint64_t) -1;