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"
33 #include "formats-util.h"
34 #include "hostname-util.h"
35 #include "login-util.h"
37 #include "string-util.h"
43 * invalid input parameters → -EINVAL
45 * process does not exist → -ESRCH
46 * cgroup does not exist → -ENOENT
47 * machine, session does not exist → -ENXIO
48 * requested metadata on object is missing → -ENODATA
51 _public_
int sd_pid_get_session(pid_t pid
, char **session
) {
53 assert_return(pid
>= 0, -EINVAL
);
54 assert_return(session
, -EINVAL
);
56 return cg_pid_get_session(pid
, session
);
59 _public_
int sd_pid_get_unit(pid_t pid
, char **unit
) {
61 assert_return(pid
>= 0, -EINVAL
);
62 assert_return(unit
, -EINVAL
);
64 return cg_pid_get_unit(pid
, unit
);
67 _public_
int sd_pid_get_user_unit(pid_t pid
, char **unit
) {
69 assert_return(pid
>= 0, -EINVAL
);
70 assert_return(unit
, -EINVAL
);
72 return cg_pid_get_user_unit(pid
, unit
);
75 _public_
int sd_pid_get_machine_name(pid_t pid
, char **name
) {
77 assert_return(pid
>= 0, -EINVAL
);
78 assert_return(name
, -EINVAL
);
80 return cg_pid_get_machine_name(pid
, name
);
83 _public_
int sd_pid_get_slice(pid_t pid
, char **slice
) {
85 assert_return(pid
>= 0, -EINVAL
);
86 assert_return(slice
, -EINVAL
);
88 return cg_pid_get_slice(pid
, slice
);
91 _public_
int sd_pid_get_user_slice(pid_t pid
, char **slice
) {
93 assert_return(pid
>= 0, -EINVAL
);
94 assert_return(slice
, -EINVAL
);
96 return cg_pid_get_user_slice(pid
, slice
);
99 _public_
int sd_pid_get_owner_uid(pid_t pid
, uid_t
*uid
) {
101 assert_return(pid
>= 0, -EINVAL
);
102 assert_return(uid
, -EINVAL
);
104 return cg_pid_get_owner_uid(pid
, uid
);
107 _public_
int sd_pid_get_cgroup(pid_t pid
, char **cgroup
) {
111 assert_return(pid
>= 0, -EINVAL
);
112 assert_return(cgroup
, -EINVAL
);
114 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &c
);
118 /* The internal APIs return the empty string for the root
119 * cgroup, let's return the "/" in the public APIs instead, as
120 * that's easier and less ambigious for people to grok. */
133 _public_
int sd_peer_get_session(int fd
, char **session
) {
134 struct ucred ucred
= {};
137 assert_return(fd
>= 0, -EBADF
);
138 assert_return(session
, -EINVAL
);
140 r
= getpeercred(fd
, &ucred
);
144 return cg_pid_get_session(ucred
.pid
, session
);
147 _public_
int sd_peer_get_owner_uid(int fd
, uid_t
*uid
) {
151 assert_return(fd
>= 0, -EBADF
);
152 assert_return(uid
, -EINVAL
);
154 r
= getpeercred(fd
, &ucred
);
158 return cg_pid_get_owner_uid(ucred
.pid
, uid
);
161 _public_
int sd_peer_get_unit(int fd
, char **unit
) {
165 assert_return(fd
>= 0, -EBADF
);
166 assert_return(unit
, -EINVAL
);
168 r
= getpeercred(fd
, &ucred
);
172 return cg_pid_get_unit(ucred
.pid
, unit
);
175 _public_
int sd_peer_get_user_unit(int fd
, char **unit
) {
179 assert_return(fd
>= 0, -EBADF
);
180 assert_return(unit
, -EINVAL
);
182 r
= getpeercred(fd
, &ucred
);
186 return cg_pid_get_user_unit(ucred
.pid
, unit
);
189 _public_
int sd_peer_get_machine_name(int fd
, char **machine
) {
193 assert_return(fd
>= 0, -EBADF
);
194 assert_return(machine
, -EINVAL
);
196 r
= getpeercred(fd
, &ucred
);
200 return cg_pid_get_machine_name(ucred
.pid
, machine
);
203 _public_
int sd_peer_get_slice(int fd
, char **slice
) {
207 assert_return(fd
>= 0, -EBADF
);
208 assert_return(slice
, -EINVAL
);
210 r
= getpeercred(fd
, &ucred
);
214 return cg_pid_get_slice(ucred
.pid
, slice
);
217 _public_
int sd_peer_get_user_slice(int fd
, char **slice
) {
221 assert_return(fd
>= 0, -EBADF
);
222 assert_return(slice
, -EINVAL
);
224 r
= getpeercred(fd
, &ucred
);
228 return cg_pid_get_user_slice(ucred
.pid
, slice
);
231 _public_
int sd_peer_get_cgroup(int fd
, char **cgroup
) {
235 assert_return(fd
>= 0, -EBADF
);
236 assert_return(cgroup
, -EINVAL
);
238 r
= getpeercred(fd
, &ucred
);
242 return sd_pid_get_cgroup(ucred
.pid
, cgroup
);
245 static int file_of_uid(uid_t uid
, char **p
) {
247 assert_return(uid_is_valid(uid
), -EINVAL
);
250 if (asprintf(p
, "/run/systemd/users/" UID_FMT
, uid
) < 0)
256 _public_
int sd_uid_get_state(uid_t uid
, char**state
) {
257 _cleanup_free_
char *p
= NULL
;
261 assert_return(state
, -EINVAL
);
263 r
= file_of_uid(uid
, &p
);
267 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
270 s
= strdup("offline");
288 _public_
int sd_uid_get_display(uid_t uid
, char **session
) {
289 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
292 assert_return(session
, -EINVAL
);
294 r
= file_of_uid(uid
, &p
);
298 r
= parse_env_file(p
, NEWLINE
, "DISPLAY", &s
, NULL
);
312 static int file_of_seat(const char *seat
, char **_p
) {
319 if (!filename_is_valid(seat
))
322 p
= strappend("/run/systemd/seats/", seat
);
324 _cleanup_free_
char *buf
= NULL
;
326 r
= sd_session_get_seat(NULL
, &buf
);
330 p
= strappend("/run/systemd/seats/", buf
);
341 _public_
int sd_uid_is_on_seat(uid_t uid
, int require_active
, const char *seat
) {
342 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *p
= NULL
;
345 const char *word
, *variable
, *state
;
347 assert_return(uid_is_valid(uid
), -EINVAL
);
349 r
= file_of_seat(seat
, &p
);
353 variable
= require_active
? "ACTIVE_UID" : "UIDS";
355 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
363 if (asprintf(&t
, UID_FMT
, uid
) < 0)
366 FOREACH_WORD(word
, l
, s
, state
)
367 if (strneq(t
, word
, l
))
373 static int uid_get_array(uid_t uid
, const char *variable
, char ***array
) {
374 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
380 r
= file_of_uid(uid
, &p
);
384 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
385 if (r
== -ENOENT
|| (r
>= 0 && isempty(s
))) {
393 a
= strv_split(s
, " ");
408 _public_
int sd_uid_get_sessions(uid_t uid
, int require_active
, char ***sessions
) {
409 return uid_get_array(
411 require_active
== 0 ? "ONLINE_SESSIONS" :
412 require_active
> 0 ? "ACTIVE_SESSIONS" :
417 _public_
int sd_uid_get_seats(uid_t uid
, int require_active
, char ***seats
) {
418 return uid_get_array(
420 require_active
== 0 ? "ONLINE_SEATS" :
421 require_active
> 0 ? "ACTIVE_SEATS" :
426 static int file_of_session(const char *session
, char **_p
) {
433 if (!session_id_valid(session
))
436 p
= strappend("/run/systemd/sessions/", session
);
438 _cleanup_free_
char *buf
= NULL
;
440 r
= sd_pid_get_session(0, &buf
);
444 p
= strappend("/run/systemd/sessions/", buf
);
454 _public_
int sd_session_is_active(const char *session
) {
455 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
458 r
= file_of_session(session
, &p
);
462 r
= parse_env_file(p
, NEWLINE
, "ACTIVE", &s
, NULL
);
470 return parse_boolean(s
);
473 _public_
int sd_session_is_remote(const char *session
) {
474 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
477 r
= file_of_session(session
, &p
);
481 r
= parse_env_file(p
, NEWLINE
, "REMOTE", &s
, NULL
);
489 return parse_boolean(s
);
492 _public_
int sd_session_get_state(const char *session
, char **state
) {
493 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
496 assert_return(state
, -EINVAL
);
498 r
= file_of_session(session
, &p
);
502 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
516 _public_
int sd_session_get_uid(const char *session
, uid_t
*uid
) {
518 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
520 assert_return(uid
, -EINVAL
);
522 r
= file_of_session(session
, &p
);
526 r
= parse_env_file(p
, NEWLINE
, "UID", &s
, NULL
);
534 return parse_uid(s
, uid
);
537 static int session_get_string(const char *session
, const char *field
, char **value
) {
538 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
541 assert_return(value
, -EINVAL
);
544 r
= file_of_session(session
, &p
);
548 r
= parse_env_file(p
, NEWLINE
, field
, &s
, NULL
);
561 _public_
int sd_session_get_seat(const char *session
, char **seat
) {
562 return session_get_string(session
, "SEAT", seat
);
565 _public_
int sd_session_get_tty(const char *session
, char **tty
) {
566 return session_get_string(session
, "TTY", tty
);
569 _public_
int sd_session_get_vt(const char *session
, unsigned *vtnr
) {
570 _cleanup_free_
char *vtnr_string
= NULL
;
574 assert_return(vtnr
, -EINVAL
);
576 r
= session_get_string(session
, "VTNR", &vtnr_string
);
580 r
= safe_atou(vtnr_string
, &u
);
588 _public_
int sd_session_get_service(const char *session
, char **service
) {
589 return session_get_string(session
, "SERVICE", service
);
592 _public_
int sd_session_get_type(const char *session
, char **type
) {
593 return session_get_string(session
, "TYPE", type
);
596 _public_
int sd_session_get_class(const char *session
, char **class) {
597 return session_get_string(session
, "CLASS", class);
600 _public_
int sd_session_get_desktop(const char *session
, char **desktop
) {
601 _cleanup_free_
char *escaped
= NULL
;
605 assert_return(desktop
, -EINVAL
);
607 r
= session_get_string(session
, "DESKTOP", &escaped
);
611 r
= cunescape(escaped
, 0, &t
);
619 _public_
int sd_session_get_display(const char *session
, char **display
) {
620 return session_get_string(session
, "DISPLAY", display
);
623 _public_
int sd_session_get_remote_user(const char *session
, char **remote_user
) {
624 return session_get_string(session
, "REMOTE_USER", remote_user
);
627 _public_
int sd_session_get_remote_host(const char *session
, char **remote_host
) {
628 return session_get_string(session
, "REMOTE_HOST", remote_host
);
631 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
632 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
635 assert_return(session
|| uid
, -EINVAL
);
637 r
= file_of_seat(seat
, &p
);
641 r
= parse_env_file(p
, NEWLINE
,
657 r
= parse_uid(t
, uid
);
670 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
671 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
672 _cleanup_strv_free_
char **a
= NULL
;
673 _cleanup_free_ uid_t
*b
= NULL
;
677 r
= file_of_seat(seat
, &p
);
681 r
= parse_env_file(p
, NEWLINE
,
683 "ACTIVE_SESSIONS", &t
,
691 a
= strv_split(s
, " ");
697 const char *word
, *state
;
700 FOREACH_WORD(word
, l
, t
, state
)
710 FOREACH_WORD(word
, l
, t
, state
) {
711 _cleanup_free_
char *k
= NULL
;
713 k
= strndup(word
, l
);
717 r
= parse_uid(k
, b
+ i
);
744 static int seat_get_can(const char *seat
, const char *variable
) {
745 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
750 r
= file_of_seat(seat
, &p
);
754 r
= parse_env_file(p
, NEWLINE
,
764 return parse_boolean(s
);
767 _public_
int sd_seat_can_multi_session(const char *seat
) {
768 return seat_get_can(seat
, "CAN_MULTI_SESSION");
771 _public_
int sd_seat_can_tty(const char *seat
) {
772 return seat_get_can(seat
, "CAN_TTY");
775 _public_
int sd_seat_can_graphical(const char *seat
) {
776 return seat_get_can(seat
, "CAN_GRAPHICAL");
779 _public_
int sd_get_seats(char ***seats
) {
780 return get_files_in_directory("/run/systemd/seats/", seats
);
783 _public_
int sd_get_sessions(char ***sessions
) {
784 return get_files_in_directory("/run/systemd/sessions/", sessions
);
787 _public_
int sd_get_uids(uid_t
**users
) {
788 _cleanup_closedir_
DIR *d
;
791 _cleanup_free_ uid_t
*l
= NULL
;
793 d
= opendir("/run/systemd/users/");
804 if (!de
&& errno
!= 0)
810 dirent_ensure_type(d
, de
);
812 if (!dirent_is_file(de
))
815 k
= parse_uid(de
->d_name
, &uid
);
820 if ((unsigned) r
>= n
) {
824 t
= realloc(l
, sizeof(uid_t
) * n
);
831 assert((unsigned) r
< n
);
845 _public_
int sd_get_machine_names(char ***machines
) {
846 char **l
= NULL
, **a
, **b
;
849 assert_return(machines
, -EINVAL
);
851 r
= get_files_in_directory("/run/systemd/machines/", &l
);
858 /* Filter out the unit: symlinks */
859 for (a
= l
, b
= l
; *a
; a
++) {
860 if (startswith(*a
, "unit:") || !machine_name_is_valid(*a
))
876 _public_
int sd_machine_get_class(const char *machine
, char **class) {
877 _cleanup_free_
char *c
= NULL
;
881 assert_return(machine_name_is_valid(machine
), -EINVAL
);
882 assert_return(class, -EINVAL
);
884 p
= strjoina("/run/systemd/machines/", machine
);
885 r
= parse_env_file(p
, NEWLINE
, "CLASS", &c
, NULL
);
899 _public_
int sd_machine_get_ifindices(const char *machine
, int **ifindices
) {
900 _cleanup_free_
char *netif
= NULL
;
901 size_t l
, allocated
= 0, nr
= 0;
903 const char *p
, *word
, *state
;
906 assert_return(machine_name_is_valid(machine
), -EINVAL
);
907 assert_return(ifindices
, -EINVAL
);
909 p
= strjoina("/run/systemd/machines/", machine
);
910 r
= parse_env_file(p
, NEWLINE
, "NETIF", &netif
, NULL
);
920 FOREACH_WORD(word
, l
, netif
, state
) {
924 *(char*) (mempcpy(buf
, word
, l
)) = 0;
926 if (safe_atoi(buf
, &ifi
) < 0)
931 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
943 static inline int MONITOR_TO_FD(sd_login_monitor
*m
) {
944 return (int) (unsigned long) m
- 1;
947 static inline sd_login_monitor
* FD_TO_MONITOR(int fd
) {
948 return (sd_login_monitor
*) (unsigned long) (fd
+ 1);
951 _public_
int sd_login_monitor_new(const char *category
, sd_login_monitor
**m
) {
955 assert_return(m
, -EINVAL
);
957 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
961 if (!category
|| streq(category
, "seat")) {
962 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
971 if (!category
|| streq(category
, "session")) {
972 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
981 if (!category
|| streq(category
, "uid")) {
982 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
991 if (!category
|| streq(category
, "machine")) {
992 k
= inotify_add_watch(fd
, "/run/systemd/machines/", IN_MOVED_TO
|IN_DELETE
);
1006 *m
= FD_TO_MONITOR(fd
);
1010 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
1013 assert_return(m
, NULL
);
1015 fd
= MONITOR_TO_FD(m
);
1021 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
1023 assert_return(m
, -EINVAL
);
1025 return flush_fd(MONITOR_TO_FD(m
));
1028 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
1030 assert_return(m
, -EINVAL
);
1032 return MONITOR_TO_FD(m
);
1035 _public_
int sd_login_monitor_get_events(sd_login_monitor
*m
) {
1037 assert_return(m
, -EINVAL
);
1039 /* For now we will only return POLLIN here, since we don't
1040 * need anything else ever for inotify. However, let's have
1041 * this API to keep our options open should we later on need
1046 _public_
int sd_login_monitor_get_timeout(sd_login_monitor
*m
, uint64_t *timeout_usec
) {
1048 assert_return(m
, -EINVAL
);
1049 assert_return(timeout_usec
, -EINVAL
);
1051 /* For now we will only return (uint64_t) -1, since we don't
1052 * need any timeout. However, let's have this API to keep our
1053 * options open should we later on need it. */
1054 *timeout_usec
= (uint64_t) -1;