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