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 "formats-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
) {
60 assert_return(pid
>= 0, -EINVAL
);
61 assert_return(session
, -EINVAL
);
63 return cg_pid_get_session(pid
, session
);
66 _public_
int sd_pid_get_unit(pid_t pid
, char **unit
) {
68 assert_return(pid
>= 0, -EINVAL
);
69 assert_return(unit
, -EINVAL
);
71 return cg_pid_get_unit(pid
, unit
);
74 _public_
int sd_pid_get_user_unit(pid_t pid
, char **unit
) {
76 assert_return(pid
>= 0, -EINVAL
);
77 assert_return(unit
, -EINVAL
);
79 return cg_pid_get_user_unit(pid
, unit
);
82 _public_
int sd_pid_get_machine_name(pid_t pid
, char **name
) {
84 assert_return(pid
>= 0, -EINVAL
);
85 assert_return(name
, -EINVAL
);
87 return cg_pid_get_machine_name(pid
, name
);
90 _public_
int sd_pid_get_slice(pid_t pid
, char **slice
) {
92 assert_return(pid
>= 0, -EINVAL
);
93 assert_return(slice
, -EINVAL
);
95 return cg_pid_get_slice(pid
, slice
);
98 _public_
int sd_pid_get_user_slice(pid_t pid
, char **slice
) {
100 assert_return(pid
>= 0, -EINVAL
);
101 assert_return(slice
, -EINVAL
);
103 return cg_pid_get_user_slice(pid
, slice
);
106 _public_
int sd_pid_get_owner_uid(pid_t pid
, uid_t
*uid
) {
108 assert_return(pid
>= 0, -EINVAL
);
109 assert_return(uid
, -EINVAL
);
111 return cg_pid_get_owner_uid(pid
, uid
);
114 _public_
int sd_pid_get_cgroup(pid_t pid
, char **cgroup
) {
118 assert_return(pid
>= 0, -EINVAL
);
119 assert_return(cgroup
, -EINVAL
);
121 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &c
);
125 /* The internal APIs return the empty string for the root
126 * cgroup, let's return the "/" in the public APIs instead, as
127 * that's easier and less ambiguous for people to grok. */
140 _public_
int sd_peer_get_session(int fd
, char **session
) {
141 struct ucred ucred
= {};
144 assert_return(fd
>= 0, -EBADF
);
145 assert_return(session
, -EINVAL
);
147 r
= getpeercred(fd
, &ucred
);
151 return cg_pid_get_session(ucred
.pid
, session
);
154 _public_
int sd_peer_get_owner_uid(int fd
, uid_t
*uid
) {
158 assert_return(fd
>= 0, -EBADF
);
159 assert_return(uid
, -EINVAL
);
161 r
= getpeercred(fd
, &ucred
);
165 return cg_pid_get_owner_uid(ucred
.pid
, uid
);
168 _public_
int sd_peer_get_unit(int fd
, char **unit
) {
172 assert_return(fd
>= 0, -EBADF
);
173 assert_return(unit
, -EINVAL
);
175 r
= getpeercred(fd
, &ucred
);
179 return cg_pid_get_unit(ucred
.pid
, unit
);
182 _public_
int sd_peer_get_user_unit(int fd
, char **unit
) {
186 assert_return(fd
>= 0, -EBADF
);
187 assert_return(unit
, -EINVAL
);
189 r
= getpeercred(fd
, &ucred
);
193 return cg_pid_get_user_unit(ucred
.pid
, unit
);
196 _public_
int sd_peer_get_machine_name(int fd
, char **machine
) {
200 assert_return(fd
>= 0, -EBADF
);
201 assert_return(machine
, -EINVAL
);
203 r
= getpeercred(fd
, &ucred
);
207 return cg_pid_get_machine_name(ucred
.pid
, machine
);
210 _public_
int sd_peer_get_slice(int fd
, char **slice
) {
214 assert_return(fd
>= 0, -EBADF
);
215 assert_return(slice
, -EINVAL
);
217 r
= getpeercred(fd
, &ucred
);
221 return cg_pid_get_slice(ucred
.pid
, slice
);
224 _public_
int sd_peer_get_user_slice(int fd
, char **slice
) {
228 assert_return(fd
>= 0, -EBADF
);
229 assert_return(slice
, -EINVAL
);
231 r
= getpeercred(fd
, &ucred
);
235 return cg_pid_get_user_slice(ucred
.pid
, slice
);
238 _public_
int sd_peer_get_cgroup(int fd
, char **cgroup
) {
242 assert_return(fd
>= 0, -EBADF
);
243 assert_return(cgroup
, -EINVAL
);
245 r
= getpeercred(fd
, &ucred
);
249 return sd_pid_get_cgroup(ucred
.pid
, cgroup
);
252 static int file_of_uid(uid_t uid
, char **p
) {
254 assert_return(uid_is_valid(uid
), -EINVAL
);
257 if (asprintf(p
, "/run/systemd/users/" UID_FMT
, uid
) < 0)
263 _public_
int sd_uid_get_state(uid_t uid
, char**state
) {
264 _cleanup_free_
char *p
= NULL
;
268 assert_return(state
, -EINVAL
);
270 r
= file_of_uid(uid
, &p
);
274 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
277 s
= strdup("offline");
295 _public_
int sd_uid_get_display(uid_t uid
, char **session
) {
296 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
299 assert_return(session
, -EINVAL
);
301 r
= file_of_uid(uid
, &p
);
305 r
= parse_env_file(p
, NEWLINE
, "DISPLAY", &s
, NULL
);
319 static int file_of_seat(const char *seat
, char **_p
) {
326 if (!filename_is_valid(seat
))
329 p
= strappend("/run/systemd/seats/", seat
);
331 _cleanup_free_
char *buf
= NULL
;
333 r
= sd_session_get_seat(NULL
, &buf
);
337 p
= strappend("/run/systemd/seats/", buf
);
348 _public_
int sd_uid_is_on_seat(uid_t uid
, int require_active
, const char *seat
) {
349 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *p
= NULL
;
352 const char *word
, *variable
, *state
;
354 assert_return(uid_is_valid(uid
), -EINVAL
);
356 r
= file_of_seat(seat
, &p
);
360 variable
= require_active
? "ACTIVE_UID" : "UIDS";
362 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
370 if (asprintf(&t
, UID_FMT
, uid
) < 0)
373 FOREACH_WORD(word
, l
, s
, state
)
374 if (strneq(t
, word
, l
))
380 static int uid_get_array(uid_t uid
, const char *variable
, char ***array
) {
381 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
387 r
= file_of_uid(uid
, &p
);
391 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
392 if (r
== -ENOENT
|| (r
>= 0 && isempty(s
))) {
400 a
= strv_split(s
, " ");
415 _public_
int sd_uid_get_sessions(uid_t uid
, int require_active
, char ***sessions
) {
416 return uid_get_array(
418 require_active
== 0 ? "ONLINE_SESSIONS" :
419 require_active
> 0 ? "ACTIVE_SESSIONS" :
424 _public_
int sd_uid_get_seats(uid_t uid
, int require_active
, char ***seats
) {
425 return uid_get_array(
427 require_active
== 0 ? "ONLINE_SEATS" :
428 require_active
> 0 ? "ACTIVE_SEATS" :
433 static int file_of_session(const char *session
, char **_p
) {
440 if (!session_id_valid(session
))
443 p
= strappend("/run/systemd/sessions/", session
);
445 _cleanup_free_
char *buf
= NULL
;
447 r
= sd_pid_get_session(0, &buf
);
451 p
= strappend("/run/systemd/sessions/", buf
);
461 _public_
int sd_session_is_active(const char *session
) {
462 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
465 r
= file_of_session(session
, &p
);
469 r
= parse_env_file(p
, NEWLINE
, "ACTIVE", &s
, NULL
);
477 return parse_boolean(s
);
480 _public_
int sd_session_is_remote(const char *session
) {
481 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
484 r
= file_of_session(session
, &p
);
488 r
= parse_env_file(p
, NEWLINE
, "REMOTE", &s
, NULL
);
496 return parse_boolean(s
);
499 _public_
int sd_session_get_state(const char *session
, char **state
) {
500 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
503 assert_return(state
, -EINVAL
);
505 r
= file_of_session(session
, &p
);
509 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
523 _public_
int sd_session_get_uid(const char *session
, uid_t
*uid
) {
525 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
527 assert_return(uid
, -EINVAL
);
529 r
= file_of_session(session
, &p
);
533 r
= parse_env_file(p
, NEWLINE
, "UID", &s
, NULL
);
541 return parse_uid(s
, uid
);
544 static int session_get_string(const char *session
, const char *field
, char **value
) {
545 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
548 assert_return(value
, -EINVAL
);
551 r
= file_of_session(session
, &p
);
555 r
= parse_env_file(p
, NEWLINE
, field
, &s
, NULL
);
568 _public_
int sd_session_get_seat(const char *session
, char **seat
) {
569 return session_get_string(session
, "SEAT", seat
);
572 _public_
int sd_session_get_tty(const char *session
, char **tty
) {
573 return session_get_string(session
, "TTY", tty
);
576 _public_
int sd_session_get_vt(const char *session
, unsigned *vtnr
) {
577 _cleanup_free_
char *vtnr_string
= NULL
;
581 assert_return(vtnr
, -EINVAL
);
583 r
= session_get_string(session
, "VTNR", &vtnr_string
);
587 r
= safe_atou(vtnr_string
, &u
);
595 _public_
int sd_session_get_service(const char *session
, char **service
) {
596 return session_get_string(session
, "SERVICE", service
);
599 _public_
int sd_session_get_type(const char *session
, char **type
) {
600 return session_get_string(session
, "TYPE", type
);
603 _public_
int sd_session_get_class(const char *session
, char **class) {
604 return session_get_string(session
, "CLASS", class);
607 _public_
int sd_session_get_desktop(const char *session
, char **desktop
) {
608 _cleanup_free_
char *escaped
= NULL
;
612 assert_return(desktop
, -EINVAL
);
614 r
= session_get_string(session
, "DESKTOP", &escaped
);
618 r
= cunescape(escaped
, 0, &t
);
626 _public_
int sd_session_get_display(const char *session
, char **display
) {
627 return session_get_string(session
, "DISPLAY", display
);
630 _public_
int sd_session_get_remote_user(const char *session
, char **remote_user
) {
631 return session_get_string(session
, "REMOTE_USER", remote_user
);
634 _public_
int sd_session_get_remote_host(const char *session
, char **remote_host
) {
635 return session_get_string(session
, "REMOTE_HOST", remote_host
);
638 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
639 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
642 assert_return(session
|| uid
, -EINVAL
);
644 r
= file_of_seat(seat
, &p
);
648 r
= parse_env_file(p
, NEWLINE
,
664 r
= parse_uid(t
, uid
);
677 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
678 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
679 _cleanup_strv_free_
char **a
= NULL
;
680 _cleanup_free_ uid_t
*b
= NULL
;
684 r
= file_of_seat(seat
, &p
);
688 r
= parse_env_file(p
, NEWLINE
,
690 "ACTIVE_SESSIONS", &t
,
698 a
= strv_split(s
, " ");
704 const char *word
, *state
;
707 FOREACH_WORD(word
, l
, t
, state
)
717 FOREACH_WORD(word
, l
, t
, state
) {
718 _cleanup_free_
char *k
= NULL
;
720 k
= strndup(word
, l
);
724 r
= parse_uid(k
, b
+ i
);
751 static int seat_get_can(const char *seat
, const char *variable
) {
752 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
757 r
= file_of_seat(seat
, &p
);
761 r
= parse_env_file(p
, NEWLINE
,
771 return parse_boolean(s
);
774 _public_
int sd_seat_can_multi_session(const char *seat
) {
775 return seat_get_can(seat
, "CAN_MULTI_SESSION");
778 _public_
int sd_seat_can_tty(const char *seat
) {
779 return seat_get_can(seat
, "CAN_TTY");
782 _public_
int sd_seat_can_graphical(const char *seat
) {
783 return seat_get_can(seat
, "CAN_GRAPHICAL");
786 _public_
int sd_get_seats(char ***seats
) {
787 return get_files_in_directory("/run/systemd/seats/", seats
);
790 _public_
int sd_get_sessions(char ***sessions
) {
791 return get_files_in_directory("/run/systemd/sessions/", sessions
);
794 _public_
int sd_get_uids(uid_t
**users
) {
795 _cleanup_closedir_
DIR *d
;
798 _cleanup_free_ uid_t
*l
= NULL
;
800 d
= opendir("/run/systemd/users/");
811 if (!de
&& errno
> 0)
817 dirent_ensure_type(d
, de
);
819 if (!dirent_is_file(de
))
822 k
= parse_uid(de
->d_name
, &uid
);
827 if ((unsigned) r
>= n
) {
831 t
= realloc(l
, sizeof(uid_t
) * n
);
838 assert((unsigned) r
< n
);
852 _public_
int sd_get_machine_names(char ***machines
) {
853 char **l
= NULL
, **a
, **b
;
856 assert_return(machines
, -EINVAL
);
858 r
= get_files_in_directory("/run/systemd/machines/", &l
);
865 /* Filter out the unit: symlinks */
866 for (a
= l
, b
= l
; *a
; a
++) {
867 if (startswith(*a
, "unit:") || !machine_name_is_valid(*a
))
883 _public_
int sd_machine_get_class(const char *machine
, char **class) {
884 _cleanup_free_
char *c
= NULL
;
888 assert_return(machine_name_is_valid(machine
), -EINVAL
);
889 assert_return(class, -EINVAL
);
891 p
= strjoina("/run/systemd/machines/", machine
);
892 r
= parse_env_file(p
, NEWLINE
, "CLASS", &c
, NULL
);
906 _public_
int sd_machine_get_ifindices(const char *machine
, int **ifindices
) {
907 _cleanup_free_
char *netif
= NULL
;
908 size_t l
, allocated
= 0, nr
= 0;
910 const char *p
, *word
, *state
;
913 assert_return(machine_name_is_valid(machine
), -EINVAL
);
914 assert_return(ifindices
, -EINVAL
);
916 p
= strjoina("/run/systemd/machines/", machine
);
917 r
= parse_env_file(p
, NEWLINE
, "NETIF", &netif
, NULL
);
927 FOREACH_WORD(word
, l
, netif
, state
) {
931 *(char*) (mempcpy(buf
, word
, l
)) = 0;
933 if (parse_ifindex(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
) {
1021 fd
= MONITOR_TO_FD(m
);
1027 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
1029 assert_return(m
, -EINVAL
);
1031 return flush_fd(MONITOR_TO_FD(m
));
1034 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
1036 assert_return(m
, -EINVAL
);
1038 return MONITOR_TO_FD(m
);
1041 _public_
int sd_login_monitor_get_events(sd_login_monitor
*m
) {
1043 assert_return(m
, -EINVAL
);
1045 /* For now we will only return POLLIN here, since we don't
1046 * need anything else ever for inotify. However, let's have
1047 * this API to keep our options open should we later on need
1052 _public_
int sd_login_monitor_get_timeout(sd_login_monitor
*m
, uint64_t *timeout_usec
) {
1054 assert_return(m
, -EINVAL
);
1055 assert_return(timeout_usec
, -EINVAL
);
1057 /* For now we will only return (uint64_t) -1, since we don't
1058 * need any timeout. However, let's have this API to keep our
1059 * options open should we later on need it. */
1060 *timeout_usec
= (uint64_t) -1;