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