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"
36 _public_ int sd_pid_get_session(pid_t pid, char **session) {
38 assert_return(pid >= 0, -EINVAL);
39 assert_return(session, -EINVAL);
41 return cg_pid_get_session(pid, session);
44 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
46 assert_return(pid >= 0, -EINVAL);
47 assert_return(unit, -EINVAL);
49 return cg_pid_get_unit(pid, unit);
52 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
54 assert_return(pid >= 0, -EINVAL);
55 assert_return(unit, -EINVAL);
57 return cg_pid_get_user_unit(pid, unit);
60 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
62 assert_return(pid >= 0, -EINVAL);
63 assert_return(name, -EINVAL);
65 return cg_pid_get_machine_name(pid, name);
68 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
70 assert_return(pid >= 0, -EINVAL);
71 assert_return(slice, -EINVAL);
73 return cg_pid_get_slice(pid, slice);
76 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
78 assert_return(pid >= 0, -EINVAL);
79 assert_return(uid, -EINVAL);
81 return cg_pid_get_owner_uid(pid, uid);
84 _public_ int sd_peer_get_session(int fd, char **session) {
88 assert_return(fd >= 0, -EINVAL);
89 assert_return(session, -EINVAL);
91 r = getpeercred(fd, &ucred);
95 return cg_pid_get_session(ucred.pid, session);
98 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
102 assert_return(fd >= 0, -EINVAL);
103 assert_return(uid, -EINVAL);
105 r = getpeercred(fd, &ucred);
109 return cg_pid_get_owner_uid(ucred.pid, uid);
112 _public_ int sd_peer_get_unit(int fd, char **unit) {
116 assert_return(fd >= 0, -EINVAL);
117 assert_return(unit, -EINVAL);
119 r = getpeercred(fd, &ucred);
123 return cg_pid_get_unit(ucred.pid, unit);
126 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
130 assert_return(fd >= 0, -EINVAL);
131 assert_return(unit, -EINVAL);
133 r = getpeercred(fd, &ucred);
137 return cg_pid_get_user_unit(ucred.pid, unit);
140 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
144 assert_return(fd >= 0, -EINVAL);
145 assert_return(machine, -EINVAL);
147 r = getpeercred(fd, &ucred);
151 return cg_pid_get_machine_name(ucred.pid, machine);
154 _public_ int sd_peer_get_slice(int fd, char **slice) {
158 assert_return(fd >= 0, -EINVAL);
159 assert_return(slice, -EINVAL);
161 r = getpeercred(fd, &ucred);
165 return cg_pid_get_slice(ucred.pid, slice);
168 _public_ int sd_uid_get_state(uid_t uid, char**state) {
169 _cleanup_free_ char *p = NULL;
173 assert_return(state, -EINVAL);
175 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
178 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
181 s = strdup("offline");
195 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
197 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
200 const char *variable;
202 assert_return(seat, -EINVAL);
204 variable = require_active ? "ACTIVE_UID" : "UIDS";
206 p = strappend("/run/systemd/seats/", seat);
210 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
218 if (asprintf(&t, "%lu", (unsigned long) uid) < 0)
221 FOREACH_WORD(w, l, s, state) {
229 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
230 _cleanup_free_ char *p = NULL, *s = NULL;
234 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
237 r = parse_env_file(p, NEWLINE,
256 a = strv_split(s, " ");
272 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
273 return uid_get_array(
275 require_active == 0 ? "ONLINE_SESSIONS" :
276 require_active > 0 ? "ACTIVE_SESSIONS" :
281 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
282 return uid_get_array(
284 require_active == 0 ? "ONLINE_SEATS" :
285 require_active > 0 ? "ACTIVE_SEATS" :
290 static int file_of_session(const char *session, char **_p) {
297 if (!session_id_valid(session))
300 p = strappend("/run/systemd/sessions/", session);
302 _cleanup_free_ char *buf = NULL;
304 r = sd_pid_get_session(0, &buf);
308 p = strappend("/run/systemd/sessions/", buf);
318 _public_ int sd_session_is_active(const char *session) {
320 _cleanup_free_ char *p = NULL, *s = NULL;
322 r = file_of_session(session, &p);
326 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
333 return parse_boolean(s);
336 _public_ int sd_session_is_remote(const char *session) {
338 _cleanup_free_ char *p = NULL, *s = NULL;
340 r = file_of_session(session, &p);
344 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
351 return parse_boolean(s);
354 _public_ int sd_session_get_state(const char *session, char **state) {
355 _cleanup_free_ char *p = NULL, *s = NULL;
358 assert_return(state, -EINVAL);
360 r = file_of_session(session, &p);
364 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
377 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
379 _cleanup_free_ char *p = NULL, *s = NULL;
381 assert_return(uid, -EINVAL);
383 r = file_of_session(session, &p);
387 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
394 return parse_uid(s, uid);
397 static int session_get_string(const char *session, const char *field, char **value) {
398 _cleanup_free_ char *p = NULL, *s = NULL;
401 assert_return(value, -EINVAL);
403 r = file_of_session(session, &p);
407 r = parse_env_file(p, NEWLINE, field, &s, NULL);
420 _public_ int sd_session_get_seat(const char *session, char **seat) {
421 return session_get_string(session, "SEAT", seat);
424 _public_ int sd_session_get_tty(const char *session, char **tty) {
425 return session_get_string(session, "TTY", tty);
428 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
429 _cleanup_free_ char *vtnr_string = NULL;
433 r = session_get_string(session, "VTNR", &vtnr_string);
437 r = safe_atou(vtnr_string, &u);
445 _public_ int sd_session_get_service(const char *session, char **service) {
446 return session_get_string(session, "SERVICE", service);
449 _public_ int sd_session_get_type(const char *session, char **type) {
450 return session_get_string(session, "TYPE", type);
453 _public_ int sd_session_get_class(const char *session, char **class) {
454 return session_get_string(session, "CLASS", class);
457 _public_ int sd_session_get_display(const char *session, char **display) {
458 return session_get_string(session, "DISPLAY", display);
461 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
462 return session_get_string(session, "REMOTE_USER", remote_user);
465 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
466 return session_get_string(session, "REMOTE_HOST", remote_host);
469 static int file_of_seat(const char *seat, char **_p) {
476 p = strappend("/run/systemd/seats/", seat);
478 _cleanup_free_ char *buf = NULL;
480 r = sd_session_get_seat(NULL, &buf);
484 p = strappend("/run/systemd/seats/", buf);
495 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
496 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
499 assert_return(session || uid, -EINVAL);
501 r = file_of_seat(seat, &p);
505 r = parse_env_file(p, NEWLINE,
519 r = parse_uid(t, uid);
532 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
533 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
534 _cleanup_strv_free_ char **a = NULL;
535 _cleanup_free_ uid_t *b = NULL;
539 r = file_of_seat(seat, &p);
543 r = parse_env_file(p, NEWLINE,
545 "ACTIVE_SESSIONS", &t,
552 a = strv_split(s, " ");
561 FOREACH_WORD(w, l, t, state)
571 FOREACH_WORD(w, l, t, state) {
572 _cleanup_free_ char *k = NULL;
578 r = parse_uid(k, b + i);
606 static int seat_get_can(const char *seat, const char *variable) {
607 _cleanup_free_ char *p = NULL, *s = NULL;
610 assert_return(variable, -EINVAL);
612 r = file_of_seat(seat, &p);
616 r = parse_env_file(p, NEWLINE,
624 return parse_boolean(s);
627 _public_ int sd_seat_can_multi_session(const char *seat) {
628 return seat_get_can(seat, "CAN_MULTI_SESSION");
631 _public_ int sd_seat_can_tty(const char *seat) {
632 return seat_get_can(seat, "CAN_TTY");
635 _public_ int sd_seat_can_graphical(const char *seat) {
636 return seat_get_can(seat, "CAN_GRAPHICAL");
639 _public_ int sd_get_seats(char ***seats) {
640 return get_files_in_directory("/run/systemd/seats/", seats);
643 _public_ int sd_get_sessions(char ***sessions) {
644 return get_files_in_directory("/run/systemd/sessions/", sessions);
647 _public_ int sd_get_uids(uid_t **users) {
648 _cleanup_closedir_ DIR *d;
651 _cleanup_free_ uid_t *l = NULL;
653 d = opendir("/run/systemd/users/");
664 if (!de && errno != 0)
670 dirent_ensure_type(d, de);
672 if (!dirent_is_file(de))
675 k = parse_uid(de->d_name, &uid);
680 if ((unsigned) r >= n) {
684 t = realloc(l, sizeof(uid_t) * n);
691 assert((unsigned) r < n);
705 _public_ int sd_get_machine_names(char ***machines) {
706 char **l = NULL, **a, **b;
709 assert_return(machines, -EINVAL);
711 r = get_files_in_directory("/run/systemd/machines/", &l);
718 /* Filter out the unit: symlinks */
719 for (a = l, b = l; *a; a++) {
720 if (startswith(*a, "unit:"))
736 _public_ int sd_machine_get_class(const char *machine, char **class) {
737 _cleanup_free_ char *c = NULL;
741 assert_return(filename_is_safe(machine), -EINVAL);
742 assert_return(class, -EINVAL);
744 p = strappenda("/run/systemd/machines/", machine);
745 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
757 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
758 return (int) (unsigned long) m - 1;
761 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
762 return (sd_login_monitor*) (unsigned long) (fd + 1);
765 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
769 assert_return(m, -EINVAL);
771 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
775 if (!category || streq(category, "seat")) {
776 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
778 close_nointr_nofail(fd);
785 if (!category || streq(category, "session")) {
786 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
788 close_nointr_nofail(fd);
795 if (!category || streq(category, "uid")) {
796 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
798 close_nointr_nofail(fd);
805 if (!category || streq(category, "machine")) {
806 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
808 close_nointr_nofail(fd);
820 *m = FD_TO_MONITOR(fd);
824 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
827 assert_return(m, NULL);
829 fd = MONITOR_TO_FD(m);
835 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
837 assert_return(m, -EINVAL);
839 return flush_fd(MONITOR_TO_FD(m));
842 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
844 assert_return(m, -EINVAL);
846 return MONITOR_TO_FD(m);
849 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
851 assert_return(m, -EINVAL);
853 /* For now we will only return POLLIN here, since we don't
854 * need anything else ever for inotify. However, let's have
855 * this API to keep our options open should we later on need
860 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
862 assert_return(m, -EINVAL);
863 assert_return(timeout_usec, -EINVAL);
865 /* For now we will only return (uint64_t) -1, since we don't
866 * need any timeout. However, let's have this API to keep our
867 * options open should we later on need it. */
868 *timeout_usec = (uint64_t) -1;