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