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
);
254 _public_
int sd_uid_is_on_seat(uid_t uid
, int require_active
, const char *seat
) {
255 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *p
= NULL
;
258 const char *word
, *variable
, *state
;
260 assert_return(seat
, -EINVAL
);
262 variable
= require_active
? "ACTIVE_UID" : "UIDS";
264 p
= strappend("/run/systemd/seats/", seat
);
268 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
276 if (asprintf(&t
, UID_FMT
, uid
) < 0)
279 FOREACH_WORD(word
, l
, s
, state
) {
280 if (strneq(t
, word
, l
))
287 static int uid_get_array(uid_t uid
, const char *variable
, char ***array
) {
288 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
292 r
= file_of_uid(uid
, &p
);
296 r
= parse_env_file(p
, NEWLINE
,
315 a
= strv_split(s
, " ");
331 _public_
int sd_uid_get_sessions(uid_t uid
, int require_active
, char ***sessions
) {
332 return uid_get_array(
334 require_active
== 0 ? "ONLINE_SESSIONS" :
335 require_active
> 0 ? "ACTIVE_SESSIONS" :
340 _public_
int sd_uid_get_seats(uid_t uid
, int require_active
, char ***seats
) {
341 return uid_get_array(
343 require_active
== 0 ? "ONLINE_SEATS" :
344 require_active
> 0 ? "ACTIVE_SEATS" :
349 static int file_of_session(const char *session
, char **_p
) {
356 if (!session_id_valid(session
))
359 p
= strappend("/run/systemd/sessions/", session
);
361 _cleanup_free_
char *buf
= NULL
;
363 r
= sd_pid_get_session(0, &buf
);
367 p
= strappend("/run/systemd/sessions/", buf
);
377 _public_
int sd_session_is_active(const char *session
) {
379 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
381 r
= file_of_session(session
, &p
);
385 r
= parse_env_file(p
, NEWLINE
, "ACTIVE", &s
, NULL
);
392 return parse_boolean(s
);
395 _public_
int sd_session_is_remote(const char *session
) {
397 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
399 r
= file_of_session(session
, &p
);
403 r
= parse_env_file(p
, NEWLINE
, "REMOTE", &s
, NULL
);
410 return parse_boolean(s
);
413 _public_
int sd_session_get_state(const char *session
, char **state
) {
414 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
417 assert_return(state
, -EINVAL
);
419 r
= file_of_session(session
, &p
);
423 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
435 _public_
int sd_session_get_uid(const char *session
, uid_t
*uid
) {
437 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
439 assert_return(uid
, -EINVAL
);
441 r
= file_of_session(session
, &p
);
445 r
= parse_env_file(p
, NEWLINE
, "UID", &s
, NULL
);
452 return parse_uid(s
, uid
);
455 static int session_get_string(const char *session
, const char *field
, char **value
) {
456 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
459 assert_return(value
, -EINVAL
);
461 r
= file_of_session(session
, &p
);
465 r
= parse_env_file(p
, NEWLINE
, field
, &s
, NULL
);
477 _public_
int sd_session_get_seat(const char *session
, char **seat
) {
478 return session_get_string(session
, "SEAT", seat
);
481 _public_
int sd_session_get_tty(const char *session
, char **tty
) {
482 return session_get_string(session
, "TTY", tty
);
485 _public_
int sd_session_get_vt(const char *session
, unsigned *vtnr
) {
486 _cleanup_free_
char *vtnr_string
= NULL
;
490 r
= session_get_string(session
, "VTNR", &vtnr_string
);
494 r
= safe_atou(vtnr_string
, &u
);
502 _public_
int sd_session_get_service(const char *session
, char **service
) {
503 return session_get_string(session
, "SERVICE", service
);
506 _public_
int sd_session_get_type(const char *session
, char **type
) {
507 return session_get_string(session
, "TYPE", type
);
510 _public_
int sd_session_get_class(const char *session
, char **class) {
511 return session_get_string(session
, "CLASS", class);
514 _public_
int sd_session_get_desktop(const char *session
, char **desktop
) {
515 _cleanup_free_
char *escaped
= NULL
;
519 assert_return(desktop
, -EINVAL
);
521 r
= session_get_string(session
, "DESKTOP", &escaped
);
525 r
= cunescape(escaped
, 0, &t
);
533 _public_
int sd_session_get_display(const char *session
, char **display
) {
534 return session_get_string(session
, "DISPLAY", display
);
537 _public_
int sd_session_get_remote_user(const char *session
, char **remote_user
) {
538 return session_get_string(session
, "REMOTE_USER", remote_user
);
541 _public_
int sd_session_get_remote_host(const char *session
, char **remote_host
) {
542 return session_get_string(session
, "REMOTE_HOST", remote_host
);
545 static int file_of_seat(const char *seat
, char **_p
) {
552 p
= strappend("/run/systemd/seats/", seat
);
554 _cleanup_free_
char *buf
= NULL
;
556 r
= sd_session_get_seat(NULL
, &buf
);
560 p
= strappend("/run/systemd/seats/", buf
);
571 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
572 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
575 assert_return(session
|| uid
, -EINVAL
);
577 r
= file_of_seat(seat
, &p
);
581 r
= parse_env_file(p
, NEWLINE
,
595 r
= parse_uid(t
, uid
);
608 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
609 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
610 _cleanup_strv_free_
char **a
= NULL
;
611 _cleanup_free_ uid_t
*b
= NULL
;
615 r
= file_of_seat(seat
, &p
);
619 r
= parse_env_file(p
, NEWLINE
,
621 "ACTIVE_SESSIONS", &t
,
628 a
= strv_split(s
, " ");
634 const char *word
, *state
;
637 FOREACH_WORD(word
, l
, t
, state
)
647 FOREACH_WORD(word
, l
, t
, state
) {
648 _cleanup_free_
char *k
= NULL
;
650 k
= strndup(word
, l
);
654 r
= parse_uid(k
, b
+ i
);
682 static int seat_get_can(const char *seat
, const char *variable
) {
683 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
686 assert_return(variable
, -EINVAL
);
688 r
= file_of_seat(seat
, &p
);
692 r
= parse_env_file(p
, NEWLINE
,
700 return parse_boolean(s
);
703 _public_
int sd_seat_can_multi_session(const char *seat
) {
704 return seat_get_can(seat
, "CAN_MULTI_SESSION");
707 _public_
int sd_seat_can_tty(const char *seat
) {
708 return seat_get_can(seat
, "CAN_TTY");
711 _public_
int sd_seat_can_graphical(const char *seat
) {
712 return seat_get_can(seat
, "CAN_GRAPHICAL");
715 _public_
int sd_get_seats(char ***seats
) {
716 return get_files_in_directory("/run/systemd/seats/", seats
);
719 _public_
int sd_get_sessions(char ***sessions
) {
720 return get_files_in_directory("/run/systemd/sessions/", sessions
);
723 _public_
int sd_get_uids(uid_t
**users
) {
724 _cleanup_closedir_
DIR *d
;
727 _cleanup_free_ uid_t
*l
= NULL
;
729 d
= opendir("/run/systemd/users/");
740 if (!de
&& errno
!= 0)
746 dirent_ensure_type(d
, de
);
748 if (!dirent_is_file(de
))
751 k
= parse_uid(de
->d_name
, &uid
);
756 if ((unsigned) r
>= n
) {
760 t
= realloc(l
, sizeof(uid_t
) * n
);
767 assert((unsigned) r
< n
);
781 _public_
int sd_get_machine_names(char ***machines
) {
782 char **l
= NULL
, **a
, **b
;
785 assert_return(machines
, -EINVAL
);
787 r
= get_files_in_directory("/run/systemd/machines/", &l
);
794 /* Filter out the unit: symlinks */
795 for (a
= l
, b
= l
; *a
; a
++) {
796 if (startswith(*a
, "unit:") || !machine_name_is_valid(*a
))
812 _public_
int sd_machine_get_class(const char *machine
, char **class) {
813 _cleanup_free_
char *c
= NULL
;
817 assert_return(machine_name_is_valid(machine
), -EINVAL
);
818 assert_return(class, -EINVAL
);
820 p
= strjoina("/run/systemd/machines/", machine
);
821 r
= parse_env_file(p
, NEWLINE
, "CLASS", &c
, NULL
);
833 _public_
int sd_machine_get_ifindices(const char *machine
, int **ifindices
) {
834 _cleanup_free_
char *netif
= NULL
;
835 size_t l
, allocated
= 0, nr
= 0;
837 const char *p
, *word
, *state
;
840 assert_return(machine_name_is_valid(machine
), -EINVAL
);
841 assert_return(ifindices
, -EINVAL
);
843 p
= strjoina("/run/systemd/machines/", machine
);
844 r
= parse_env_file(p
, NEWLINE
, "NETIF", &netif
, NULL
);
852 FOREACH_WORD(word
, l
, netif
, state
) {
856 *(char*) (mempcpy(buf
, word
, l
)) = 0;
858 if (safe_atoi(buf
, &ifi
) < 0)
863 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
875 static inline int MONITOR_TO_FD(sd_login_monitor
*m
) {
876 return (int) (unsigned long) m
- 1;
879 static inline sd_login_monitor
* FD_TO_MONITOR(int fd
) {
880 return (sd_login_monitor
*) (unsigned long) (fd
+ 1);
883 _public_
int sd_login_monitor_new(const char *category
, sd_login_monitor
**m
) {
887 assert_return(m
, -EINVAL
);
889 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
893 if (!category
|| streq(category
, "seat")) {
894 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
903 if (!category
|| streq(category
, "session")) {
904 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
913 if (!category
|| streq(category
, "uid")) {
914 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
923 if (!category
|| streq(category
, "machine")) {
924 k
= inotify_add_watch(fd
, "/run/systemd/machines/", IN_MOVED_TO
|IN_DELETE
);
938 *m
= FD_TO_MONITOR(fd
);
942 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
945 assert_return(m
, NULL
);
947 fd
= MONITOR_TO_FD(m
);
953 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
955 assert_return(m
, -EINVAL
);
957 return flush_fd(MONITOR_TO_FD(m
));
960 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
962 assert_return(m
, -EINVAL
);
964 return MONITOR_TO_FD(m
);
967 _public_
int sd_login_monitor_get_events(sd_login_monitor
*m
) {
969 assert_return(m
, -EINVAL
);
971 /* For now we will only return POLLIN here, since we don't
972 * need anything else ever for inotify. However, let's have
973 * this API to keep our options open should we later on need
978 _public_
int sd_login_monitor_get_timeout(sd_login_monitor
*m
, uint64_t *timeout_usec
) {
980 assert_return(m
, -EINVAL
);
981 assert_return(timeout_usec
, -EINVAL
);
983 /* For now we will only return (uint64_t) -1, since we don't
984 * need any timeout. However, let's have this API to keep our
985 * options open should we later on need it. */
986 *timeout_usec
= (uint64_t) -1;