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"
35 _public_ int sd_pid_get_session(pid_t pid, char **session) {
42 return cg_pid_get_session(pid, session);
45 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
52 return cg_pid_get_unit(pid, unit);
55 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
62 return cg_pid_get_user_unit(pid, unit);
65 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
72 return cg_pid_get_machine_name(pid, name);
75 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
77 _cleanup_free_ char *root = NULL, *cgroup = NULL, *p = NULL, *cc = NULL;
86 r = cg_pid_get_path_shifted(pid, &root, &cgroup);
90 if (!startswith(cgroup, "/user/"))
93 p = strchr(cgroup + 6, '/');
101 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, cgroup, &cc);
111 if (!S_ISDIR(st.st_mode))
118 _public_ int sd_uid_get_state(uid_t uid, char**state) {
125 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
128 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
133 s = strdup("offline");
149 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
151 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
154 const char *variable;
159 variable = require_active ? "ACTIVE_UID" : "UIDS";
161 p = strappend("/run/systemd/seats/", seat);
165 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
173 if (asprintf(&t, "%lu", (unsigned long) uid) < 0)
176 FOREACH_WORD(w, l, s, state) {
184 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
185 _cleanup_free_ char *p = NULL, *s = NULL;
189 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
192 r = parse_env_file(p, NEWLINE,
211 a = strv_split(s, " ");
227 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
228 return uid_get_array(
230 require_active == 0 ? "ONLINE_SESSIONS" :
231 require_active > 0 ? "ACTIVE_SESSIONS" :
236 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
237 return uid_get_array(
239 require_active == 0 ? "ONLINE_SEATS" :
240 require_active > 0 ? "ACTIVE_SEATS" :
245 static int file_of_session(const char *session, char **_p) {
252 p = strappend("/run/systemd/sessions/", session);
256 r = sd_pid_get_session(0, &buf);
260 p = strappend("/run/systemd/sessions/", buf);
271 _public_ int sd_session_is_active(const char *session) {
273 _cleanup_free_ char *p = NULL, *s = NULL;
275 r = file_of_session(session, &p);
279 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
287 r = parse_boolean(s);
292 _public_ int sd_session_get_state(const char *session, char **state) {
293 _cleanup_free_ char *p = NULL, *s = NULL;
299 r = file_of_session(session, &p);
303 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
316 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
318 _cleanup_free_ char *p = NULL, *s = NULL;
323 r = file_of_session(session, &p);
327 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
335 r = parse_uid(s, uid);
340 static int session_get_string(const char *session, const char *field, char **value) {
341 _cleanup_free_ char *p = NULL, *s = NULL;
347 r = file_of_session(session, &p);
351 r = parse_env_file(p, NEWLINE, field, &s, NULL);
364 _public_ int sd_session_get_seat(const char *session, char **seat) {
365 return session_get_string(session, "SEAT", seat);
368 _public_ int sd_session_get_tty(const char *session, char **tty) {
369 return session_get_string(session, "TTY", tty);
372 _public_ int sd_session_get_service(const char *session, char **service) {
373 return session_get_string(session, "SERVICE", service);
376 _public_ int sd_session_get_type(const char *session, char **type) {
377 return session_get_string(session, "TYPE", type);
380 _public_ int sd_session_get_class(const char *session, char **class) {
381 return session_get_string(session, "CLASS", class);
384 _public_ int sd_session_get_display(const char *session, char **display) {
385 return session_get_string(session, "DISPLAY", display);
388 static int file_of_seat(const char *seat, char **_p) {
395 p = strappend("/run/systemd/seats/", seat);
397 _cleanup_free_ char *buf = NULL;
399 r = sd_session_get_seat(NULL, &buf);
403 p = strappend("/run/systemd/seats/", buf);
414 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
415 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
418 if (!session && !uid)
421 r = file_of_seat(seat, &p);
425 r = parse_env_file(p, NEWLINE,
439 r = parse_uid(t, uid);
452 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
453 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
454 _cleanup_strv_free_ char **a = NULL;
455 _cleanup_free_ uid_t *b = NULL;
459 r = file_of_seat(seat, &p);
463 r = parse_env_file(p, NEWLINE,
465 "ACTIVE_SESSIONS", &t,
472 a = strv_split(s, " ");
481 FOREACH_WORD(w, l, t, state)
491 FOREACH_WORD(w, l, t, state) {
492 _cleanup_free_ char *k = NULL;
498 r = parse_uid(k, b + i);
526 static int seat_get_can(const char *seat, const char *variable) {
527 _cleanup_free_ char *p = NULL, *s = NULL;
530 r = file_of_seat(seat, &p);
534 r = parse_env_file(p, NEWLINE,
541 r = parse_boolean(s);
548 _public_ int sd_seat_can_multi_session(const char *seat) {
549 return seat_get_can(seat, "CAN_MULTI_SESSION");
552 _public_ int sd_seat_can_tty(const char *seat) {
553 return seat_get_can(seat, "CAN_TTY");
556 _public_ int sd_seat_can_graphical(const char *seat) {
557 return seat_get_can(seat, "CAN_GRAPHICAL");
560 _public_ int sd_get_seats(char ***seats) {
561 return get_files_in_directory("/run/systemd/seats/", seats);
564 _public_ int sd_get_sessions(char ***sessions) {
565 return get_files_in_directory("/run/systemd/sessions/", sessions);
568 _public_ int sd_get_uids(uid_t **users) {
569 _cleanup_closedir_ DIR *d;
572 _cleanup_free_ uid_t *l = NULL;
574 d = opendir("/run/systemd/users/");
580 union dirent_storage buf;
584 k = readdir_r(d, &buf.de, &de);
591 dirent_ensure_type(d, de);
593 if (!dirent_is_file(de))
596 k = parse_uid(de->d_name, &uid);
601 if ((unsigned) r >= n) {
605 t = realloc(l, sizeof(uid_t) * n);
612 assert((unsigned) r < n);
626 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
627 return (int) (unsigned long) m - 1;
630 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
631 return (sd_login_monitor*) (unsigned long) (fd + 1);
634 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
641 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
645 if (!category || streq(category, "seat")) {
646 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
648 close_nointr_nofail(fd);
655 if (!category || streq(category, "session")) {
656 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
658 close_nointr_nofail(fd);
665 if (!category || streq(category, "uid")) {
666 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
668 close_nointr_nofail(fd);
680 *m = FD_TO_MONITOR(fd);
684 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
690 fd = MONITOR_TO_FD(m);
696 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
701 return flush_fd(MONITOR_TO_FD(m));
704 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
709 return MONITOR_TO_FD(m);
712 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
717 /* For now we will only return POLLIN here, since we don't
718 * need anything else ever for inotify. However, let's have
719 * this API to keep our options open should we later on need
724 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
731 /* For now we will only return (uint64_t) -1, since we don't
732 * need any timeout. However, let's have this API to keep our
733 * options open should we later on need it. */
734 *timeout_usec = (uint64_t) -1;