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