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-shared.h"
34 #include "formats-util.h"
37 _public_ int sd_pid_get_session(pid_t pid, char **session) {
39 assert_return(pid >= 0, -EINVAL);
40 assert_return(session, -EINVAL);
42 return cg_pid_get_session(pid, session);
45 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
47 assert_return(pid >= 0, -EINVAL);
48 assert_return(unit, -EINVAL);
53 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
55 assert_return(pid >= 0, -EINVAL);
56 assert_return(unit, -EINVAL);
61 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
63 assert_return(pid >= 0, -EINVAL);
64 assert_return(name, -EINVAL);
69 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
71 assert_return(pid >= 0, -EINVAL);
72 assert_return(slice, -EINVAL);
77 _public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
79 assert_return(pid >= 0, -EINVAL);
80 assert_return(slice, -EINVAL);
82 return cg_pid_get_user_slice(pid, slice);
85 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
87 assert_return(pid >= 0, -EINVAL);
88 assert_return(uid, -EINVAL);
93 _public_ int sd_peer_get_session(int fd, char **session) {
94 struct ucred ucred = {};
97 assert_return(fd >= 0, -EINVAL);
98 assert_return(session, -EINVAL);
100 r = getpeercred(fd, &ucred);
104 return cg_pid_get_session(ucred.pid, session);
107 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
111 assert_return(fd >= 0, -EINVAL);
112 assert_return(uid, -EINVAL);
114 r = getpeercred(fd, &ucred);
121 _public_ int sd_peer_get_unit(int fd, char **unit) {
125 assert_return(fd >= 0, -EINVAL);
126 assert_return(unit, -EINVAL);
128 r = getpeercred(fd, &ucred);
135 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
139 assert_return(fd >= 0, -EINVAL);
140 assert_return(unit, -EINVAL);
142 r = getpeercred(fd, &ucred);
149 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
153 assert_return(fd >= 0, -EINVAL);
154 assert_return(machine, -EINVAL);
156 r = getpeercred(fd, &ucred);
163 _public_ int sd_peer_get_slice(int fd, char **slice) {
167 assert_return(fd >= 0, -EINVAL);
168 assert_return(slice, -EINVAL);
170 r = getpeercred(fd, &ucred);
177 _public_ int sd_peer_get_user_slice(int fd, char **slice) {
181 assert_return(fd >= 0, -EINVAL);
182 assert_return(slice, -EINVAL);
184 r = getpeercred(fd, &ucred);
188 return cg_pid_get_user_slice(ucred.pid, slice);
191 static int file_of_uid(uid_t uid, char **p) {
194 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
200 _public_ int sd_uid_get_state(uid_t uid, char**state) {
201 _cleanup_free_ char *p = NULL;
205 assert_return(state, -EINVAL);
207 r = file_of_uid(uid, &p);
211 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
214 s = strdup("offline");
228 _public_ int sd_uid_get_display(uid_t uid, char **session) {
229 _cleanup_free_ char *p = NULL, *s = NULL;
232 assert_return(session, -EINVAL);
234 r = file_of_uid(uid, &p);
238 r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
251 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
252 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
255 const char *word, *variable, *state;
257 assert_return(seat, -EINVAL);
259 variable = require_active ? "ACTIVE_UID" : "UIDS";
261 p = strappend("/run/systemd/seats/", seat);
265 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
273 if (asprintf(&t, UID_FMT, uid) < 0)
276 FOREACH_WORD(word, l, s, state) {
277 if (strneq(t, word, l))
284 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
285 _cleanup_free_ char *p = NULL, *s = NULL;
289 r = file_of_uid(uid, &p);
293 r = parse_env_file(p, NEWLINE,
312 a = strv_split(s, " ");
328 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
329 return uid_get_array(
331 require_active == 0 ? "ONLINE_SESSIONS" :
332 require_active > 0 ? "ACTIVE_SESSIONS" :
337 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
338 return uid_get_array(
340 require_active == 0 ? "ONLINE_SEATS" :
341 require_active > 0 ? "ACTIVE_SEATS" :
346 static int file_of_session(const char *session, char **_p) {
353 if (!session_id_valid(session))
356 p = strappend("/run/systemd/sessions/", session);
358 _cleanup_free_ char *buf = NULL;
360 r = sd_pid_get_session(0, &buf);
364 p = strappend("/run/systemd/sessions/", buf);
374 _public_ int sd_session_is_active(const char *session) {
376 _cleanup_free_ char *p = NULL, *s = NULL;
378 r = file_of_session(session, &p);
382 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
389 return parse_boolean(s);
392 _public_ int sd_session_is_remote(const char *session) {
394 _cleanup_free_ char *p = NULL, *s = NULL;
396 r = file_of_session(session, &p);
400 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
407 return parse_boolean(s);
410 _public_ int sd_session_get_state(const char *session, char **state) {
411 _cleanup_free_ char *p = NULL, *s = NULL;
414 assert_return(state, -EINVAL);
416 r = file_of_session(session, &p);
420 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
432 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
434 _cleanup_free_ char *p = NULL, *s = NULL;
436 assert_return(uid, -EINVAL);
438 r = file_of_session(session, &p);
442 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
449 return parse_uid(s, uid);
452 static int session_get_string(const char *session, const char *field, char **value) {
453 _cleanup_free_ char *p = NULL, *s = NULL;
456 assert_return(value, -EINVAL);
458 r = file_of_session(session, &p);
462 r = parse_env_file(p, NEWLINE, field, &s, NULL);
474 _public_ int sd_session_get_seat(const char *session, char **seat) {
475 return session_get_string(session, "SEAT", seat);
478 _public_ int sd_session_get_tty(const char *session, char **tty) {
479 return session_get_string(session, "TTY", tty);
482 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
483 _cleanup_free_ char *vtnr_string = NULL;
487 r = session_get_string(session, "VTNR", &vtnr_string);
491 r = safe_atou(vtnr_string, &u);
499 _public_ int sd_session_get_service(const char *session, char **service) {
500 return session_get_string(session, "SERVICE", service);
503 _public_ int sd_session_get_type(const char *session, char **type) {
504 return session_get_string(session, "TYPE", type);
507 _public_ int sd_session_get_class(const char *session, char **class) {
508 return session_get_string(session, "CLASS", class);
511 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
512 _cleanup_free_ char *escaped = NULL;
516 assert_return(desktop, -EINVAL);
518 r = session_get_string(session, "DESKTOP", &escaped);
522 r = cunescape(escaped, 0, &t);
530 _public_ int sd_session_get_display(const char *session, char **display) {
531 return session_get_string(session, "DISPLAY", display);
534 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
535 return session_get_string(session, "REMOTE_USER", remote_user);
538 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
539 return session_get_string(session, "REMOTE_HOST", remote_host);
542 static int file_of_seat(const char *seat, char **_p) {
549 p = strappend("/run/systemd/seats/", seat);
551 _cleanup_free_ char *buf = NULL;
553 r = sd_session_get_seat(NULL, &buf);
557 p = strappend("/run/systemd/seats/", buf);
568 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
569 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
572 assert_return(session || uid, -EINVAL);
574 r = file_of_seat(seat, &p);
578 r = parse_env_file(p, NEWLINE,
592 r = parse_uid(t, uid);
605 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
606 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
607 _cleanup_strv_free_ char **a = NULL;
608 _cleanup_free_ uid_t *b = NULL;
612 r = file_of_seat(seat, &p);
616 r = parse_env_file(p, NEWLINE,
618 "ACTIVE_SESSIONS", &t,
625 a = strv_split(s, " ");
631 const char *word, *state;
634 FOREACH_WORD(word, l, t, state)
644 FOREACH_WORD(word, l, t, state) {
645 _cleanup_free_ char *k = NULL;
647 k = strndup(word, l);
651 r = parse_uid(k, b + i);
679 static int seat_get_can(const char *seat, const char *variable) {
680 _cleanup_free_ char *p = NULL, *s = NULL;
683 assert_return(variable, -EINVAL);
685 r = file_of_seat(seat, &p);
689 r = parse_env_file(p, NEWLINE,
697 return parse_boolean(s);
700 _public_ int sd_seat_can_multi_session(const char *seat) {
701 return seat_get_can(seat, "CAN_MULTI_SESSION");
704 _public_ int sd_seat_can_tty(const char *seat) {
705 return seat_get_can(seat, "CAN_TTY");
708 _public_ int sd_seat_can_graphical(const char *seat) {
709 return seat_get_can(seat, "CAN_GRAPHICAL");
712 _public_ int sd_get_seats(char ***seats) {
713 return get_files_in_directory("/run/systemd/seats/", seats);
716 _public_ int sd_get_sessions(char ***sessions) {
717 return get_files_in_directory("/run/systemd/sessions/", sessions);
720 _public_ int sd_get_uids(uid_t **users) {
721 _cleanup_closedir_ DIR *d;
724 _cleanup_free_ uid_t *l = NULL;
726 d = opendir("/run/systemd/users/");
737 if (!de && errno != 0)
743 dirent_ensure_type(d, de);
745 if (!dirent_is_file(de))
748 k = parse_uid(de->d_name, &uid);
753 if ((unsigned) r >= n) {
757 t = realloc(l, sizeof(uid_t) * n);
764 assert((unsigned) r < n);
778 _public_ int sd_get_machine_names(char ***machines) {
779 char **l = NULL, **a, **b;
782 assert_return(machines, -EINVAL);
784 r = get_files_in_directory("/run/systemd/machines/", &l);
791 /* Filter out the unit: symlinks */
792 for (a = l, b = l; *a; a++) {
793 if (startswith(*a, "unit:"))
809 _public_ int sd_machine_get_class(const char *machine, char **class) {
810 _cleanup_free_ char *c = NULL;
814 assert_return(machine_name_is_valid(machine), -EINVAL);
815 assert_return(class, -EINVAL);
817 p = strjoina("/run/systemd/machines/", machine);
818 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
830 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
831 _cleanup_free_ char *netif = NULL;
832 size_t l, allocated = 0, nr = 0;
834 const char *p, *word, *state;
837 assert_return(machine_name_is_valid(machine), -EINVAL);
838 assert_return(ifindices, -EINVAL);
840 p = strjoina("/run/systemd/machines/", machine);
841 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
849 FOREACH_WORD(word, l, netif, state) {
853 *(char*) (mempcpy(buf, word, l)) = 0;
855 if (safe_atoi(buf, &ifi) < 0)
860 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
872 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
873 return (int) (unsigned long) m - 1;
876 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
877 return (sd_login_monitor*) (unsigned long) (fd + 1);
880 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
884 assert_return(m, -EINVAL);
886 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
890 if (!category || streq(category, "seat")) {
891 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
900 if (!category || streq(category, "session")) {
901 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
910 if (!category || streq(category, "uid")) {
911 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
920 if (!category || streq(category, "machine")) {
921 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
935 *m = FD_TO_MONITOR(fd);
939 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
942 assert_return(m, NULL);
944 fd = MONITOR_TO_FD(m);
950 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
952 assert_return(m, -EINVAL);
954 return flush_fd(MONITOR_TO_FD(m));
957 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
959 assert_return(m, -EINVAL);
961 return MONITOR_TO_FD(m);
964 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
966 assert_return(m, -EINVAL);
968 /* For now we will only return POLLIN here, since we don't
969 * need anything else ever for inotify. However, let's have
970 * this API to keep our options open should we later on need
975 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
977 assert_return(m, -EINVAL);
978 assert_return(timeout_usec, -EINVAL);
980 /* For now we will only return (uint64_t) -1, since we don't
981 * need any timeout. However, let's have this API to keep our
982 * options open should we later on need it. */
983 *timeout_usec = (uint64_t) -1;