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