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"
31 #include "dirent-util.h"
35 #include "formats-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
) {
61 assert_return(pid
>= 0, -EINVAL
);
62 assert_return(session
, -EINVAL
);
64 return cg_pid_get_session(pid
, session
);
67 _public_
int sd_pid_get_unit(pid_t pid
, char **unit
) {
69 assert_return(pid
>= 0, -EINVAL
);
70 assert_return(unit
, -EINVAL
);
72 return cg_pid_get_unit(pid
, unit
);
75 _public_
int sd_pid_get_user_unit(pid_t pid
, char **unit
) {
77 assert_return(pid
>= 0, -EINVAL
);
78 assert_return(unit
, -EINVAL
);
80 return cg_pid_get_user_unit(pid
, unit
);
83 _public_
int sd_pid_get_machine_name(pid_t pid
, char **name
) {
85 assert_return(pid
>= 0, -EINVAL
);
86 assert_return(name
, -EINVAL
);
88 return cg_pid_get_machine_name(pid
, name
);
91 _public_
int sd_pid_get_slice(pid_t pid
, char **slice
) {
93 assert_return(pid
>= 0, -EINVAL
);
94 assert_return(slice
, -EINVAL
);
96 return cg_pid_get_slice(pid
, slice
);
99 _public_
int sd_pid_get_user_slice(pid_t pid
, char **slice
) {
101 assert_return(pid
>= 0, -EINVAL
);
102 assert_return(slice
, -EINVAL
);
104 return cg_pid_get_user_slice(pid
, slice
);
107 _public_
int sd_pid_get_owner_uid(pid_t pid
, uid_t
*uid
) {
109 assert_return(pid
>= 0, -EINVAL
);
110 assert_return(uid
, -EINVAL
);
112 return cg_pid_get_owner_uid(pid
, uid
);
115 _public_
int sd_pid_get_cgroup(pid_t pid
, char **cgroup
) {
119 assert_return(pid
>= 0, -EINVAL
);
120 assert_return(cgroup
, -EINVAL
);
122 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &c
);
126 /* The internal APIs return the empty string for the root
127 * cgroup, let's return the "/" in the public APIs instead, as
128 * that's easier and less ambigious for people to grok. */
141 _public_
int sd_peer_get_session(int fd
, char **session
) {
142 struct ucred ucred
= {};
145 assert_return(fd
>= 0, -EBADF
);
146 assert_return(session
, -EINVAL
);
148 r
= getpeercred(fd
, &ucred
);
152 return cg_pid_get_session(ucred
.pid
, session
);
155 _public_
int sd_peer_get_owner_uid(int fd
, uid_t
*uid
) {
159 assert_return(fd
>= 0, -EBADF
);
160 assert_return(uid
, -EINVAL
);
162 r
= getpeercred(fd
, &ucred
);
166 return cg_pid_get_owner_uid(ucred
.pid
, uid
);
169 _public_
int sd_peer_get_unit(int fd
, char **unit
) {
173 assert_return(fd
>= 0, -EBADF
);
174 assert_return(unit
, -EINVAL
);
176 r
= getpeercred(fd
, &ucred
);
180 return cg_pid_get_unit(ucred
.pid
, unit
);
183 _public_
int sd_peer_get_user_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_user_unit(ucred
.pid
, unit
);
197 _public_
int sd_peer_get_machine_name(int fd
, char **machine
) {
201 assert_return(fd
>= 0, -EBADF
);
202 assert_return(machine
, -EINVAL
);
204 r
= getpeercred(fd
, &ucred
);
208 return cg_pid_get_machine_name(ucred
.pid
, machine
);
211 _public_
int sd_peer_get_slice(int fd
, char **slice
) {
215 assert_return(fd
>= 0, -EBADF
);
216 assert_return(slice
, -EINVAL
);
218 r
= getpeercred(fd
, &ucred
);
222 return cg_pid_get_slice(ucred
.pid
, slice
);
225 _public_
int sd_peer_get_user_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_user_slice(ucred
.pid
, slice
);
239 _public_
int sd_peer_get_cgroup(int fd
, char **cgroup
) {
243 assert_return(fd
>= 0, -EBADF
);
244 assert_return(cgroup
, -EINVAL
);
246 r
= getpeercred(fd
, &ucred
);
250 return sd_pid_get_cgroup(ucred
.pid
, cgroup
);
253 static int file_of_uid(uid_t uid
, char **p
) {
255 assert_return(uid_is_valid(uid
), -EINVAL
);
258 if (asprintf(p
, "/run/systemd/users/" UID_FMT
, uid
) < 0)
264 _public_
int sd_uid_get_state(uid_t uid
, char**state
) {
265 _cleanup_free_
char *p
= NULL
;
269 assert_return(state
, -EINVAL
);
271 r
= file_of_uid(uid
, &p
);
275 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
278 s
= strdup("offline");
296 _public_
int sd_uid_get_display(uid_t uid
, char **session
) {
297 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
300 assert_return(session
, -EINVAL
);
302 r
= file_of_uid(uid
, &p
);
306 r
= parse_env_file(p
, NEWLINE
, "DISPLAY", &s
, NULL
);
320 static int file_of_seat(const char *seat
, char **_p
) {
327 if (!filename_is_valid(seat
))
330 p
= strappend("/run/systemd/seats/", seat
);
332 _cleanup_free_
char *buf
= NULL
;
334 r
= sd_session_get_seat(NULL
, &buf
);
338 p
= strappend("/run/systemd/seats/", buf
);
349 _public_
int sd_uid_is_on_seat(uid_t uid
, int require_active
, const char *seat
) {
350 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *p
= NULL
;
353 const char *word
, *variable
, *state
;
355 assert_return(uid_is_valid(uid
), -EINVAL
);
357 r
= file_of_seat(seat
, &p
);
361 variable
= require_active
? "ACTIVE_UID" : "UIDS";
363 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
371 if (asprintf(&t
, UID_FMT
, uid
) < 0)
374 FOREACH_WORD(word
, l
, s
, state
)
375 if (strneq(t
, word
, l
))
381 static int uid_get_array(uid_t uid
, const char *variable
, char ***array
) {
382 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
388 r
= file_of_uid(uid
, &p
);
392 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
393 if (r
== -ENOENT
|| (r
>= 0 && isempty(s
))) {
401 a
= strv_split(s
, " ");
416 _public_
int sd_uid_get_sessions(uid_t uid
, int require_active
, char ***sessions
) {
417 return uid_get_array(
419 require_active
== 0 ? "ONLINE_SESSIONS" :
420 require_active
> 0 ? "ACTIVE_SESSIONS" :
425 _public_
int sd_uid_get_seats(uid_t uid
, int require_active
, char ***seats
) {
426 return uid_get_array(
428 require_active
== 0 ? "ONLINE_SEATS" :
429 require_active
> 0 ? "ACTIVE_SEATS" :
434 static int file_of_session(const char *session
, char **_p
) {
441 if (!session_id_valid(session
))
444 p
= strappend("/run/systemd/sessions/", session
);
446 _cleanup_free_
char *buf
= NULL
;
448 r
= sd_pid_get_session(0, &buf
);
452 p
= strappend("/run/systemd/sessions/", buf
);
462 _public_
int sd_session_is_active(const char *session
) {
463 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
466 r
= file_of_session(session
, &p
);
470 r
= parse_env_file(p
, NEWLINE
, "ACTIVE", &s
, NULL
);
478 return parse_boolean(s
);
481 _public_
int sd_session_is_remote(const char *session
) {
482 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
485 r
= file_of_session(session
, &p
);
489 r
= parse_env_file(p
, NEWLINE
, "REMOTE", &s
, NULL
);
497 return parse_boolean(s
);
500 _public_
int sd_session_get_state(const char *session
, char **state
) {
501 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
504 assert_return(state
, -EINVAL
);
506 r
= file_of_session(session
, &p
);
510 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
524 _public_
int sd_session_get_uid(const char *session
, uid_t
*uid
) {
526 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
528 assert_return(uid
, -EINVAL
);
530 r
= file_of_session(session
, &p
);
534 r
= parse_env_file(p
, NEWLINE
, "UID", &s
, NULL
);
542 return parse_uid(s
, uid
);
545 static int session_get_string(const char *session
, const char *field
, char **value
) {
546 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
549 assert_return(value
, -EINVAL
);
552 r
= file_of_session(session
, &p
);
556 r
= parse_env_file(p
, NEWLINE
, field
, &s
, NULL
);
569 _public_
int sd_session_get_seat(const char *session
, char **seat
) {
570 return session_get_string(session
, "SEAT", seat
);
573 _public_
int sd_session_get_tty(const char *session
, char **tty
) {
574 return session_get_string(session
, "TTY", tty
);
577 _public_
int sd_session_get_vt(const char *session
, unsigned *vtnr
) {
578 _cleanup_free_
char *vtnr_string
= NULL
;
582 assert_return(vtnr
, -EINVAL
);
584 r
= session_get_string(session
, "VTNR", &vtnr_string
);
588 r
= safe_atou(vtnr_string
, &u
);
596 _public_
int sd_session_get_service(const char *session
, char **service
) {
597 return session_get_string(session
, "SERVICE", service
);
600 _public_
int sd_session_get_type(const char *session
, char **type
) {
601 return session_get_string(session
, "TYPE", type
);
604 _public_
int sd_session_get_class(const char *session
, char **class) {
605 return session_get_string(session
, "CLASS", class);
608 _public_
int sd_session_get_desktop(const char *session
, char **desktop
) {
609 _cleanup_free_
char *escaped
= NULL
;
613 assert_return(desktop
, -EINVAL
);
615 r
= session_get_string(session
, "DESKTOP", &escaped
);
619 r
= cunescape(escaped
, 0, &t
);
627 _public_
int sd_session_get_display(const char *session
, char **display
) {
628 return session_get_string(session
, "DISPLAY", display
);
631 _public_
int sd_session_get_remote_user(const char *session
, char **remote_user
) {
632 return session_get_string(session
, "REMOTE_USER", remote_user
);
635 _public_
int sd_session_get_remote_host(const char *session
, char **remote_host
) {
636 return session_get_string(session
, "REMOTE_HOST", remote_host
);
639 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
640 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
643 assert_return(session
|| uid
, -EINVAL
);
645 r
= file_of_seat(seat
, &p
);
649 r
= parse_env_file(p
, NEWLINE
,
665 r
= parse_uid(t
, uid
);
678 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
679 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
680 _cleanup_strv_free_
char **a
= NULL
;
681 _cleanup_free_ uid_t
*b
= NULL
;
685 r
= file_of_seat(seat
, &p
);
689 r
= parse_env_file(p
, NEWLINE
,
691 "ACTIVE_SESSIONS", &t
,
699 a
= strv_split(s
, " ");
705 const char *word
, *state
;
708 FOREACH_WORD(word
, l
, t
, state
)
718 FOREACH_WORD(word
, l
, t
, state
) {
719 _cleanup_free_
char *k
= NULL
;
721 k
= strndup(word
, l
);
725 r
= parse_uid(k
, b
+ i
);
752 static int seat_get_can(const char *seat
, const char *variable
) {
753 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
758 r
= file_of_seat(seat
, &p
);
762 r
= parse_env_file(p
, NEWLINE
,
772 return parse_boolean(s
);
775 _public_
int sd_seat_can_multi_session(const char *seat
) {
776 return seat_get_can(seat
, "CAN_MULTI_SESSION");
779 _public_
int sd_seat_can_tty(const char *seat
) {
780 return seat_get_can(seat
, "CAN_TTY");
783 _public_
int sd_seat_can_graphical(const char *seat
) {
784 return seat_get_can(seat
, "CAN_GRAPHICAL");
787 _public_
int sd_get_seats(char ***seats
) {
788 return get_files_in_directory("/run/systemd/seats/", seats
);
791 _public_
int sd_get_sessions(char ***sessions
) {
792 return get_files_in_directory("/run/systemd/sessions/", sessions
);
795 _public_
int sd_get_uids(uid_t
**users
) {
796 _cleanup_closedir_
DIR *d
;
799 _cleanup_free_ uid_t
*l
= NULL
;
801 d
= opendir("/run/systemd/users/");
812 if (!de
&& errno
!= 0)
818 dirent_ensure_type(d
, de
);
820 if (!dirent_is_file(de
))
823 k
= parse_uid(de
->d_name
, &uid
);
828 if ((unsigned) r
>= n
) {
832 t
= realloc(l
, sizeof(uid_t
) * n
);
839 assert((unsigned) r
< n
);
853 _public_
int sd_get_machine_names(char ***machines
) {
854 char **l
= NULL
, **a
, **b
;
857 assert_return(machines
, -EINVAL
);
859 r
= get_files_in_directory("/run/systemd/machines/", &l
);
866 /* Filter out the unit: symlinks */
867 for (a
= l
, b
= l
; *a
; a
++) {
868 if (startswith(*a
, "unit:") || !machine_name_is_valid(*a
))
884 _public_
int sd_machine_get_class(const char *machine
, char **class) {
885 _cleanup_free_
char *c
= NULL
;
889 assert_return(machine_name_is_valid(machine
), -EINVAL
);
890 assert_return(class, -EINVAL
);
892 p
= strjoina("/run/systemd/machines/", machine
);
893 r
= parse_env_file(p
, NEWLINE
, "CLASS", &c
, NULL
);
907 _public_
int sd_machine_get_ifindices(const char *machine
, int **ifindices
) {
908 _cleanup_free_
char *netif
= NULL
;
909 size_t l
, allocated
= 0, nr
= 0;
911 const char *p
, *word
, *state
;
914 assert_return(machine_name_is_valid(machine
), -EINVAL
);
915 assert_return(ifindices
, -EINVAL
);
917 p
= strjoina("/run/systemd/machines/", machine
);
918 r
= parse_env_file(p
, NEWLINE
, "NETIF", &netif
, NULL
);
928 FOREACH_WORD(word
, l
, netif
, state
) {
932 *(char*) (mempcpy(buf
, word
, l
)) = 0;
934 if (safe_atoi(buf
, &ifi
) < 0)
939 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
951 static inline int MONITOR_TO_FD(sd_login_monitor
*m
) {
952 return (int) (unsigned long) m
- 1;
955 static inline sd_login_monitor
* FD_TO_MONITOR(int fd
) {
956 return (sd_login_monitor
*) (unsigned long) (fd
+ 1);
959 _public_
int sd_login_monitor_new(const char *category
, sd_login_monitor
**m
) {
963 assert_return(m
, -EINVAL
);
965 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
969 if (!category
|| streq(category
, "seat")) {
970 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
979 if (!category
|| streq(category
, "session")) {
980 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
989 if (!category
|| streq(category
, "uid")) {
990 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
999 if (!category
|| streq(category
, "machine")) {
1000 k
= inotify_add_watch(fd
, "/run/systemd/machines/", IN_MOVED_TO
|IN_DELETE
);
1014 *m
= FD_TO_MONITOR(fd
);
1018 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
1021 assert_return(m
, NULL
);
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;