1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <sys/inotify.h>
29 #include "alloc-util.h"
30 #include "cgroup-util.h"
31 #include "dirent-util.h"
35 #include "format-util.h"
37 #include "hostname-util.h"
39 #include "login-util.h"
41 #include "parse-util.h"
42 #include "path-util.h"
43 #include "socket-util.h"
44 #include "string-util.h"
46 #include "user-util.h"
51 * invalid input parameters → -EINVAL
53 * process does not exist → -ESRCH
54 * cgroup does not exist → -ENOENT
55 * machine, session does not exist → -ENXIO
56 * requested metadata on object is missing → -ENODATA
59 _public_
int sd_pid_get_session(pid_t pid
, char **session
) {
62 assert_return(pid
>= 0, -EINVAL
);
63 assert_return(session
, -EINVAL
);
65 r
= cg_pid_get_session(pid
, session
);
66 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
69 _public_
int sd_pid_get_unit(pid_t pid
, char **unit
) {
72 assert_return(pid
>= 0, -EINVAL
);
73 assert_return(unit
, -EINVAL
);
75 r
= cg_pid_get_unit(pid
, unit
);
76 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
79 _public_
int sd_pid_get_user_unit(pid_t pid
, char **unit
) {
82 assert_return(pid
>= 0, -EINVAL
);
83 assert_return(unit
, -EINVAL
);
85 r
= cg_pid_get_user_unit(pid
, unit
);
86 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
89 _public_
int sd_pid_get_machine_name(pid_t pid
, char **name
) {
92 assert_return(pid
>= 0, -EINVAL
);
93 assert_return(name
, -EINVAL
);
95 r
= cg_pid_get_machine_name(pid
, name
);
96 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
99 _public_
int sd_pid_get_slice(pid_t pid
, char **slice
) {
102 assert_return(pid
>= 0, -EINVAL
);
103 assert_return(slice
, -EINVAL
);
105 r
= cg_pid_get_slice(pid
, slice
);
106 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
109 _public_
int sd_pid_get_user_slice(pid_t pid
, char **slice
) {
112 assert_return(pid
>= 0, -EINVAL
);
113 assert_return(slice
, -EINVAL
);
115 r
= cg_pid_get_user_slice(pid
, slice
);
116 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
119 _public_
int sd_pid_get_owner_uid(pid_t pid
, uid_t
*uid
) {
122 assert_return(pid
>= 0, -EINVAL
);
123 assert_return(uid
, -EINVAL
);
125 r
= cg_pid_get_owner_uid(pid
, uid
);
126 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
129 _public_
int sd_pid_get_cgroup(pid_t pid
, char **cgroup
) {
133 assert_return(pid
>= 0, -EINVAL
);
134 assert_return(cgroup
, -EINVAL
);
136 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &c
);
140 /* The internal APIs return the empty string for the root
141 * cgroup, let's return the "/" in the public APIs instead, as
142 * that's easier and less ambiguous for people to grok. */
155 _public_
int sd_peer_get_session(int fd
, char **session
) {
156 struct ucred ucred
= {};
159 assert_return(fd
>= 0, -EBADF
);
160 assert_return(session
, -EINVAL
);
162 r
= getpeercred(fd
, &ucred
);
166 return cg_pid_get_session(ucred
.pid
, session
);
169 _public_
int sd_peer_get_owner_uid(int fd
, uid_t
*uid
) {
173 assert_return(fd
>= 0, -EBADF
);
174 assert_return(uid
, -EINVAL
);
176 r
= getpeercred(fd
, &ucred
);
180 return cg_pid_get_owner_uid(ucred
.pid
, uid
);
183 _public_
int sd_peer_get_unit(int fd
, char **unit
) {
187 assert_return(fd
>= 0, -EBADF
);
188 assert_return(unit
, -EINVAL
);
190 r
= getpeercred(fd
, &ucred
);
194 return cg_pid_get_unit(ucred
.pid
, unit
);
197 _public_
int sd_peer_get_user_unit(int fd
, char **unit
) {
201 assert_return(fd
>= 0, -EBADF
);
202 assert_return(unit
, -EINVAL
);
204 r
= getpeercred(fd
, &ucred
);
208 return cg_pid_get_user_unit(ucred
.pid
, unit
);
211 _public_
int sd_peer_get_machine_name(int fd
, char **machine
) {
215 assert_return(fd
>= 0, -EBADF
);
216 assert_return(machine
, -EINVAL
);
218 r
= getpeercred(fd
, &ucred
);
222 return cg_pid_get_machine_name(ucred
.pid
, machine
);
225 _public_
int sd_peer_get_slice(int fd
, char **slice
) {
229 assert_return(fd
>= 0, -EBADF
);
230 assert_return(slice
, -EINVAL
);
232 r
= getpeercred(fd
, &ucred
);
236 return cg_pid_get_slice(ucred
.pid
, slice
);
239 _public_
int sd_peer_get_user_slice(int fd
, char **slice
) {
243 assert_return(fd
>= 0, -EBADF
);
244 assert_return(slice
, -EINVAL
);
246 r
= getpeercred(fd
, &ucred
);
250 return cg_pid_get_user_slice(ucred
.pid
, slice
);
253 _public_
int sd_peer_get_cgroup(int fd
, char **cgroup
) {
257 assert_return(fd
>= 0, -EBADF
);
258 assert_return(cgroup
, -EINVAL
);
260 r
= getpeercred(fd
, &ucred
);
264 return sd_pid_get_cgroup(ucred
.pid
, cgroup
);
267 static int file_of_uid(uid_t uid
, char **p
) {
269 assert_return(uid_is_valid(uid
), -EINVAL
);
272 if (asprintf(p
, "/run/systemd/users/" UID_FMT
, uid
) < 0)
278 _public_
int sd_uid_get_state(uid_t uid
, char**state
) {
279 _cleanup_free_
char *p
= NULL
;
283 assert_return(state
, -EINVAL
);
285 r
= file_of_uid(uid
, &p
);
289 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
292 s
= strdup("offline");
310 _public_
int sd_uid_get_display(uid_t uid
, char **session
) {
311 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
314 assert_return(session
, -EINVAL
);
316 r
= file_of_uid(uid
, &p
);
320 r
= parse_env_file(p
, NEWLINE
, "DISPLAY", &s
, NULL
);
328 *session
= TAKE_PTR(s
);
333 static int file_of_seat(const char *seat
, char **_p
) {
340 if (!filename_is_valid(seat
))
343 p
= strappend("/run/systemd/seats/", seat
);
345 _cleanup_free_
char *buf
= NULL
;
347 r
= sd_session_get_seat(NULL
, &buf
);
351 p
= strappend("/run/systemd/seats/", buf
);
361 _public_
int sd_uid_is_on_seat(uid_t uid
, int require_active
, const char *seat
) {
362 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *p
= NULL
;
365 const char *word
, *variable
, *state
;
367 assert_return(uid_is_valid(uid
), -EINVAL
);
369 r
= file_of_seat(seat
, &p
);
373 variable
= require_active
? "ACTIVE_UID" : "UIDS";
375 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
383 if (asprintf(&t
, UID_FMT
, uid
) < 0)
386 FOREACH_WORD(word
, l
, s
, state
)
387 if (strneq(t
, word
, l
))
393 static int uid_get_array(uid_t uid
, const char *variable
, char ***array
) {
394 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
400 r
= file_of_uid(uid
, &p
);
404 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
405 if (r
== -ENOENT
|| (r
>= 0 && isempty(s
))) {
413 a
= strv_split(s
, " ");
428 _public_
int sd_uid_get_sessions(uid_t uid
, int require_active
, char ***sessions
) {
429 return uid_get_array(
431 require_active
== 0 ? "ONLINE_SESSIONS" :
432 require_active
> 0 ? "ACTIVE_SESSIONS" :
437 _public_
int sd_uid_get_seats(uid_t uid
, int require_active
, char ***seats
) {
438 return uid_get_array(
440 require_active
== 0 ? "ONLINE_SEATS" :
441 require_active
> 0 ? "ACTIVE_SEATS" :
446 static int file_of_session(const char *session
, char **_p
) {
453 if (!session_id_valid(session
))
456 p
= strappend("/run/systemd/sessions/", session
);
458 _cleanup_free_
char *buf
= NULL
;
460 r
= sd_pid_get_session(0, &buf
);
464 p
= strappend("/run/systemd/sessions/", buf
);
474 _public_
int sd_session_is_active(const char *session
) {
475 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
478 r
= file_of_session(session
, &p
);
482 r
= parse_env_file(p
, NEWLINE
, "ACTIVE", &s
, NULL
);
490 return parse_boolean(s
);
493 _public_
int sd_session_is_remote(const char *session
) {
494 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
497 r
= file_of_session(session
, &p
);
501 r
= parse_env_file(p
, NEWLINE
, "REMOTE", &s
, NULL
);
509 return parse_boolean(s
);
512 _public_
int sd_session_get_state(const char *session
, char **state
) {
513 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
516 assert_return(state
, -EINVAL
);
518 r
= file_of_session(session
, &p
);
522 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
530 *state
= TAKE_PTR(s
);
535 _public_
int sd_session_get_uid(const char *session
, uid_t
*uid
) {
537 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
539 assert_return(uid
, -EINVAL
);
541 r
= file_of_session(session
, &p
);
545 r
= parse_env_file(p
, NEWLINE
, "UID", &s
, NULL
);
553 return parse_uid(s
, uid
);
556 static int session_get_string(const char *session
, const char *field
, char **value
) {
557 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
560 assert_return(value
, -EINVAL
);
563 r
= file_of_session(session
, &p
);
567 r
= parse_env_file(p
, NEWLINE
, field
, &s
, NULL
);
575 *value
= TAKE_PTR(s
);
579 _public_
int sd_session_get_seat(const char *session
, char **seat
) {
580 return session_get_string(session
, "SEAT", seat
);
583 _public_
int sd_session_get_tty(const char *session
, char **tty
) {
584 return session_get_string(session
, "TTY", tty
);
587 _public_
int sd_session_get_vt(const char *session
, unsigned *vtnr
) {
588 _cleanup_free_
char *vtnr_string
= NULL
;
592 assert_return(vtnr
, -EINVAL
);
594 r
= session_get_string(session
, "VTNR", &vtnr_string
);
598 r
= safe_atou(vtnr_string
, &u
);
606 _public_
int sd_session_get_service(const char *session
, char **service
) {
607 return session_get_string(session
, "SERVICE", service
);
610 _public_
int sd_session_get_type(const char *session
, char **type
) {
611 return session_get_string(session
, "TYPE", type
);
614 _public_
int sd_session_get_class(const char *session
, char **class) {
615 return session_get_string(session
, "CLASS", class);
618 _public_
int sd_session_get_desktop(const char *session
, char **desktop
) {
619 _cleanup_free_
char *escaped
= NULL
;
623 assert_return(desktop
, -EINVAL
);
625 r
= session_get_string(session
, "DESKTOP", &escaped
);
629 r
= cunescape(escaped
, 0, &t
);
637 _public_
int sd_session_get_display(const char *session
, char **display
) {
638 return session_get_string(session
, "DISPLAY", display
);
641 _public_
int sd_session_get_remote_user(const char *session
, char **remote_user
) {
642 return session_get_string(session
, "REMOTE_USER", remote_user
);
645 _public_
int sd_session_get_remote_host(const char *session
, char **remote_host
) {
646 return session_get_string(session
, "REMOTE_HOST", remote_host
);
649 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
650 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
653 assert_return(session
|| uid
, -EINVAL
);
655 r
= file_of_seat(seat
, &p
);
659 r
= parse_env_file(p
, NEWLINE
,
675 r
= parse_uid(t
, uid
);
681 *session
= TAKE_PTR(s
);
686 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
687 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
688 _cleanup_strv_free_
char **a
= NULL
;
689 _cleanup_free_ uid_t
*b
= NULL
;
693 r
= file_of_seat(seat
, &p
);
697 r
= parse_env_file(p
, NEWLINE
,
707 a
= strv_split(s
, " ");
713 const char *word
, *state
;
716 FOREACH_WORD(word
, l
, t
, state
)
726 FOREACH_WORD(word
, l
, t
, state
) {
727 _cleanup_free_
char *k
= NULL
;
729 k
= strndup(word
, l
);
733 r
= parse_uid(k
, b
+ i
);
760 static int seat_get_can(const char *seat
, const char *variable
) {
761 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
766 r
= file_of_seat(seat
, &p
);
770 r
= parse_env_file(p
, NEWLINE
,
780 return parse_boolean(s
);
783 _public_
int sd_seat_can_multi_session(const char *seat
) {
784 return seat_get_can(seat
, "CAN_MULTI_SESSION");
787 _public_
int sd_seat_can_tty(const char *seat
) {
788 return seat_get_can(seat
, "CAN_TTY");
791 _public_
int sd_seat_can_graphical(const char *seat
) {
792 return seat_get_can(seat
, "CAN_GRAPHICAL");
795 _public_
int sd_get_seats(char ***seats
) {
798 r
= get_files_in_directory("/run/systemd/seats/", seats
);
807 _public_
int sd_get_sessions(char ***sessions
) {
810 r
= get_files_in_directory("/run/systemd/sessions/", sessions
);
819 _public_
int sd_get_uids(uid_t
**users
) {
820 _cleanup_closedir_
DIR *d
;
824 _cleanup_free_ uid_t
*l
= NULL
;
826 d
= opendir("/run/systemd/users/");
828 if (errno
== ENOENT
) {
836 FOREACH_DIRENT_ALL(de
, d
, return -errno
) {
840 dirent_ensure_type(d
, de
);
842 if (!dirent_is_file(de
))
845 k
= parse_uid(de
->d_name
, &uid
);
850 if ((unsigned) r
>= n
) {
854 t
= realloc(l
, sizeof(uid_t
) * n
);
861 assert((unsigned) r
< n
);
875 _public_
int sd_get_machine_names(char ***machines
) {
876 _cleanup_strv_free_
char **l
= NULL
;
880 r
= get_files_in_directory("/run/systemd/machines/", &l
);
892 /* Filter out the unit: symlinks */
893 for (a
= b
= l
; *a
; a
++) {
894 if (startswith(*a
, "unit:") || !machine_name_is_valid(*a
))
907 *machines
= TAKE_PTR(l
);
912 _public_
int sd_machine_get_class(const char *machine
, char **class) {
913 _cleanup_free_
char *c
= NULL
;
917 assert_return(machine_name_is_valid(machine
), -EINVAL
);
918 assert_return(class, -EINVAL
);
920 p
= strjoina("/run/systemd/machines/", machine
);
921 r
= parse_env_file(p
, NEWLINE
, "CLASS", &c
, NULL
);
929 *class = TAKE_PTR(c
);
934 _public_
int sd_machine_get_ifindices(const char *machine
, int **ifindices
) {
935 _cleanup_free_
char *netif
= NULL
;
936 size_t l
, allocated
= 0, nr
= 0;
938 const char *p
, *word
, *state
;
941 assert_return(machine_name_is_valid(machine
), -EINVAL
);
942 assert_return(ifindices
, -EINVAL
);
944 p
= strjoina("/run/systemd/machines/", machine
);
945 r
= parse_env_file(p
, NEWLINE
, "NETIF", &netif
, NULL
);
955 FOREACH_WORD(word
, l
, netif
, state
) {
959 *(char*) (mempcpy(buf
, word
, l
)) = 0;
961 if (parse_ifindex(buf
, &ifi
) < 0)
964 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
976 static inline int MONITOR_TO_FD(sd_login_monitor
*m
) {
977 return (int) (unsigned long) m
- 1;
980 static inline sd_login_monitor
* FD_TO_MONITOR(int fd
) {
981 return (sd_login_monitor
*) (unsigned long) (fd
+ 1);
984 _public_
int sd_login_monitor_new(const char *category
, sd_login_monitor
**m
) {
985 _cleanup_close_
int fd
= -1;
989 assert_return(m
, -EINVAL
);
991 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
995 if (!category
|| streq(category
, "seat")) {
996 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
1003 if (!category
|| streq(category
, "session")) {
1004 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
1011 if (!category
|| streq(category
, "uid")) {
1012 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
1019 if (!category
|| streq(category
, "machine")) {
1020 k
= inotify_add_watch(fd
, "/run/systemd/machines/", IN_MOVED_TO
|IN_DELETE
);
1030 *m
= FD_TO_MONITOR(fd
);
1036 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
1042 fd
= MONITOR_TO_FD(m
);
1048 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
1051 assert_return(m
, -EINVAL
);
1053 r
= flush_fd(MONITOR_TO_FD(m
));
1060 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
1062 assert_return(m
, -EINVAL
);
1064 return MONITOR_TO_FD(m
);
1067 _public_
int sd_login_monitor_get_events(sd_login_monitor
*m
) {
1069 assert_return(m
, -EINVAL
);
1071 /* For now we will only return POLLIN here, since we don't
1072 * need anything else ever for inotify. However, let's have
1073 * this API to keep our options open should we later on need
1078 _public_
int sd_login_monitor_get_timeout(sd_login_monitor
*m
, uint64_t *timeout_usec
) {
1080 assert_return(m
, -EINVAL
);
1081 assert_return(timeout_usec
, -EINVAL
);
1083 /* For now we will only return (uint64_t) -1, since we don't
1084 * need any timeout. However, let's have this API to keep our
1085 * options open should we later on need it. */
1086 *timeout_usec
= (uint64_t) -1;