2 This file is part of systemd.
4 Copyright 2011 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <sys/inotify.h>
28 #include "alloc-util.h"
29 #include "cgroup-util.h"
30 #include "dirent-util.h"
34 #include "format-util.h"
36 #include "hostname-util.h"
38 #include "login-util.h"
40 #include "parse-util.h"
41 #include "path-util.h"
42 #include "socket-util.h"
43 #include "string-util.h"
45 #include "user-util.h"
50 * invalid input parameters → -EINVAL
52 * process does not exist → -ESRCH
53 * cgroup does not exist → -ENOENT
54 * machine, session does not exist → -ENXIO
55 * requested metadata on object is missing → -ENODATA
58 _public_
int sd_pid_get_session(pid_t pid
, char **session
) {
61 assert_return(pid
>= 0, -EINVAL
);
62 assert_return(session
, -EINVAL
);
64 r
= cg_pid_get_session(pid
, session
);
65 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
68 _public_
int sd_pid_get_unit(pid_t pid
, char **unit
) {
71 assert_return(pid
>= 0, -EINVAL
);
72 assert_return(unit
, -EINVAL
);
74 r
= cg_pid_get_unit(pid
, unit
);
75 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
78 _public_
int sd_pid_get_user_unit(pid_t pid
, char **unit
) {
81 assert_return(pid
>= 0, -EINVAL
);
82 assert_return(unit
, -EINVAL
);
84 r
= cg_pid_get_user_unit(pid
, unit
);
85 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
88 _public_
int sd_pid_get_machine_name(pid_t pid
, char **name
) {
91 assert_return(pid
>= 0, -EINVAL
);
92 assert_return(name
, -EINVAL
);
94 r
= cg_pid_get_machine_name(pid
, name
);
95 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
98 _public_
int sd_pid_get_slice(pid_t pid
, char **slice
) {
101 assert_return(pid
>= 0, -EINVAL
);
102 assert_return(slice
, -EINVAL
);
104 r
= cg_pid_get_slice(pid
, slice
);
105 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
108 _public_
int sd_pid_get_user_slice(pid_t pid
, char **slice
) {
111 assert_return(pid
>= 0, -EINVAL
);
112 assert_return(slice
, -EINVAL
);
114 r
= cg_pid_get_user_slice(pid
, slice
);
115 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
118 _public_
int sd_pid_get_owner_uid(pid_t pid
, uid_t
*uid
) {
121 assert_return(pid
>= 0, -EINVAL
);
122 assert_return(uid
, -EINVAL
);
124 r
= cg_pid_get_owner_uid(pid
, uid
);
125 return IN_SET(r
, -ENXIO
, -ENOMEDIUM
) ? -ENODATA
: r
;
128 _public_
int sd_pid_get_cgroup(pid_t pid
, char **cgroup
) {
132 assert_return(pid
>= 0, -EINVAL
);
133 assert_return(cgroup
, -EINVAL
);
135 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &c
);
139 /* The internal APIs return the empty string for the root
140 * cgroup, let's return the "/" in the public APIs instead, as
141 * that's easier and less ambiguous for people to grok. */
154 _public_
int sd_peer_get_session(int fd
, char **session
) {
155 struct ucred ucred
= {};
158 assert_return(fd
>= 0, -EBADF
);
159 assert_return(session
, -EINVAL
);
161 r
= getpeercred(fd
, &ucred
);
165 return cg_pid_get_session(ucred
.pid
, session
);
168 _public_
int sd_peer_get_owner_uid(int fd
, uid_t
*uid
) {
172 assert_return(fd
>= 0, -EBADF
);
173 assert_return(uid
, -EINVAL
);
175 r
= getpeercred(fd
, &ucred
);
179 return cg_pid_get_owner_uid(ucred
.pid
, uid
);
182 _public_
int sd_peer_get_unit(int fd
, char **unit
) {
186 assert_return(fd
>= 0, -EBADF
);
187 assert_return(unit
, -EINVAL
);
189 r
= getpeercred(fd
, &ucred
);
193 return cg_pid_get_unit(ucred
.pid
, unit
);
196 _public_
int sd_peer_get_user_unit(int fd
, char **unit
) {
200 assert_return(fd
>= 0, -EBADF
);
201 assert_return(unit
, -EINVAL
);
203 r
= getpeercred(fd
, &ucred
);
207 return cg_pid_get_user_unit(ucred
.pid
, unit
);
210 _public_
int sd_peer_get_machine_name(int fd
, char **machine
) {
214 assert_return(fd
>= 0, -EBADF
);
215 assert_return(machine
, -EINVAL
);
217 r
= getpeercred(fd
, &ucred
);
221 return cg_pid_get_machine_name(ucred
.pid
, machine
);
224 _public_
int sd_peer_get_slice(int fd
, char **slice
) {
228 assert_return(fd
>= 0, -EBADF
);
229 assert_return(slice
, -EINVAL
);
231 r
= getpeercred(fd
, &ucred
);
235 return cg_pid_get_slice(ucred
.pid
, slice
);
238 _public_
int sd_peer_get_user_slice(int fd
, char **slice
) {
242 assert_return(fd
>= 0, -EBADF
);
243 assert_return(slice
, -EINVAL
);
245 r
= getpeercred(fd
, &ucred
);
249 return cg_pid_get_user_slice(ucred
.pid
, slice
);
252 _public_
int sd_peer_get_cgroup(int fd
, char **cgroup
) {
256 assert_return(fd
>= 0, -EBADF
);
257 assert_return(cgroup
, -EINVAL
);
259 r
= getpeercred(fd
, &ucred
);
263 return sd_pid_get_cgroup(ucred
.pid
, cgroup
);
266 static int file_of_uid(uid_t uid
, char **p
) {
268 assert_return(uid_is_valid(uid
), -EINVAL
);
271 if (asprintf(p
, "/run/systemd/users/" UID_FMT
, uid
) < 0)
277 _public_
int sd_uid_get_state(uid_t uid
, char**state
) {
278 _cleanup_free_
char *p
= NULL
;
282 assert_return(state
, -EINVAL
);
284 r
= file_of_uid(uid
, &p
);
288 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
291 s
= strdup("offline");
309 _public_
int sd_uid_get_display(uid_t uid
, char **session
) {
310 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
313 assert_return(session
, -EINVAL
);
315 r
= file_of_uid(uid
, &p
);
319 r
= parse_env_file(p
, NEWLINE
, "DISPLAY", &s
, NULL
);
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
);
362 _public_
int sd_uid_is_on_seat(uid_t uid
, int require_active
, const char *seat
) {
363 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *p
= NULL
;
366 const char *word
, *variable
, *state
;
368 assert_return(uid_is_valid(uid
), -EINVAL
);
370 r
= file_of_seat(seat
, &p
);
374 variable
= require_active
? "ACTIVE_UID" : "UIDS";
376 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
384 if (asprintf(&t
, UID_FMT
, uid
) < 0)
387 FOREACH_WORD(word
, l
, s
, state
)
388 if (strneq(t
, word
, l
))
394 static int uid_get_array(uid_t uid
, const char *variable
, char ***array
) {
395 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
401 r
= file_of_uid(uid
, &p
);
405 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
406 if (r
== -ENOENT
|| (r
>= 0 && isempty(s
))) {
414 a
= strv_split(s
, " ");
429 _public_
int sd_uid_get_sessions(uid_t uid
, int require_active
, char ***sessions
) {
430 return uid_get_array(
432 require_active
== 0 ? "ONLINE_SESSIONS" :
433 require_active
> 0 ? "ACTIVE_SESSIONS" :
438 _public_
int sd_uid_get_seats(uid_t uid
, int require_active
, char ***seats
) {
439 return uid_get_array(
441 require_active
== 0 ? "ONLINE_SEATS" :
442 require_active
> 0 ? "ACTIVE_SEATS" :
447 static int file_of_session(const char *session
, char **_p
) {
454 if (!session_id_valid(session
))
457 p
= strappend("/run/systemd/sessions/", session
);
459 _cleanup_free_
char *buf
= NULL
;
461 r
= sd_pid_get_session(0, &buf
);
465 p
= strappend("/run/systemd/sessions/", buf
);
475 _public_
int sd_session_is_active(const char *session
) {
476 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
479 r
= file_of_session(session
, &p
);
483 r
= parse_env_file(p
, NEWLINE
, "ACTIVE", &s
, NULL
);
491 return parse_boolean(s
);
494 _public_
int sd_session_is_remote(const char *session
) {
495 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
498 r
= file_of_session(session
, &p
);
502 r
= parse_env_file(p
, NEWLINE
, "REMOTE", &s
, NULL
);
510 return parse_boolean(s
);
513 _public_
int sd_session_get_state(const char *session
, char **state
) {
514 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
517 assert_return(state
, -EINVAL
);
519 r
= file_of_session(session
, &p
);
523 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
537 _public_
int sd_session_get_uid(const char *session
, uid_t
*uid
) {
539 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
541 assert_return(uid
, -EINVAL
);
543 r
= file_of_session(session
, &p
);
547 r
= parse_env_file(p
, NEWLINE
, "UID", &s
, NULL
);
555 return parse_uid(s
, uid
);
558 static int session_get_string(const char *session
, const char *field
, char **value
) {
559 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
562 assert_return(value
, -EINVAL
);
565 r
= file_of_session(session
, &p
);
569 r
= parse_env_file(p
, NEWLINE
, field
, &s
, NULL
);
582 _public_
int sd_session_get_seat(const char *session
, char **seat
) {
583 return session_get_string(session
, "SEAT", seat
);
586 _public_
int sd_session_get_tty(const char *session
, char **tty
) {
587 return session_get_string(session
, "TTY", tty
);
590 _public_
int sd_session_get_vt(const char *session
, unsigned *vtnr
) {
591 _cleanup_free_
char *vtnr_string
= NULL
;
595 assert_return(vtnr
, -EINVAL
);
597 r
= session_get_string(session
, "VTNR", &vtnr_string
);
601 r
= safe_atou(vtnr_string
, &u
);
609 _public_
int sd_session_get_service(const char *session
, char **service
) {
610 return session_get_string(session
, "SERVICE", service
);
613 _public_
int sd_session_get_type(const char *session
, char **type
) {
614 return session_get_string(session
, "TYPE", type
);
617 _public_
int sd_session_get_class(const char *session
, char **class) {
618 return session_get_string(session
, "CLASS", class);
621 _public_
int sd_session_get_desktop(const char *session
, char **desktop
) {
622 _cleanup_free_
char *escaped
= NULL
;
626 assert_return(desktop
, -EINVAL
);
628 r
= session_get_string(session
, "DESKTOP", &escaped
);
632 r
= cunescape(escaped
, 0, &t
);
640 _public_
int sd_session_get_display(const char *session
, char **display
) {
641 return session_get_string(session
, "DISPLAY", display
);
644 _public_
int sd_session_get_remote_user(const char *session
, char **remote_user
) {
645 return session_get_string(session
, "REMOTE_USER", remote_user
);
648 _public_
int sd_session_get_remote_host(const char *session
, char **remote_host
) {
649 return session_get_string(session
, "REMOTE_HOST", remote_host
);
652 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
653 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
656 assert_return(session
|| uid
, -EINVAL
);
658 r
= file_of_seat(seat
, &p
);
662 r
= parse_env_file(p
, NEWLINE
,
678 r
= parse_uid(t
, uid
);
691 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
692 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
693 _cleanup_strv_free_
char **a
= NULL
;
694 _cleanup_free_ uid_t
*b
= NULL
;
698 r
= file_of_seat(seat
, &p
);
702 r
= parse_env_file(p
, NEWLINE
,
712 a
= strv_split(s
, " ");
718 const char *word
, *state
;
721 FOREACH_WORD(word
, l
, t
, state
)
731 FOREACH_WORD(word
, l
, t
, state
) {
732 _cleanup_free_
char *k
= NULL
;
734 k
= strndup(word
, l
);
738 r
= parse_uid(k
, b
+ i
);
765 static int seat_get_can(const char *seat
, const char *variable
) {
766 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
771 r
= file_of_seat(seat
, &p
);
775 r
= parse_env_file(p
, NEWLINE
,
785 return parse_boolean(s
);
788 _public_
int sd_seat_can_multi_session(const char *seat
) {
789 return seat_get_can(seat
, "CAN_MULTI_SESSION");
792 _public_
int sd_seat_can_tty(const char *seat
) {
793 return seat_get_can(seat
, "CAN_TTY");
796 _public_
int sd_seat_can_graphical(const char *seat
) {
797 return seat_get_can(seat
, "CAN_GRAPHICAL");
800 _public_
int sd_get_seats(char ***seats
) {
803 r
= get_files_in_directory("/run/systemd/seats/", seats
);
812 _public_
int sd_get_sessions(char ***sessions
) {
815 r
= get_files_in_directory("/run/systemd/sessions/", sessions
);
824 _public_
int sd_get_uids(uid_t
**users
) {
825 _cleanup_closedir_
DIR *d
;
829 _cleanup_free_ uid_t
*l
= NULL
;
831 d
= opendir("/run/systemd/users/");
833 if (errno
== ENOENT
) {
841 FOREACH_DIRENT_ALL(de
, d
, return -errno
) {
845 dirent_ensure_type(d
, de
);
847 if (!dirent_is_file(de
))
850 k
= parse_uid(de
->d_name
, &uid
);
855 if ((unsigned) r
>= n
) {
859 t
= realloc(l
, sizeof(uid_t
) * n
);
866 assert((unsigned) r
< n
);
880 _public_
int sd_get_machine_names(char ***machines
) {
884 r
= get_files_in_directory("/run/systemd/machines/", &l
);
896 /* Filter out the unit: symlinks */
897 for (a
= b
= l
; *a
; a
++) {
898 if (startswith(*a
, "unit:") || !machine_name_is_valid(*a
))
915 _public_
int sd_machine_get_class(const char *machine
, char **class) {
916 _cleanup_free_
char *c
= NULL
;
920 assert_return(machine_name_is_valid(machine
), -EINVAL
);
921 assert_return(class, -EINVAL
);
923 p
= strjoina("/run/systemd/machines/", machine
);
924 r
= parse_env_file(p
, NEWLINE
, "CLASS", &c
, NULL
);
938 _public_
int sd_machine_get_ifindices(const char *machine
, int **ifindices
) {
939 _cleanup_free_
char *netif
= NULL
;
940 size_t l
, allocated
= 0, nr
= 0;
942 const char *p
, *word
, *state
;
945 assert_return(machine_name_is_valid(machine
), -EINVAL
);
946 assert_return(ifindices
, -EINVAL
);
948 p
= strjoina("/run/systemd/machines/", machine
);
949 r
= parse_env_file(p
, NEWLINE
, "NETIF", &netif
, NULL
);
959 FOREACH_WORD(word
, l
, netif
, state
) {
963 *(char*) (mempcpy(buf
, word
, l
)) = 0;
965 if (parse_ifindex(buf
, &ifi
) < 0)
968 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
980 static inline int MONITOR_TO_FD(sd_login_monitor
*m
) {
981 return (int) (unsigned long) m
- 1;
984 static inline sd_login_monitor
* FD_TO_MONITOR(int fd
) {
985 return (sd_login_monitor
*) (unsigned long) (fd
+ 1);
988 _public_
int sd_login_monitor_new(const char *category
, sd_login_monitor
**m
) {
992 assert_return(m
, -EINVAL
);
994 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
998 if (!category
|| streq(category
, "seat")) {
999 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
1008 if (!category
|| streq(category
, "session")) {
1009 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
1018 if (!category
|| streq(category
, "uid")) {
1019 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
1028 if (!category
|| streq(category
, "machine")) {
1029 k
= inotify_add_watch(fd
, "/run/systemd/machines/", IN_MOVED_TO
|IN_DELETE
);
1043 *m
= FD_TO_MONITOR(fd
);
1047 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
1053 fd
= MONITOR_TO_FD(m
);
1059 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
1061 assert_return(m
, -EINVAL
);
1063 return flush_fd(MONITOR_TO_FD(m
));
1066 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
1068 assert_return(m
, -EINVAL
);
1070 return MONITOR_TO_FD(m
);
1073 _public_
int sd_login_monitor_get_events(sd_login_monitor
*m
) {
1075 assert_return(m
, -EINVAL
);
1077 /* For now we will only return POLLIN here, since we don't
1078 * need anything else ever for inotify. However, let's have
1079 * this API to keep our options open should we later on need
1084 _public_
int sd_login_monitor_get_timeout(sd_login_monitor
*m
, uint64_t *timeout_usec
) {
1086 assert_return(m
, -EINVAL
);
1087 assert_return(timeout_usec
, -EINVAL
);
1089 /* For now we will only return (uint64_t) -1, since we don't
1090 * need any timeout. However, let's have this API to keep our
1091 * options open should we later on need it. */
1092 *timeout_usec
= (uint64_t) -1;