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 r
== -ENXIO
? -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 r
== -ENXIO
? -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 r
== -ENXIO
? -ENODATA
: r
;
88 _public_
int sd_pid_get_machine_name(pid_t pid
, char **name
) {
90 assert_return(pid
>= 0, -EINVAL
);
91 assert_return(name
, -EINVAL
);
93 return cg_pid_get_machine_name(pid
, name
);
96 _public_
int sd_pid_get_slice(pid_t pid
, char **slice
) {
98 assert_return(pid
>= 0, -EINVAL
);
99 assert_return(slice
, -EINVAL
);
101 return cg_pid_get_slice(pid
, slice
);
104 _public_
int sd_pid_get_user_slice(pid_t pid
, char **slice
) {
106 assert_return(pid
>= 0, -EINVAL
);
107 assert_return(slice
, -EINVAL
);
109 return cg_pid_get_user_slice(pid
, slice
);
112 _public_
int sd_pid_get_owner_uid(pid_t pid
, uid_t
*uid
) {
114 assert_return(pid
>= 0, -EINVAL
);
115 assert_return(uid
, -EINVAL
);
117 return cg_pid_get_owner_uid(pid
, uid
);
120 _public_
int sd_pid_get_cgroup(pid_t pid
, char **cgroup
) {
124 assert_return(pid
>= 0, -EINVAL
);
125 assert_return(cgroup
, -EINVAL
);
127 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &c
);
131 /* The internal APIs return the empty string for the root
132 * cgroup, let's return the "/" in the public APIs instead, as
133 * that's easier and less ambiguous for people to grok. */
146 _public_
int sd_peer_get_session(int fd
, char **session
) {
147 struct ucred ucred
= {};
150 assert_return(fd
>= 0, -EBADF
);
151 assert_return(session
, -EINVAL
);
153 r
= getpeercred(fd
, &ucred
);
157 return cg_pid_get_session(ucred
.pid
, session
);
160 _public_
int sd_peer_get_owner_uid(int fd
, uid_t
*uid
) {
164 assert_return(fd
>= 0, -EBADF
);
165 assert_return(uid
, -EINVAL
);
167 r
= getpeercred(fd
, &ucred
);
171 return cg_pid_get_owner_uid(ucred
.pid
, uid
);
174 _public_
int sd_peer_get_unit(int fd
, char **unit
) {
178 assert_return(fd
>= 0, -EBADF
);
179 assert_return(unit
, -EINVAL
);
181 r
= getpeercred(fd
, &ucred
);
185 return cg_pid_get_unit(ucred
.pid
, unit
);
188 _public_
int sd_peer_get_user_unit(int fd
, char **unit
) {
192 assert_return(fd
>= 0, -EBADF
);
193 assert_return(unit
, -EINVAL
);
195 r
= getpeercred(fd
, &ucred
);
199 return cg_pid_get_user_unit(ucred
.pid
, unit
);
202 _public_
int sd_peer_get_machine_name(int fd
, char **machine
) {
206 assert_return(fd
>= 0, -EBADF
);
207 assert_return(machine
, -EINVAL
);
209 r
= getpeercred(fd
, &ucred
);
213 return cg_pid_get_machine_name(ucred
.pid
, machine
);
216 _public_
int sd_peer_get_slice(int fd
, char **slice
) {
220 assert_return(fd
>= 0, -EBADF
);
221 assert_return(slice
, -EINVAL
);
223 r
= getpeercred(fd
, &ucred
);
227 return cg_pid_get_slice(ucred
.pid
, slice
);
230 _public_
int sd_peer_get_user_slice(int fd
, char **slice
) {
234 assert_return(fd
>= 0, -EBADF
);
235 assert_return(slice
, -EINVAL
);
237 r
= getpeercred(fd
, &ucred
);
241 return cg_pid_get_user_slice(ucred
.pid
, slice
);
244 _public_
int sd_peer_get_cgroup(int fd
, char **cgroup
) {
248 assert_return(fd
>= 0, -EBADF
);
249 assert_return(cgroup
, -EINVAL
);
251 r
= getpeercred(fd
, &ucred
);
255 return sd_pid_get_cgroup(ucred
.pid
, cgroup
);
258 static int file_of_uid(uid_t uid
, char **p
) {
260 assert_return(uid_is_valid(uid
), -EINVAL
);
263 if (asprintf(p
, "/run/systemd/users/" UID_FMT
, uid
) < 0)
269 _public_
int sd_uid_get_state(uid_t uid
, char**state
) {
270 _cleanup_free_
char *p
= NULL
;
274 assert_return(state
, -EINVAL
);
276 r
= file_of_uid(uid
, &p
);
280 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
283 s
= strdup("offline");
301 _public_
int sd_uid_get_display(uid_t uid
, char **session
) {
302 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
305 assert_return(session
, -EINVAL
);
307 r
= file_of_uid(uid
, &p
);
311 r
= parse_env_file(p
, NEWLINE
, "DISPLAY", &s
, NULL
);
325 static int file_of_seat(const char *seat
, char **_p
) {
332 if (!filename_is_valid(seat
))
335 p
= strappend("/run/systemd/seats/", seat
);
337 _cleanup_free_
char *buf
= NULL
;
339 r
= sd_session_get_seat(NULL
, &buf
);
343 p
= strappend("/run/systemd/seats/", buf
);
354 _public_
int sd_uid_is_on_seat(uid_t uid
, int require_active
, const char *seat
) {
355 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *p
= NULL
;
358 const char *word
, *variable
, *state
;
360 assert_return(uid_is_valid(uid
), -EINVAL
);
362 r
= file_of_seat(seat
, &p
);
366 variable
= require_active
? "ACTIVE_UID" : "UIDS";
368 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
376 if (asprintf(&t
, UID_FMT
, uid
) < 0)
379 FOREACH_WORD(word
, l
, s
, state
)
380 if (strneq(t
, word
, l
))
386 static int uid_get_array(uid_t uid
, const char *variable
, char ***array
) {
387 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
393 r
= file_of_uid(uid
, &p
);
397 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
398 if (r
== -ENOENT
|| (r
>= 0 && isempty(s
))) {
406 a
= strv_split(s
, " ");
421 _public_
int sd_uid_get_sessions(uid_t uid
, int require_active
, char ***sessions
) {
422 return uid_get_array(
424 require_active
== 0 ? "ONLINE_SESSIONS" :
425 require_active
> 0 ? "ACTIVE_SESSIONS" :
430 _public_
int sd_uid_get_seats(uid_t uid
, int require_active
, char ***seats
) {
431 return uid_get_array(
433 require_active
== 0 ? "ONLINE_SEATS" :
434 require_active
> 0 ? "ACTIVE_SEATS" :
439 static int file_of_session(const char *session
, char **_p
) {
446 if (!session_id_valid(session
))
449 p
= strappend("/run/systemd/sessions/", session
);
451 _cleanup_free_
char *buf
= NULL
;
453 r
= sd_pid_get_session(0, &buf
);
457 p
= strappend("/run/systemd/sessions/", buf
);
467 _public_
int sd_session_is_active(const char *session
) {
468 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
471 r
= file_of_session(session
, &p
);
475 r
= parse_env_file(p
, NEWLINE
, "ACTIVE", &s
, NULL
);
483 return parse_boolean(s
);
486 _public_
int sd_session_is_remote(const char *session
) {
487 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
490 r
= file_of_session(session
, &p
);
494 r
= parse_env_file(p
, NEWLINE
, "REMOTE", &s
, NULL
);
502 return parse_boolean(s
);
505 _public_
int sd_session_get_state(const char *session
, char **state
) {
506 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
509 assert_return(state
, -EINVAL
);
511 r
= file_of_session(session
, &p
);
515 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
529 _public_
int sd_session_get_uid(const char *session
, uid_t
*uid
) {
531 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
533 assert_return(uid
, -EINVAL
);
535 r
= file_of_session(session
, &p
);
539 r
= parse_env_file(p
, NEWLINE
, "UID", &s
, NULL
);
547 return parse_uid(s
, uid
);
550 static int session_get_string(const char *session
, const char *field
, char **value
) {
551 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
554 assert_return(value
, -EINVAL
);
557 r
= file_of_session(session
, &p
);
561 r
= parse_env_file(p
, NEWLINE
, field
, &s
, NULL
);
574 _public_
int sd_session_get_seat(const char *session
, char **seat
) {
575 return session_get_string(session
, "SEAT", seat
);
578 _public_
int sd_session_get_tty(const char *session
, char **tty
) {
579 return session_get_string(session
, "TTY", tty
);
582 _public_
int sd_session_get_vt(const char *session
, unsigned *vtnr
) {
583 _cleanup_free_
char *vtnr_string
= NULL
;
587 assert_return(vtnr
, -EINVAL
);
589 r
= session_get_string(session
, "VTNR", &vtnr_string
);
593 r
= safe_atou(vtnr_string
, &u
);
601 _public_
int sd_session_get_service(const char *session
, char **service
) {
602 return session_get_string(session
, "SERVICE", service
);
605 _public_
int sd_session_get_type(const char *session
, char **type
) {
606 return session_get_string(session
, "TYPE", type
);
609 _public_
int sd_session_get_class(const char *session
, char **class) {
610 return session_get_string(session
, "CLASS", class);
613 _public_
int sd_session_get_desktop(const char *session
, char **desktop
) {
614 _cleanup_free_
char *escaped
= NULL
;
618 assert_return(desktop
, -EINVAL
);
620 r
= session_get_string(session
, "DESKTOP", &escaped
);
624 r
= cunescape(escaped
, 0, &t
);
632 _public_
int sd_session_get_display(const char *session
, char **display
) {
633 return session_get_string(session
, "DISPLAY", display
);
636 _public_
int sd_session_get_remote_user(const char *session
, char **remote_user
) {
637 return session_get_string(session
, "REMOTE_USER", remote_user
);
640 _public_
int sd_session_get_remote_host(const char *session
, char **remote_host
) {
641 return session_get_string(session
, "REMOTE_HOST", remote_host
);
644 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
645 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
648 assert_return(session
|| uid
, -EINVAL
);
650 r
= file_of_seat(seat
, &p
);
654 r
= parse_env_file(p
, NEWLINE
,
670 r
= parse_uid(t
, uid
);
683 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
684 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
685 _cleanup_strv_free_
char **a
= NULL
;
686 _cleanup_free_ uid_t
*b
= NULL
;
690 r
= file_of_seat(seat
, &p
);
694 r
= parse_env_file(p
, NEWLINE
,
704 a
= strv_split(s
, " ");
710 const char *word
, *state
;
713 FOREACH_WORD(word
, l
, t
, state
)
723 FOREACH_WORD(word
, l
, t
, state
) {
724 _cleanup_free_
char *k
= NULL
;
726 k
= strndup(word
, l
);
730 r
= parse_uid(k
, b
+ i
);
757 static int seat_get_can(const char *seat
, const char *variable
) {
758 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
763 r
= file_of_seat(seat
, &p
);
767 r
= parse_env_file(p
, NEWLINE
,
777 return parse_boolean(s
);
780 _public_
int sd_seat_can_multi_session(const char *seat
) {
781 return seat_get_can(seat
, "CAN_MULTI_SESSION");
784 _public_
int sd_seat_can_tty(const char *seat
) {
785 return seat_get_can(seat
, "CAN_TTY");
788 _public_
int sd_seat_can_graphical(const char *seat
) {
789 return seat_get_can(seat
, "CAN_GRAPHICAL");
792 _public_
int sd_get_seats(char ***seats
) {
793 return get_files_in_directory("/run/systemd/seats/", seats
);
796 _public_
int sd_get_sessions(char ***sessions
) {
797 return get_files_in_directory("/run/systemd/sessions/", sessions
);
800 _public_
int sd_get_uids(uid_t
**users
) {
801 _cleanup_closedir_
DIR *d
;
805 _cleanup_free_ uid_t
*l
= NULL
;
807 d
= opendir("/run/systemd/users/");
811 FOREACH_DIRENT_ALL(de
, d
, return -errno
) {
815 dirent_ensure_type(d
, de
);
817 if (!dirent_is_file(de
))
820 k
= parse_uid(de
->d_name
, &uid
);
825 if ((unsigned) r
>= n
) {
829 t
= realloc(l
, sizeof(uid_t
) * n
);
836 assert((unsigned) r
< n
);
850 _public_
int sd_get_machine_names(char ***machines
) {
851 char **l
= NULL
, **a
, **b
;
854 assert_return(machines
, -EINVAL
);
856 r
= get_files_in_directory("/run/systemd/machines/", &l
);
867 /* Filter out the unit: symlinks */
868 for (a
= l
, b
= l
; *a
; a
++) {
869 if (startswith(*a
, "unit:") || !machine_name_is_valid(*a
))
885 _public_
int sd_machine_get_class(const char *machine
, char **class) {
886 _cleanup_free_
char *c
= NULL
;
890 assert_return(machine_name_is_valid(machine
), -EINVAL
);
891 assert_return(class, -EINVAL
);
893 p
= strjoina("/run/systemd/machines/", machine
);
894 r
= parse_env_file(p
, NEWLINE
, "CLASS", &c
, NULL
);
908 _public_
int sd_machine_get_ifindices(const char *machine
, int **ifindices
) {
909 _cleanup_free_
char *netif
= NULL
;
910 size_t l
, allocated
= 0, nr
= 0;
912 const char *p
, *word
, *state
;
915 assert_return(machine_name_is_valid(machine
), -EINVAL
);
916 assert_return(ifindices
, -EINVAL
);
918 p
= strjoina("/run/systemd/machines/", machine
);
919 r
= parse_env_file(p
, NEWLINE
, "NETIF", &netif
, NULL
);
929 FOREACH_WORD(word
, l
, netif
, state
) {
933 *(char*) (mempcpy(buf
, word
, l
)) = 0;
935 if (parse_ifindex(buf
, &ifi
) < 0)
938 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
950 static inline int MONITOR_TO_FD(sd_login_monitor
*m
) {
951 return (int) (unsigned long) m
- 1;
954 static inline sd_login_monitor
* FD_TO_MONITOR(int fd
) {
955 return (sd_login_monitor
*) (unsigned long) (fd
+ 1);
958 _public_
int sd_login_monitor_new(const char *category
, sd_login_monitor
**m
) {
962 assert_return(m
, -EINVAL
);
964 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
968 if (!category
|| streq(category
, "seat")) {
969 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
978 if (!category
|| streq(category
, "session")) {
979 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
988 if (!category
|| streq(category
, "uid")) {
989 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
998 if (!category
|| streq(category
, "machine")) {
999 k
= inotify_add_watch(fd
, "/run/systemd/machines/", IN_MOVED_TO
|IN_DELETE
);
1013 *m
= FD_TO_MONITOR(fd
);
1017 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
1023 fd
= MONITOR_TO_FD(m
);
1029 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
1031 assert_return(m
, -EINVAL
);
1033 return flush_fd(MONITOR_TO_FD(m
));
1036 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
1038 assert_return(m
, -EINVAL
);
1040 return MONITOR_TO_FD(m
);
1043 _public_
int sd_login_monitor_get_events(sd_login_monitor
*m
) {
1045 assert_return(m
, -EINVAL
);
1047 /* For now we will only return POLLIN here, since we don't
1048 * need anything else ever for inotify. However, let's have
1049 * this API to keep our options open should we later on need
1054 _public_
int sd_login_monitor_get_timeout(sd_login_monitor
*m
, uint64_t *timeout_usec
) {
1056 assert_return(m
, -EINVAL
);
1057 assert_return(timeout_usec
, -EINVAL
);
1059 /* For now we will only return (uint64_t) -1, since we don't
1060 * need any timeout. However, let's have this API to keep our
1061 * options open should we later on need it. */
1062 *timeout_usec
= (uint64_t) -1;