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 "path-util.h"
41 #include "socket-util.h"
42 #include "string-util.h"
44 #include "user-util.h"
46 #include "dirent-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 ambigious 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 (safe_atoi(buf
, &ifi
) < 0)
938 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
950 static inline int MONITOR_TO_FD(sd_login_monitor
*m
) {
951 return (int) (unsigned long) m
- 1;
954 static inline sd_login_monitor
* FD_TO_MONITOR(int fd
) {
955 return (sd_login_monitor
*) (unsigned long) (fd
+ 1);
958 _public_
int sd_login_monitor_new(const char *category
, sd_login_monitor
**m
) {
962 assert_return(m
, -EINVAL
);
964 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
968 if (!category
|| streq(category
, "seat")) {
969 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
978 if (!category
|| streq(category
, "session")) {
979 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
988 if (!category
|| streq(category
, "uid")) {
989 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
998 if (!category
|| streq(category
, "machine")) {
999 k
= inotify_add_watch(fd
, "/run/systemd/machines/", IN_MOVED_TO
|IN_DELETE
);
1013 *m
= FD_TO_MONITOR(fd
);
1017 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
1020 assert_return(m
, NULL
);
1022 fd
= MONITOR_TO_FD(m
);
1028 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
1030 assert_return(m
, -EINVAL
);
1032 return flush_fd(MONITOR_TO_FD(m
));
1035 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
1037 assert_return(m
, -EINVAL
);
1039 return MONITOR_TO_FD(m
);
1042 _public_
int sd_login_monitor_get_events(sd_login_monitor
*m
) {
1044 assert_return(m
, -EINVAL
);
1046 /* For now we will only return POLLIN here, since we don't
1047 * need anything else ever for inotify. However, let's have
1048 * this API to keep our options open should we later on need
1053 _public_
int sd_login_monitor_get_timeout(sd_login_monitor
*m
, uint64_t *timeout_usec
) {
1055 assert_return(m
, -EINVAL
);
1056 assert_return(timeout_usec
, -EINVAL
);
1058 /* For now we will only return (uint64_t) -1, since we don't
1059 * need any timeout. However, let's have this API to keep our
1060 * options open should we later on need it. */
1061 *timeout_usec
= (uint64_t) -1;