]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-login/sd-login.c
d12d9dc6cf92e743d03e36343b926efe817c3e0c
[thirdparty/systemd.git] / src / libsystemd / sd-login / sd-login.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <poll.h>
23 #include <string.h>
24 #include <sys/inotify.h>
25 #include <unistd.h>
26
27 #include "sd-login.h"
28
29 #include "alloc-util.h"
30 #include "cgroup-util.h"
31 #include "dirent-util.h"
32 #include "escape.h"
33 #include "fd-util.h"
34 #include "fileio.h"
35 #include "format-util.h"
36 #include "fs-util.h"
37 #include "hostname-util.h"
38 #include "io-util.h"
39 #include "login-util.h"
40 #include "macro.h"
41 #include "parse-util.h"
42 #include "path-util.h"
43 #include "socket-util.h"
44 #include "string-util.h"
45 #include "strv.h"
46 #include "user-util.h"
47 #include "util.h"
48
49 /* Error codes:
50 *
51 * invalid input parameters → -EINVAL
52 * invalid fd → -EBADF
53 * process does not exist → -ESRCH
54 * cgroup does not exist → -ENOENT
55 * machine, session does not exist → -ENXIO
56 * requested metadata on object is missing → -ENODATA
57 */
58
59 _public_ int sd_pid_get_session(pid_t pid, char **session) {
60 int r;
61
62 assert_return(pid >= 0, -EINVAL);
63 assert_return(session, -EINVAL);
64
65 r = cg_pid_get_session(pid, session);
66 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
67 }
68
69 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
70 int r;
71
72 assert_return(pid >= 0, -EINVAL);
73 assert_return(unit, -EINVAL);
74
75 r = cg_pid_get_unit(pid, unit);
76 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
77 }
78
79 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
80 int r;
81
82 assert_return(pid >= 0, -EINVAL);
83 assert_return(unit, -EINVAL);
84
85 r = cg_pid_get_user_unit(pid, unit);
86 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
87 }
88
89 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
90 int r;
91
92 assert_return(pid >= 0, -EINVAL);
93 assert_return(name, -EINVAL);
94
95 r = cg_pid_get_machine_name(pid, name);
96 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
97 }
98
99 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
100 int r;
101
102 assert_return(pid >= 0, -EINVAL);
103 assert_return(slice, -EINVAL);
104
105 r = cg_pid_get_slice(pid, slice);
106 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
107 }
108
109 _public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
110 int r;
111
112 assert_return(pid >= 0, -EINVAL);
113 assert_return(slice, -EINVAL);
114
115 r = cg_pid_get_user_slice(pid, slice);
116 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
117 }
118
119 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
120 int r;
121
122 assert_return(pid >= 0, -EINVAL);
123 assert_return(uid, -EINVAL);
124
125 r = cg_pid_get_owner_uid(pid, uid);
126 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
127 }
128
129 _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
130 char *c;
131 int r;
132
133 assert_return(pid >= 0, -EINVAL);
134 assert_return(cgroup, -EINVAL);
135
136 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c);
137 if (r < 0)
138 return r;
139
140 /* The internal APIs return the empty string for the root
141 * cgroup, let's return the "/" in the public APIs instead, as
142 * that's easier and less ambiguous for people to grok. */
143 if (isempty(c)) {
144 free(c);
145 c = strdup("/");
146 if (!c)
147 return -ENOMEM;
148
149 }
150
151 *cgroup = c;
152 return 0;
153 }
154
155 _public_ int sd_peer_get_session(int fd, char **session) {
156 struct ucred ucred = {};
157 int r;
158
159 assert_return(fd >= 0, -EBADF);
160 assert_return(session, -EINVAL);
161
162 r = getpeercred(fd, &ucred);
163 if (r < 0)
164 return r;
165
166 return cg_pid_get_session(ucred.pid, session);
167 }
168
169 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
170 struct ucred ucred;
171 int r;
172
173 assert_return(fd >= 0, -EBADF);
174 assert_return(uid, -EINVAL);
175
176 r = getpeercred(fd, &ucred);
177 if (r < 0)
178 return r;
179
180 return cg_pid_get_owner_uid(ucred.pid, uid);
181 }
182
183 _public_ int sd_peer_get_unit(int fd, char **unit) {
184 struct ucred ucred;
185 int r;
186
187 assert_return(fd >= 0, -EBADF);
188 assert_return(unit, -EINVAL);
189
190 r = getpeercred(fd, &ucred);
191 if (r < 0)
192 return r;
193
194 return cg_pid_get_unit(ucred.pid, unit);
195 }
196
197 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
198 struct ucred ucred;
199 int r;
200
201 assert_return(fd >= 0, -EBADF);
202 assert_return(unit, -EINVAL);
203
204 r = getpeercred(fd, &ucred);
205 if (r < 0)
206 return r;
207
208 return cg_pid_get_user_unit(ucred.pid, unit);
209 }
210
211 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
212 struct ucred ucred;
213 int r;
214
215 assert_return(fd >= 0, -EBADF);
216 assert_return(machine, -EINVAL);
217
218 r = getpeercred(fd, &ucred);
219 if (r < 0)
220 return r;
221
222 return cg_pid_get_machine_name(ucred.pid, machine);
223 }
224
225 _public_ int sd_peer_get_slice(int fd, char **slice) {
226 struct ucred ucred;
227 int r;
228
229 assert_return(fd >= 0, -EBADF);
230 assert_return(slice, -EINVAL);
231
232 r = getpeercred(fd, &ucred);
233 if (r < 0)
234 return r;
235
236 return cg_pid_get_slice(ucred.pid, slice);
237 }
238
239 _public_ int sd_peer_get_user_slice(int fd, char **slice) {
240 struct ucred ucred;
241 int r;
242
243 assert_return(fd >= 0, -EBADF);
244 assert_return(slice, -EINVAL);
245
246 r = getpeercred(fd, &ucred);
247 if (r < 0)
248 return r;
249
250 return cg_pid_get_user_slice(ucred.pid, slice);
251 }
252
253 _public_ int sd_peer_get_cgroup(int fd, char **cgroup) {
254 struct ucred ucred;
255 int r;
256
257 assert_return(fd >= 0, -EBADF);
258 assert_return(cgroup, -EINVAL);
259
260 r = getpeercred(fd, &ucred);
261 if (r < 0)
262 return r;
263
264 return sd_pid_get_cgroup(ucred.pid, cgroup);
265 }
266
267 static int file_of_uid(uid_t uid, char **p) {
268
269 assert_return(uid_is_valid(uid), -EINVAL);
270 assert(p);
271
272 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
273 return -ENOMEM;
274
275 return 0;
276 }
277
278 _public_ int sd_uid_get_state(uid_t uid, char**state) {
279 _cleanup_free_ char *p = NULL;
280 char *s = NULL;
281 int r;
282
283 assert_return(state, -EINVAL);
284
285 r = file_of_uid(uid, &p);
286 if (r < 0)
287 return r;
288
289 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
290 if (r == -ENOENT) {
291 free(s);
292 s = strdup("offline");
293 if (!s)
294 return -ENOMEM;
295
296 }
297 else if (r < 0) {
298 free(s);
299 return r;
300 }
301 if (isempty(s)) {
302 free(s);
303 return -EIO;
304 }
305
306 *state = s;
307 return 0;
308 }
309
310 _public_ int sd_uid_get_display(uid_t uid, char **session) {
311 _cleanup_free_ char *p = NULL, *s = NULL;
312 int r;
313
314 assert_return(session, -EINVAL);
315
316 r = file_of_uid(uid, &p);
317 if (r < 0)
318 return r;
319
320 r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
321 if (r == -ENOENT)
322 return -ENODATA;
323 if (r < 0)
324 return r;
325 if (isempty(s))
326 return -ENODATA;
327
328 *session = TAKE_PTR(s);
329
330 return 0;
331 }
332
333 static int file_of_seat(const char *seat, char **_p) {
334 char *p;
335 int r;
336
337 assert(_p);
338
339 if (seat) {
340 if (!filename_is_valid(seat))
341 return -EINVAL;
342
343 p = strappend("/run/systemd/seats/", seat);
344 } else {
345 _cleanup_free_ char *buf = NULL;
346
347 r = sd_session_get_seat(NULL, &buf);
348 if (r < 0)
349 return r;
350
351 p = strappend("/run/systemd/seats/", buf);
352 }
353
354 if (!p)
355 return -ENOMEM;
356
357 *_p = TAKE_PTR(p);
358 return 0;
359 }
360
361 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
362 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
363 size_t l;
364 int r;
365 const char *word, *variable, *state;
366
367 assert_return(uid_is_valid(uid), -EINVAL);
368
369 r = file_of_seat(seat, &p);
370 if (r < 0)
371 return r;
372
373 variable = require_active ? "ACTIVE_UID" : "UIDS";
374
375 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
376 if (r == -ENOENT)
377 return 0;
378 if (r < 0)
379 return r;
380 if (isempty(s))
381 return 0;
382
383 if (asprintf(&t, UID_FMT, uid) < 0)
384 return -ENOMEM;
385
386 FOREACH_WORD(word, l, s, state)
387 if (strneq(t, word, l))
388 return 1;
389
390 return 0;
391 }
392
393 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
394 _cleanup_free_ char *p = NULL, *s = NULL;
395 char **a;
396 int r;
397
398 assert(variable);
399
400 r = file_of_uid(uid, &p);
401 if (r < 0)
402 return r;
403
404 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
405 if (r == -ENOENT || (r >= 0 && isempty(s))) {
406 if (array)
407 *array = NULL;
408 return 0;
409 }
410 if (r < 0)
411 return r;
412
413 a = strv_split(s, " ");
414 if (!a)
415 return -ENOMEM;
416
417 strv_uniq(a);
418 r = strv_length(a);
419
420 if (array)
421 *array = a;
422 else
423 strv_free(a);
424
425 return r;
426 }
427
428 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
429 return uid_get_array(
430 uid,
431 require_active == 0 ? "ONLINE_SESSIONS" :
432 require_active > 0 ? "ACTIVE_SESSIONS" :
433 "SESSIONS",
434 sessions);
435 }
436
437 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
438 return uid_get_array(
439 uid,
440 require_active == 0 ? "ONLINE_SEATS" :
441 require_active > 0 ? "ACTIVE_SEATS" :
442 "SEATS",
443 seats);
444 }
445
446 static int file_of_session(const char *session, char **_p) {
447 char *p;
448 int r;
449
450 assert(_p);
451
452 if (session) {
453 if (!session_id_valid(session))
454 return -EINVAL;
455
456 p = strappend("/run/systemd/sessions/", session);
457 } else {
458 _cleanup_free_ char *buf = NULL;
459
460 r = sd_pid_get_session(0, &buf);
461 if (r < 0)
462 return r;
463
464 p = strappend("/run/systemd/sessions/", buf);
465 }
466
467 if (!p)
468 return -ENOMEM;
469
470 *_p = p;
471 return 0;
472 }
473
474 _public_ int sd_session_is_active(const char *session) {
475 _cleanup_free_ char *p = NULL, *s = NULL;
476 int r;
477
478 r = file_of_session(session, &p);
479 if (r < 0)
480 return r;
481
482 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
483 if (r == -ENOENT)
484 return -ENXIO;
485 if (r < 0)
486 return r;
487 if (isempty(s))
488 return -EIO;
489
490 return parse_boolean(s);
491 }
492
493 _public_ int sd_session_is_remote(const char *session) {
494 _cleanup_free_ char *p = NULL, *s = NULL;
495 int r;
496
497 r = file_of_session(session, &p);
498 if (r < 0)
499 return r;
500
501 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
502 if (r == -ENOENT)
503 return -ENXIO;
504 if (r < 0)
505 return r;
506 if (isempty(s))
507 return -ENODATA;
508
509 return parse_boolean(s);
510 }
511
512 _public_ int sd_session_get_state(const char *session, char **state) {
513 _cleanup_free_ char *p = NULL, *s = NULL;
514 int r;
515
516 assert_return(state, -EINVAL);
517
518 r = file_of_session(session, &p);
519 if (r < 0)
520 return r;
521
522 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
523 if (r == -ENOENT)
524 return -ENXIO;
525 if (r < 0)
526 return r;
527 if (isempty(s))
528 return -EIO;
529
530 *state = TAKE_PTR(s);
531
532 return 0;
533 }
534
535 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
536 int r;
537 _cleanup_free_ char *p = NULL, *s = NULL;
538
539 assert_return(uid, -EINVAL);
540
541 r = file_of_session(session, &p);
542 if (r < 0)
543 return r;
544
545 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
546 if (r == -ENOENT)
547 return -ENXIO;
548 if (r < 0)
549 return r;
550 if (isempty(s))
551 return -EIO;
552
553 return parse_uid(s, uid);
554 }
555
556 static int session_get_string(const char *session, const char *field, char **value) {
557 _cleanup_free_ char *p = NULL, *s = NULL;
558 int r;
559
560 assert_return(value, -EINVAL);
561 assert(field);
562
563 r = file_of_session(session, &p);
564 if (r < 0)
565 return r;
566
567 r = parse_env_file(p, NEWLINE, field, &s, NULL);
568 if (r == -ENOENT)
569 return -ENXIO;
570 if (r < 0)
571 return r;
572 if (isempty(s))
573 return -ENODATA;
574
575 *value = TAKE_PTR(s);
576 return 0;
577 }
578
579 _public_ int sd_session_get_seat(const char *session, char **seat) {
580 return session_get_string(session, "SEAT", seat);
581 }
582
583 _public_ int sd_session_get_tty(const char *session, char **tty) {
584 return session_get_string(session, "TTY", tty);
585 }
586
587 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
588 _cleanup_free_ char *vtnr_string = NULL;
589 unsigned u;
590 int r;
591
592 assert_return(vtnr, -EINVAL);
593
594 r = session_get_string(session, "VTNR", &vtnr_string);
595 if (r < 0)
596 return r;
597
598 r = safe_atou(vtnr_string, &u);
599 if (r < 0)
600 return r;
601
602 *vtnr = u;
603 return 0;
604 }
605
606 _public_ int sd_session_get_service(const char *session, char **service) {
607 return session_get_string(session, "SERVICE", service);
608 }
609
610 _public_ int sd_session_get_type(const char *session, char **type) {
611 return session_get_string(session, "TYPE", type);
612 }
613
614 _public_ int sd_session_get_class(const char *session, char **class) {
615 return session_get_string(session, "CLASS", class);
616 }
617
618 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
619 _cleanup_free_ char *escaped = NULL;
620 char *t;
621 int r;
622
623 assert_return(desktop, -EINVAL);
624
625 r = session_get_string(session, "DESKTOP", &escaped);
626 if (r < 0)
627 return r;
628
629 r = cunescape(escaped, 0, &t);
630 if (r < 0)
631 return r;
632
633 *desktop = t;
634 return 0;
635 }
636
637 _public_ int sd_session_get_display(const char *session, char **display) {
638 return session_get_string(session, "DISPLAY", display);
639 }
640
641 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
642 return session_get_string(session, "REMOTE_USER", remote_user);
643 }
644
645 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
646 return session_get_string(session, "REMOTE_HOST", remote_host);
647 }
648
649 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
650 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
651 int r;
652
653 assert_return(session || uid, -EINVAL);
654
655 r = file_of_seat(seat, &p);
656 if (r < 0)
657 return r;
658
659 r = parse_env_file(p, NEWLINE,
660 "ACTIVE", &s,
661 "ACTIVE_UID", &t,
662 NULL);
663 if (r == -ENOENT)
664 return -ENXIO;
665 if (r < 0)
666 return r;
667
668 if (session && !s)
669 return -ENODATA;
670
671 if (uid && !t)
672 return -ENODATA;
673
674 if (uid && t) {
675 r = parse_uid(t, uid);
676 if (r < 0)
677 return r;
678 }
679
680 if (session && s)
681 *session = TAKE_PTR(s);
682
683 return 0;
684 }
685
686 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
687 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
688 _cleanup_strv_free_ char **a = NULL;
689 _cleanup_free_ uid_t *b = NULL;
690 unsigned n = 0;
691 int r;
692
693 r = file_of_seat(seat, &p);
694 if (r < 0)
695 return r;
696
697 r = parse_env_file(p, NEWLINE,
698 "SESSIONS", &s,
699 "UIDS", &t,
700 NULL);
701 if (r == -ENOENT)
702 return -ENXIO;
703 if (r < 0)
704 return r;
705
706 if (s) {
707 a = strv_split(s, " ");
708 if (!a)
709 return -ENOMEM;
710 }
711
712 if (uids && t) {
713 const char *word, *state;
714 size_t l;
715
716 FOREACH_WORD(word, l, t, state)
717 n++;
718
719 if (n > 0) {
720 unsigned i = 0;
721
722 b = new(uid_t, n);
723 if (!b)
724 return -ENOMEM;
725
726 FOREACH_WORD(word, l, t, state) {
727 _cleanup_free_ char *k = NULL;
728
729 k = strndup(word, l);
730 if (!k)
731 return -ENOMEM;
732
733 r = parse_uid(k, b + i);
734 if (r < 0)
735 return r;
736
737 i++;
738 }
739 }
740 }
741
742 r = strv_length(a);
743
744 if (sessions)
745 *sessions = TAKE_PTR(a);
746
747 if (uids)
748 *uids = TAKE_PTR(b);
749
750 if (n_uids)
751 *n_uids = n;
752
753 return r;
754 }
755
756 static int seat_get_can(const char *seat, const char *variable) {
757 _cleanup_free_ char *p = NULL, *s = NULL;
758 int r;
759
760 assert(variable);
761
762 r = file_of_seat(seat, &p);
763 if (r < 0)
764 return r;
765
766 r = parse_env_file(p, NEWLINE,
767 variable, &s,
768 NULL);
769 if (r == -ENOENT)
770 return -ENXIO;
771 if (r < 0)
772 return r;
773 if (isempty(s))
774 return -ENODATA;
775
776 return parse_boolean(s);
777 }
778
779 _public_ int sd_seat_can_multi_session(const char *seat) {
780 return seat_get_can(seat, "CAN_MULTI_SESSION");
781 }
782
783 _public_ int sd_seat_can_tty(const char *seat) {
784 return seat_get_can(seat, "CAN_TTY");
785 }
786
787 _public_ int sd_seat_can_graphical(const char *seat) {
788 return seat_get_can(seat, "CAN_GRAPHICAL");
789 }
790
791 _public_ int sd_get_seats(char ***seats) {
792 int r;
793
794 r = get_files_in_directory("/run/systemd/seats/", seats);
795 if (r == -ENOENT) {
796 if (seats)
797 *seats = NULL;
798 return 0;
799 }
800 return r;
801 }
802
803 _public_ int sd_get_sessions(char ***sessions) {
804 int r;
805
806 r = get_files_in_directory("/run/systemd/sessions/", sessions);
807 if (r == -ENOENT) {
808 if (sessions)
809 *sessions = NULL;
810 return 0;
811 }
812 return r;
813 }
814
815 _public_ int sd_get_uids(uid_t **users) {
816 _cleanup_closedir_ DIR *d;
817 struct dirent *de;
818 int r = 0;
819 unsigned n = 0;
820 _cleanup_free_ uid_t *l = NULL;
821
822 d = opendir("/run/systemd/users/");
823 if (!d) {
824 if (errno == ENOENT) {
825 if (users)
826 *users = NULL;
827 return 0;
828 }
829 return -errno;
830 }
831
832 FOREACH_DIRENT_ALL(de, d, return -errno) {
833 int k;
834 uid_t uid;
835
836 dirent_ensure_type(d, de);
837
838 if (!dirent_is_file(de))
839 continue;
840
841 k = parse_uid(de->d_name, &uid);
842 if (k < 0)
843 continue;
844
845 if (users) {
846 if ((unsigned) r >= n) {
847 uid_t *t;
848
849 n = MAX(16, 2*r);
850 t = realloc(l, sizeof(uid_t) * n);
851 if (!t)
852 return -ENOMEM;
853
854 l = t;
855 }
856
857 assert((unsigned) r < n);
858 l[r++] = uid;
859 } else
860 r++;
861 }
862
863 if (users)
864 *users = TAKE_PTR(l);
865
866 return r;
867 }
868
869 _public_ int sd_get_machine_names(char ***machines) {
870 _cleanup_strv_free_ char **l = NULL;
871 char **a, **b;
872 int r;
873
874 r = get_files_in_directory("/run/systemd/machines/", &l);
875 if (r == -ENOENT) {
876 if (machines)
877 *machines = NULL;
878 return 0;
879 }
880 if (r < 0)
881 return r;
882
883 if (l) {
884 r = 0;
885
886 /* Filter out the unit: symlinks */
887 for (a = b = l; *a; a++) {
888 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
889 free(*a);
890 else {
891 *b = *a;
892 b++;
893 r++;
894 }
895 }
896
897 *b = NULL;
898 }
899
900 if (machines)
901 *machines = TAKE_PTR(l);
902
903 return r;
904 }
905
906 _public_ int sd_machine_get_class(const char *machine, char **class) {
907 _cleanup_free_ char *c = NULL;
908 const char *p;
909 int r;
910
911 assert_return(machine_name_is_valid(machine), -EINVAL);
912 assert_return(class, -EINVAL);
913
914 p = strjoina("/run/systemd/machines/", machine);
915 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
916 if (r == -ENOENT)
917 return -ENXIO;
918 if (r < 0)
919 return r;
920 if (!c)
921 return -EIO;
922
923 *class = TAKE_PTR(c);
924
925 return 0;
926 }
927
928 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
929 _cleanup_free_ char *netif = NULL;
930 size_t l, allocated = 0, nr = 0;
931 int *ni = NULL;
932 const char *p, *word, *state;
933 int r;
934
935 assert_return(machine_name_is_valid(machine), -EINVAL);
936 assert_return(ifindices, -EINVAL);
937
938 p = strjoina("/run/systemd/machines/", machine);
939 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
940 if (r == -ENOENT)
941 return -ENXIO;
942 if (r < 0)
943 return r;
944 if (!netif) {
945 *ifindices = NULL;
946 return 0;
947 }
948
949 FOREACH_WORD(word, l, netif, state) {
950 char buf[l+1];
951 int ifi;
952
953 *(char*) (mempcpy(buf, word, l)) = 0;
954
955 if (parse_ifindex(buf, &ifi) < 0)
956 continue;
957
958 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
959 free(ni);
960 return -ENOMEM;
961 }
962
963 ni[nr++] = ifi;
964 }
965
966 *ifindices = ni;
967 return nr;
968 }
969
970 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
971 return (int) (unsigned long) m - 1;
972 }
973
974 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
975 return (sd_login_monitor*) (unsigned long) (fd + 1);
976 }
977
978 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
979 _cleanup_close_ int fd = -1;
980 bool good = false;
981 int k;
982
983 assert_return(m, -EINVAL);
984
985 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
986 if (fd < 0)
987 return -errno;
988
989 if (!category || streq(category, "seat")) {
990 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
991 if (k < 0)
992 return -errno;
993
994 good = true;
995 }
996
997 if (!category || streq(category, "session")) {
998 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
999 if (k < 0)
1000 return -errno;
1001
1002 good = true;
1003 }
1004
1005 if (!category || streq(category, "uid")) {
1006 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1007 if (k < 0)
1008 return -errno;
1009
1010 good = true;
1011 }
1012
1013 if (!category || streq(category, "machine")) {
1014 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1015 if (k < 0)
1016 return -errno;
1017
1018 good = true;
1019 }
1020
1021 if (!good)
1022 return -EINVAL;
1023
1024 *m = FD_TO_MONITOR(fd);
1025 fd = -1;
1026
1027 return 0;
1028 }
1029
1030 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1031 int fd;
1032
1033 if (!m)
1034 return NULL;
1035
1036 fd = MONITOR_TO_FD(m);
1037 close_nointr(fd);
1038
1039 return NULL;
1040 }
1041
1042 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1043 int r;
1044
1045 assert_return(m, -EINVAL);
1046
1047 r = flush_fd(MONITOR_TO_FD(m));
1048 if (r < 0)
1049 return r;
1050
1051 return 0;
1052 }
1053
1054 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1055
1056 assert_return(m, -EINVAL);
1057
1058 return MONITOR_TO_FD(m);
1059 }
1060
1061 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1062
1063 assert_return(m, -EINVAL);
1064
1065 /* For now we will only return POLLIN here, since we don't
1066 * need anything else ever for inotify. However, let's have
1067 * this API to keep our options open should we later on need
1068 * it. */
1069 return POLLIN;
1070 }
1071
1072 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1073
1074 assert_return(m, -EINVAL);
1075 assert_return(timeout_usec, -EINVAL);
1076
1077 /* For now we will only return (uint64_t) -1, since we don't
1078 * need any timeout. However, let's have this API to keep our
1079 * options open should we later on need it. */
1080 *timeout_usec = (uint64_t) -1;
1081 return 0;
1082 }