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>
28 #include "cgroup-util.h"
33 static int pid_get_cgroup(pid_t pid, char **root, char **cgroup) {
34 char *cg_process, *cg_init, *p;
43 r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &cg_process);
47 r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &cg_init);
53 if (endswith(cg_init, "/system"))
54 cg_init[strlen(cg_init)-7] = 0;
55 else if (streq(cg_init, "/"))
58 if (startswith(cg_process, cg_init))
59 p = cg_process + strlen(cg_init);
78 cg_process[p-cg_process] = 0;
86 _public_ int sd_pid_get_session(pid_t pid, char **session) {
93 r = pid_get_cgroup(pid, NULL, &cgroup);
97 if (!startswith(cgroup, "/user/")) {
102 p = strchr(cgroup + 6, '/');
109 if (startswith(p, "shared/") || streq(p, "shared")) {
114 p = strndup(p, strcspn(p, "/"));
124 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
126 char *cgroup, *p, *at, *b;
132 r = pid_get_cgroup(pid, NULL, &cgroup);
136 if (!startswith(cgroup, "/system/")) {
144 at = memchr(p, '@', k);
145 if (at && at[1] == '.') {
148 /* This is a templated service */
154 j = strcspn(p+k+1, "/");
156 b = malloc(k + j + 1);
159 memcpy(b, p, at - p + 1);
160 memcpy(b + (at - p) + 1, p + k + 1, j);
161 memcpy(b + (at - p) + 1 + j, at + 1, k - (at - p) - 1);
176 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
178 char *root, *cgroup, *p, *cc;
184 r = pid_get_cgroup(pid, &root, &cgroup);
188 if (!startswith(cgroup, "/user/")) {
194 p = strchr(cgroup + 6, '/');
201 p += strcspn(p, "/");
204 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, cgroup, &cc);
217 if (!S_ISDIR(st.st_mode))
224 _public_ int sd_uid_get_state(uid_t uid, char**state) {
231 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
234 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
239 s = strdup("offline");
255 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
256 char *p, *w, *t, *state, *s = NULL;
259 const char *variable;
264 variable = require_active ? "ACTIVE_UID" : "UIDS";
266 p = strappend("/run/systemd/seats/", seat);
270 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
281 if (asprintf(&t, "%lu", (unsigned long) uid) < 0) {
286 FOREACH_WORD(w, l, s, state) {
287 if (strncmp(t, w, l) == 0) {
301 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
306 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
309 r = parse_env_file(p, NEWLINE,
332 a = strv_split(s, " ");
349 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
350 return uid_get_array(uid, require_active ? "ACTIVE_SESSIONS" : "SESSIONS", sessions);
353 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
354 return uid_get_array(uid, require_active ? "ACTIVE_SEATS" : "SEATS", seats);
357 static int file_of_session(const char *session, char **_p) {
364 p = strappend("/run/systemd/sessions/", session);
368 r = sd_pid_get_session(0, &buf);
372 p = strappend("/run/systemd/sessions/", buf);
383 _public_ int sd_session_is_active(const char *session) {
387 r = file_of_session(session, &p);
391 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
402 r = parse_boolean(s);
408 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
415 r = file_of_session(session, &p);
419 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
430 r = parse_uid(s, uid);
436 static int session_get_string(const char *session, const char *field, char **value) {
443 r = file_of_session(session, &p);
447 r = parse_env_file(p, NEWLINE, field, &s, NULL);
462 _public_ int sd_session_get_seat(const char *session, char **seat) {
463 return session_get_string(session, "SEAT", seat);
466 _public_ int sd_session_get_service(const char *session, char **service) {
467 return session_get_string(session, "SERVICE", service);
470 _public_ int sd_session_get_type(const char *session, char **type) {
471 return session_get_string(session, "TYPE", type);
474 _public_ int sd_session_get_class(const char *session, char **class) {
475 return session_get_string(session, "CLASS", class);
478 _public_ int sd_session_get_display(const char *session, char **display) {
479 return session_get_string(session, "DISPLAY", display);
482 static int file_of_seat(const char *seat, char **_p) {
489 p = strappend("/run/systemd/seats/", seat);
493 r = sd_session_get_seat(NULL, &buf);
497 p = strappend("/run/systemd/seats/", buf);
508 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
509 char *p, *s = NULL, *t = NULL;
512 if (!session && !uid)
515 r = file_of_seat(seat, &p);
519 r = parse_env_file(p, NEWLINE,
542 r = parse_uid(t, uid);
560 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
561 char *p, *s = NULL, *t = NULL, **a = NULL;
566 r = file_of_seat(seat, &p);
570 r = parse_env_file(p, NEWLINE,
572 "ACTIVE_SESSIONS", &t,
583 a = strv_split(s, " ");
597 FOREACH_WORD(w, l, t, state)
611 FOREACH_WORD(w, l, t, state) {
622 r = parse_uid(k, b + i);
650 _public_ int sd_seat_can_multi_session(const char *seat) {
654 r = file_of_seat(seat, &p);
658 r = parse_env_file(p, NEWLINE,
659 "CAN_MULTI_SESSION", &s,
669 r = parse_boolean(s);
677 _public_ int sd_get_seats(char ***seats) {
678 return get_files_in_directory("/run/systemd/seats/", seats);
681 _public_ int sd_get_sessions(char ***sessions) {
682 return get_files_in_directory("/run/systemd/sessions/", sessions);
685 _public_ int sd_get_uids(uid_t **users) {
691 d = opendir("/run/systemd/users/");
696 struct dirent buffer, *de;
700 k = readdir_r(d, &buffer, &de);
709 dirent_ensure_type(d, de);
711 if (!dirent_is_file(de))
714 k = parse_uid(de->d_name, &uid);
719 if ((unsigned) r >= n) {
723 t = realloc(l, sizeof(uid_t) * n);
732 assert((unsigned) r < n);
751 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
752 return (int) (unsigned long) m - 1;
755 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
756 return (sd_login_monitor*) (unsigned long) (fd + 1);
759 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
766 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
770 if (!category || streq(category, "seat")) {
771 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
773 close_nointr_nofail(fd);
780 if (!category || streq(category, "session")) {
781 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
783 close_nointr_nofail(fd);
790 if (!category || streq(category, "uid")) {
791 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
793 close_nointr_nofail(fd);
805 *m = FD_TO_MONITOR(fd);
809 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
815 fd = MONITOR_TO_FD(m);
821 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
826 return flush_fd(MONITOR_TO_FD(m));
829 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
834 return MONITOR_TO_FD(m);