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