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