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