1 /* SPDX-License-Identifier: LGPL-2.1+ */
6 #include <sys/inotify.h>
11 #include "alloc-util.h"
12 #include "cgroup-util.h"
13 #include "dirent-util.h"
17 #include "format-util.h"
19 #include "hostname-util.h"
21 #include "login-util.h"
23 #include "parse-util.h"
24 #include "path-util.h"
25 #include "socket-util.h"
26 #include "string-util.h"
28 #include "user-util.h"
33 * invalid input parameters → -EINVAL
35 * process does not exist → -ESRCH
36 * cgroup does not exist → -ENOENT
37 * machine, session does not exist → -ENXIO
38 * requested metadata on object is missing → -ENODATA
41 _public_
int sd_pid_get_session(pid_t pid
, char **session
) {
44 assert_return(pid
>= 0, -EINVAL
);
45 assert_return(session
, -EINVAL
);
47 r
= cg_pid_get_session(pid
, session
);
48 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
51 _public_
int sd_pid_get_unit(pid_t pid
, char **unit
) {
54 assert_return(pid
>= 0, -EINVAL
);
55 assert_return(unit
, -EINVAL
);
57 r
= cg_pid_get_unit(pid
, unit
);
58 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
61 _public_
int sd_pid_get_user_unit(pid_t pid
, char **unit
) {
64 assert_return(pid
>= 0, -EINVAL
);
65 assert_return(unit
, -EINVAL
);
67 r
= cg_pid_get_user_unit(pid
, unit
);
68 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
71 _public_
int sd_pid_get_machine_name(pid_t pid
, char **name
) {
74 assert_return(pid
>= 0, -EINVAL
);
75 assert_return(name
, -EINVAL
);
77 r
= cg_pid_get_machine_name(pid
, name
);
78 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
81 _public_
int sd_pid_get_slice(pid_t pid
, char **slice
) {
84 assert_return(pid
>= 0, -EINVAL
);
85 assert_return(slice
, -EINVAL
);
87 r
= cg_pid_get_slice(pid
, slice
);
88 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
91 _public_
int sd_pid_get_user_slice(pid_t pid
, char **slice
) {
94 assert_return(pid
>= 0, -EINVAL
);
95 assert_return(slice
, -EINVAL
);
97 r
= cg_pid_get_user_slice(pid
, slice
);
98 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
101 _public_
int sd_pid_get_owner_uid(pid_t pid
, uid_t
*uid
) {
104 assert_return(pid
>= 0, -EINVAL
);
105 assert_return(uid
, -EINVAL
);
107 r
= cg_pid_get_owner_uid(pid
, uid
);
108 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
111 _public_
int sd_pid_get_cgroup(pid_t pid
, char **cgroup
) {
115 assert_return(pid
>= 0, -EINVAL
);
116 assert_return(cgroup
, -EINVAL
);
118 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &c
);
122 /* The internal APIs return the empty string for the root
123 * cgroup, let's return the "/" in the public APIs instead, as
124 * that's easier and less ambiguous for people to grok. */
137 _public_
int sd_peer_get_session(int fd
, char **session
) {
138 struct ucred ucred
= {};
141 assert_return(fd
>= 0, -EBADF
);
142 assert_return(session
, -EINVAL
);
144 r
= getpeercred(fd
, &ucred
);
148 return cg_pid_get_session(ucred
.pid
, session
);
151 _public_
int sd_peer_get_owner_uid(int fd
, uid_t
*uid
) {
155 assert_return(fd
>= 0, -EBADF
);
156 assert_return(uid
, -EINVAL
);
158 r
= getpeercred(fd
, &ucred
);
162 return cg_pid_get_owner_uid(ucred
.pid
, uid
);
165 _public_
int sd_peer_get_unit(int fd
, char **unit
) {
169 assert_return(fd
>= 0, -EBADF
);
170 assert_return(unit
, -EINVAL
);
172 r
= getpeercred(fd
, &ucred
);
176 return cg_pid_get_unit(ucred
.pid
, unit
);
179 _public_
int sd_peer_get_user_unit(int fd
, char **unit
) {
183 assert_return(fd
>= 0, -EBADF
);
184 assert_return(unit
, -EINVAL
);
186 r
= getpeercred(fd
, &ucred
);
190 return cg_pid_get_user_unit(ucred
.pid
, unit
);
193 _public_
int sd_peer_get_machine_name(int fd
, char **machine
) {
197 assert_return(fd
>= 0, -EBADF
);
198 assert_return(machine
, -EINVAL
);
200 r
= getpeercred(fd
, &ucred
);
204 return cg_pid_get_machine_name(ucred
.pid
, machine
);
207 _public_
int sd_peer_get_slice(int fd
, char **slice
) {
211 assert_return(fd
>= 0, -EBADF
);
212 assert_return(slice
, -EINVAL
);
214 r
= getpeercred(fd
, &ucred
);
218 return cg_pid_get_slice(ucred
.pid
, slice
);
221 _public_
int sd_peer_get_user_slice(int fd
, char **slice
) {
225 assert_return(fd
>= 0, -EBADF
);
226 assert_return(slice
, -EINVAL
);
228 r
= getpeercred(fd
, &ucred
);
232 return cg_pid_get_user_slice(ucred
.pid
, slice
);
235 _public_
int sd_peer_get_cgroup(int fd
, char **cgroup
) {
239 assert_return(fd
>= 0, -EBADF
);
240 assert_return(cgroup
, -EINVAL
);
242 r
= getpeercred(fd
, &ucred
);
246 return sd_pid_get_cgroup(ucred
.pid
, cgroup
);
249 static int file_of_uid(uid_t uid
, char **p
) {
251 assert_return(uid_is_valid(uid
), -EINVAL
);
254 if (asprintf(p
, "/run/systemd/users/" UID_FMT
, uid
) < 0)
260 _public_
int sd_uid_get_state(uid_t uid
, char**state
) {
261 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
264 assert_return(state
, -EINVAL
);
266 r
= file_of_uid(uid
, &p
);
270 r
= parse_env_file(NULL
, p
, "STATE", &s
);
272 r
= free_and_strdup(&s
, "offline");
280 *state
= TAKE_PTR(s
);
284 _public_
int sd_uid_get_display(uid_t uid
, char **session
) {
285 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
288 assert_return(session
, -EINVAL
);
290 r
= file_of_uid(uid
, &p
);
294 r
= parse_env_file(NULL
, p
, "DISPLAY", &s
);
302 *session
= TAKE_PTR(s
);
307 static int file_of_seat(const char *seat
, char **_p
) {
314 if (!filename_is_valid(seat
))
317 p
= strappend("/run/systemd/seats/", seat
);
319 _cleanup_free_
char *buf
= NULL
;
321 r
= sd_session_get_seat(NULL
, &buf
);
325 p
= strappend("/run/systemd/seats/", buf
);
335 _public_
int sd_uid_is_on_seat(uid_t uid
, int require_active
, const char *seat
) {
336 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *p
= NULL
;
339 const char *word
, *variable
, *state
;
341 assert_return(uid_is_valid(uid
), -EINVAL
);
343 r
= file_of_seat(seat
, &p
);
347 variable
= require_active
? "ACTIVE_UID" : "UIDS";
349 r
= parse_env_file(NULL
, p
, variable
, &s
);
357 if (asprintf(&t
, UID_FMT
, uid
) < 0)
360 FOREACH_WORD(word
, l
, s
, state
)
361 if (strneq(t
, word
, l
))
367 static int uid_get_array(uid_t uid
, const char *variable
, char ***array
) {
368 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
374 r
= file_of_uid(uid
, &p
);
378 r
= parse_env_file(NULL
, p
, variable
, &s
);
379 if (r
== -ENOENT
|| (r
>= 0 && isempty(s
))) {
387 a
= strv_split(s
, " ");
392 r
= (int) strv_length(a
);
402 _public_
int sd_uid_get_sessions(uid_t uid
, int require_active
, char ***sessions
) {
403 return uid_get_array(
405 require_active
== 0 ? "ONLINE_SESSIONS" :
406 require_active
> 0 ? "ACTIVE_SESSIONS" :
411 _public_
int sd_uid_get_seats(uid_t uid
, int require_active
, char ***seats
) {
412 return uid_get_array(
414 require_active
== 0 ? "ONLINE_SEATS" :
415 require_active
> 0 ? "ACTIVE_SEATS" :
420 static int file_of_session(const char *session
, char **_p
) {
427 if (!session_id_valid(session
))
430 p
= strappend("/run/systemd/sessions/", session
);
432 _cleanup_free_
char *buf
= NULL
;
434 r
= sd_pid_get_session(0, &buf
);
438 p
= strappend("/run/systemd/sessions/", buf
);
448 _public_
int sd_session_is_active(const char *session
) {
449 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
452 r
= file_of_session(session
, &p
);
456 r
= parse_env_file(NULL
, p
, "ACTIVE", &s
);
464 return parse_boolean(s
);
467 _public_
int sd_session_is_remote(const char *session
) {
468 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
471 r
= file_of_session(session
, &p
);
475 r
= parse_env_file(NULL
, p
, "REMOTE", &s
);
483 return parse_boolean(s
);
486 _public_
int sd_session_get_state(const char *session
, char **state
) {
487 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
490 assert_return(state
, -EINVAL
);
492 r
= file_of_session(session
, &p
);
496 r
= parse_env_file(NULL
, p
, "STATE", &s
);
504 *state
= TAKE_PTR(s
);
509 _public_
int sd_session_get_uid(const char *session
, uid_t
*uid
) {
511 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
513 assert_return(uid
, -EINVAL
);
515 r
= file_of_session(session
, &p
);
519 r
= parse_env_file(NULL
, p
, "UID", &s
);
527 return parse_uid(s
, uid
);
530 static int session_get_string(const char *session
, const char *field
, char **value
) {
531 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
534 assert_return(value
, -EINVAL
);
537 r
= file_of_session(session
, &p
);
541 r
= parse_env_file(NULL
, p
, field
, &s
);
549 *value
= TAKE_PTR(s
);
553 _public_
int sd_session_get_seat(const char *session
, char **seat
) {
554 return session_get_string(session
, "SEAT", seat
);
557 _public_
int sd_session_get_tty(const char *session
, char **tty
) {
558 return session_get_string(session
, "TTY", tty
);
561 _public_
int sd_session_get_vt(const char *session
, unsigned *vtnr
) {
562 _cleanup_free_
char *vtnr_string
= NULL
;
566 assert_return(vtnr
, -EINVAL
);
568 r
= session_get_string(session
, "VTNR", &vtnr_string
);
572 r
= safe_atou(vtnr_string
, &u
);
580 _public_
int sd_session_get_service(const char *session
, char **service
) {
581 return session_get_string(session
, "SERVICE", service
);
584 _public_
int sd_session_get_type(const char *session
, char **type
) {
585 return session_get_string(session
, "TYPE", type
);
588 _public_
int sd_session_get_class(const char *session
, char **class) {
589 return session_get_string(session
, "CLASS", class);
592 _public_
int sd_session_get_desktop(const char *session
, char **desktop
) {
593 _cleanup_free_
char *escaped
= NULL
;
597 assert_return(desktop
, -EINVAL
);
599 r
= session_get_string(session
, "DESKTOP", &escaped
);
603 r
= cunescape(escaped
, 0, &t
);
611 _public_
int sd_session_get_display(const char *session
, char **display
) {
612 return session_get_string(session
, "DISPLAY", display
);
615 _public_
int sd_session_get_remote_user(const char *session
, char **remote_user
) {
616 return session_get_string(session
, "REMOTE_USER", remote_user
);
619 _public_
int sd_session_get_remote_host(const char *session
, char **remote_host
) {
620 return session_get_string(session
, "REMOTE_HOST", remote_host
);
623 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
624 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
627 assert_return(session
|| uid
, -EINVAL
);
629 r
= file_of_seat(seat
, &p
);
633 r
= parse_env_file(NULL
, p
,
648 r
= parse_uid(t
, uid
);
654 *session
= TAKE_PTR(s
);
659 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
660 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
661 _cleanup_strv_free_
char **a
= NULL
;
662 _cleanup_free_ uid_t
*b
= NULL
;
666 r
= file_of_seat(seat
, &p
);
670 r
= parse_env_file(NULL
, p
,
679 a
= strv_split(s
, " ");
685 const char *word
, *state
;
688 FOREACH_WORD(word
, l
, t
, state
)
698 FOREACH_WORD(word
, l
, t
, state
) {
699 _cleanup_free_
char *k
= NULL
;
701 k
= strndup(word
, l
);
705 r
= parse_uid(k
, b
+ i
);
714 r
= (int) strv_length(a
);
717 *sessions
= TAKE_PTR(a
);
728 static int seat_get_can(const char *seat
, const char *variable
) {
729 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
734 r
= file_of_seat(seat
, &p
);
738 r
= parse_env_file(NULL
, p
,
747 return parse_boolean(s
);
750 _public_
int sd_seat_can_multi_session(const char *seat
) {
751 return seat_get_can(seat
, "CAN_MULTI_SESSION");
754 _public_
int sd_seat_can_tty(const char *seat
) {
755 return seat_get_can(seat
, "CAN_TTY");
758 _public_
int sd_seat_can_graphical(const char *seat
) {
759 return seat_get_can(seat
, "CAN_GRAPHICAL");
762 _public_
int sd_get_seats(char ***seats
) {
765 r
= get_files_in_directory("/run/systemd/seats/", seats
);
774 _public_
int sd_get_sessions(char ***sessions
) {
777 r
= get_files_in_directory("/run/systemd/sessions/", sessions
);
786 _public_
int sd_get_uids(uid_t
**users
) {
787 _cleanup_closedir_
DIR *d
;
791 _cleanup_free_ uid_t
*l
= NULL
;
793 d
= opendir("/run/systemd/users/");
795 if (errno
== ENOENT
) {
803 FOREACH_DIRENT_ALL(de
, d
, return -errno
) {
807 dirent_ensure_type(d
, de
);
809 if (!dirent_is_file(de
))
812 k
= parse_uid(de
->d_name
, &uid
);
817 if ((unsigned) r
>= n
) {
821 t
= realloc(l
, sizeof(uid_t
) * n
);
828 assert((unsigned) r
< n
);
835 *users
= TAKE_PTR(l
);
840 _public_
int sd_get_machine_names(char ***machines
) {
841 _cleanup_strv_free_
char **l
= NULL
;
845 r
= get_files_in_directory("/run/systemd/machines/", &l
);
857 /* Filter out the unit: symlinks */
858 for (a
= b
= l
; *a
; a
++) {
859 if (startswith(*a
, "unit:") || !machine_name_is_valid(*a
))
872 *machines
= TAKE_PTR(l
);
877 _public_
int sd_machine_get_class(const char *machine
, char **class) {
878 _cleanup_free_
char *c
= NULL
;
882 assert_return(class, -EINVAL
);
884 if (streq(machine
, ".host")) {
889 if (!machine_name_is_valid(machine
))
892 p
= strjoina("/run/systemd/machines/", machine
);
893 r
= parse_env_file(NULL
, p
, "CLASS", &c
);
902 *class = TAKE_PTR(c
);
906 _public_
int sd_machine_get_ifindices(const char *machine
, int **ifindices
) {
907 _cleanup_free_
char *netif
= NULL
;
908 size_t l
, allocated
= 0, nr
= 0;
910 const char *p
, *word
, *state
;
913 assert_return(machine_name_is_valid(machine
), -EINVAL
);
914 assert_return(ifindices
, -EINVAL
);
916 p
= strjoina("/run/systemd/machines/", machine
);
917 r
= parse_env_file(NULL
, p
, "NETIF", &netif
);
927 FOREACH_WORD(word
, l
, netif
, state
) {
931 *(char*) (mempcpy(buf
, word
, l
)) = 0;
933 if (parse_ifindex(buf
, &ifi
) < 0)
936 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
948 static int MONITOR_TO_FD(sd_login_monitor
*m
) {
949 return (int) (unsigned long) m
- 1;
952 static sd_login_monitor
* FD_TO_MONITOR(int fd
) {
953 return (sd_login_monitor
*) (unsigned long) (fd
+ 1);
956 _public_
int sd_login_monitor_new(const char *category
, sd_login_monitor
**m
) {
957 _cleanup_close_
int fd
= -1;
961 assert_return(m
, -EINVAL
);
963 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
967 if (!category
|| streq(category
, "seat")) {
968 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
975 if (!category
|| streq(category
, "session")) {
976 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
983 if (!category
|| streq(category
, "uid")) {
984 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
991 if (!category
|| streq(category
, "machine")) {
992 k
= inotify_add_watch(fd
, "/run/systemd/machines/", IN_MOVED_TO
|IN_DELETE
);
1002 *m
= FD_TO_MONITOR(fd
);
1008 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
1014 fd
= MONITOR_TO_FD(m
);
1020 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
1023 assert_return(m
, -EINVAL
);
1025 r
= flush_fd(MONITOR_TO_FD(m
));
1032 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
1034 assert_return(m
, -EINVAL
);
1036 return MONITOR_TO_FD(m
);
1039 _public_
int sd_login_monitor_get_events(sd_login_monitor
*m
) {
1041 assert_return(m
, -EINVAL
);
1043 /* For now we will only return POLLIN here, since we don't
1044 * need anything else ever for inotify. However, let's have
1045 * this API to keep our options open should we later on need
1050 _public_
int sd_login_monitor_get_timeout(sd_login_monitor
*m
, uint64_t *timeout_usec
) {
1052 assert_return(m
, -EINVAL
);
1053 assert_return(timeout_usec
, -EINVAL
);
1055 /* For now we will only return (uint64_t) -1, since we don't
1056 * need any timeout. However, let's have this API to keep our
1057 * options open should we later on need it. */
1058 *timeout_usec
= (uint64_t) -1;