]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-login/sd-login.c
Merge pull request #2373 from keszybz/man-api-build-3
[thirdparty/systemd.git] / src / libsystemd / sd-login / sd-login.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <errno.h>
23 #include <poll.h>
24 #include <string.h>
25 #include <sys/inotify.h>
26 #include <unistd.h>
27
28 #include "sd-login.h"
29
30 #include "alloc-util.h"
31 #include "cgroup-util.h"
32 #include "dirent-util.h"
33 #include "escape.h"
34 #include "fd-util.h"
35 #include "fileio.h"
36 #include "formats-util.h"
37 #include "fs-util.h"
38 #include "hostname-util.h"
39 #include "io-util.h"
40 #include "login-util.h"
41 #include "macro.h"
42 #include "parse-util.h"
43 #include "path-util.h"
44 #include "socket-util.h"
45 #include "string-util.h"
46 #include "strv.h"
47 #include "user-util.h"
48 #include "util.h"
49
50 /* Error codes:
51 *
52 * invalid input parameters → -EINVAL
53 * invalid fd → -EBADF
54 * process does not exist → -ESRCH
55 * cgroup does not exist → -ENOENT
56 * machine, session does not exist → -ENXIO
57 * requested metadata on object is missing → -ENODATA
58 */
59
60 _public_ int sd_pid_get_session(pid_t pid, char **session) {
61
62 assert_return(pid >= 0, -EINVAL);
63 assert_return(session, -EINVAL);
64
65 return cg_pid_get_session(pid, session);
66 }
67
68 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
69
70 assert_return(pid >= 0, -EINVAL);
71 assert_return(unit, -EINVAL);
72
73 return cg_pid_get_unit(pid, unit);
74 }
75
76 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
77
78 assert_return(pid >= 0, -EINVAL);
79 assert_return(unit, -EINVAL);
80
81 return cg_pid_get_user_unit(pid, unit);
82 }
83
84 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
85
86 assert_return(pid >= 0, -EINVAL);
87 assert_return(name, -EINVAL);
88
89 return cg_pid_get_machine_name(pid, name);
90 }
91
92 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
93
94 assert_return(pid >= 0, -EINVAL);
95 assert_return(slice, -EINVAL);
96
97 return cg_pid_get_slice(pid, slice);
98 }
99
100 _public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
101
102 assert_return(pid >= 0, -EINVAL);
103 assert_return(slice, -EINVAL);
104
105 return cg_pid_get_user_slice(pid, slice);
106 }
107
108 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
109
110 assert_return(pid >= 0, -EINVAL);
111 assert_return(uid, -EINVAL);
112
113 return cg_pid_get_owner_uid(pid, uid);
114 }
115
116 _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
117 char *c;
118 int r;
119
120 assert_return(pid >= 0, -EINVAL);
121 assert_return(cgroup, -EINVAL);
122
123 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c);
124 if (r < 0)
125 return r;
126
127 /* The internal APIs return the empty string for the root
128 * cgroup, let's return the "/" in the public APIs instead, as
129 * that's easier and less ambigious for people to grok. */
130 if (isempty(c)) {
131 free(c);
132 c = strdup("/");
133 if (!c)
134 return -ENOMEM;
135
136 }
137
138 *cgroup = c;
139 return 0;
140 }
141
142 _public_ int sd_peer_get_session(int fd, char **session) {
143 struct ucred ucred = {};
144 int r;
145
146 assert_return(fd >= 0, -EBADF);
147 assert_return(session, -EINVAL);
148
149 r = getpeercred(fd, &ucred);
150 if (r < 0)
151 return r;
152
153 return cg_pid_get_session(ucred.pid, session);
154 }
155
156 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
157 struct ucred ucred;
158 int r;
159
160 assert_return(fd >= 0, -EBADF);
161 assert_return(uid, -EINVAL);
162
163 r = getpeercred(fd, &ucred);
164 if (r < 0)
165 return r;
166
167 return cg_pid_get_owner_uid(ucred.pid, uid);
168 }
169
170 _public_ int sd_peer_get_unit(int fd, char **unit) {
171 struct ucred ucred;
172 int r;
173
174 assert_return(fd >= 0, -EBADF);
175 assert_return(unit, -EINVAL);
176
177 r = getpeercred(fd, &ucred);
178 if (r < 0)
179 return r;
180
181 return cg_pid_get_unit(ucred.pid, unit);
182 }
183
184 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
185 struct ucred ucred;
186 int r;
187
188 assert_return(fd >= 0, -EBADF);
189 assert_return(unit, -EINVAL);
190
191 r = getpeercred(fd, &ucred);
192 if (r < 0)
193 return r;
194
195 return cg_pid_get_user_unit(ucred.pid, unit);
196 }
197
198 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
199 struct ucred ucred;
200 int r;
201
202 assert_return(fd >= 0, -EBADF);
203 assert_return(machine, -EINVAL);
204
205 r = getpeercred(fd, &ucred);
206 if (r < 0)
207 return r;
208
209 return cg_pid_get_machine_name(ucred.pid, machine);
210 }
211
212 _public_ int sd_peer_get_slice(int fd, char **slice) {
213 struct ucred ucred;
214 int r;
215
216 assert_return(fd >= 0, -EBADF);
217 assert_return(slice, -EINVAL);
218
219 r = getpeercred(fd, &ucred);
220 if (r < 0)
221 return r;
222
223 return cg_pid_get_slice(ucred.pid, slice);
224 }
225
226 _public_ int sd_peer_get_user_slice(int fd, char **slice) {
227 struct ucred ucred;
228 int r;
229
230 assert_return(fd >= 0, -EBADF);
231 assert_return(slice, -EINVAL);
232
233 r = getpeercred(fd, &ucred);
234 if (r < 0)
235 return r;
236
237 return cg_pid_get_user_slice(ucred.pid, slice);
238 }
239
240 _public_ int sd_peer_get_cgroup(int fd, char **cgroup) {
241 struct ucred ucred;
242 int r;
243
244 assert_return(fd >= 0, -EBADF);
245 assert_return(cgroup, -EINVAL);
246
247 r = getpeercred(fd, &ucred);
248 if (r < 0)
249 return r;
250
251 return sd_pid_get_cgroup(ucred.pid, cgroup);
252 }
253
254 static int file_of_uid(uid_t uid, char **p) {
255
256 assert_return(uid_is_valid(uid), -EINVAL);
257 assert(p);
258
259 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
260 return -ENOMEM;
261
262 return 0;
263 }
264
265 _public_ int sd_uid_get_state(uid_t uid, char**state) {
266 _cleanup_free_ char *p = NULL;
267 char *s = NULL;
268 int r;
269
270 assert_return(state, -EINVAL);
271
272 r = file_of_uid(uid, &p);
273 if (r < 0)
274 return r;
275
276 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
277 if (r == -ENOENT) {
278 free(s);
279 s = strdup("offline");
280 if (!s)
281 return -ENOMEM;
282
283 }
284 if (r < 0) {
285 free(s);
286 return r;
287 }
288 if (isempty(s)) {
289 free(s);
290 return -EIO;
291 }
292
293 *state = s;
294 return 0;
295 }
296
297 _public_ int sd_uid_get_display(uid_t uid, char **session) {
298 _cleanup_free_ char *p = NULL, *s = NULL;
299 int r;
300
301 assert_return(session, -EINVAL);
302
303 r = file_of_uid(uid, &p);
304 if (r < 0)
305 return r;
306
307 r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
308 if (r == -ENOENT)
309 return -ENODATA;
310 if (r < 0)
311 return r;
312 if (isempty(s))
313 return -ENODATA;
314
315 *session = s;
316 s = NULL;
317
318 return 0;
319 }
320
321 static int file_of_seat(const char *seat, char **_p) {
322 char *p;
323 int r;
324
325 assert(_p);
326
327 if (seat) {
328 if (!filename_is_valid(seat))
329 return -EINVAL;
330
331 p = strappend("/run/systemd/seats/", seat);
332 } else {
333 _cleanup_free_ char *buf = NULL;
334
335 r = sd_session_get_seat(NULL, &buf);
336 if (r < 0)
337 return r;
338
339 p = strappend("/run/systemd/seats/", buf);
340 }
341
342 if (!p)
343 return -ENOMEM;
344
345 *_p = p;
346 p = NULL;
347 return 0;
348 }
349
350 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
351 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
352 size_t l;
353 int r;
354 const char *word, *variable, *state;
355
356 assert_return(uid_is_valid(uid), -EINVAL);
357
358 r = file_of_seat(seat, &p);
359 if (r < 0)
360 return r;
361
362 variable = require_active ? "ACTIVE_UID" : "UIDS";
363
364 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
365 if (r == -ENOENT)
366 return 0;
367 if (r < 0)
368 return r;
369 if (isempty(s))
370 return 0;
371
372 if (asprintf(&t, UID_FMT, uid) < 0)
373 return -ENOMEM;
374
375 FOREACH_WORD(word, l, s, state)
376 if (strneq(t, word, l))
377 return 1;
378
379 return 0;
380 }
381
382 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
383 _cleanup_free_ char *p = NULL, *s = NULL;
384 char **a;
385 int r;
386
387 assert(variable);
388
389 r = file_of_uid(uid, &p);
390 if (r < 0)
391 return r;
392
393 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
394 if (r == -ENOENT || (r >= 0 && isempty(s))) {
395 if (array)
396 *array = NULL;
397 return 0;
398 }
399 if (r < 0)
400 return r;
401
402 a = strv_split(s, " ");
403 if (!a)
404 return -ENOMEM;
405
406 strv_uniq(a);
407 r = strv_length(a);
408
409 if (array)
410 *array = a;
411 else
412 strv_free(a);
413
414 return r;
415 }
416
417 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
418 return uid_get_array(
419 uid,
420 require_active == 0 ? "ONLINE_SESSIONS" :
421 require_active > 0 ? "ACTIVE_SESSIONS" :
422 "SESSIONS",
423 sessions);
424 }
425
426 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
427 return uid_get_array(
428 uid,
429 require_active == 0 ? "ONLINE_SEATS" :
430 require_active > 0 ? "ACTIVE_SEATS" :
431 "SEATS",
432 seats);
433 }
434
435 static int file_of_session(const char *session, char **_p) {
436 char *p;
437 int r;
438
439 assert(_p);
440
441 if (session) {
442 if (!session_id_valid(session))
443 return -EINVAL;
444
445 p = strappend("/run/systemd/sessions/", session);
446 } else {
447 _cleanup_free_ char *buf = NULL;
448
449 r = sd_pid_get_session(0, &buf);
450 if (r < 0)
451 return r;
452
453 p = strappend("/run/systemd/sessions/", buf);
454 }
455
456 if (!p)
457 return -ENOMEM;
458
459 *_p = p;
460 return 0;
461 }
462
463 _public_ int sd_session_is_active(const char *session) {
464 _cleanup_free_ char *p = NULL, *s = NULL;
465 int r;
466
467 r = file_of_session(session, &p);
468 if (r < 0)
469 return r;
470
471 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
472 if (r == -ENOENT)
473 return -ENXIO;
474 if (r < 0)
475 return r;
476 if (isempty(s))
477 return -EIO;
478
479 return parse_boolean(s);
480 }
481
482 _public_ int sd_session_is_remote(const char *session) {
483 _cleanup_free_ char *p = NULL, *s = NULL;
484 int r;
485
486 r = file_of_session(session, &p);
487 if (r < 0)
488 return r;
489
490 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
491 if (r == -ENOENT)
492 return -ENXIO;
493 if (r < 0)
494 return r;
495 if (isempty(s))
496 return -ENODATA;
497
498 return parse_boolean(s);
499 }
500
501 _public_ int sd_session_get_state(const char *session, char **state) {
502 _cleanup_free_ char *p = NULL, *s = NULL;
503 int r;
504
505 assert_return(state, -EINVAL);
506
507 r = file_of_session(session, &p);
508 if (r < 0)
509 return r;
510
511 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
512 if (r == -ENOENT)
513 return -ENXIO;
514 if (r < 0)
515 return r;
516 if (isempty(s))
517 return -EIO;
518
519 *state = s;
520 s = NULL;
521
522 return 0;
523 }
524
525 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
526 int r;
527 _cleanup_free_ char *p = NULL, *s = NULL;
528
529 assert_return(uid, -EINVAL);
530
531 r = file_of_session(session, &p);
532 if (r < 0)
533 return r;
534
535 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
536 if (r == -ENOENT)
537 return -ENXIO;
538 if (r < 0)
539 return r;
540 if (isempty(s))
541 return -EIO;
542
543 return parse_uid(s, uid);
544 }
545
546 static int session_get_string(const char *session, const char *field, char **value) {
547 _cleanup_free_ char *p = NULL, *s = NULL;
548 int r;
549
550 assert_return(value, -EINVAL);
551 assert(field);
552
553 r = file_of_session(session, &p);
554 if (r < 0)
555 return r;
556
557 r = parse_env_file(p, NEWLINE, field, &s, NULL);
558 if (r == -ENOENT)
559 return -ENXIO;
560 if (r < 0)
561 return r;
562 if (isempty(s))
563 return -ENODATA;
564
565 *value = s;
566 s = NULL;
567 return 0;
568 }
569
570 _public_ int sd_session_get_seat(const char *session, char **seat) {
571 return session_get_string(session, "SEAT", seat);
572 }
573
574 _public_ int sd_session_get_tty(const char *session, char **tty) {
575 return session_get_string(session, "TTY", tty);
576 }
577
578 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
579 _cleanup_free_ char *vtnr_string = NULL;
580 unsigned u;
581 int r;
582
583 assert_return(vtnr, -EINVAL);
584
585 r = session_get_string(session, "VTNR", &vtnr_string);
586 if (r < 0)
587 return r;
588
589 r = safe_atou(vtnr_string, &u);
590 if (r < 0)
591 return r;
592
593 *vtnr = u;
594 return 0;
595 }
596
597 _public_ int sd_session_get_service(const char *session, char **service) {
598 return session_get_string(session, "SERVICE", service);
599 }
600
601 _public_ int sd_session_get_type(const char *session, char **type) {
602 return session_get_string(session, "TYPE", type);
603 }
604
605 _public_ int sd_session_get_class(const char *session, char **class) {
606 return session_get_string(session, "CLASS", class);
607 }
608
609 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
610 _cleanup_free_ char *escaped = NULL;
611 char *t;
612 int r;
613
614 assert_return(desktop, -EINVAL);
615
616 r = session_get_string(session, "DESKTOP", &escaped);
617 if (r < 0)
618 return r;
619
620 r = cunescape(escaped, 0, &t);
621 if (r < 0)
622 return r;
623
624 *desktop = t;
625 return 0;
626 }
627
628 _public_ int sd_session_get_display(const char *session, char **display) {
629 return session_get_string(session, "DISPLAY", display);
630 }
631
632 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
633 return session_get_string(session, "REMOTE_USER", remote_user);
634 }
635
636 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
637 return session_get_string(session, "REMOTE_HOST", remote_host);
638 }
639
640 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
641 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
642 int r;
643
644 assert_return(session || uid, -EINVAL);
645
646 r = file_of_seat(seat, &p);
647 if (r < 0)
648 return r;
649
650 r = parse_env_file(p, NEWLINE,
651 "ACTIVE", &s,
652 "ACTIVE_UID", &t,
653 NULL);
654 if (r == -ENOENT)
655 return -ENXIO;
656 if (r < 0)
657 return r;
658
659 if (session && !s)
660 return -ENODATA;
661
662 if (uid && !t)
663 return -ENODATA;
664
665 if (uid && t) {
666 r = parse_uid(t, uid);
667 if (r < 0)
668 return r;
669 }
670
671 if (session && s) {
672 *session = s;
673 s = NULL;
674 }
675
676 return 0;
677 }
678
679 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
680 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
681 _cleanup_strv_free_ char **a = NULL;
682 _cleanup_free_ uid_t *b = NULL;
683 unsigned n = 0;
684 int r;
685
686 r = file_of_seat(seat, &p);
687 if (r < 0)
688 return r;
689
690 r = parse_env_file(p, NEWLINE,
691 "SESSIONS", &s,
692 "ACTIVE_SESSIONS", &t,
693 NULL);
694 if (r == -ENOENT)
695 return -ENXIO;
696 if (r < 0)
697 return r;
698
699 if (s) {
700 a = strv_split(s, " ");
701 if (!a)
702 return -ENOMEM;
703 }
704
705 if (uids && t) {
706 const char *word, *state;
707 size_t l;
708
709 FOREACH_WORD(word, l, t, state)
710 n++;
711
712 if (n > 0) {
713 unsigned i = 0;
714
715 b = new(uid_t, n);
716 if (!b)
717 return -ENOMEM;
718
719 FOREACH_WORD(word, l, t, state) {
720 _cleanup_free_ char *k = NULL;
721
722 k = strndup(word, l);
723 if (!k)
724 return -ENOMEM;
725
726 r = parse_uid(k, b + i);
727 if (r < 0)
728 continue;
729
730 i++;
731 }
732 }
733 }
734
735 r = strv_length(a);
736
737 if (sessions) {
738 *sessions = a;
739 a = NULL;
740 }
741
742 if (uids) {
743 *uids = b;
744 b = NULL;
745 }
746
747 if (n_uids)
748 *n_uids = n;
749
750 return r;
751 }
752
753 static int seat_get_can(const char *seat, const char *variable) {
754 _cleanup_free_ char *p = NULL, *s = NULL;
755 int r;
756
757 assert(variable);
758
759 r = file_of_seat(seat, &p);
760 if (r < 0)
761 return r;
762
763 r = parse_env_file(p, NEWLINE,
764 variable, &s,
765 NULL);
766 if (r == -ENOENT)
767 return -ENXIO;
768 if (r < 0)
769 return r;
770 if (isempty(s))
771 return -ENODATA;
772
773 return parse_boolean(s);
774 }
775
776 _public_ int sd_seat_can_multi_session(const char *seat) {
777 return seat_get_can(seat, "CAN_MULTI_SESSION");
778 }
779
780 _public_ int sd_seat_can_tty(const char *seat) {
781 return seat_get_can(seat, "CAN_TTY");
782 }
783
784 _public_ int sd_seat_can_graphical(const char *seat) {
785 return seat_get_can(seat, "CAN_GRAPHICAL");
786 }
787
788 _public_ int sd_get_seats(char ***seats) {
789 return get_files_in_directory("/run/systemd/seats/", seats);
790 }
791
792 _public_ int sd_get_sessions(char ***sessions) {
793 return get_files_in_directory("/run/systemd/sessions/", sessions);
794 }
795
796 _public_ int sd_get_uids(uid_t **users) {
797 _cleanup_closedir_ DIR *d;
798 int r = 0;
799 unsigned n = 0;
800 _cleanup_free_ uid_t *l = NULL;
801
802 d = opendir("/run/systemd/users/");
803 if (!d)
804 return -errno;
805
806 for (;;) {
807 struct dirent *de;
808 int k;
809 uid_t uid;
810
811 errno = 0;
812 de = readdir(d);
813 if (!de && errno > 0)
814 return -errno;
815
816 if (!de)
817 break;
818
819 dirent_ensure_type(d, de);
820
821 if (!dirent_is_file(de))
822 continue;
823
824 k = parse_uid(de->d_name, &uid);
825 if (k < 0)
826 continue;
827
828 if (users) {
829 if ((unsigned) r >= n) {
830 uid_t *t;
831
832 n = MAX(16, 2*r);
833 t = realloc(l, sizeof(uid_t) * n);
834 if (!t)
835 return -ENOMEM;
836
837 l = t;
838 }
839
840 assert((unsigned) r < n);
841 l[r++] = uid;
842 } else
843 r++;
844 }
845
846 if (users) {
847 *users = l;
848 l = NULL;
849 }
850
851 return r;
852 }
853
854 _public_ int sd_get_machine_names(char ***machines) {
855 char **l = NULL, **a, **b;
856 int r;
857
858 assert_return(machines, -EINVAL);
859
860 r = get_files_in_directory("/run/systemd/machines/", &l);
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 }