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