udev: String substitutions can be done in ENV, too
[systemd_ALT.git] / src / libsystemd / sd-login / sd-login.c
blobf9e86c6608e3d37af6d321d9c8e28df0d68ece2a
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <errno.h>
4 #include <poll.h>
5 #include <sys/inotify.h>
6 #include <unistd.h>
8 #include "sd-login.h"
10 #include "alloc-util.h"
11 #include "cgroup-util.h"
12 #include "dirent-util.h"
13 #include "env-file.h"
14 #include "escape.h"
15 #include "extract-word.h"
16 #include "fd-util.h"
17 #include "format-util.h"
18 #include "fs-util.h"
19 #include "hostname-util.h"
20 #include "io-util.h"
21 #include "login-util.h"
22 #include "macro.h"
23 #include "parse-util.h"
24 #include "path-util.h"
25 #include "process-util.h"
26 #include "socket-util.h"
27 #include "stdio-util.h"
28 #include "string-util.h"
29 #include "strv.h"
30 #include "user-util.h"
32 /* Error codes:
34 * invalid input parameters → -EINVAL
35 * invalid fd → -EBADF
36 * process does not exist → -ESRCH
37 * cgroup does not exist → -ENOENT
38 * machine, session does not exist → -ENXIO
39 * requested metadata on object is missing → -ENODATA
42 _public_ int sd_pid_get_session(pid_t pid, char **session) {
43 int r;
45 assert_return(pid >= 0, -EINVAL);
46 assert_return(session, -EINVAL);
48 r = cg_pid_get_session(pid, session);
49 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
52 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
53 int r;
55 assert_return(pid >= 0, -EINVAL);
56 assert_return(unit, -EINVAL);
58 r = cg_pid_get_unit(pid, unit);
59 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
62 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
63 int r;
65 assert_return(pid >= 0, -EINVAL);
66 assert_return(unit, -EINVAL);
68 r = cg_pid_get_user_unit(pid, unit);
69 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
72 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
73 int r;
75 assert_return(pid >= 0, -EINVAL);
76 assert_return(name, -EINVAL);
78 r = cg_pid_get_machine_name(pid, name);
79 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
82 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
83 int r;
85 assert_return(pid >= 0, -EINVAL);
86 assert_return(slice, -EINVAL);
88 r = cg_pid_get_slice(pid, slice);
89 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
92 _public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
93 int r;
95 assert_return(pid >= 0, -EINVAL);
96 assert_return(slice, -EINVAL);
98 r = cg_pid_get_user_slice(pid, slice);
99 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
102 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
103 int r;
105 assert_return(pid >= 0, -EINVAL);
106 assert_return(uid, -EINVAL);
108 r = cg_pid_get_owner_uid(pid, uid);
109 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
112 _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
113 char *c;
114 int r;
116 assert_return(pid >= 0, -EINVAL);
117 assert_return(cgroup, -EINVAL);
119 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c);
120 if (r < 0)
121 return r;
123 /* The internal APIs return the empty string for the root
124 * cgroup, let's return the "/" in the public APIs instead, as
125 * that's easier and less ambiguous for people to grok. */
126 if (isempty(c)) {
127 r = free_and_strdup(&c, "/");
128 if (r < 0)
129 return r;
133 *cgroup = c;
134 return 0;
137 _public_ int sd_pidfd_get_session(int pidfd, char **ret_session) {
138 _cleanup_free_ char *session = NULL;
139 pid_t pid;
140 int r;
142 assert_return(pidfd >= 0, -EBADF);
143 assert_return(ret_session, -EINVAL);
145 r = pidfd_get_pid(pidfd, &pid);
146 if (r < 0)
147 return r;
149 r = sd_pid_get_session(pid, &session);
150 if (r < 0)
151 return r;
153 r = pidfd_verify_pid(pidfd, pid);
154 if (r < 0)
155 return r;
157 *ret_session = TAKE_PTR(session);
159 return 0;
162 _public_ int sd_pidfd_get_unit(int pidfd, char **ret_unit) {
163 _cleanup_free_ char *unit = NULL;
164 pid_t pid;
165 int r;
167 assert_return(pidfd >= 0, -EBADF);
168 assert_return(ret_unit, -EINVAL);
170 r = pidfd_get_pid(pidfd, &pid);
171 if (r < 0)
172 return r;
174 r = sd_pid_get_unit(pid, &unit);
175 if (r < 0)
176 return r;
178 r = pidfd_verify_pid(pidfd, pid);
179 if (r < 0)
180 return r;
182 *ret_unit = TAKE_PTR(unit);
184 return 0;
187 _public_ int sd_pidfd_get_user_unit(int pidfd, char **ret_unit) {
188 _cleanup_free_ char *unit = NULL;
189 pid_t pid;
190 int r;
192 assert_return(pidfd >= 0, -EBADF);
193 assert_return(ret_unit, -EINVAL);
195 r = pidfd_get_pid(pidfd, &pid);
196 if (r < 0)
197 return r;
199 r = sd_pid_get_user_unit(pid, &unit);
200 if (r < 0)
201 return r;
203 r = pidfd_verify_pid(pidfd, pid);
204 if (r < 0)
205 return r;
207 *ret_unit = TAKE_PTR(unit);
209 return 0;
212 _public_ int sd_pidfd_get_machine_name(int pidfd, char **ret_name) {
213 _cleanup_free_ char *name = NULL;
214 pid_t pid;
215 int r;
217 assert_return(pidfd >= 0, -EBADF);
218 assert_return(ret_name, -EINVAL);
220 r = pidfd_get_pid(pidfd, &pid);
221 if (r < 0)
222 return r;
224 r = sd_pid_get_machine_name(pid, &name);
225 if (r < 0)
226 return r;
228 r = pidfd_verify_pid(pidfd, pid);
229 if (r < 0)
230 return r;
232 *ret_name = TAKE_PTR(name);
234 return 0;
237 _public_ int sd_pidfd_get_slice(int pidfd, char **ret_slice) {
238 _cleanup_free_ char *slice = NULL;
239 pid_t pid;
240 int r;
242 assert_return(pidfd >= 0, -EBADF);
243 assert_return(ret_slice, -EINVAL);
245 r = pidfd_get_pid(pidfd, &pid);
246 if (r < 0)
247 return r;
249 r = sd_pid_get_slice(pid, &slice);
250 if (r < 0)
251 return r;
253 r = pidfd_verify_pid(pidfd, pid);
254 if (r < 0)
255 return r;
257 *ret_slice = TAKE_PTR(slice);
259 return 0;
262 _public_ int sd_pidfd_get_user_slice(int pidfd, char **ret_slice) {
263 _cleanup_free_ char *slice = NULL;
264 pid_t pid;
265 int r;
267 assert_return(pidfd >= 0, -EBADF);
268 assert_return(ret_slice, -EINVAL);
270 r = pidfd_get_pid(pidfd, &pid);
271 if (r < 0)
272 return r;
274 r = sd_pid_get_user_slice(pid, &slice);
275 if (r < 0)
276 return r;
278 r = pidfd_verify_pid(pidfd, pid);
279 if (r < 0)
280 return r;
282 *ret_slice = TAKE_PTR(slice);
284 return 0;
287 _public_ int sd_pidfd_get_owner_uid(int pidfd, uid_t *ret_uid) {
288 uid_t uid;
289 pid_t pid;
290 int r;
292 assert_return(pidfd >= 0, -EINVAL);
293 assert_return(ret_uid, -EINVAL);
295 r = pidfd_get_pid(pidfd, &pid);
296 if (r < 0)
297 return r;
299 r = sd_pid_get_owner_uid(pid, &uid);
300 if (r < 0)
301 return r;
303 r = pidfd_verify_pid(pidfd, pid);
304 if (r < 0)
305 return r;
307 *ret_uid = uid;
309 return 0;
312 _public_ int sd_pidfd_get_cgroup(int pidfd, char **ret_cgroup) {
313 _cleanup_free_ char *cgroup = NULL;
314 pid_t pid;
315 int r;
317 assert_return(pidfd >= 0, -EBADF);
318 assert_return(ret_cgroup, -EINVAL);
320 r = pidfd_get_pid(pidfd, &pid);
321 if (r < 0)
322 return r;
324 r = sd_pid_get_cgroup(pid, &cgroup);
325 if (r < 0)
326 return r;
328 r = pidfd_verify_pid(pidfd, pid);
329 if (r < 0)
330 return r;
332 *ret_cgroup = TAKE_PTR(cgroup);
334 return 0;
337 _public_ int sd_peer_get_session(int fd, char **session) {
338 struct ucred ucred = UCRED_INVALID;
339 int r;
341 assert_return(fd >= 0, -EBADF);
342 assert_return(session, -EINVAL);
344 r = getpeercred(fd, &ucred);
345 if (r < 0)
346 return r;
348 return cg_pid_get_session(ucred.pid, session);
351 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
352 struct ucred ucred;
353 int r;
355 assert_return(fd >= 0, -EBADF);
356 assert_return(uid, -EINVAL);
358 r = getpeercred(fd, &ucred);
359 if (r < 0)
360 return r;
362 return cg_pid_get_owner_uid(ucred.pid, uid);
365 _public_ int sd_peer_get_unit(int fd, char **unit) {
366 struct ucred ucred;
367 int r;
369 assert_return(fd >= 0, -EBADF);
370 assert_return(unit, -EINVAL);
372 r = getpeercred(fd, &ucred);
373 if (r < 0)
374 return r;
376 return cg_pid_get_unit(ucred.pid, unit);
379 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
380 struct ucred ucred;
381 int r;
383 assert_return(fd >= 0, -EBADF);
384 assert_return(unit, -EINVAL);
386 r = getpeercred(fd, &ucred);
387 if (r < 0)
388 return r;
390 return cg_pid_get_user_unit(ucred.pid, unit);
393 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
394 struct ucred ucred;
395 int r;
397 assert_return(fd >= 0, -EBADF);
398 assert_return(machine, -EINVAL);
400 r = getpeercred(fd, &ucred);
401 if (r < 0)
402 return r;
404 return cg_pid_get_machine_name(ucred.pid, machine);
407 _public_ int sd_peer_get_slice(int fd, char **slice) {
408 struct ucred ucred;
409 int r;
411 assert_return(fd >= 0, -EBADF);
412 assert_return(slice, -EINVAL);
414 r = getpeercred(fd, &ucred);
415 if (r < 0)
416 return r;
418 return cg_pid_get_slice(ucred.pid, slice);
421 _public_ int sd_peer_get_user_slice(int fd, char **slice) {
422 struct ucred ucred;
423 int r;
425 assert_return(fd >= 0, -EBADF);
426 assert_return(slice, -EINVAL);
428 r = getpeercred(fd, &ucred);
429 if (r < 0)
430 return r;
432 return cg_pid_get_user_slice(ucred.pid, slice);
435 _public_ int sd_peer_get_cgroup(int fd, char **cgroup) {
436 struct ucred ucred;
437 int r;
439 assert_return(fd >= 0, -EBADF);
440 assert_return(cgroup, -EINVAL);
442 r = getpeercred(fd, &ucred);
443 if (r < 0)
444 return r;
446 return sd_pid_get_cgroup(ucred.pid, cgroup);
449 static int file_of_uid(uid_t uid, char **p) {
451 assert_return(uid_is_valid(uid), -EINVAL);
452 assert(p);
454 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
455 return -ENOMEM;
457 return 0;
460 _public_ int sd_uid_get_state(uid_t uid, char**state) {
461 _cleanup_free_ char *p = NULL, *s = NULL;
462 int r;
464 assert_return(state, -EINVAL);
466 r = file_of_uid(uid, &p);
467 if (r < 0)
468 return r;
470 r = parse_env_file(NULL, p, "STATE", &s);
471 if (r == -ENOENT)
472 r = free_and_strdup(&s, "offline");
473 if (r < 0)
474 return r;
475 if (isempty(s))
476 return -EIO;
478 *state = TAKE_PTR(s);
479 return 0;
482 _public_ int sd_uid_get_display(uid_t uid, char **session) {
483 _cleanup_free_ char *p = NULL, *s = NULL;
484 int r;
486 assert_return(session, -EINVAL);
488 r = file_of_uid(uid, &p);
489 if (r < 0)
490 return r;
492 r = parse_env_file(NULL, p, "DISPLAY", &s);
493 if (r == -ENOENT)
494 return -ENODATA;
495 if (r < 0)
496 return r;
497 if (isempty(s))
498 return -ENODATA;
500 *session = TAKE_PTR(s);
502 return 0;
505 _public_ int sd_uid_get_login_time(uid_t uid, uint64_t *usec) {
506 _cleanup_free_ char *p = NULL, *s = NULL, *rt = NULL;
507 usec_t t;
508 int r;
510 assert_return(usec, -EINVAL);
512 r = file_of_uid(uid, &p);
513 if (r < 0)
514 return r;
516 r = parse_env_file(NULL, p, "STATE", &s, "REALTIME", &rt);
517 if (r == -ENOENT)
518 return -ENXIO;
519 if (r < 0)
520 return r;
521 if (isempty(s) || isempty(rt))
522 return -EIO;
524 if (!STR_IN_SET(s, "active", "online"))
525 return -ENXIO;
527 r = safe_atou64(rt, &t);
528 if (r < 0)
529 return r;
531 *usec = t;
532 return 0;
535 static int file_of_seat(const char *seat, char **_p) {
536 char *p;
537 int r;
539 assert(_p);
541 if (seat) {
542 if (!filename_is_valid(seat))
543 return -EINVAL;
545 p = path_join("/run/systemd/seats", seat);
546 } else {
547 _cleanup_free_ char *buf = NULL;
549 r = sd_session_get_seat(NULL, &buf);
550 if (r < 0)
551 return r;
553 p = path_join("/run/systemd/seats", buf);
555 if (!p)
556 return -ENOMEM;
558 *_p = TAKE_PTR(p);
559 return 0;
562 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
563 _cleanup_free_ char *filename = NULL, *content = NULL;
564 int r;
566 assert_return(uid_is_valid(uid), -EINVAL);
568 r = file_of_seat(seat, &filename);
569 if (r < 0)
570 return r;
572 r = parse_env_file(NULL, filename,
573 require_active ? "ACTIVE_UID" : "UIDS",
574 &content);
575 if (r == -ENOENT)
576 return 0;
577 if (r < 0)
578 return r;
579 if (isempty(content))
580 return 0;
582 char t[DECIMAL_STR_MAX(uid_t)];
583 xsprintf(t, UID_FMT, uid);
585 return string_contains_word(content, NULL, t);
588 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
589 _cleanup_free_ char *p = NULL, *s = NULL;
590 char **a;
591 int r;
593 assert(variable);
595 r = file_of_uid(uid, &p);
596 if (r < 0)
597 return r;
599 r = parse_env_file(NULL, p, variable, &s);
600 if (r == -ENOENT || (r >= 0 && isempty(s))) {
601 if (array)
602 *array = NULL;
603 return 0;
605 if (r < 0)
606 return r;
608 a = strv_split(s, NULL);
609 if (!a)
610 return -ENOMEM;
612 strv_uniq(a);
613 r = (int) strv_length(a);
615 if (array)
616 *array = a;
617 else
618 strv_free(a);
620 return r;
623 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
624 return uid_get_array(
625 uid,
626 require_active == 0 ? "ONLINE_SESSIONS" :
627 require_active > 0 ? "ACTIVE_SESSIONS" :
628 "SESSIONS",
629 sessions);
632 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
633 return uid_get_array(
634 uid,
635 require_active == 0 ? "ONLINE_SEATS" :
636 require_active > 0 ? "ACTIVE_SEATS" :
637 "SEATS",
638 seats);
641 static int file_of_session(const char *session, char **_p) {
642 char *p;
643 int r;
645 assert(_p);
647 if (session) {
648 if (!session_id_valid(session))
649 return -EINVAL;
651 p = path_join("/run/systemd/sessions", session);
652 } else {
653 _cleanup_free_ char *buf = NULL;
655 r = sd_pid_get_session(0, &buf);
656 if (r < 0)
657 return r;
659 p = path_join("/run/systemd/sessions", buf);
662 if (!p)
663 return -ENOMEM;
665 *_p = p;
666 return 0;
669 _public_ int sd_session_is_active(const char *session) {
670 _cleanup_free_ char *p = NULL, *s = NULL;
671 int r;
673 r = file_of_session(session, &p);
674 if (r < 0)
675 return r;
677 r = parse_env_file(NULL, p, "ACTIVE", &s);
678 if (r == -ENOENT)
679 return -ENXIO;
680 if (r < 0)
681 return r;
682 if (isempty(s))
683 return -EIO;
685 return parse_boolean(s);
688 _public_ int sd_session_is_remote(const char *session) {
689 _cleanup_free_ char *p = NULL, *s = NULL;
690 int r;
692 r = file_of_session(session, &p);
693 if (r < 0)
694 return r;
696 r = parse_env_file(NULL, p, "REMOTE", &s);
697 if (r == -ENOENT)
698 return -ENXIO;
699 if (r < 0)
700 return r;
701 if (isempty(s))
702 return -ENODATA;
704 return parse_boolean(s);
707 _public_ int sd_session_get_state(const char *session, char **state) {
708 _cleanup_free_ char *p = NULL, *s = NULL;
709 int r;
711 assert_return(state, -EINVAL);
713 r = file_of_session(session, &p);
714 if (r < 0)
715 return r;
717 r = parse_env_file(NULL, p, "STATE", &s);
718 if (r == -ENOENT)
719 return -ENXIO;
720 if (r < 0)
721 return r;
722 if (isempty(s))
723 return -EIO;
725 *state = TAKE_PTR(s);
727 return 0;
730 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
731 int r;
732 _cleanup_free_ char *p = NULL, *s = NULL;
734 assert_return(uid, -EINVAL);
736 r = file_of_session(session, &p);
737 if (r < 0)
738 return r;
740 r = parse_env_file(NULL, p, "UID", &s);
741 if (r == -ENOENT)
742 return -ENXIO;
743 if (r < 0)
744 return r;
745 if (isempty(s))
746 return -EIO;
748 return parse_uid(s, uid);
751 static int session_get_string(const char *session, const char *field, char **value) {
752 _cleanup_free_ char *p = NULL, *s = NULL;
753 int r;
755 assert_return(value, -EINVAL);
756 assert(field);
758 r = file_of_session(session, &p);
759 if (r < 0)
760 return r;
762 r = parse_env_file(NULL, p, field, &s);
763 if (r == -ENOENT)
764 return -ENXIO;
765 if (r < 0)
766 return r;
767 if (isempty(s))
768 return -ENODATA;
770 *value = TAKE_PTR(s);
771 return 0;
774 _public_ int sd_session_get_username(const char *session, char **username) {
775 return session_get_string(session, "USER", username);
778 _public_ int sd_session_get_seat(const char *session, char **seat) {
779 return session_get_string(session, "SEAT", seat);
782 _public_ int sd_session_get_start_time(const char *session, uint64_t *usec) {
783 _cleanup_free_ char *p = NULL, *s = NULL;
784 usec_t t;
785 int r;
787 assert_return(usec, -EINVAL);
789 r = file_of_session(session, &p);
790 if (r < 0)
791 return r;
793 r = parse_env_file(NULL, p, "REALTIME", &s);
794 if (r == -ENOENT)
795 return -ENXIO;
796 if (r < 0)
797 return r;
798 if (isempty(s))
799 return -EIO;
801 r = safe_atou64(s, &t);
802 if (r < 0)
803 return r;
805 *usec = t;
806 return 0;
809 _public_ int sd_session_get_tty(const char *session, char **tty) {
810 return session_get_string(session, "TTY", tty);
813 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
814 _cleanup_free_ char *vtnr_string = NULL;
815 unsigned u;
816 int r;
818 assert_return(vtnr, -EINVAL);
820 r = session_get_string(session, "VTNR", &vtnr_string);
821 if (r < 0)
822 return r;
824 r = safe_atou(vtnr_string, &u);
825 if (r < 0)
826 return r;
828 *vtnr = u;
829 return 0;
832 _public_ int sd_session_get_service(const char *session, char **service) {
833 return session_get_string(session, "SERVICE", service);
836 _public_ int sd_session_get_type(const char *session, char **type) {
837 return session_get_string(session, "TYPE", type);
840 _public_ int sd_session_get_class(const char *session, char **class) {
841 return session_get_string(session, "CLASS", class);
844 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
845 _cleanup_free_ char *escaped = NULL;
846 int r;
847 ssize_t l;
849 assert_return(desktop, -EINVAL);
851 r = session_get_string(session, "DESKTOP", &escaped);
852 if (r < 0)
853 return r;
855 l = cunescape(escaped, 0, desktop);
856 if (l < 0)
857 return l;
858 return 0;
861 _public_ int sd_session_get_display(const char *session, char **display) {
862 return session_get_string(session, "DISPLAY", display);
865 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
866 return session_get_string(session, "REMOTE_USER", remote_user);
869 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
870 return session_get_string(session, "REMOTE_HOST", remote_host);
873 _public_ int sd_session_get_leader(const char *session, pid_t *leader) {
874 _cleanup_free_ char *leader_string = NULL;
875 pid_t pid;
876 int r;
878 assert_return(leader, -EINVAL);
880 r = session_get_string(session, "LEADER", &leader_string);
881 if (r < 0)
882 return r;
884 r = parse_pid(leader_string, &pid);
885 if (r < 0)
886 return r;
888 *leader = pid;
889 return 0;
892 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
893 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
894 int r;
896 assert_return(session || uid, -EINVAL);
898 r = file_of_seat(seat, &p);
899 if (r < 0)
900 return r;
902 r = parse_env_file(NULL, p,
903 "ACTIVE", &s,
904 "ACTIVE_UID", &t);
905 if (r == -ENOENT)
906 return -ENXIO;
907 if (r < 0)
908 return r;
910 if (session && !s)
911 return -ENODATA;
913 if (uid && !t)
914 return -ENODATA;
916 if (uid && t) {
917 r = parse_uid(t, uid);
918 if (r < 0)
919 return r;
922 if (session && s)
923 *session = TAKE_PTR(s);
925 return 0;
928 _public_ int sd_seat_get_sessions(
929 const char *seat,
930 char ***ret_sessions,
931 uid_t **ret_uids,
932 unsigned *ret_n_uids) {
934 _cleanup_free_ char *fname = NULL, *session_line = NULL, *uid_line = NULL;
935 _cleanup_strv_free_ char **sessions = NULL;
936 _cleanup_free_ uid_t *uids = NULL;
937 unsigned n_sessions = 0;
938 int r;
940 r = file_of_seat(seat, &fname);
941 if (r < 0)
942 return r;
944 r = parse_env_file(NULL, fname,
945 "SESSIONS", &session_line,
946 "UIDS", &uid_line);
947 if (r == -ENOENT)
948 return -ENXIO;
949 if (r < 0)
950 return r;
952 if (session_line) {
953 sessions = strv_split(session_line, NULL);
954 if (!sessions)
955 return -ENOMEM;
957 n_sessions = strv_length(sessions);
960 if (ret_uids && uid_line) {
961 uids = new(uid_t, n_sessions);
962 if (!uids)
963 return -ENOMEM;
965 size_t n = 0;
966 for (const char *p = uid_line;;) {
967 _cleanup_free_ char *word = NULL;
969 r = extract_first_word(&p, &word, NULL, 0);
970 if (r < 0)
971 return r;
972 if (r == 0)
973 break;
975 r = parse_uid(word, &uids[n++]);
976 if (r < 0)
977 return r;
980 if (n != n_sessions)
981 return -EUCLEAN;
984 if (ret_sessions)
985 *ret_sessions = TAKE_PTR(sessions);
986 if (ret_uids)
987 *ret_uids = TAKE_PTR(uids);
988 if (ret_n_uids)
989 *ret_n_uids = n_sessions;
991 return n_sessions;
994 static int seat_get_can(const char *seat, const char *variable) {
995 _cleanup_free_ char *p = NULL, *s = NULL;
996 int r;
998 assert(variable);
1000 r = file_of_seat(seat, &p);
1001 if (r < 0)
1002 return r;
1004 r = parse_env_file(NULL, p,
1005 variable, &s);
1006 if (r == -ENOENT)
1007 return -ENXIO;
1008 if (r < 0)
1009 return r;
1010 if (isempty(s))
1011 return -ENODATA;
1013 return parse_boolean(s);
1016 _public_ int sd_seat_can_multi_session(const char *seat) {
1017 return true;
1020 _public_ int sd_seat_can_tty(const char *seat) {
1021 return seat_get_can(seat, "CAN_TTY");
1024 _public_ int sd_seat_can_graphical(const char *seat) {
1025 return seat_get_can(seat, "CAN_GRAPHICAL");
1028 _public_ int sd_get_seats(char ***seats) {
1029 int r;
1031 r = get_files_in_directory("/run/systemd/seats/", seats);
1032 if (r == -ENOENT) {
1033 if (seats)
1034 *seats = NULL;
1035 return 0;
1037 return r;
1040 _public_ int sd_get_sessions(char ***sessions) {
1041 int r;
1043 r = get_files_in_directory("/run/systemd/sessions/", sessions);
1044 if (r == -ENOENT) {
1045 if (sessions)
1046 *sessions = NULL;
1047 return 0;
1049 return r;
1052 _public_ int sd_get_uids(uid_t **users) {
1053 _cleanup_closedir_ DIR *d = NULL;
1054 int r = 0;
1055 unsigned n = 0;
1056 _cleanup_free_ uid_t *l = NULL;
1058 d = opendir("/run/systemd/users/");
1059 if (!d) {
1060 if (errno == ENOENT) {
1061 if (users)
1062 *users = NULL;
1063 return 0;
1065 return -errno;
1068 FOREACH_DIRENT_ALL(de, d, return -errno) {
1069 int k;
1070 uid_t uid;
1072 if (!dirent_is_file(de))
1073 continue;
1075 k = parse_uid(de->d_name, &uid);
1076 if (k < 0)
1077 continue;
1079 if (users) {
1080 if ((unsigned) r >= n) {
1081 uid_t *t;
1083 n = MAX(16, 2*r);
1084 t = reallocarray(l, n, sizeof(uid_t));
1085 if (!t)
1086 return -ENOMEM;
1088 l = t;
1091 assert((unsigned) r < n);
1092 l[r++] = uid;
1093 } else
1094 r++;
1097 if (users)
1098 *users = TAKE_PTR(l);
1100 return r;
1103 _public_ int sd_get_machine_names(char ***machines) {
1104 _cleanup_strv_free_ char **l = NULL;
1105 char **a, **b;
1106 int r;
1108 r = get_files_in_directory("/run/systemd/machines/", &l);
1109 if (r == -ENOENT) {
1110 if (machines)
1111 *machines = NULL;
1112 return 0;
1114 if (r < 0)
1115 return r;
1117 if (l) {
1118 r = 0;
1120 /* Filter out the unit: symlinks */
1121 for (a = b = l; *a; a++) {
1122 if (startswith(*a, "unit:") || !hostname_is_valid(*a, 0))
1123 free(*a);
1124 else {
1125 *b = *a;
1126 b++;
1127 r++;
1131 *b = NULL;
1134 if (machines)
1135 *machines = TAKE_PTR(l);
1137 return r;
1140 _public_ int sd_machine_get_class(const char *machine, char **class) {
1141 _cleanup_free_ char *c = NULL;
1142 const char *p;
1143 int r;
1145 assert_return(class, -EINVAL);
1147 if (streq(machine, ".host")) {
1148 c = strdup("host");
1149 if (!c)
1150 return -ENOMEM;
1151 } else {
1152 if (!hostname_is_valid(machine, 0))
1153 return -EINVAL;
1155 p = strjoina("/run/systemd/machines/", machine);
1156 r = parse_env_file(NULL, p, "CLASS", &c);
1157 if (r == -ENOENT)
1158 return -ENXIO;
1159 if (r < 0)
1160 return r;
1161 if (!c)
1162 return -EIO;
1165 *class = TAKE_PTR(c);
1166 return 0;
1169 _public_ int sd_machine_get_ifindices(const char *machine, int **ret_ifindices) {
1170 _cleanup_free_ char *netif_line = NULL;
1171 const char *p;
1172 int r;
1174 assert_return(hostname_is_valid(machine, 0), -EINVAL);
1176 p = strjoina("/run/systemd/machines/", machine);
1177 r = parse_env_file(NULL, p, "NETIF", &netif_line);
1178 if (r == -ENOENT)
1179 return -ENXIO;
1180 if (r < 0)
1181 return r;
1182 if (!netif_line) {
1183 *ret_ifindices = NULL;
1184 return 0;
1187 _cleanup_strv_free_ char **tt = strv_split(netif_line, NULL);
1188 if (!tt)
1189 return -ENOMEM;
1191 _cleanup_free_ int *ifindices = NULL;
1192 if (ret_ifindices) {
1193 ifindices = new(int, strv_length(tt));
1194 if (!ifindices)
1195 return -ENOMEM;
1198 size_t n = 0;
1199 for (size_t i = 0; tt[i]; i++) {
1200 int ind;
1202 ind = parse_ifindex(tt[i]);
1203 if (ind < 0)
1204 /* Return -EUCLEAN to distinguish from -EINVAL for invalid args */
1205 return ind == -EINVAL ? -EUCLEAN : ind;
1207 if (ret_ifindices)
1208 ifindices[n] = ind;
1209 n++;
1212 if (ret_ifindices)
1213 *ret_ifindices = TAKE_PTR(ifindices);
1215 return n;
1218 static int MONITOR_TO_FD(sd_login_monitor *m) {
1219 return (int) (unsigned long) m - 1;
1222 static sd_login_monitor* FD_TO_MONITOR(int fd) {
1223 return (sd_login_monitor*) (unsigned long) (fd + 1);
1226 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
1227 _cleanup_close_ int fd = -EBADF;
1228 bool good = false;
1229 int k;
1231 assert_return(m, -EINVAL);
1233 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1234 if (fd < 0)
1235 return -errno;
1237 if (!category || streq(category, "seat")) {
1238 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
1239 if (k < 0)
1240 return -errno;
1242 good = true;
1245 if (!category || streq(category, "session")) {
1246 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
1247 if (k < 0)
1248 return -errno;
1250 good = true;
1253 if (!category || streq(category, "uid")) {
1254 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1255 if (k < 0)
1256 return -errno;
1258 good = true;
1261 if (!category || streq(category, "machine")) {
1262 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1263 if (k < 0)
1264 return -errno;
1266 good = true;
1269 if (!good)
1270 return -EINVAL;
1272 *m = FD_TO_MONITOR(TAKE_FD(fd));
1273 return 0;
1276 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1277 if (m)
1278 (void) close_nointr(MONITOR_TO_FD(m));
1280 return NULL;
1283 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1284 int r;
1286 assert_return(m, -EINVAL);
1288 r = flush_fd(MONITOR_TO_FD(m));
1289 if (r < 0)
1290 return r;
1292 return 0;
1295 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1297 assert_return(m, -EINVAL);
1299 return MONITOR_TO_FD(m);
1302 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1304 assert_return(m, -EINVAL);
1306 /* For now we will only return POLLIN here, since we don't
1307 * need anything else ever for inotify. However, let's have
1308 * this API to keep our options open should we later on need
1309 * it. */
1310 return POLLIN;
1313 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1315 assert_return(m, -EINVAL);
1316 assert_return(timeout_usec, -EINVAL);
1318 /* For now we will only return UINT64_MAX, since we don't
1319 * need any timeout. However, let's have this API to keep our
1320 * options open should we later on need it. */
1321 *timeout_usec = UINT64_MAX;
1322 return 0;