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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
18 You should have received a copy of the GNU 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 static int file_of_seat(const char *seat
, char **_p
) {
485 p
= strappend("/run/systemd/seats/", seat
);
489 r
= sd_session_get_seat(NULL
, &buf
);
493 p
= strappend("/run/systemd/seats/", buf
);
504 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
505 char *p
, *s
= NULL
, *t
= NULL
;
508 if (!session
&& !uid
)
511 r
= file_of_seat(seat
, &p
);
515 r
= parse_env_file(p
, NEWLINE
,
538 r
= parse_uid(t
, uid
);
556 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
557 char *p
, *s
= NULL
, *t
= NULL
, **a
= NULL
;
562 r
= file_of_seat(seat
, &p
);
566 r
= parse_env_file(p
, NEWLINE
,
568 "ACTIVE_SESSIONS", &t
,
579 a
= strv_split(s
, " ");
593 FOREACH_WORD(w
, l
, t
, state
)
607 FOREACH_WORD(w
, l
, t
, state
) {
618 r
= parse_uid(k
, b
+ i
);
646 _public_
int sd_seat_can_multi_session(const char *seat
) {
650 r
= file_of_seat(seat
, &p
);
654 r
= parse_env_file(p
, NEWLINE
,
655 "CAN_MULTI_SESSION", &s
,
665 r
= parse_boolean(s
);
673 _public_
int sd_get_seats(char ***seats
) {
674 return get_files_in_directory("/run/systemd/seats/", seats
);
677 _public_
int sd_get_sessions(char ***sessions
) {
678 return get_files_in_directory("/run/systemd/sessions/", sessions
);
681 _public_
int sd_get_uids(uid_t
**users
) {
687 d
= opendir("/run/systemd/users/");
692 struct dirent buffer
, *de
;
696 k
= readdir_r(d
, &buffer
, &de
);
705 dirent_ensure_type(d
, de
);
707 if (!dirent_is_file(de
))
710 k
= parse_uid(de
->d_name
, &uid
);
715 if ((unsigned) r
>= n
) {
719 t
= realloc(l
, sizeof(uid_t
) * n
);
728 assert((unsigned) r
< n
);
747 static inline int MONITOR_TO_FD(sd_login_monitor
*m
) {
748 return (int) (unsigned long) m
- 1;
751 static inline sd_login_monitor
* FD_TO_MONITOR(int fd
) {
752 return (sd_login_monitor
*) (unsigned long) (fd
+ 1);
755 _public_
int sd_login_monitor_new(const char *category
, sd_login_monitor
**m
) {
762 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
766 if (!category
|| streq(category
, "seat")) {
767 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
769 close_nointr_nofail(fd
);
776 if (!category
|| streq(category
, "session")) {
777 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
779 close_nointr_nofail(fd
);
786 if (!category
|| streq(category
, "uid")) {
787 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
789 close_nointr_nofail(fd
);
801 *m
= FD_TO_MONITOR(fd
);
805 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
811 fd
= MONITOR_TO_FD(m
);
817 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
822 return flush_fd(MONITOR_TO_FD(m
));
825 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
830 return MONITOR_TO_FD(m
);