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 _public_
int sd_pid_get_session(pid_t pid
, char **session
) {
43 r
= cg_pid_get_cgroup(pid
, NULL
, &cgroup
);
47 if (!startswith(cgroup
, "/user/")) {
52 p
= strchr(cgroup
+ 6, '/');
59 if (startswith(p
, "shared/") || streq(p
, "shared")) {
64 p
= strndup(p
, strcspn(p
, "/"));
74 _public_
int sd_pid_get_unit(pid_t pid
, char **unit
) {
82 return cg_pid_get_unit(pid
, unit
);
85 _public_
int sd_pid_get_owner_uid(pid_t pid
, uid_t
*uid
) {
87 char *root
, *cgroup
, *p
, *cc
;
96 r
= cg_pid_get_cgroup(pid
, &root
, &cgroup
);
100 if (!startswith(cgroup
, "/user/")) {
106 p
= strchr(cgroup
+ 6, '/');
113 p
+= strcspn(p
, "/");
116 r
= cg_get_path(SYSTEMD_CGROUP_CONTROLLER
, root
, cgroup
, &cc
);
129 if (!S_ISDIR(st
.st_mode
))
136 _public_
int sd_uid_get_state(uid_t uid
, char**state
) {
143 if (asprintf(&p
, "/run/systemd/users/%lu", (unsigned long) uid
) < 0)
146 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
151 s
= strdup("offline");
167 _public_
int sd_uid_is_on_seat(uid_t uid
, int require_active
, const char *seat
) {
168 char *p
, *w
, *t
, *state
, *s
= NULL
;
171 const char *variable
;
176 variable
= require_active
? "ACTIVE_UID" : "UIDS";
178 p
= strappend("/run/systemd/seats/", seat
);
182 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
193 if (asprintf(&t
, "%lu", (unsigned long) uid
) < 0) {
198 FOREACH_WORD(w
, l
, s
, state
) {
199 if (strncmp(t
, w
, l
) == 0) {
213 static int uid_get_array(uid_t uid
, const char *variable
, char ***array
) {
218 if (asprintf(&p
, "/run/systemd/users/%lu", (unsigned long) uid
) < 0)
221 r
= parse_env_file(p
, NEWLINE
,
244 a
= strv_split(s
, " ");
261 _public_
int sd_uid_get_sessions(uid_t uid
, int require_active
, char ***sessions
) {
262 return uid_get_array(uid
, require_active
? "ACTIVE_SESSIONS" : "SESSIONS", sessions
);
265 _public_
int sd_uid_get_seats(uid_t uid
, int require_active
, char ***seats
) {
266 return uid_get_array(uid
, require_active
? "ACTIVE_SEATS" : "SEATS", seats
);
269 static int file_of_session(const char *session
, char **_p
) {
276 p
= strappend("/run/systemd/sessions/", session
);
280 r
= sd_pid_get_session(0, &buf
);
284 p
= strappend("/run/systemd/sessions/", buf
);
295 _public_
int sd_session_is_active(const char *session
) {
299 r
= file_of_session(session
, &p
);
303 r
= parse_env_file(p
, NEWLINE
, "ACTIVE", &s
, NULL
);
314 r
= parse_boolean(s
);
320 _public_
int sd_session_get_state(const char *session
, char **state
) {
327 r
= file_of_session(session
, &p
);
331 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
344 _public_
int sd_session_get_uid(const char *session
, uid_t
*uid
) {
351 r
= file_of_session(session
, &p
);
355 r
= parse_env_file(p
, NEWLINE
, "UID", &s
, NULL
);
366 r
= parse_uid(s
, uid
);
372 static int session_get_string(const char *session
, const char *field
, char **value
) {
379 r
= file_of_session(session
, &p
);
383 r
= parse_env_file(p
, NEWLINE
, field
, &s
, NULL
);
398 _public_
int sd_session_get_seat(const char *session
, char **seat
) {
399 return session_get_string(session
, "SEAT", seat
);
402 _public_
int sd_session_get_service(const char *session
, char **service
) {
403 return session_get_string(session
, "SERVICE", service
);
406 _public_
int sd_session_get_type(const char *session
, char **type
) {
407 return session_get_string(session
, "TYPE", type
);
410 _public_
int sd_session_get_class(const char *session
, char **class) {
411 return session_get_string(session
, "CLASS", class);
414 _public_
int sd_session_get_display(const char *session
, char **display
) {
415 return session_get_string(session
, "DISPLAY", display
);
418 static int file_of_seat(const char *seat
, char **_p
) {
425 p
= strappend("/run/systemd/seats/", seat
);
429 r
= sd_session_get_seat(NULL
, &buf
);
433 p
= strappend("/run/systemd/seats/", buf
);
444 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
445 char *p
, *s
= NULL
, *t
= NULL
;
448 if (!session
&& !uid
)
451 r
= file_of_seat(seat
, &p
);
455 r
= parse_env_file(p
, NEWLINE
,
478 r
= parse_uid(t
, uid
);
496 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
497 char *p
, *s
= NULL
, *t
= NULL
, **a
= NULL
;
502 r
= file_of_seat(seat
, &p
);
506 r
= parse_env_file(p
, NEWLINE
,
508 "ACTIVE_SESSIONS", &t
,
519 a
= strv_split(s
, " ");
533 FOREACH_WORD(w
, l
, t
, state
)
547 FOREACH_WORD(w
, l
, t
, state
) {
558 r
= parse_uid(k
, b
+ i
);
586 static int seat_get_can(const char *seat
, const char *variable
) {
590 r
= file_of_seat(seat
, &p
);
594 r
= parse_env_file(p
, NEWLINE
,
605 r
= parse_boolean(s
);
613 _public_
int sd_seat_can_multi_session(const char *seat
) {
614 return seat_get_can(seat
, "CAN_MULTI_SESSION");
617 _public_
int sd_seat_can_tty(const char *seat
) {
618 return seat_get_can(seat
, "CAN_TTY");
621 _public_
int sd_seat_can_graphical(const char *seat
) {
622 return seat_get_can(seat
, "CAN_GRAPHICAL");
625 _public_
int sd_get_seats(char ***seats
) {
626 return get_files_in_directory("/run/systemd/seats/", seats
);
629 _public_
int sd_get_sessions(char ***sessions
) {
630 return get_files_in_directory("/run/systemd/sessions/", sessions
);
633 _public_
int sd_get_uids(uid_t
**users
) {
639 d
= opendir("/run/systemd/users/");
644 struct dirent buffer
, *de
;
648 k
= readdir_r(d
, &buffer
, &de
);
657 dirent_ensure_type(d
, de
);
659 if (!dirent_is_file(de
))
662 k
= parse_uid(de
->d_name
, &uid
);
667 if ((unsigned) r
>= n
) {
671 t
= realloc(l
, sizeof(uid_t
) * n
);
680 assert((unsigned) r
< n
);
699 static inline int MONITOR_TO_FD(sd_login_monitor
*m
) {
700 return (int) (unsigned long) m
- 1;
703 static inline sd_login_monitor
* FD_TO_MONITOR(int fd
) {
704 return (sd_login_monitor
*) (unsigned long) (fd
+ 1);
707 _public_
int sd_login_monitor_new(const char *category
, sd_login_monitor
**m
) {
714 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
718 if (!category
|| streq(category
, "seat")) {
719 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
721 close_nointr_nofail(fd
);
728 if (!category
|| streq(category
, "session")) {
729 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
731 close_nointr_nofail(fd
);
738 if (!category
|| streq(category
, "uid")) {
739 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
741 close_nointr_nofail(fd
);
753 *m
= FD_TO_MONITOR(fd
);
757 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
763 fd
= MONITOR_TO_FD(m
);
769 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
774 return flush_fd(MONITOR_TO_FD(m
));
777 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
782 return MONITOR_TO_FD(m
);