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"
36 #include "login-util.h"
38 #include "string-util.h"
44 * invalid input parameters → -EINVAL
46 * process does not exist → -ESRCH
47 * cgroup does not exist → -ENOENT
48 * machine, session does not exist → -ENXIO
49 * requested metadata on object is missing → -ENODATA
52 _public_
int sd_pid_get_session(pid_t pid
, char **session
) {
54 assert_return(pid
>= 0, -EINVAL
);
55 assert_return(session
, -EINVAL
);
57 return cg_pid_get_session(pid
, session
);
60 _public_
int sd_pid_get_unit(pid_t pid
, char **unit
) {
62 assert_return(pid
>= 0, -EINVAL
);
63 assert_return(unit
, -EINVAL
);
65 return cg_pid_get_unit(pid
, unit
);
68 _public_
int sd_pid_get_user_unit(pid_t pid
, char **unit
) {
70 assert_return(pid
>= 0, -EINVAL
);
71 assert_return(unit
, -EINVAL
);
73 return cg_pid_get_user_unit(pid
, unit
);
76 _public_
int sd_pid_get_machine_name(pid_t pid
, char **name
) {
78 assert_return(pid
>= 0, -EINVAL
);
79 assert_return(name
, -EINVAL
);
81 return cg_pid_get_machine_name(pid
, name
);
84 _public_
int sd_pid_get_slice(pid_t pid
, char **slice
) {
86 assert_return(pid
>= 0, -EINVAL
);
87 assert_return(slice
, -EINVAL
);
89 return cg_pid_get_slice(pid
, slice
);
92 _public_
int sd_pid_get_user_slice(pid_t pid
, char **slice
) {
94 assert_return(pid
>= 0, -EINVAL
);
95 assert_return(slice
, -EINVAL
);
97 return cg_pid_get_user_slice(pid
, slice
);
100 _public_
int sd_pid_get_owner_uid(pid_t pid
, uid_t
*uid
) {
102 assert_return(pid
>= 0, -EINVAL
);
103 assert_return(uid
, -EINVAL
);
105 return cg_pid_get_owner_uid(pid
, uid
);
108 _public_
int sd_pid_get_cgroup(pid_t pid
, char **cgroup
) {
112 assert_return(pid
>= 0, -EINVAL
);
113 assert_return(cgroup
, -EINVAL
);
115 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &c
);
119 /* The internal APIs return the empty string for the root
120 * cgroup, let's return the "/" in the public APIs instead, as
121 * that's easier and less ambigious for people to grok. */
134 _public_
int sd_peer_get_session(int fd
, char **session
) {
135 struct ucred ucred
= {};
138 assert_return(fd
>= 0, -EBADF
);
139 assert_return(session
, -EINVAL
);
141 r
= getpeercred(fd
, &ucred
);
145 return cg_pid_get_session(ucred
.pid
, session
);
148 _public_
int sd_peer_get_owner_uid(int fd
, uid_t
*uid
) {
152 assert_return(fd
>= 0, -EBADF
);
153 assert_return(uid
, -EINVAL
);
155 r
= getpeercred(fd
, &ucred
);
159 return cg_pid_get_owner_uid(ucred
.pid
, uid
);
162 _public_
int sd_peer_get_unit(int fd
, char **unit
) {
166 assert_return(fd
>= 0, -EBADF
);
167 assert_return(unit
, -EINVAL
);
169 r
= getpeercred(fd
, &ucred
);
173 return cg_pid_get_unit(ucred
.pid
, unit
);
176 _public_
int sd_peer_get_user_unit(int fd
, char **unit
) {
180 assert_return(fd
>= 0, -EBADF
);
181 assert_return(unit
, -EINVAL
);
183 r
= getpeercred(fd
, &ucred
);
187 return cg_pid_get_user_unit(ucred
.pid
, unit
);
190 _public_
int sd_peer_get_machine_name(int fd
, char **machine
) {
194 assert_return(fd
>= 0, -EBADF
);
195 assert_return(machine
, -EINVAL
);
197 r
= getpeercred(fd
, &ucred
);
201 return cg_pid_get_machine_name(ucred
.pid
, machine
);
204 _public_
int sd_peer_get_slice(int fd
, char **slice
) {
208 assert_return(fd
>= 0, -EBADF
);
209 assert_return(slice
, -EINVAL
);
211 r
= getpeercred(fd
, &ucred
);
215 return cg_pid_get_slice(ucred
.pid
, slice
);
218 _public_
int sd_peer_get_user_slice(int fd
, char **slice
) {
222 assert_return(fd
>= 0, -EBADF
);
223 assert_return(slice
, -EINVAL
);
225 r
= getpeercred(fd
, &ucred
);
229 return cg_pid_get_user_slice(ucred
.pid
, slice
);
232 _public_
int sd_peer_get_cgroup(int fd
, char **cgroup
) {
236 assert_return(fd
>= 0, -EBADF
);
237 assert_return(cgroup
, -EINVAL
);
239 r
= getpeercred(fd
, &ucred
);
243 return sd_pid_get_cgroup(ucred
.pid
, cgroup
);
246 static int file_of_uid(uid_t uid
, char **p
) {
248 assert_return(uid_is_valid(uid
), -EINVAL
);
251 if (asprintf(p
, "/run/systemd/users/" UID_FMT
, uid
) < 0)
257 _public_
int sd_uid_get_state(uid_t uid
, char**state
) {
258 _cleanup_free_
char *p
= NULL
;
262 assert_return(state
, -EINVAL
);
264 r
= file_of_uid(uid
, &p
);
268 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
271 s
= strdup("offline");
289 _public_
int sd_uid_get_display(uid_t uid
, char **session
) {
290 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
293 assert_return(session
, -EINVAL
);
295 r
= file_of_uid(uid
, &p
);
299 r
= parse_env_file(p
, NEWLINE
, "DISPLAY", &s
, NULL
);
313 static int file_of_seat(const char *seat
, char **_p
) {
320 if (!filename_is_valid(seat
))
323 p
= strappend("/run/systemd/seats/", seat
);
325 _cleanup_free_
char *buf
= NULL
;
327 r
= sd_session_get_seat(NULL
, &buf
);
331 p
= strappend("/run/systemd/seats/", buf
);
342 _public_
int sd_uid_is_on_seat(uid_t uid
, int require_active
, const char *seat
) {
343 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *p
= NULL
;
346 const char *word
, *variable
, *state
;
348 assert_return(uid_is_valid(uid
), -EINVAL
);
350 r
= file_of_seat(seat
, &p
);
354 variable
= require_active
? "ACTIVE_UID" : "UIDS";
356 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
364 if (asprintf(&t
, UID_FMT
, uid
) < 0)
367 FOREACH_WORD(word
, l
, s
, state
)
368 if (strneq(t
, word
, l
))
374 static int uid_get_array(uid_t uid
, const char *variable
, char ***array
) {
375 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
381 r
= file_of_uid(uid
, &p
);
385 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
386 if (r
== -ENOENT
|| (r
>= 0 && isempty(s
))) {
394 a
= strv_split(s
, " ");
409 _public_
int sd_uid_get_sessions(uid_t uid
, int require_active
, char ***sessions
) {
410 return uid_get_array(
412 require_active
== 0 ? "ONLINE_SESSIONS" :
413 require_active
> 0 ? "ACTIVE_SESSIONS" :
418 _public_
int sd_uid_get_seats(uid_t uid
, int require_active
, char ***seats
) {
419 return uid_get_array(
421 require_active
== 0 ? "ONLINE_SEATS" :
422 require_active
> 0 ? "ACTIVE_SEATS" :
427 static int file_of_session(const char *session
, char **_p
) {
434 if (!session_id_valid(session
))
437 p
= strappend("/run/systemd/sessions/", session
);
439 _cleanup_free_
char *buf
= NULL
;
441 r
= sd_pid_get_session(0, &buf
);
445 p
= strappend("/run/systemd/sessions/", buf
);
455 _public_
int sd_session_is_active(const char *session
) {
456 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
459 r
= file_of_session(session
, &p
);
463 r
= parse_env_file(p
, NEWLINE
, "ACTIVE", &s
, NULL
);
471 return parse_boolean(s
);
474 _public_
int sd_session_is_remote(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
, "REMOTE", &s
, NULL
);
490 return parse_boolean(s
);
493 _public_
int sd_session_get_state(const char *session
, char **state
) {
494 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
497 assert_return(state
, -EINVAL
);
499 r
= file_of_session(session
, &p
);
503 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
517 _public_
int sd_session_get_uid(const char *session
, uid_t
*uid
) {
519 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
521 assert_return(uid
, -EINVAL
);
523 r
= file_of_session(session
, &p
);
527 r
= parse_env_file(p
, NEWLINE
, "UID", &s
, NULL
);
535 return parse_uid(s
, uid
);
538 static int session_get_string(const char *session
, const char *field
, char **value
) {
539 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
542 assert_return(value
, -EINVAL
);
545 r
= file_of_session(session
, &p
);
549 r
= parse_env_file(p
, NEWLINE
, field
, &s
, NULL
);
562 _public_
int sd_session_get_seat(const char *session
, char **seat
) {
563 return session_get_string(session
, "SEAT", seat
);
566 _public_
int sd_session_get_tty(const char *session
, char **tty
) {
567 return session_get_string(session
, "TTY", tty
);
570 _public_
int sd_session_get_vt(const char *session
, unsigned *vtnr
) {
571 _cleanup_free_
char *vtnr_string
= NULL
;
575 assert_return(vtnr
, -EINVAL
);
577 r
= session_get_string(session
, "VTNR", &vtnr_string
);
581 r
= safe_atou(vtnr_string
, &u
);
589 _public_
int sd_session_get_service(const char *session
, char **service
) {
590 return session_get_string(session
, "SERVICE", service
);
593 _public_
int sd_session_get_type(const char *session
, char **type
) {
594 return session_get_string(session
, "TYPE", type
);
597 _public_
int sd_session_get_class(const char *session
, char **class) {
598 return session_get_string(session
, "CLASS", class);
601 _public_
int sd_session_get_desktop(const char *session
, char **desktop
) {
602 _cleanup_free_
char *escaped
= NULL
;
606 assert_return(desktop
, -EINVAL
);
608 r
= session_get_string(session
, "DESKTOP", &escaped
);
612 r
= cunescape(escaped
, 0, &t
);
620 _public_
int sd_session_get_display(const char *session
, char **display
) {
621 return session_get_string(session
, "DISPLAY", display
);
624 _public_
int sd_session_get_remote_user(const char *session
, char **remote_user
) {
625 return session_get_string(session
, "REMOTE_USER", remote_user
);
628 _public_
int sd_session_get_remote_host(const char *session
, char **remote_host
) {
629 return session_get_string(session
, "REMOTE_HOST", remote_host
);
632 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
633 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
636 assert_return(session
|| uid
, -EINVAL
);
638 r
= file_of_seat(seat
, &p
);
642 r
= parse_env_file(p
, NEWLINE
,
658 r
= parse_uid(t
, uid
);
671 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
672 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
673 _cleanup_strv_free_
char **a
= NULL
;
674 _cleanup_free_ uid_t
*b
= NULL
;
678 r
= file_of_seat(seat
, &p
);
682 r
= parse_env_file(p
, NEWLINE
,
684 "ACTIVE_SESSIONS", &t
,
692 a
= strv_split(s
, " ");
698 const char *word
, *state
;
701 FOREACH_WORD(word
, l
, t
, state
)
711 FOREACH_WORD(word
, l
, t
, state
) {
712 _cleanup_free_
char *k
= NULL
;
714 k
= strndup(word
, l
);
718 r
= parse_uid(k
, b
+ i
);
745 static int seat_get_can(const char *seat
, const char *variable
) {
746 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
751 r
= file_of_seat(seat
, &p
);
755 r
= parse_env_file(p
, NEWLINE
,
765 return parse_boolean(s
);
768 _public_
int sd_seat_can_multi_session(const char *seat
) {
769 return seat_get_can(seat
, "CAN_MULTI_SESSION");
772 _public_
int sd_seat_can_tty(const char *seat
) {
773 return seat_get_can(seat
, "CAN_TTY");
776 _public_
int sd_seat_can_graphical(const char *seat
) {
777 return seat_get_can(seat
, "CAN_GRAPHICAL");
780 _public_
int sd_get_seats(char ***seats
) {
781 return get_files_in_directory("/run/systemd/seats/", seats
);
784 _public_
int sd_get_sessions(char ***sessions
) {
785 return get_files_in_directory("/run/systemd/sessions/", sessions
);
788 _public_
int sd_get_uids(uid_t
**users
) {
789 _cleanup_closedir_
DIR *d
;
792 _cleanup_free_ uid_t
*l
= NULL
;
794 d
= opendir("/run/systemd/users/");
805 if (!de
&& errno
!= 0)
811 dirent_ensure_type(d
, de
);
813 if (!dirent_is_file(de
))
816 k
= parse_uid(de
->d_name
, &uid
);
821 if ((unsigned) r
>= n
) {
825 t
= realloc(l
, sizeof(uid_t
) * n
);
832 assert((unsigned) r
< n
);
846 _public_
int sd_get_machine_names(char ***machines
) {
847 char **l
= NULL
, **a
, **b
;
850 assert_return(machines
, -EINVAL
);
852 r
= get_files_in_directory("/run/systemd/machines/", &l
);
859 /* Filter out the unit: symlinks */
860 for (a
= l
, b
= l
; *a
; a
++) {
861 if (startswith(*a
, "unit:") || !machine_name_is_valid(*a
))
877 _public_
int sd_machine_get_class(const char *machine
, char **class) {
878 _cleanup_free_
char *c
= NULL
;
882 assert_return(machine_name_is_valid(machine
), -EINVAL
);
883 assert_return(class, -EINVAL
);
885 p
= strjoina("/run/systemd/machines/", machine
);
886 r
= parse_env_file(p
, NEWLINE
, "CLASS", &c
, NULL
);
900 _public_
int sd_machine_get_ifindices(const char *machine
, int **ifindices
) {
901 _cleanup_free_
char *netif
= NULL
;
902 size_t l
, allocated
= 0, nr
= 0;
904 const char *p
, *word
, *state
;
907 assert_return(machine_name_is_valid(machine
), -EINVAL
);
908 assert_return(ifindices
, -EINVAL
);
910 p
= strjoina("/run/systemd/machines/", machine
);
911 r
= parse_env_file(p
, NEWLINE
, "NETIF", &netif
, NULL
);
921 FOREACH_WORD(word
, l
, netif
, state
) {
925 *(char*) (mempcpy(buf
, word
, l
)) = 0;
927 if (safe_atoi(buf
, &ifi
) < 0)
932 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
944 static inline int MONITOR_TO_FD(sd_login_monitor
*m
) {
945 return (int) (unsigned long) m
- 1;
948 static inline sd_login_monitor
* FD_TO_MONITOR(int fd
) {
949 return (sd_login_monitor
*) (unsigned long) (fd
+ 1);
952 _public_
int sd_login_monitor_new(const char *category
, sd_login_monitor
**m
) {
956 assert_return(m
, -EINVAL
);
958 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
962 if (!category
|| streq(category
, "seat")) {
963 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
972 if (!category
|| streq(category
, "session")) {
973 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
982 if (!category
|| streq(category
, "uid")) {
983 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
992 if (!category
|| streq(category
, "machine")) {
993 k
= inotify_add_watch(fd
, "/run/systemd/machines/", IN_MOVED_TO
|IN_DELETE
);
1007 *m
= FD_TO_MONITOR(fd
);
1011 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
1014 assert_return(m
, NULL
);
1016 fd
= MONITOR_TO_FD(m
);
1022 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
1024 assert_return(m
, -EINVAL
);
1026 return flush_fd(MONITOR_TO_FD(m
));
1029 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
1031 assert_return(m
, -EINVAL
);
1033 return MONITOR_TO_FD(m
);
1036 _public_
int sd_login_monitor_get_events(sd_login_monitor
*m
) {
1038 assert_return(m
, -EINVAL
);
1040 /* For now we will only return POLLIN here, since we don't
1041 * need anything else ever for inotify. However, let's have
1042 * this API to keep our options open should we later on need
1047 _public_
int sd_login_monitor_get_timeout(sd_login_monitor
*m
, uint64_t *timeout_usec
) {
1049 assert_return(m
, -EINVAL
);
1050 assert_return(timeout_usec
, -EINVAL
);
1052 /* For now we will only return (uint64_t) -1, since we don't
1053 * need any timeout. However, let's have this API to keep our
1054 * options open should we later on need it. */
1055 *timeout_usec
= (uint64_t) -1;