]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-login/sd-login.c
Merge pull request #4859 from keszybz/networkd
[thirdparty/systemd.git] / src / libsystemd / sd-login / sd-login.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2011 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <poll.h>
22 #include <string.h>
23 #include <sys/inotify.h>
24 #include <unistd.h>
25
26 #include "sd-login.h"
27
28 #include "alloc-util.h"
29 #include "cgroup-util.h"
30 #include "dirent-util.h"
31 #include "escape.h"
32 #include "fd-util.h"
33 #include "fileio.h"
34 #include "format-util.h"
35 #include "fs-util.h"
36 #include "hostname-util.h"
37 #include "io-util.h"
38 #include "login-util.h"
39 #include "macro.h"
40 #include "parse-util.h"
41 #include "path-util.h"
42 #include "socket-util.h"
43 #include "string-util.h"
44 #include "strv.h"
45 #include "user-util.h"
46 #include "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 ambiguous 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 struct dirent *de;
797 int r = 0;
798 unsigned n = 0;
799 _cleanup_free_ uid_t *l = NULL;
800
801 d = opendir("/run/systemd/users/");
802 if (!d)
803 return -errno;
804
805 FOREACH_DIRENT_ALL(de, d, return -errno) {
806 int k;
807 uid_t uid;
808
809 dirent_ensure_type(d, de);
810
811 if (!dirent_is_file(de))
812 continue;
813
814 k = parse_uid(de->d_name, &uid);
815 if (k < 0)
816 continue;
817
818 if (users) {
819 if ((unsigned) r >= n) {
820 uid_t *t;
821
822 n = MAX(16, 2*r);
823 t = realloc(l, sizeof(uid_t) * n);
824 if (!t)
825 return -ENOMEM;
826
827 l = t;
828 }
829
830 assert((unsigned) r < n);
831 l[r++] = uid;
832 } else
833 r++;
834 }
835
836 if (users) {
837 *users = l;
838 l = NULL;
839 }
840
841 return r;
842 }
843
844 _public_ int sd_get_machine_names(char ***machines) {
845 char **l = NULL, **a, **b;
846 int r;
847
848 assert_return(machines, -EINVAL);
849
850 r = get_files_in_directory("/run/systemd/machines/", &l);
851 if (r < 0)
852 return r;
853
854 if (l) {
855 r = 0;
856
857 /* Filter out the unit: symlinks */
858 for (a = l, b = l; *a; a++) {
859 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
860 free(*a);
861 else {
862 *b = *a;
863 b++;
864 r++;
865 }
866 }
867
868 *b = NULL;
869 }
870
871 *machines = l;
872 return r;
873 }
874
875 _public_ int sd_machine_get_class(const char *machine, char **class) {
876 _cleanup_free_ char *c = NULL;
877 const char *p;
878 int r;
879
880 assert_return(machine_name_is_valid(machine), -EINVAL);
881 assert_return(class, -EINVAL);
882
883 p = strjoina("/run/systemd/machines/", machine);
884 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
885 if (r == -ENOENT)
886 return -ENXIO;
887 if (r < 0)
888 return r;
889 if (!c)
890 return -EIO;
891
892 *class = c;
893 c = NULL;
894
895 return 0;
896 }
897
898 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
899 _cleanup_free_ char *netif = NULL;
900 size_t l, allocated = 0, nr = 0;
901 int *ni = NULL;
902 const char *p, *word, *state;
903 int r;
904
905 assert_return(machine_name_is_valid(machine), -EINVAL);
906 assert_return(ifindices, -EINVAL);
907
908 p = strjoina("/run/systemd/machines/", machine);
909 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
910 if (r == -ENOENT)
911 return -ENXIO;
912 if (r < 0)
913 return r;
914 if (!netif) {
915 *ifindices = NULL;
916 return 0;
917 }
918
919 FOREACH_WORD(word, l, netif, state) {
920 char buf[l+1];
921 int ifi;
922
923 *(char*) (mempcpy(buf, word, l)) = 0;
924
925 if (parse_ifindex(buf, &ifi) < 0)
926 continue;
927
928 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
929 free(ni);
930 return -ENOMEM;
931 }
932
933 ni[nr++] = ifi;
934 }
935
936 *ifindices = ni;
937 return nr;
938 }
939
940 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
941 return (int) (unsigned long) m - 1;
942 }
943
944 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
945 return (sd_login_monitor*) (unsigned long) (fd + 1);
946 }
947
948 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
949 int fd, k;
950 bool good = false;
951
952 assert_return(m, -EINVAL);
953
954 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
955 if (fd < 0)
956 return -errno;
957
958 if (!category || streq(category, "seat")) {
959 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
960 if (k < 0) {
961 safe_close(fd);
962 return -errno;
963 }
964
965 good = true;
966 }
967
968 if (!category || streq(category, "session")) {
969 k = inotify_add_watch(fd, "/run/systemd/sessions/", 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, "uid")) {
979 k = inotify_add_watch(fd, "/run/systemd/users/", 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, "machine")) {
989 k = inotify_add_watch(fd, "/run/systemd/machines/", 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 (!good) {
999 close_nointr(fd);
1000 return -EINVAL;
1001 }
1002
1003 *m = FD_TO_MONITOR(fd);
1004 return 0;
1005 }
1006
1007 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1008 int fd;
1009
1010 if (!m)
1011 return NULL;
1012
1013 fd = MONITOR_TO_FD(m);
1014 close_nointr(fd);
1015
1016 return NULL;
1017 }
1018
1019 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1020
1021 assert_return(m, -EINVAL);
1022
1023 return flush_fd(MONITOR_TO_FD(m));
1024 }
1025
1026 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1027
1028 assert_return(m, -EINVAL);
1029
1030 return MONITOR_TO_FD(m);
1031 }
1032
1033 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1034
1035 assert_return(m, -EINVAL);
1036
1037 /* For now we will only return POLLIN here, since we don't
1038 * need anything else ever for inotify. However, let's have
1039 * this API to keep our options open should we later on need
1040 * it. */
1041 return POLLIN;
1042 }
1043
1044 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1045
1046 assert_return(m, -EINVAL);
1047 assert_return(timeout_usec, -EINVAL);
1048
1049 /* For now we will only return (uint64_t) -1, since we don't
1050 * need any timeout. However, let's have this API to keep our
1051 * options open should we later on need it. */
1052 *timeout_usec = (uint64_t) -1;
1053 return 0;
1054 }