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>
30 #include "cgroup-util.h"
34 #include "formats-util.h"
35 #include "hostname-util.h"
37 #include "login-util.h"
39 #include "parse-util.h"
40 #include "socket-util.h"
41 #include "string-util.h"
43 #include "user-util.h"
48 * invalid input parameters → -EINVAL
50 * process does not exist → -ESRCH
51 * cgroup does not exist → -ENOENT
52 * machine, session does not exist → -ENXIO
53 * requested metadata on object is missing → -ENODATA
56 _public_
int sd_pid_get_session(pid_t pid
, char **session
) {
58 assert_return(pid
>= 0, -EINVAL
);
59 assert_return(session
, -EINVAL
);
61 return cg_pid_get_session(pid
, session
);
64 _public_
int sd_pid_get_unit(pid_t pid
, char **unit
) {
66 assert_return(pid
>= 0, -EINVAL
);
67 assert_return(unit
, -EINVAL
);
69 return cg_pid_get_unit(pid
, unit
);
72 _public_
int sd_pid_get_user_unit(pid_t pid
, char **unit
) {
74 assert_return(pid
>= 0, -EINVAL
);
75 assert_return(unit
, -EINVAL
);
77 return cg_pid_get_user_unit(pid
, unit
);
80 _public_
int sd_pid_get_machine_name(pid_t pid
, char **name
) {
82 assert_return(pid
>= 0, -EINVAL
);
83 assert_return(name
, -EINVAL
);
85 return cg_pid_get_machine_name(pid
, name
);
88 _public_
int sd_pid_get_slice(pid_t pid
, char **slice
) {
90 assert_return(pid
>= 0, -EINVAL
);
91 assert_return(slice
, -EINVAL
);
93 return cg_pid_get_slice(pid
, slice
);
96 _public_
int sd_pid_get_user_slice(pid_t pid
, char **slice
) {
98 assert_return(pid
>= 0, -EINVAL
);
99 assert_return(slice
, -EINVAL
);
101 return cg_pid_get_user_slice(pid
, slice
);
104 _public_
int sd_pid_get_owner_uid(pid_t pid
, uid_t
*uid
) {
106 assert_return(pid
>= 0, -EINVAL
);
107 assert_return(uid
, -EINVAL
);
109 return cg_pid_get_owner_uid(pid
, uid
);
112 _public_
int sd_pid_get_cgroup(pid_t pid
, char **cgroup
) {
116 assert_return(pid
>= 0, -EINVAL
);
117 assert_return(cgroup
, -EINVAL
);
119 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &c
);
123 /* The internal APIs return the empty string for the root
124 * cgroup, let's return the "/" in the public APIs instead, as
125 * that's easier and less ambigious for people to grok. */
138 _public_
int sd_peer_get_session(int fd
, char **session
) {
139 struct ucred ucred
= {};
142 assert_return(fd
>= 0, -EBADF
);
143 assert_return(session
, -EINVAL
);
145 r
= getpeercred(fd
, &ucred
);
149 return cg_pid_get_session(ucred
.pid
, session
);
152 _public_
int sd_peer_get_owner_uid(int fd
, uid_t
*uid
) {
156 assert_return(fd
>= 0, -EBADF
);
157 assert_return(uid
, -EINVAL
);
159 r
= getpeercred(fd
, &ucred
);
163 return cg_pid_get_owner_uid(ucred
.pid
, uid
);
166 _public_
int sd_peer_get_unit(int fd
, char **unit
) {
170 assert_return(fd
>= 0, -EBADF
);
171 assert_return(unit
, -EINVAL
);
173 r
= getpeercred(fd
, &ucred
);
177 return cg_pid_get_unit(ucred
.pid
, unit
);
180 _public_
int sd_peer_get_user_unit(int fd
, char **unit
) {
184 assert_return(fd
>= 0, -EBADF
);
185 assert_return(unit
, -EINVAL
);
187 r
= getpeercred(fd
, &ucred
);
191 return cg_pid_get_user_unit(ucred
.pid
, unit
);
194 _public_
int sd_peer_get_machine_name(int fd
, char **machine
) {
198 assert_return(fd
>= 0, -EBADF
);
199 assert_return(machine
, -EINVAL
);
201 r
= getpeercred(fd
, &ucred
);
205 return cg_pid_get_machine_name(ucred
.pid
, machine
);
208 _public_
int sd_peer_get_slice(int fd
, char **slice
) {
212 assert_return(fd
>= 0, -EBADF
);
213 assert_return(slice
, -EINVAL
);
215 r
= getpeercred(fd
, &ucred
);
219 return cg_pid_get_slice(ucred
.pid
, slice
);
222 _public_
int sd_peer_get_user_slice(int fd
, char **slice
) {
226 assert_return(fd
>= 0, -EBADF
);
227 assert_return(slice
, -EINVAL
);
229 r
= getpeercred(fd
, &ucred
);
233 return cg_pid_get_user_slice(ucred
.pid
, slice
);
236 _public_
int sd_peer_get_cgroup(int fd
, char **cgroup
) {
240 assert_return(fd
>= 0, -EBADF
);
241 assert_return(cgroup
, -EINVAL
);
243 r
= getpeercred(fd
, &ucred
);
247 return sd_pid_get_cgroup(ucred
.pid
, cgroup
);
250 static int file_of_uid(uid_t uid
, char **p
) {
252 assert_return(uid_is_valid(uid
), -EINVAL
);
255 if (asprintf(p
, "/run/systemd/users/" UID_FMT
, uid
) < 0)
261 _public_
int sd_uid_get_state(uid_t uid
, char**state
) {
262 _cleanup_free_
char *p
= NULL
;
266 assert_return(state
, -EINVAL
);
268 r
= file_of_uid(uid
, &p
);
272 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
275 s
= strdup("offline");
293 _public_
int sd_uid_get_display(uid_t uid
, char **session
) {
294 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
297 assert_return(session
, -EINVAL
);
299 r
= file_of_uid(uid
, &p
);
303 r
= parse_env_file(p
, NEWLINE
, "DISPLAY", &s
, NULL
);
317 static int file_of_seat(const char *seat
, char **_p
) {
324 if (!filename_is_valid(seat
))
327 p
= strappend("/run/systemd/seats/", seat
);
329 _cleanup_free_
char *buf
= NULL
;
331 r
= sd_session_get_seat(NULL
, &buf
);
335 p
= strappend("/run/systemd/seats/", buf
);
346 _public_
int sd_uid_is_on_seat(uid_t uid
, int require_active
, const char *seat
) {
347 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *p
= NULL
;
350 const char *word
, *variable
, *state
;
352 assert_return(uid_is_valid(uid
), -EINVAL
);
354 r
= file_of_seat(seat
, &p
);
358 variable
= require_active
? "ACTIVE_UID" : "UIDS";
360 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
368 if (asprintf(&t
, UID_FMT
, uid
) < 0)
371 FOREACH_WORD(word
, l
, s
, state
)
372 if (strneq(t
, word
, l
))
378 static int uid_get_array(uid_t uid
, const char *variable
, char ***array
) {
379 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
385 r
= file_of_uid(uid
, &p
);
389 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
390 if (r
== -ENOENT
|| (r
>= 0 && isempty(s
))) {
398 a
= strv_split(s
, " ");
413 _public_
int sd_uid_get_sessions(uid_t uid
, int require_active
, char ***sessions
) {
414 return uid_get_array(
416 require_active
== 0 ? "ONLINE_SESSIONS" :
417 require_active
> 0 ? "ACTIVE_SESSIONS" :
422 _public_
int sd_uid_get_seats(uid_t uid
, int require_active
, char ***seats
) {
423 return uid_get_array(
425 require_active
== 0 ? "ONLINE_SEATS" :
426 require_active
> 0 ? "ACTIVE_SEATS" :
431 static int file_of_session(const char *session
, char **_p
) {
438 if (!session_id_valid(session
))
441 p
= strappend("/run/systemd/sessions/", session
);
443 _cleanup_free_
char *buf
= NULL
;
445 r
= sd_pid_get_session(0, &buf
);
449 p
= strappend("/run/systemd/sessions/", buf
);
459 _public_
int sd_session_is_active(const char *session
) {
460 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
463 r
= file_of_session(session
, &p
);
467 r
= parse_env_file(p
, NEWLINE
, "ACTIVE", &s
, NULL
);
475 return parse_boolean(s
);
478 _public_
int sd_session_is_remote(const char *session
) {
479 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
482 r
= file_of_session(session
, &p
);
486 r
= parse_env_file(p
, NEWLINE
, "REMOTE", &s
, NULL
);
494 return parse_boolean(s
);
497 _public_
int sd_session_get_state(const char *session
, char **state
) {
498 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
501 assert_return(state
, -EINVAL
);
503 r
= file_of_session(session
, &p
);
507 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
521 _public_
int sd_session_get_uid(const char *session
, uid_t
*uid
) {
523 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
525 assert_return(uid
, -EINVAL
);
527 r
= file_of_session(session
, &p
);
531 r
= parse_env_file(p
, NEWLINE
, "UID", &s
, NULL
);
539 return parse_uid(s
, uid
);
542 static int session_get_string(const char *session
, const char *field
, char **value
) {
543 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
546 assert_return(value
, -EINVAL
);
549 r
= file_of_session(session
, &p
);
553 r
= parse_env_file(p
, NEWLINE
, field
, &s
, NULL
);
566 _public_
int sd_session_get_seat(const char *session
, char **seat
) {
567 return session_get_string(session
, "SEAT", seat
);
570 _public_
int sd_session_get_tty(const char *session
, char **tty
) {
571 return session_get_string(session
, "TTY", tty
);
574 _public_
int sd_session_get_vt(const char *session
, unsigned *vtnr
) {
575 _cleanup_free_
char *vtnr_string
= NULL
;
579 assert_return(vtnr
, -EINVAL
);
581 r
= session_get_string(session
, "VTNR", &vtnr_string
);
585 r
= safe_atou(vtnr_string
, &u
);
593 _public_
int sd_session_get_service(const char *session
, char **service
) {
594 return session_get_string(session
, "SERVICE", service
);
597 _public_
int sd_session_get_type(const char *session
, char **type
) {
598 return session_get_string(session
, "TYPE", type
);
601 _public_
int sd_session_get_class(const char *session
, char **class) {
602 return session_get_string(session
, "CLASS", class);
605 _public_
int sd_session_get_desktop(const char *session
, char **desktop
) {
606 _cleanup_free_
char *escaped
= NULL
;
610 assert_return(desktop
, -EINVAL
);
612 r
= session_get_string(session
, "DESKTOP", &escaped
);
616 r
= cunescape(escaped
, 0, &t
);
624 _public_
int sd_session_get_display(const char *session
, char **display
) {
625 return session_get_string(session
, "DISPLAY", display
);
628 _public_
int sd_session_get_remote_user(const char *session
, char **remote_user
) {
629 return session_get_string(session
, "REMOTE_USER", remote_user
);
632 _public_
int sd_session_get_remote_host(const char *session
, char **remote_host
) {
633 return session_get_string(session
, "REMOTE_HOST", remote_host
);
636 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
637 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
640 assert_return(session
|| uid
, -EINVAL
);
642 r
= file_of_seat(seat
, &p
);
646 r
= parse_env_file(p
, NEWLINE
,
662 r
= parse_uid(t
, uid
);
675 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
676 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
677 _cleanup_strv_free_
char **a
= NULL
;
678 _cleanup_free_ uid_t
*b
= NULL
;
682 r
= file_of_seat(seat
, &p
);
686 r
= parse_env_file(p
, NEWLINE
,
688 "ACTIVE_SESSIONS", &t
,
696 a
= strv_split(s
, " ");
702 const char *word
, *state
;
705 FOREACH_WORD(word
, l
, t
, state
)
715 FOREACH_WORD(word
, l
, t
, state
) {
716 _cleanup_free_
char *k
= NULL
;
718 k
= strndup(word
, l
);
722 r
= parse_uid(k
, b
+ i
);
749 static int seat_get_can(const char *seat
, const char *variable
) {
750 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
755 r
= file_of_seat(seat
, &p
);
759 r
= parse_env_file(p
, NEWLINE
,
769 return parse_boolean(s
);
772 _public_
int sd_seat_can_multi_session(const char *seat
) {
773 return seat_get_can(seat
, "CAN_MULTI_SESSION");
776 _public_
int sd_seat_can_tty(const char *seat
) {
777 return seat_get_can(seat
, "CAN_TTY");
780 _public_
int sd_seat_can_graphical(const char *seat
) {
781 return seat_get_can(seat
, "CAN_GRAPHICAL");
784 _public_
int sd_get_seats(char ***seats
) {
785 return get_files_in_directory("/run/systemd/seats/", seats
);
788 _public_
int sd_get_sessions(char ***sessions
) {
789 return get_files_in_directory("/run/systemd/sessions/", sessions
);
792 _public_
int sd_get_uids(uid_t
**users
) {
793 _cleanup_closedir_
DIR *d
;
796 _cleanup_free_ uid_t
*l
= NULL
;
798 d
= opendir("/run/systemd/users/");
809 if (!de
&& errno
!= 0)
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
);
863 /* Filter out the unit: symlinks */
864 for (a
= l
, b
= l
; *a
; a
++) {
865 if (startswith(*a
, "unit:") || !machine_name_is_valid(*a
))
881 _public_
int sd_machine_get_class(const char *machine
, char **class) {
882 _cleanup_free_
char *c
= NULL
;
886 assert_return(machine_name_is_valid(machine
), -EINVAL
);
887 assert_return(class, -EINVAL
);
889 p
= strjoina("/run/systemd/machines/", machine
);
890 r
= parse_env_file(p
, NEWLINE
, "CLASS", &c
, NULL
);
904 _public_
int sd_machine_get_ifindices(const char *machine
, int **ifindices
) {
905 _cleanup_free_
char *netif
= NULL
;
906 size_t l
, allocated
= 0, nr
= 0;
908 const char *p
, *word
, *state
;
911 assert_return(machine_name_is_valid(machine
), -EINVAL
);
912 assert_return(ifindices
, -EINVAL
);
914 p
= strjoina("/run/systemd/machines/", machine
);
915 r
= parse_env_file(p
, NEWLINE
, "NETIF", &netif
, NULL
);
925 FOREACH_WORD(word
, l
, netif
, state
) {
929 *(char*) (mempcpy(buf
, word
, l
)) = 0;
931 if (safe_atoi(buf
, &ifi
) < 0)
936 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
948 static inline int MONITOR_TO_FD(sd_login_monitor
*m
) {
949 return (int) (unsigned long) m
- 1;
952 static inline 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
) {
960 assert_return(m
, -EINVAL
);
962 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
966 if (!category
|| streq(category
, "seat")) {
967 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
976 if (!category
|| streq(category
, "session")) {
977 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
986 if (!category
|| streq(category
, "uid")) {
987 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
996 if (!category
|| streq(category
, "machine")) {
997 k
= inotify_add_watch(fd
, "/run/systemd/machines/", IN_MOVED_TO
|IN_DELETE
);
1011 *m
= FD_TO_MONITOR(fd
);
1015 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
1018 assert_return(m
, NULL
);
1020 fd
= MONITOR_TO_FD(m
);
1026 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
1028 assert_return(m
, -EINVAL
);
1030 return flush_fd(MONITOR_TO_FD(m
));
1033 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
1035 assert_return(m
, -EINVAL
);
1037 return MONITOR_TO_FD(m
);
1040 _public_
int sd_login_monitor_get_events(sd_login_monitor
*m
) {
1042 assert_return(m
, -EINVAL
);
1044 /* For now we will only return POLLIN here, since we don't
1045 * need anything else ever for inotify. However, let's have
1046 * this API to keep our options open should we later on need
1051 _public_
int sd_login_monitor_get_timeout(sd_login_monitor
*m
, uint64_t *timeout_usec
) {
1053 assert_return(m
, -EINVAL
);
1054 assert_return(timeout_usec
, -EINVAL
);
1056 /* For now we will only return (uint64_t) -1, since we don't
1057 * need any timeout. However, let's have this API to keep our
1058 * options open should we later on need it. */
1059 *timeout_usec
= (uint64_t) -1;