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_peer_get_session(int fd, char **session) {
105 struct ucred ucred = {};
108 assert_return(fd >= 0, -EBADF);
109 assert_return(session, -EINVAL);
111 r = getpeercred(fd, &ucred);
115 return cg_pid_get_session(ucred.pid, session);
118 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
122 assert_return(fd >= 0, -EBADF);
123 assert_return(uid, -EINVAL);
125 r = getpeercred(fd, &ucred);
129 return cg_pid_get_owner_uid(ucred.pid, uid);
132 _public_ int sd_peer_get_unit(int fd, char **unit) {
136 assert_return(fd >= 0, -EBADF);
137 assert_return(unit, -EINVAL);
139 r = getpeercred(fd, &ucred);
143 return cg_pid_get_unit(ucred.pid, unit);
146 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
150 assert_return(fd >= 0, -EBADF);
151 assert_return(unit, -EINVAL);
153 r = getpeercred(fd, &ucred);
157 return cg_pid_get_user_unit(ucred.pid, unit);
160 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
164 assert_return(fd >= 0, -EBADF);
165 assert_return(machine, -EINVAL);
167 r = getpeercred(fd, &ucred);
171 return cg_pid_get_machine_name(ucred.pid, machine);
174 _public_ int sd_peer_get_slice(int fd, char **slice) {
178 assert_return(fd >= 0, -EBADF);
179 assert_return(slice, -EINVAL);
181 r = getpeercred(fd, &ucred);
185 return cg_pid_get_slice(ucred.pid, slice);
188 _public_ int sd_peer_get_user_slice(int fd, char **slice) {
192 assert_return(fd >= 0, -EBADF);
193 assert_return(slice, -EINVAL);
195 r = getpeercred(fd, &ucred);
199 return cg_pid_get_user_slice(ucred.pid, slice);
202 static int file_of_uid(uid_t uid, char **p) {
204 assert_return(uid_is_valid(uid), -EINVAL);
207 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
213 _public_ int sd_uid_get_state(uid_t uid, char**state) {
214 _cleanup_free_ char *p = NULL;
218 assert_return(state, -EINVAL);
220 r = file_of_uid(uid, &p);
224 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
227 s = strdup("offline");
245 _public_ int sd_uid_get_display(uid_t uid, char **session) {
246 _cleanup_free_ char *p = NULL, *s = NULL;
249 assert_return(session, -EINVAL);
251 r = file_of_uid(uid, &p);
255 r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
269 static int file_of_seat(const char *seat, char **_p) {
276 if (!filename_is_valid(seat))
279 p = strappend("/run/systemd/seats/", seat);
281 _cleanup_free_ char *buf = NULL;
283 r = sd_session_get_seat(NULL, &buf);
287 p = strappend("/run/systemd/seats/", buf);
298 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
299 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
302 const char *word, *variable, *state;
304 assert_return(uid_is_valid(uid), -EINVAL);
306 r = file_of_seat(seat, &p);
310 variable = require_active ? "ACTIVE_UID" : "UIDS";
312 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
320 if (asprintf(&t, UID_FMT, uid) < 0)
323 FOREACH_WORD(word, l, s, state)
324 if (strneq(t, word, l))
330 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
331 _cleanup_free_ char *p = NULL, *s = NULL;
337 r = file_of_uid(uid, &p);
341 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
342 if (r == -ENOENT || (r >= 0 && isempty(s))) {
350 a = strv_split(s, " ");
365 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
366 return uid_get_array(
368 require_active == 0 ? "ONLINE_SESSIONS" :
369 require_active > 0 ? "ACTIVE_SESSIONS" :
374 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
375 return uid_get_array(
377 require_active == 0 ? "ONLINE_SEATS" :
378 require_active > 0 ? "ACTIVE_SEATS" :
383 static int file_of_session(const char *session, char **_p) {
390 if (!session_id_valid(session))
393 p = strappend("/run/systemd/sessions/", session);
395 _cleanup_free_ char *buf = NULL;
397 r = sd_pid_get_session(0, &buf);
401 p = strappend("/run/systemd/sessions/", buf);
411 _public_ int sd_session_is_active(const char *session) {
412 _cleanup_free_ char *p = NULL, *s = NULL;
415 r = file_of_session(session, &p);
419 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
427 return parse_boolean(s);
430 _public_ int sd_session_is_remote(const char *session) {
431 _cleanup_free_ char *p = NULL, *s = NULL;
434 r = file_of_session(session, &p);
438 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
446 return parse_boolean(s);
449 _public_ int sd_session_get_state(const char *session, char **state) {
450 _cleanup_free_ char *p = NULL, *s = NULL;
453 assert_return(state, -EINVAL);
455 r = file_of_session(session, &p);
459 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
473 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
475 _cleanup_free_ char *p = NULL, *s = NULL;
477 assert_return(uid, -EINVAL);
479 r = file_of_session(session, &p);
483 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
491 return parse_uid(s, uid);
494 static int session_get_string(const char *session, const char *field, char **value) {
495 _cleanup_free_ char *p = NULL, *s = NULL;
498 assert_return(value, -EINVAL);
501 r = file_of_session(session, &p);
505 r = parse_env_file(p, NEWLINE, field, &s, NULL);
518 _public_ int sd_session_get_seat(const char *session, char **seat) {
519 return session_get_string(session, "SEAT", seat);
522 _public_ int sd_session_get_tty(const char *session, char **tty) {
523 return session_get_string(session, "TTY", tty);
526 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
527 _cleanup_free_ char *vtnr_string = NULL;
531 assert_return(vtnr, -EINVAL);
533 r = session_get_string(session, "VTNR", &vtnr_string);
537 r = safe_atou(vtnr_string, &u);
545 _public_ int sd_session_get_service(const char *session, char **service) {
546 return session_get_string(session, "SERVICE", service);
549 _public_ int sd_session_get_type(const char *session, char **type) {
550 return session_get_string(session, "TYPE", type);
553 _public_ int sd_session_get_class(const char *session, char **class) {
554 return session_get_string(session, "CLASS", class);
557 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
558 _cleanup_free_ char *escaped = NULL;
562 assert_return(desktop, -EINVAL);
564 r = session_get_string(session, "DESKTOP", &escaped);
568 r = cunescape(escaped, 0, &t);
576 _public_ int sd_session_get_display(const char *session, char **display) {
577 return session_get_string(session, "DISPLAY", display);
580 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
581 return session_get_string(session, "REMOTE_USER", remote_user);
584 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
585 return session_get_string(session, "REMOTE_HOST", remote_host);
588 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
589 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
592 assert_return(session || uid, -EINVAL);
594 r = file_of_seat(seat, &p);
598 r = parse_env_file(p, NEWLINE,
614 r = parse_uid(t, uid);
627 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
628 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
629 _cleanup_strv_free_ char **a = NULL;
630 _cleanup_free_ uid_t *b = NULL;
634 r = file_of_seat(seat, &p);
638 r = parse_env_file(p, NEWLINE,
640 "ACTIVE_SESSIONS", &t,
648 a = strv_split(s, " ");
654 const char *word, *state;
657 FOREACH_WORD(word, l, t, state)
667 FOREACH_WORD(word, l, t, state) {
668 _cleanup_free_ char *k = NULL;
670 k = strndup(word, l);
674 r = parse_uid(k, b + i);
701 static int seat_get_can(const char *seat, const char *variable) {
702 _cleanup_free_ char *p = NULL, *s = NULL;
707 r = file_of_seat(seat, &p);
711 r = parse_env_file(p, NEWLINE,
721 return parse_boolean(s);
724 _public_ int sd_seat_can_multi_session(const char *seat) {
725 return seat_get_can(seat, "CAN_MULTI_SESSION");
728 _public_ int sd_seat_can_tty(const char *seat) {
729 return seat_get_can(seat, "CAN_TTY");
732 _public_ int sd_seat_can_graphical(const char *seat) {
733 return seat_get_can(seat, "CAN_GRAPHICAL");
736 _public_ int sd_get_seats(char ***seats) {
737 return get_files_in_directory("/run/systemd/seats/", seats);
740 _public_ int sd_get_sessions(char ***sessions) {
741 return get_files_in_directory("/run/systemd/sessions/", sessions);
744 _public_ int sd_get_uids(uid_t **users) {
745 _cleanup_closedir_ DIR *d;
748 _cleanup_free_ uid_t *l = NULL;
750 d = opendir("/run/systemd/users/");
761 if (!de && errno != 0)
767 dirent_ensure_type(d, de);
769 if (!dirent_is_file(de))
772 k = parse_uid(de->d_name, &uid);
777 if ((unsigned) r >= n) {
781 t = realloc(l, sizeof(uid_t) * n);
788 assert((unsigned) r < n);
802 _public_ int sd_get_machine_names(char ***machines) {
803 char **l = NULL, **a, **b;
806 assert_return(machines, -EINVAL);
808 r = get_files_in_directory("/run/systemd/machines/", &l);
815 /* Filter out the unit: symlinks */
816 for (a = l, b = l; *a; a++) {
817 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
833 _public_ int sd_machine_get_class(const char *machine, char **class) {
834 _cleanup_free_ char *c = NULL;
838 assert_return(machine_name_is_valid(machine), -EINVAL);
839 assert_return(class, -EINVAL);
841 p = strjoina("/run/systemd/machines/", machine);
842 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
856 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
857 _cleanup_free_ char *netif = NULL;
858 size_t l, allocated = 0, nr = 0;
860 const char *p, *word, *state;
863 assert_return(machine_name_is_valid(machine), -EINVAL);
864 assert_return(ifindices, -EINVAL);
866 p = strjoina("/run/systemd/machines/", machine);
867 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
877 FOREACH_WORD(word, l, netif, state) {
881 *(char*) (mempcpy(buf, word, l)) = 0;
883 if (safe_atoi(buf, &ifi) < 0)
888 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
900 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
901 return (int) (unsigned long) m - 1;
904 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
905 return (sd_login_monitor*) (unsigned long) (fd + 1);
908 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
912 assert_return(m, -EINVAL);
914 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
918 if (!category || streq(category, "seat")) {
919 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
928 if (!category || streq(category, "session")) {
929 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
938 if (!category || streq(category, "uid")) {
939 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
948 if (!category || streq(category, "machine")) {
949 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
963 *m = FD_TO_MONITOR(fd);
967 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
970 assert_return(m, NULL);
972 fd = MONITOR_TO_FD(m);
978 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
980 assert_return(m, -EINVAL);
982 return flush_fd(MONITOR_TO_FD(m));
985 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
987 assert_return(m, -EINVAL);
989 return MONITOR_TO_FD(m);
992 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
994 assert_return(m, -EINVAL);
996 /* For now we will only return POLLIN here, since we don't
997 * need anything else ever for inotify. However, let's have
998 * this API to keep our options open should we later on need
1003 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1005 assert_return(m, -EINVAL);
1006 assert_return(timeout_usec, -EINVAL);
1008 /* For now we will only return (uint64_t) -1, since we don't
1009 * need any timeout. However, let's have this API to keep our
1010 * options open should we later on need it. */
1011 *timeout_usec = (uint64_t) -1;