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 "string-util.h"
45 * invalid input parameters → -EINVAL
47 * process does not exist → -ESRCH
48 * cgroup does not exist → -ENOENT
49 * machine, session does not exist → -ENXIO
50 * requested metadata on object is missing → -ENODATA
53 _public_
int sd_pid_get_session(pid_t pid
, char **session
) {
55 assert_return(pid
>= 0, -EINVAL
);
56 assert_return(session
, -EINVAL
);
58 return cg_pid_get_session(pid
, session
);
61 _public_
int sd_pid_get_unit(pid_t pid
, char **unit
) {
63 assert_return(pid
>= 0, -EINVAL
);
64 assert_return(unit
, -EINVAL
);
66 return cg_pid_get_unit(pid
, unit
);
69 _public_
int sd_pid_get_user_unit(pid_t pid
, char **unit
) {
71 assert_return(pid
>= 0, -EINVAL
);
72 assert_return(unit
, -EINVAL
);
74 return cg_pid_get_user_unit(pid
, unit
);
77 _public_
int sd_pid_get_machine_name(pid_t pid
, char **name
) {
79 assert_return(pid
>= 0, -EINVAL
);
80 assert_return(name
, -EINVAL
);
82 return cg_pid_get_machine_name(pid
, name
);
85 _public_
int sd_pid_get_slice(pid_t pid
, char **slice
) {
87 assert_return(pid
>= 0, -EINVAL
);
88 assert_return(slice
, -EINVAL
);
90 return cg_pid_get_slice(pid
, slice
);
93 _public_
int sd_pid_get_user_slice(pid_t pid
, char **slice
) {
95 assert_return(pid
>= 0, -EINVAL
);
96 assert_return(slice
, -EINVAL
);
98 return cg_pid_get_user_slice(pid
, slice
);
101 _public_
int sd_pid_get_owner_uid(pid_t pid
, uid_t
*uid
) {
103 assert_return(pid
>= 0, -EINVAL
);
104 assert_return(uid
, -EINVAL
);
106 return cg_pid_get_owner_uid(pid
, uid
);
109 _public_
int sd_pid_get_cgroup(pid_t pid
, char **cgroup
) {
113 assert_return(pid
>= 0, -EINVAL
);
114 assert_return(cgroup
, -EINVAL
);
116 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &c
);
120 /* The internal APIs return the empty string for the root
121 * cgroup, let's return the "/" in the public APIs instead, as
122 * that's easier and less ambigious for people to grok. */
135 _public_
int sd_peer_get_session(int fd
, char **session
) {
136 struct ucred ucred
= {};
139 assert_return(fd
>= 0, -EBADF
);
140 assert_return(session
, -EINVAL
);
142 r
= getpeercred(fd
, &ucred
);
146 return cg_pid_get_session(ucred
.pid
, session
);
149 _public_
int sd_peer_get_owner_uid(int fd
, uid_t
*uid
) {
153 assert_return(fd
>= 0, -EBADF
);
154 assert_return(uid
, -EINVAL
);
156 r
= getpeercred(fd
, &ucred
);
160 return cg_pid_get_owner_uid(ucred
.pid
, uid
);
163 _public_
int sd_peer_get_unit(int fd
, char **unit
) {
167 assert_return(fd
>= 0, -EBADF
);
168 assert_return(unit
, -EINVAL
);
170 r
= getpeercred(fd
, &ucred
);
174 return cg_pid_get_unit(ucred
.pid
, unit
);
177 _public_
int sd_peer_get_user_unit(int fd
, char **unit
) {
181 assert_return(fd
>= 0, -EBADF
);
182 assert_return(unit
, -EINVAL
);
184 r
= getpeercred(fd
, &ucred
);
188 return cg_pid_get_user_unit(ucred
.pid
, unit
);
191 _public_
int sd_peer_get_machine_name(int fd
, char **machine
) {
195 assert_return(fd
>= 0, -EBADF
);
196 assert_return(machine
, -EINVAL
);
198 r
= getpeercred(fd
, &ucred
);
202 return cg_pid_get_machine_name(ucred
.pid
, machine
);
205 _public_
int sd_peer_get_slice(int fd
, char **slice
) {
209 assert_return(fd
>= 0, -EBADF
);
210 assert_return(slice
, -EINVAL
);
212 r
= getpeercred(fd
, &ucred
);
216 return cg_pid_get_slice(ucred
.pid
, slice
);
219 _public_
int sd_peer_get_user_slice(int fd
, char **slice
) {
223 assert_return(fd
>= 0, -EBADF
);
224 assert_return(slice
, -EINVAL
);
226 r
= getpeercred(fd
, &ucred
);
230 return cg_pid_get_user_slice(ucred
.pid
, slice
);
233 _public_
int sd_peer_get_cgroup(int fd
, char **cgroup
) {
237 assert_return(fd
>= 0, -EBADF
);
238 assert_return(cgroup
, -EINVAL
);
240 r
= getpeercred(fd
, &ucred
);
244 return sd_pid_get_cgroup(ucred
.pid
, cgroup
);
247 static int file_of_uid(uid_t uid
, char **p
) {
249 assert_return(uid_is_valid(uid
), -EINVAL
);
252 if (asprintf(p
, "/run/systemd/users/" UID_FMT
, uid
) < 0)
258 _public_
int sd_uid_get_state(uid_t uid
, char**state
) {
259 _cleanup_free_
char *p
= NULL
;
263 assert_return(state
, -EINVAL
);
265 r
= file_of_uid(uid
, &p
);
269 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
272 s
= strdup("offline");
290 _public_
int sd_uid_get_display(uid_t uid
, char **session
) {
291 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
294 assert_return(session
, -EINVAL
);
296 r
= file_of_uid(uid
, &p
);
300 r
= parse_env_file(p
, NEWLINE
, "DISPLAY", &s
, NULL
);
314 static int file_of_seat(const char *seat
, char **_p
) {
321 if (!filename_is_valid(seat
))
324 p
= strappend("/run/systemd/seats/", seat
);
326 _cleanup_free_
char *buf
= NULL
;
328 r
= sd_session_get_seat(NULL
, &buf
);
332 p
= strappend("/run/systemd/seats/", buf
);
343 _public_
int sd_uid_is_on_seat(uid_t uid
, int require_active
, const char *seat
) {
344 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *p
= NULL
;
347 const char *word
, *variable
, *state
;
349 assert_return(uid_is_valid(uid
), -EINVAL
);
351 r
= file_of_seat(seat
, &p
);
355 variable
= require_active
? "ACTIVE_UID" : "UIDS";
357 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
365 if (asprintf(&t
, UID_FMT
, uid
) < 0)
368 FOREACH_WORD(word
, l
, s
, state
)
369 if (strneq(t
, word
, l
))
375 static int uid_get_array(uid_t uid
, const char *variable
, char ***array
) {
376 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
382 r
= file_of_uid(uid
, &p
);
386 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
387 if (r
== -ENOENT
|| (r
>= 0 && isempty(s
))) {
395 a
= strv_split(s
, " ");
410 _public_
int sd_uid_get_sessions(uid_t uid
, int require_active
, char ***sessions
) {
411 return uid_get_array(
413 require_active
== 0 ? "ONLINE_SESSIONS" :
414 require_active
> 0 ? "ACTIVE_SESSIONS" :
419 _public_
int sd_uid_get_seats(uid_t uid
, int require_active
, char ***seats
) {
420 return uid_get_array(
422 require_active
== 0 ? "ONLINE_SEATS" :
423 require_active
> 0 ? "ACTIVE_SEATS" :
428 static int file_of_session(const char *session
, char **_p
) {
435 if (!session_id_valid(session
))
438 p
= strappend("/run/systemd/sessions/", session
);
440 _cleanup_free_
char *buf
= NULL
;
442 r
= sd_pid_get_session(0, &buf
);
446 p
= strappend("/run/systemd/sessions/", buf
);
456 _public_
int sd_session_is_active(const char *session
) {
457 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
460 r
= file_of_session(session
, &p
);
464 r
= parse_env_file(p
, NEWLINE
, "ACTIVE", &s
, NULL
);
472 return parse_boolean(s
);
475 _public_
int sd_session_is_remote(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
, "REMOTE", &s
, NULL
);
491 return parse_boolean(s
);
494 _public_
int sd_session_get_state(const char *session
, char **state
) {
495 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
498 assert_return(state
, -EINVAL
);
500 r
= file_of_session(session
, &p
);
504 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
518 _public_
int sd_session_get_uid(const char *session
, uid_t
*uid
) {
520 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
522 assert_return(uid
, -EINVAL
);
524 r
= file_of_session(session
, &p
);
528 r
= parse_env_file(p
, NEWLINE
, "UID", &s
, NULL
);
536 return parse_uid(s
, uid
);
539 static int session_get_string(const char *session
, const char *field
, char **value
) {
540 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
543 assert_return(value
, -EINVAL
);
546 r
= file_of_session(session
, &p
);
550 r
= parse_env_file(p
, NEWLINE
, field
, &s
, NULL
);
563 _public_
int sd_session_get_seat(const char *session
, char **seat
) {
564 return session_get_string(session
, "SEAT", seat
);
567 _public_
int sd_session_get_tty(const char *session
, char **tty
) {
568 return session_get_string(session
, "TTY", tty
);
571 _public_
int sd_session_get_vt(const char *session
, unsigned *vtnr
) {
572 _cleanup_free_
char *vtnr_string
= NULL
;
576 assert_return(vtnr
, -EINVAL
);
578 r
= session_get_string(session
, "VTNR", &vtnr_string
);
582 r
= safe_atou(vtnr_string
, &u
);
590 _public_
int sd_session_get_service(const char *session
, char **service
) {
591 return session_get_string(session
, "SERVICE", service
);
594 _public_
int sd_session_get_type(const char *session
, char **type
) {
595 return session_get_string(session
, "TYPE", type
);
598 _public_
int sd_session_get_class(const char *session
, char **class) {
599 return session_get_string(session
, "CLASS", class);
602 _public_
int sd_session_get_desktop(const char *session
, char **desktop
) {
603 _cleanup_free_
char *escaped
= NULL
;
607 assert_return(desktop
, -EINVAL
);
609 r
= session_get_string(session
, "DESKTOP", &escaped
);
613 r
= cunescape(escaped
, 0, &t
);
621 _public_
int sd_session_get_display(const char *session
, char **display
) {
622 return session_get_string(session
, "DISPLAY", display
);
625 _public_
int sd_session_get_remote_user(const char *session
, char **remote_user
) {
626 return session_get_string(session
, "REMOTE_USER", remote_user
);
629 _public_
int sd_session_get_remote_host(const char *session
, char **remote_host
) {
630 return session_get_string(session
, "REMOTE_HOST", remote_host
);
633 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
634 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
637 assert_return(session
|| uid
, -EINVAL
);
639 r
= file_of_seat(seat
, &p
);
643 r
= parse_env_file(p
, NEWLINE
,
659 r
= parse_uid(t
, uid
);
672 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
673 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
674 _cleanup_strv_free_
char **a
= NULL
;
675 _cleanup_free_ uid_t
*b
= NULL
;
679 r
= file_of_seat(seat
, &p
);
683 r
= parse_env_file(p
, NEWLINE
,
685 "ACTIVE_SESSIONS", &t
,
693 a
= strv_split(s
, " ");
699 const char *word
, *state
;
702 FOREACH_WORD(word
, l
, t
, state
)
712 FOREACH_WORD(word
, l
, t
, state
) {
713 _cleanup_free_
char *k
= NULL
;
715 k
= strndup(word
, l
);
719 r
= parse_uid(k
, b
+ i
);
746 static int seat_get_can(const char *seat
, const char *variable
) {
747 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
752 r
= file_of_seat(seat
, &p
);
756 r
= parse_env_file(p
, NEWLINE
,
766 return parse_boolean(s
);
769 _public_
int sd_seat_can_multi_session(const char *seat
) {
770 return seat_get_can(seat
, "CAN_MULTI_SESSION");
773 _public_
int sd_seat_can_tty(const char *seat
) {
774 return seat_get_can(seat
, "CAN_TTY");
777 _public_
int sd_seat_can_graphical(const char *seat
) {
778 return seat_get_can(seat
, "CAN_GRAPHICAL");
781 _public_
int sd_get_seats(char ***seats
) {
782 return get_files_in_directory("/run/systemd/seats/", seats
);
785 _public_
int sd_get_sessions(char ***sessions
) {
786 return get_files_in_directory("/run/systemd/sessions/", sessions
);
789 _public_
int sd_get_uids(uid_t
**users
) {
790 _cleanup_closedir_
DIR *d
;
793 _cleanup_free_ uid_t
*l
= NULL
;
795 d
= opendir("/run/systemd/users/");
806 if (!de
&& errno
!= 0)
812 dirent_ensure_type(d
, de
);
814 if (!dirent_is_file(de
))
817 k
= parse_uid(de
->d_name
, &uid
);
822 if ((unsigned) r
>= n
) {
826 t
= realloc(l
, sizeof(uid_t
) * n
);
833 assert((unsigned) r
< n
);
847 _public_
int sd_get_machine_names(char ***machines
) {
848 char **l
= NULL
, **a
, **b
;
851 assert_return(machines
, -EINVAL
);
853 r
= get_files_in_directory("/run/systemd/machines/", &l
);
860 /* Filter out the unit: symlinks */
861 for (a
= l
, b
= l
; *a
; a
++) {
862 if (startswith(*a
, "unit:") || !machine_name_is_valid(*a
))
878 _public_
int sd_machine_get_class(const char *machine
, char **class) {
879 _cleanup_free_
char *c
= NULL
;
883 assert_return(machine_name_is_valid(machine
), -EINVAL
);
884 assert_return(class, -EINVAL
);
886 p
= strjoina("/run/systemd/machines/", machine
);
887 r
= parse_env_file(p
, NEWLINE
, "CLASS", &c
, NULL
);
901 _public_
int sd_machine_get_ifindices(const char *machine
, int **ifindices
) {
902 _cleanup_free_
char *netif
= NULL
;
903 size_t l
, allocated
= 0, nr
= 0;
905 const char *p
, *word
, *state
;
908 assert_return(machine_name_is_valid(machine
), -EINVAL
);
909 assert_return(ifindices
, -EINVAL
);
911 p
= strjoina("/run/systemd/machines/", machine
);
912 r
= parse_env_file(p
, NEWLINE
, "NETIF", &netif
, NULL
);
922 FOREACH_WORD(word
, l
, netif
, state
) {
926 *(char*) (mempcpy(buf
, word
, l
)) = 0;
928 if (safe_atoi(buf
, &ifi
) < 0)
933 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
945 static inline int MONITOR_TO_FD(sd_login_monitor
*m
) {
946 return (int) (unsigned long) m
- 1;
949 static inline sd_login_monitor
* FD_TO_MONITOR(int fd
) {
950 return (sd_login_monitor
*) (unsigned long) (fd
+ 1);
953 _public_
int sd_login_monitor_new(const char *category
, sd_login_monitor
**m
) {
957 assert_return(m
, -EINVAL
);
959 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
963 if (!category
|| streq(category
, "seat")) {
964 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
973 if (!category
|| streq(category
, "session")) {
974 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
983 if (!category
|| streq(category
, "uid")) {
984 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
993 if (!category
|| streq(category
, "machine")) {
994 k
= inotify_add_watch(fd
, "/run/systemd/machines/", IN_MOVED_TO
|IN_DELETE
);
1008 *m
= FD_TO_MONITOR(fd
);
1012 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
1015 assert_return(m
, NULL
);
1017 fd
= MONITOR_TO_FD(m
);
1023 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
1025 assert_return(m
, -EINVAL
);
1027 return flush_fd(MONITOR_TO_FD(m
));
1030 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
1032 assert_return(m
, -EINVAL
);
1034 return MONITOR_TO_FD(m
);
1037 _public_
int sd_login_monitor_get_events(sd_login_monitor
*m
) {
1039 assert_return(m
, -EINVAL
);
1041 /* For now we will only return POLLIN here, since we don't
1042 * need anything else ever for inotify. However, let's have
1043 * this API to keep our options open should we later on need
1048 _public_
int sd_login_monitor_get_timeout(sd_login_monitor
*m
, uint64_t *timeout_usec
) {
1050 assert_return(m
, -EINVAL
);
1051 assert_return(timeout_usec
, -EINVAL
);
1053 /* For now we will only return (uint64_t) -1, since we don't
1054 * need any timeout. However, let's have this API to keep our
1055 * options open should we later on need it. */
1056 *timeout_usec
= (uint64_t) -1;