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"
41 #include "user-util.h"
46 * invalid input parameters → -EINVAL
48 * process does not exist → -ESRCH
49 * cgroup does not exist → -ENOENT
50 * machine, session does not exist → -ENXIO
51 * requested metadata on object is missing → -ENODATA
54 _public_
int sd_pid_get_session(pid_t pid
, char **session
) {
56 assert_return(pid
>= 0, -EINVAL
);
57 assert_return(session
, -EINVAL
);
59 return cg_pid_get_session(pid
, session
);
62 _public_
int sd_pid_get_unit(pid_t pid
, char **unit
) {
64 assert_return(pid
>= 0, -EINVAL
);
65 assert_return(unit
, -EINVAL
);
67 return cg_pid_get_unit(pid
, unit
);
70 _public_
int sd_pid_get_user_unit(pid_t pid
, char **unit
) {
72 assert_return(pid
>= 0, -EINVAL
);
73 assert_return(unit
, -EINVAL
);
75 return cg_pid_get_user_unit(pid
, unit
);
78 _public_
int sd_pid_get_machine_name(pid_t pid
, char **name
) {
80 assert_return(pid
>= 0, -EINVAL
);
81 assert_return(name
, -EINVAL
);
83 return cg_pid_get_machine_name(pid
, name
);
86 _public_
int sd_pid_get_slice(pid_t pid
, char **slice
) {
88 assert_return(pid
>= 0, -EINVAL
);
89 assert_return(slice
, -EINVAL
);
91 return cg_pid_get_slice(pid
, slice
);
94 _public_
int sd_pid_get_user_slice(pid_t pid
, char **slice
) {
96 assert_return(pid
>= 0, -EINVAL
);
97 assert_return(slice
, -EINVAL
);
99 return cg_pid_get_user_slice(pid
, slice
);
102 _public_
int sd_pid_get_owner_uid(pid_t pid
, uid_t
*uid
) {
104 assert_return(pid
>= 0, -EINVAL
);
105 assert_return(uid
, -EINVAL
);
107 return cg_pid_get_owner_uid(pid
, uid
);
110 _public_
int sd_pid_get_cgroup(pid_t pid
, char **cgroup
) {
114 assert_return(pid
>= 0, -EINVAL
);
115 assert_return(cgroup
, -EINVAL
);
117 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &c
);
121 /* The internal APIs return the empty string for the root
122 * cgroup, let's return the "/" in the public APIs instead, as
123 * that's easier and less ambigious for people to grok. */
136 _public_
int sd_peer_get_session(int fd
, char **session
) {
137 struct ucred ucred
= {};
140 assert_return(fd
>= 0, -EBADF
);
141 assert_return(session
, -EINVAL
);
143 r
= getpeercred(fd
, &ucred
);
147 return cg_pid_get_session(ucred
.pid
, session
);
150 _public_
int sd_peer_get_owner_uid(int fd
, uid_t
*uid
) {
154 assert_return(fd
>= 0, -EBADF
);
155 assert_return(uid
, -EINVAL
);
157 r
= getpeercred(fd
, &ucred
);
161 return cg_pid_get_owner_uid(ucred
.pid
, uid
);
164 _public_
int sd_peer_get_unit(int fd
, char **unit
) {
168 assert_return(fd
>= 0, -EBADF
);
169 assert_return(unit
, -EINVAL
);
171 r
= getpeercred(fd
, &ucred
);
175 return cg_pid_get_unit(ucred
.pid
, unit
);
178 _public_
int sd_peer_get_user_unit(int fd
, char **unit
) {
182 assert_return(fd
>= 0, -EBADF
);
183 assert_return(unit
, -EINVAL
);
185 r
= getpeercred(fd
, &ucred
);
189 return cg_pid_get_user_unit(ucred
.pid
, unit
);
192 _public_
int sd_peer_get_machine_name(int fd
, char **machine
) {
196 assert_return(fd
>= 0, -EBADF
);
197 assert_return(machine
, -EINVAL
);
199 r
= getpeercred(fd
, &ucred
);
203 return cg_pid_get_machine_name(ucred
.pid
, machine
);
206 _public_
int sd_peer_get_slice(int fd
, char **slice
) {
210 assert_return(fd
>= 0, -EBADF
);
211 assert_return(slice
, -EINVAL
);
213 r
= getpeercred(fd
, &ucred
);
217 return cg_pid_get_slice(ucred
.pid
, slice
);
220 _public_
int sd_peer_get_user_slice(int fd
, char **slice
) {
224 assert_return(fd
>= 0, -EBADF
);
225 assert_return(slice
, -EINVAL
);
227 r
= getpeercred(fd
, &ucred
);
231 return cg_pid_get_user_slice(ucred
.pid
, slice
);
234 _public_
int sd_peer_get_cgroup(int fd
, char **cgroup
) {
238 assert_return(fd
>= 0, -EBADF
);
239 assert_return(cgroup
, -EINVAL
);
241 r
= getpeercred(fd
, &ucred
);
245 return sd_pid_get_cgroup(ucred
.pid
, cgroup
);
248 static int file_of_uid(uid_t uid
, char **p
) {
250 assert_return(uid_is_valid(uid
), -EINVAL
);
253 if (asprintf(p
, "/run/systemd/users/" UID_FMT
, uid
) < 0)
259 _public_
int sd_uid_get_state(uid_t uid
, char**state
) {
260 _cleanup_free_
char *p
= NULL
;
264 assert_return(state
, -EINVAL
);
266 r
= file_of_uid(uid
, &p
);
270 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
273 s
= strdup("offline");
291 _public_
int sd_uid_get_display(uid_t uid
, char **session
) {
292 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
295 assert_return(session
, -EINVAL
);
297 r
= file_of_uid(uid
, &p
);
301 r
= parse_env_file(p
, NEWLINE
, "DISPLAY", &s
, NULL
);
315 static int file_of_seat(const char *seat
, char **_p
) {
322 if (!filename_is_valid(seat
))
325 p
= strappend("/run/systemd/seats/", seat
);
327 _cleanup_free_
char *buf
= NULL
;
329 r
= sd_session_get_seat(NULL
, &buf
);
333 p
= strappend("/run/systemd/seats/", buf
);
344 _public_
int sd_uid_is_on_seat(uid_t uid
, int require_active
, const char *seat
) {
345 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *p
= NULL
;
348 const char *word
, *variable
, *state
;
350 assert_return(uid_is_valid(uid
), -EINVAL
);
352 r
= file_of_seat(seat
, &p
);
356 variable
= require_active
? "ACTIVE_UID" : "UIDS";
358 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
366 if (asprintf(&t
, UID_FMT
, uid
) < 0)
369 FOREACH_WORD(word
, l
, s
, state
)
370 if (strneq(t
, word
, l
))
376 static int uid_get_array(uid_t uid
, const char *variable
, char ***array
) {
377 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
383 r
= file_of_uid(uid
, &p
);
387 r
= parse_env_file(p
, NEWLINE
, variable
, &s
, NULL
);
388 if (r
== -ENOENT
|| (r
>= 0 && isempty(s
))) {
396 a
= strv_split(s
, " ");
411 _public_
int sd_uid_get_sessions(uid_t uid
, int require_active
, char ***sessions
) {
412 return uid_get_array(
414 require_active
== 0 ? "ONLINE_SESSIONS" :
415 require_active
> 0 ? "ACTIVE_SESSIONS" :
420 _public_
int sd_uid_get_seats(uid_t uid
, int require_active
, char ***seats
) {
421 return uid_get_array(
423 require_active
== 0 ? "ONLINE_SEATS" :
424 require_active
> 0 ? "ACTIVE_SEATS" :
429 static int file_of_session(const char *session
, char **_p
) {
436 if (!session_id_valid(session
))
439 p
= strappend("/run/systemd/sessions/", session
);
441 _cleanup_free_
char *buf
= NULL
;
443 r
= sd_pid_get_session(0, &buf
);
447 p
= strappend("/run/systemd/sessions/", buf
);
457 _public_
int sd_session_is_active(const char *session
) {
458 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
461 r
= file_of_session(session
, &p
);
465 r
= parse_env_file(p
, NEWLINE
, "ACTIVE", &s
, NULL
);
473 return parse_boolean(s
);
476 _public_
int sd_session_is_remote(const char *session
) {
477 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
480 r
= file_of_session(session
, &p
);
484 r
= parse_env_file(p
, NEWLINE
, "REMOTE", &s
, NULL
);
492 return parse_boolean(s
);
495 _public_
int sd_session_get_state(const char *session
, char **state
) {
496 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
499 assert_return(state
, -EINVAL
);
501 r
= file_of_session(session
, &p
);
505 r
= parse_env_file(p
, NEWLINE
, "STATE", &s
, NULL
);
519 _public_
int sd_session_get_uid(const char *session
, uid_t
*uid
) {
521 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
523 assert_return(uid
, -EINVAL
);
525 r
= file_of_session(session
, &p
);
529 r
= parse_env_file(p
, NEWLINE
, "UID", &s
, NULL
);
537 return parse_uid(s
, uid
);
540 static int session_get_string(const char *session
, const char *field
, char **value
) {
541 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
544 assert_return(value
, -EINVAL
);
547 r
= file_of_session(session
, &p
);
551 r
= parse_env_file(p
, NEWLINE
, field
, &s
, NULL
);
564 _public_
int sd_session_get_seat(const char *session
, char **seat
) {
565 return session_get_string(session
, "SEAT", seat
);
568 _public_
int sd_session_get_tty(const char *session
, char **tty
) {
569 return session_get_string(session
, "TTY", tty
);
572 _public_
int sd_session_get_vt(const char *session
, unsigned *vtnr
) {
573 _cleanup_free_
char *vtnr_string
= NULL
;
577 assert_return(vtnr
, -EINVAL
);
579 r
= session_get_string(session
, "VTNR", &vtnr_string
);
583 r
= safe_atou(vtnr_string
, &u
);
591 _public_
int sd_session_get_service(const char *session
, char **service
) {
592 return session_get_string(session
, "SERVICE", service
);
595 _public_
int sd_session_get_type(const char *session
, char **type
) {
596 return session_get_string(session
, "TYPE", type
);
599 _public_
int sd_session_get_class(const char *session
, char **class) {
600 return session_get_string(session
, "CLASS", class);
603 _public_
int sd_session_get_desktop(const char *session
, char **desktop
) {
604 _cleanup_free_
char *escaped
= NULL
;
608 assert_return(desktop
, -EINVAL
);
610 r
= session_get_string(session
, "DESKTOP", &escaped
);
614 r
= cunescape(escaped
, 0, &t
);
622 _public_
int sd_session_get_display(const char *session
, char **display
) {
623 return session_get_string(session
, "DISPLAY", display
);
626 _public_
int sd_session_get_remote_user(const char *session
, char **remote_user
) {
627 return session_get_string(session
, "REMOTE_USER", remote_user
);
630 _public_
int sd_session_get_remote_host(const char *session
, char **remote_host
) {
631 return session_get_string(session
, "REMOTE_HOST", remote_host
);
634 _public_
int sd_seat_get_active(const char *seat
, char **session
, uid_t
*uid
) {
635 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
638 assert_return(session
|| uid
, -EINVAL
);
640 r
= file_of_seat(seat
, &p
);
644 r
= parse_env_file(p
, NEWLINE
,
660 r
= parse_uid(t
, uid
);
673 _public_
int sd_seat_get_sessions(const char *seat
, char ***sessions
, uid_t
**uids
, unsigned *n_uids
) {
674 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
675 _cleanup_strv_free_
char **a
= NULL
;
676 _cleanup_free_ uid_t
*b
= NULL
;
680 r
= file_of_seat(seat
, &p
);
684 r
= parse_env_file(p
, NEWLINE
,
686 "ACTIVE_SESSIONS", &t
,
694 a
= strv_split(s
, " ");
700 const char *word
, *state
;
703 FOREACH_WORD(word
, l
, t
, state
)
713 FOREACH_WORD(word
, l
, t
, state
) {
714 _cleanup_free_
char *k
= NULL
;
716 k
= strndup(word
, l
);
720 r
= parse_uid(k
, b
+ i
);
747 static int seat_get_can(const char *seat
, const char *variable
) {
748 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
753 r
= file_of_seat(seat
, &p
);
757 r
= parse_env_file(p
, NEWLINE
,
767 return parse_boolean(s
);
770 _public_
int sd_seat_can_multi_session(const char *seat
) {
771 return seat_get_can(seat
, "CAN_MULTI_SESSION");
774 _public_
int sd_seat_can_tty(const char *seat
) {
775 return seat_get_can(seat
, "CAN_TTY");
778 _public_
int sd_seat_can_graphical(const char *seat
) {
779 return seat_get_can(seat
, "CAN_GRAPHICAL");
782 _public_
int sd_get_seats(char ***seats
) {
783 return get_files_in_directory("/run/systemd/seats/", seats
);
786 _public_
int sd_get_sessions(char ***sessions
) {
787 return get_files_in_directory("/run/systemd/sessions/", sessions
);
790 _public_
int sd_get_uids(uid_t
**users
) {
791 _cleanup_closedir_
DIR *d
;
794 _cleanup_free_ uid_t
*l
= NULL
;
796 d
= opendir("/run/systemd/users/");
807 if (!de
&& errno
!= 0)
813 dirent_ensure_type(d
, de
);
815 if (!dirent_is_file(de
))
818 k
= parse_uid(de
->d_name
, &uid
);
823 if ((unsigned) r
>= n
) {
827 t
= realloc(l
, sizeof(uid_t
) * n
);
834 assert((unsigned) r
< n
);
848 _public_
int sd_get_machine_names(char ***machines
) {
849 char **l
= NULL
, **a
, **b
;
852 assert_return(machines
, -EINVAL
);
854 r
= get_files_in_directory("/run/systemd/machines/", &l
);
861 /* Filter out the unit: symlinks */
862 for (a
= l
, b
= l
; *a
; a
++) {
863 if (startswith(*a
, "unit:") || !machine_name_is_valid(*a
))
879 _public_
int sd_machine_get_class(const char *machine
, char **class) {
880 _cleanup_free_
char *c
= NULL
;
884 assert_return(machine_name_is_valid(machine
), -EINVAL
);
885 assert_return(class, -EINVAL
);
887 p
= strjoina("/run/systemd/machines/", machine
);
888 r
= parse_env_file(p
, NEWLINE
, "CLASS", &c
, NULL
);
902 _public_
int sd_machine_get_ifindices(const char *machine
, int **ifindices
) {
903 _cleanup_free_
char *netif
= NULL
;
904 size_t l
, allocated
= 0, nr
= 0;
906 const char *p
, *word
, *state
;
909 assert_return(machine_name_is_valid(machine
), -EINVAL
);
910 assert_return(ifindices
, -EINVAL
);
912 p
= strjoina("/run/systemd/machines/", machine
);
913 r
= parse_env_file(p
, NEWLINE
, "NETIF", &netif
, NULL
);
923 FOREACH_WORD(word
, l
, netif
, state
) {
927 *(char*) (mempcpy(buf
, word
, l
)) = 0;
929 if (safe_atoi(buf
, &ifi
) < 0)
934 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
946 static inline int MONITOR_TO_FD(sd_login_monitor
*m
) {
947 return (int) (unsigned long) m
- 1;
950 static inline sd_login_monitor
* FD_TO_MONITOR(int fd
) {
951 return (sd_login_monitor
*) (unsigned long) (fd
+ 1);
954 _public_
int sd_login_monitor_new(const char *category
, sd_login_monitor
**m
) {
958 assert_return(m
, -EINVAL
);
960 fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
964 if (!category
|| streq(category
, "seat")) {
965 k
= inotify_add_watch(fd
, "/run/systemd/seats/", IN_MOVED_TO
|IN_DELETE
);
974 if (!category
|| streq(category
, "session")) {
975 k
= inotify_add_watch(fd
, "/run/systemd/sessions/", IN_MOVED_TO
|IN_DELETE
);
984 if (!category
|| streq(category
, "uid")) {
985 k
= inotify_add_watch(fd
, "/run/systemd/users/", IN_MOVED_TO
|IN_DELETE
);
994 if (!category
|| streq(category
, "machine")) {
995 k
= inotify_add_watch(fd
, "/run/systemd/machines/", IN_MOVED_TO
|IN_DELETE
);
1009 *m
= FD_TO_MONITOR(fd
);
1013 _public_ sd_login_monitor
* sd_login_monitor_unref(sd_login_monitor
*m
) {
1016 assert_return(m
, NULL
);
1018 fd
= MONITOR_TO_FD(m
);
1024 _public_
int sd_login_monitor_flush(sd_login_monitor
*m
) {
1026 assert_return(m
, -EINVAL
);
1028 return flush_fd(MONITOR_TO_FD(m
));
1031 _public_
int sd_login_monitor_get_fd(sd_login_monitor
*m
) {
1033 assert_return(m
, -EINVAL
);
1035 return MONITOR_TO_FD(m
);
1038 _public_
int sd_login_monitor_get_events(sd_login_monitor
*m
) {
1040 assert_return(m
, -EINVAL
);
1042 /* For now we will only return POLLIN here, since we don't
1043 * need anything else ever for inotify. However, let's have
1044 * this API to keep our options open should we later on need
1049 _public_
int sd_login_monitor_get_timeout(sd_login_monitor
*m
, uint64_t *timeout_usec
) {
1051 assert_return(m
, -EINVAL
);
1052 assert_return(timeout_usec
, -EINVAL
);
1054 /* For now we will only return (uint64_t) -1, since we don't
1055 * need any timeout. However, let's have this API to keep our
1056 * options open should we later on need it. */
1057 *timeout_usec
= (uint64_t) -1;