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-util.h"
34 #include "formats-util.h"
35 #include "hostname-util.h"
38 _public_
int sd_pid_get_session(pid_t pid
, char **session
) {
40 assert_return(pid
>= 0, -EINVAL
);
41 assert_return(session
, -EINVAL
);
43 return cg_pid_get_session(pid
, session
);
46 _public_
int sd_pid_get_unit(pid_t pid
, char **unit
) {
48 assert_return(pid
>= 0, -EINVAL
);
49 assert_return(unit
, -EINVAL
);
51 return cg_pid_get_unit(pid
, unit
);
54 _public_
int sd_pid_get_user_unit(pid_t pid
, char **unit
) {
56 assert_return(pid
>= 0, -EINVAL
);
57 assert_return(unit
, -EINVAL
);
59 return cg_pid_get_user_unit(pid
, unit
);
62 _public_
int sd_pid_get_machine_name(pid_t pid
, char **name
) {
64 assert_return(pid
>= 0, -EINVAL
);
65 assert_return(name
, -EINVAL
);
67 return cg_pid_get_machine_name(pid
, name
);
70 _public_
int sd_pid_get_slice(pid_t pid
, char **slice
) {
72 assert_return(pid
>= 0, -EINVAL
);
73 assert_return(slice
, -EINVAL
);
75 return cg_pid_get_slice(pid
, slice
);
78 _public_
int sd_pid_get_user_slice(pid_t pid
, char **slice
) {
80 assert_return(pid
>= 0, -EINVAL
);
81 assert_return(slice
, -EINVAL
);
83 return cg_pid_get_user_slice(pid
, slice
);
86 _public_
int sd_pid_get_owner_uid(pid_t pid
, uid_t
*uid
) {
88 assert_return(pid
>= 0, -EINVAL
);
89 assert_return(uid
, -EINVAL
);
91 return cg_pid_get_owner_uid(pid
, uid
);
94 _public_
int sd_peer_get_session(int fd
, char **session
) {
95 struct ucred ucred
= {};
98 assert_return(fd
>= 0, -EBADF
);
99 assert_return(session
, -EINVAL
);
101 r
= getpeercred(fd
, &ucred
);
105 return cg_pid_get_session(ucred
.pid
, session
);
108 _public_
int sd_peer_get_owner_uid(int fd
, uid_t
*uid
) {
112 assert_return(fd
>= 0, -EBADF
);
113 assert_return(uid
, -EINVAL
);
115 r
= getpeercred(fd
, &ucred
);
119 return cg_pid_get_owner_uid(ucred
.pid
, uid
);
122 _public_
int sd_peer_get_unit(int fd
, char **unit
) {
126 assert_return(fd
>= 0, -EBADF
);
127 assert_return(unit
, -EINVAL
);
129 r
= getpeercred(fd
, &ucred
);
133 return cg_pid_get_unit(ucred
.pid
, unit
);
136 _public_
int sd_peer_get_user_unit(int fd
, char **unit
) {
140 assert_return(fd
>= 0, -EBADF
);
141 assert_return(unit
, -EINVAL
);
143 r
= getpeercred(fd
, &ucred
);
147 return cg_pid_get_user_unit(ucred
.pid
, unit
);
150 _public_
int sd_peer_get_machine_name(int fd
, char **machine
) {
154 assert_return(fd
>= 0, -EBADF
);
155 assert_return(machine
, -EINVAL
);
157 r
= getpeercred(fd
, &ucred
);
161 return cg_pid_get_machine_name(ucred
.pid
, machine
);
164 _public_
int sd_peer_get_slice(int fd
, char **slice
) {
168 assert_return(fd
>= 0, -EBADF
);
169 assert_return(slice
, -EINVAL
);
171 r
= getpeercred(fd
, &ucred
);
175 return cg_pid_get_slice(ucred
.pid
, slice
);
178 _public_
int sd_peer_get_user_slice(int fd
, char **slice
) {
182 assert_return(fd
>= 0, -EBADF
);
183 assert_return(slice
, -EINVAL
);
185 r
= getpeercred(fd
, &ucred
);
189 return cg_pid_get_user_slice(ucred
.pid
, slice
);
192 static int file_of_uid(uid_t uid
, char **p
) {
195 if (asprintf(p
, "/run/systemd/users/" UID_FMT
, uid
) < 0)
201 _public_
int sd_uid_get_state(uid_t uid
, char**state
) {
202 _cleanup_free_
char *p
= NULL
;
206 assert_return(state
, -EINVAL
);
208 r
= file_of_uid(uid
, &p
);
212 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
215 s
= strdup("offline");
229 _public_
int sd_uid_get_display(uid_t uid
, char **session
) {
230 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
233 assert_return(session
, -EINVAL
);
235 r
= file_of_uid(uid
, &p
);
239 r
= parse_env_file(p
, NEWLINE
, "DISPLAY", &s
, NULL
);
252 _public_
int sd_uid_is_on_seat(uid_t uid
, int require_active
, const char *seat
) {
253 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *p
= NULL
;
256 const char *word
, *variable
, *state
;
258 assert_return(seat
, -EINVAL
);
260 variable
= require_active
? "ACTIVE_UID" : "UIDS";
262 p
= strappend("/run/systemd/seats/", seat
);
266 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
274 if (asprintf(&t
, UID_FMT
, uid
) < 0)
277 FOREACH_WORD(word
, l
, s
, state
) {
278 if (strneq(t
, word
, l
))
285 static int uid_get_array(uid_t uid
, const char *variable
, char ***array
) {
286 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
290 r
= file_of_uid(uid
, &p
);
294 r
= parse_env_file(p
, NEWLINE
,
313 a
= strv_split(s
, " ");
329 _public_
int sd_uid_get_sessions(uid_t uid
, int require_active
, char ***sessions
) {
330 return uid_get_array(
332 require_active
== 0 ? "ONLINE_SESSIONS" :
333 require_active
> 0 ? "ACTIVE_SESSIONS" :
338 _public_
int sd_uid_get_seats(uid_t uid
, int require_active
, char ***seats
) {
339 return uid_get_array(
341 require_active
== 0 ? "ONLINE_SEATS" :
342 require_active
> 0 ? "ACTIVE_SEATS" :
347 static int file_of_session(const char *session
, char **_p
) {
354 if (!session_id_valid(session
))
357 p
= strappend("/run/systemd/sessions/", session
);
359 _cleanup_free_
char *buf
= NULL
;
361 r
= sd_pid_get_session(0, &buf
);
365 p
= strappend("/run/systemd/sessions/", buf
);
375 _public_
int sd_session_is_active(const char *session
) {
377 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
379 r
= file_of_session(session
, &p
);
383 r
= parse_env_file(p
, NEWLINE
, "ACTIVE", &s
, NULL
);
390 return parse_boolean(s
);
393 _public_
int sd_session_is_remote(const char *session
) {
395 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
397 r
= file_of_session(session
, &p
);
401 r
= parse_env_file(p
, NEWLINE
, "REMOTE", &s
, NULL
);
408 return parse_boolean(s
);
411 _public_
int sd_session_get_state(const char *session
, char **state
) {
412 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
415 assert_return(state
, -EINVAL
);
417 r
= file_of_session(session
, &p
);
421 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
433 _public_
int sd_session_get_uid(const char *session
, uid_t
*uid
) {
435 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
437 assert_return(uid
, -EINVAL
);
439 r
= file_of_session(session
, &p
);
443 r
= parse_env_file(p
, NEWLINE
, "UID", &s
, NULL
);
450 return parse_uid(s
, uid
);
453 static int session_get_string(const char *session
, const char *field
, char **value
) {
454 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
457 assert_return(value
, -EINVAL
);
459 r
= file_of_session(session
, &p
);
463 r
= parse_env_file(p
, NEWLINE
, field
, &s
, NULL
);
475 _public_
int sd_session_get_seat(const char *session
, char **seat
) {
476 return session_get_string(session
, "SEAT", seat
);
479 _public_
int sd_session_get_tty(const char *session
, char **tty
) {
480 return session_get_string(session
, "TTY", tty
);
483 _public_
int sd_session_get_vt(const char *session
, unsigned *vtnr
) {
484 _cleanup_free_
char *vtnr_string
= NULL
;
488 r
= session_get_string(session
, "VTNR", &vtnr_string
);
492 r
= safe_atou(vtnr_string
, &u
);
500 _public_
int sd_session_get_service(const char *session
, char **service
) {
501 return session_get_string(session
, "SERVICE", service
);
504 _public_
int sd_session_get_type(const char *session
, char **type
) {
505 return session_get_string(session
, "TYPE", type
);
508 _public_
int sd_session_get_class(const char *session
, char **class) {
509 return session_get_string(session
, "CLASS", class);
512 _public_
int sd_session_get_desktop(const char *session
, char **desktop
) {
513 _cleanup_free_
char *escaped
= NULL
;
517 assert_return(desktop
, -EINVAL
);
519 r
= session_get_string(session
, "DESKTOP", &escaped
);
523 r
= cunescape(escaped
, 0, &t
);
531 _public_
int sd_session_get_display(const char *session
, char **display
) {
532 return session_get_string(session
, "DISPLAY", display
);
535 _public_
int sd_session_get_remote_user(const char *session
, char **remote_user
) {
536 return session_get_string(session
, "REMOTE_USER", remote_user
);
539 _public_
int sd_session_get_remote_host(const char *session
, char **remote_host
) {
540 return session_get_string(session
, "REMOTE_HOST", remote_host
);
543 static int file_of_seat(const char *seat
, char **_p
) {
550 p
= strappend("/run/systemd/seats/", seat
);
552 _cleanup_free_
char *buf
= NULL
;
554 r
= sd_session_get_seat(NULL
, &buf
);
558 p
= strappend("/run/systemd/seats/", buf
);
569 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
570 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
573 assert_return(session
|| uid
, -EINVAL
);
575 r
= file_of_seat(seat
, &p
);
579 r
= parse_env_file(p
, NEWLINE
,
593 r
= parse_uid(t
, uid
);
606 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
607 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
608 _cleanup_strv_free_
char **a
= NULL
;
609 _cleanup_free_ uid_t
*b
= NULL
;
613 r
= file_of_seat(seat
, &p
);
617 r
= parse_env_file(p
, NEWLINE
,
619 "ACTIVE_SESSIONS", &t
,
626 a
= strv_split(s
, " ");
632 const char *word
, *state
;
635 FOREACH_WORD(word
, l
, t
, state
)
645 FOREACH_WORD(word
, l
, t
, state
) {
646 _cleanup_free_
char *k
= NULL
;
648 k
= strndup(word
, l
);
652 r
= parse_uid(k
, b
+ i
);
680 static int seat_get_can(const char *seat
, const char *variable
) {
681 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
684 assert_return(variable
, -EINVAL
);
686 r
= file_of_seat(seat
, &p
);
690 r
= parse_env_file(p
, NEWLINE
,
698 return parse_boolean(s
);
701 _public_
int sd_seat_can_multi_session(const char *seat
) {
702 return seat_get_can(seat
, "CAN_MULTI_SESSION");
705 _public_
int sd_seat_can_tty(const char *seat
) {
706 return seat_get_can(seat
, "CAN_TTY");
709 _public_
int sd_seat_can_graphical(const char *seat
) {
710 return seat_get_can(seat
, "CAN_GRAPHICAL");
713 _public_
int sd_get_seats(char ***seats
) {
714 return get_files_in_directory("/run/systemd/seats/", seats
);
717 _public_
int sd_get_sessions(char ***sessions
) {
718 return get_files_in_directory("/run/systemd/sessions/", sessions
);
721 _public_
int sd_get_uids(uid_t
**users
) {
722 _cleanup_closedir_
DIR *d
;
725 _cleanup_free_ uid_t
*l
= NULL
;
727 d
= opendir("/run/systemd/users/");
738 if (!de
&& errno
!= 0)
744 dirent_ensure_type(d
, de
);
746 if (!dirent_is_file(de
))
749 k
= parse_uid(de
->d_name
, &uid
);
754 if ((unsigned) r
>= n
) {
758 t
= realloc(l
, sizeof(uid_t
) * n
);
765 assert((unsigned) r
< n
);
779 _public_
int sd_get_machine_names(char ***machines
) {
780 char **l
= NULL
, **a
, **b
;
783 assert_return(machines
, -EINVAL
);
785 r
= get_files_in_directory("/run/systemd/machines/", &l
);
792 /* Filter out the unit: symlinks */
793 for (a
= l
, b
= l
; *a
; a
++) {
794 if (startswith(*a
, "unit:") || !machine_name_is_valid(*a
))
810 _public_
int sd_machine_get_class(const char *machine
, char **class) {
811 _cleanup_free_
char *c
= NULL
;
815 assert_return(machine_name_is_valid(machine
), -EINVAL
);
816 assert_return(class, -EINVAL
);
818 p
= strjoina("/run/systemd/machines/", machine
);
819 r
= parse_env_file(p
, NEWLINE
, "CLASS", &c
, NULL
);
831 _public_
int sd_machine_get_ifindices(const char *machine
, int **ifindices
) {
832 _cleanup_free_
char *netif
= NULL
;
833 size_t l
, allocated
= 0, nr
= 0;
835 const char *p
, *word
, *state
;
838 assert_return(machine_name_is_valid(machine
), -EINVAL
);
839 assert_return(ifindices
, -EINVAL
);
841 p
= strjoina("/run/systemd/machines/", machine
);
842 r
= parse_env_file(p
, NEWLINE
, "NETIF", &netif
, NULL
);
850 FOREACH_WORD(word
, l
, netif
, state
) {
854 *(char*) (mempcpy(buf
, word
, l
)) = 0;
856 if (safe_atoi(buf
, &ifi
) < 0)
861 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
873 static inline int MONITOR_TO_FD(sd_login_monitor
*m
) {
874 return (int) (unsigned long) m
- 1;
877 static inline sd_login_monitor
* FD_TO_MONITOR(int fd
) {
878 return (sd_login_monitor
*) (unsigned long) (fd
+ 1);
881 _public_
int sd_login_monitor_new(const char *category
, sd_login_monitor
**m
) {
885 assert_return(m
, -EINVAL
);
887 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
891 if (!category
|| streq(category
, "seat")) {
892 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
901 if (!category
|| streq(category
, "session")) {
902 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
911 if (!category
|| streq(category
, "uid")) {
912 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
921 if (!category
|| streq(category
, "machine")) {
922 k
= inotify_add_watch(fd
, "/run/systemd/machines/", IN_MOVED_TO
|IN_DELETE
);
936 *m
= FD_TO_MONITOR(fd
);
940 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
943 assert_return(m
, NULL
);
945 fd
= MONITOR_TO_FD(m
);
951 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
953 assert_return(m
, -EINVAL
);
955 return flush_fd(MONITOR_TO_FD(m
));
958 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
960 assert_return(m
, -EINVAL
);
962 return MONITOR_TO_FD(m
);
965 _public_
int sd_login_monitor_get_events(sd_login_monitor
*m
) {
967 assert_return(m
, -EINVAL
);
969 /* For now we will only return POLLIN here, since we don't
970 * need anything else ever for inotify. However, let's have
971 * this API to keep our options open should we later on need
976 _public_
int sd_login_monitor_get_timeout(sd_login_monitor
*m
, uint64_t *timeout_usec
) {
978 assert_return(m
, -EINVAL
);
979 assert_return(timeout_usec
, -EINVAL
);
981 /* For now we will only return (uint64_t) -1, since we don't
982 * need any timeout. However, let's have this API to keep our
983 * options open should we later on need it. */
984 *timeout_usec
= (uint64_t) -1;