]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-login/sd-login.c
Merge pull request #9620 from poettering/type-exec
[thirdparty/systemd.git] / src / libsystemd / sd-login / sd-login.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <errno.h>
4 #include <poll.h>
5 #include <string.h>
6 #include <sys/inotify.h>
7 #include <unistd.h>
8
9 #include "sd-login.h"
10
11 #include "alloc-util.h"
12 #include "cgroup-util.h"
13 #include "dirent-util.h"
14 #include "escape.h"
15 #include "fd-util.h"
16 #include "fileio.h"
17 #include "format-util.h"
18 #include "fs-util.h"
19 #include "hostname-util.h"
20 #include "io-util.h"
21 #include "login-util.h"
22 #include "macro.h"
23 #include "parse-util.h"
24 #include "path-util.h"
25 #include "socket-util.h"
26 #include "string-util.h"
27 #include "strv.h"
28 #include "user-util.h"
29 #include "util.h"
30
31 /* Error codes:
32 *
33 * invalid input parameters → -EINVAL
34 * invalid fd → -EBADF
35 * process does not exist → -ESRCH
36 * cgroup does not exist → -ENOENT
37 * machine, session does not exist → -ENXIO
38 * requested metadata on object is missing → -ENODATA
39 */
40
41 _public_ int sd_pid_get_session(pid_t pid, char **session) {
42 int r;
43
44 assert_return(pid >= 0, -EINVAL);
45 assert_return(session, -EINVAL);
46
47 r = cg_pid_get_session(pid, session);
48 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
49 }
50
51 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
52 int r;
53
54 assert_return(pid >= 0, -EINVAL);
55 assert_return(unit, -EINVAL);
56
57 r = cg_pid_get_unit(pid, unit);
58 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
59 }
60
61 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
62 int r;
63
64 assert_return(pid >= 0, -EINVAL);
65 assert_return(unit, -EINVAL);
66
67 r = cg_pid_get_user_unit(pid, unit);
68 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
69 }
70
71 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
72 int r;
73
74 assert_return(pid >= 0, -EINVAL);
75 assert_return(name, -EINVAL);
76
77 r = cg_pid_get_machine_name(pid, name);
78 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
79 }
80
81 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
82 int r;
83
84 assert_return(pid >= 0, -EINVAL);
85 assert_return(slice, -EINVAL);
86
87 r = cg_pid_get_slice(pid, slice);
88 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
89 }
90
91 _public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
92 int r;
93
94 assert_return(pid >= 0, -EINVAL);
95 assert_return(slice, -EINVAL);
96
97 r = cg_pid_get_user_slice(pid, slice);
98 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
99 }
100
101 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
102 int r;
103
104 assert_return(pid >= 0, -EINVAL);
105 assert_return(uid, -EINVAL);
106
107 r = cg_pid_get_owner_uid(pid, uid);
108 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
109 }
110
111 _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
112 char *c;
113 int r;
114
115 assert_return(pid >= 0, -EINVAL);
116 assert_return(cgroup, -EINVAL);
117
118 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c);
119 if (r < 0)
120 return r;
121
122 /* The internal APIs return the empty string for the root
123 * cgroup, let's return the "/" in the public APIs instead, as
124 * that's easier and less ambiguous for people to grok. */
125 if (isempty(c)) {
126 free(c);
127 c = strdup("/");
128 if (!c)
129 return -ENOMEM;
130
131 }
132
133 *cgroup = c;
134 return 0;
135 }
136
137 _public_ int sd_peer_get_session(int fd, char **session) {
138 struct ucred ucred = {};
139 int r;
140
141 assert_return(fd >= 0, -EBADF);
142 assert_return(session, -EINVAL);
143
144 r = getpeercred(fd, &ucred);
145 if (r < 0)
146 return r;
147
148 return cg_pid_get_session(ucred.pid, session);
149 }
150
151 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
152 struct ucred ucred;
153 int r;
154
155 assert_return(fd >= 0, -EBADF);
156 assert_return(uid, -EINVAL);
157
158 r = getpeercred(fd, &ucred);
159 if (r < 0)
160 return r;
161
162 return cg_pid_get_owner_uid(ucred.pid, uid);
163 }
164
165 _public_ int sd_peer_get_unit(int fd, char **unit) {
166 struct ucred ucred;
167 int r;
168
169 assert_return(fd >= 0, -EBADF);
170 assert_return(unit, -EINVAL);
171
172 r = getpeercred(fd, &ucred);
173 if (r < 0)
174 return r;
175
176 return cg_pid_get_unit(ucred.pid, unit);
177 }
178
179 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
180 struct ucred ucred;
181 int r;
182
183 assert_return(fd >= 0, -EBADF);
184 assert_return(unit, -EINVAL);
185
186 r = getpeercred(fd, &ucred);
187 if (r < 0)
188 return r;
189
190 return cg_pid_get_user_unit(ucred.pid, unit);
191 }
192
193 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
194 struct ucred ucred;
195 int r;
196
197 assert_return(fd >= 0, -EBADF);
198 assert_return(machine, -EINVAL);
199
200 r = getpeercred(fd, &ucred);
201 if (r < 0)
202 return r;
203
204 return cg_pid_get_machine_name(ucred.pid, machine);
205 }
206
207 _public_ int sd_peer_get_slice(int fd, char **slice) {
208 struct ucred ucred;
209 int r;
210
211 assert_return(fd >= 0, -EBADF);
212 assert_return(slice, -EINVAL);
213
214 r = getpeercred(fd, &ucred);
215 if (r < 0)
216 return r;
217
218 return cg_pid_get_slice(ucred.pid, slice);
219 }
220
221 _public_ int sd_peer_get_user_slice(int fd, char **slice) {
222 struct ucred ucred;
223 int r;
224
225 assert_return(fd >= 0, -EBADF);
226 assert_return(slice, -EINVAL);
227
228 r = getpeercred(fd, &ucred);
229 if (r < 0)
230 return r;
231
232 return cg_pid_get_user_slice(ucred.pid, slice);
233 }
234
235 _public_ int sd_peer_get_cgroup(int fd, char **cgroup) {
236 struct ucred ucred;
237 int r;
238
239 assert_return(fd >= 0, -EBADF);
240 assert_return(cgroup, -EINVAL);
241
242 r = getpeercred(fd, &ucred);
243 if (r < 0)
244 return r;
245
246 return sd_pid_get_cgroup(ucred.pid, cgroup);
247 }
248
249 static int file_of_uid(uid_t uid, char **p) {
250
251 assert_return(uid_is_valid(uid), -EINVAL);
252 assert(p);
253
254 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
255 return -ENOMEM;
256
257 return 0;
258 }
259
260 _public_ int sd_uid_get_state(uid_t uid, char**state) {
261 _cleanup_free_ char *p = NULL;
262 char *s = NULL;
263 int r;
264
265 assert_return(state, -EINVAL);
266
267 r = file_of_uid(uid, &p);
268 if (r < 0)
269 return r;
270
271 r = parse_env_file(NULL, p, NEWLINE, "STATE", &s, NULL);
272 if (r == -ENOENT) {
273 free(s);
274 s = strdup("offline");
275 if (!s)
276 return -ENOMEM;
277
278 }
279 else if (r < 0) {
280 free(s);
281 return r;
282 }
283 if (isempty(s)) {
284 free(s);
285 return -EIO;
286 }
287
288 *state = s;
289 return 0;
290 }
291
292 _public_ int sd_uid_get_display(uid_t uid, char **session) {
293 _cleanup_free_ char *p = NULL, *s = NULL;
294 int r;
295
296 assert_return(session, -EINVAL);
297
298 r = file_of_uid(uid, &p);
299 if (r < 0)
300 return r;
301
302 r = parse_env_file(NULL, p, NEWLINE, "DISPLAY", &s, NULL);
303 if (r == -ENOENT)
304 return -ENODATA;
305 if (r < 0)
306 return r;
307 if (isempty(s))
308 return -ENODATA;
309
310 *session = TAKE_PTR(s);
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 = TAKE_PTR(p);
340 return 0;
341 }
342
343 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
344 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
345 size_t l;
346 int r;
347 const char *word, *variable, *state;
348
349 assert_return(uid_is_valid(uid), -EINVAL);
350
351 r = file_of_seat(seat, &p);
352 if (r < 0)
353 return r;
354
355 variable = require_active ? "ACTIVE_UID" : "UIDS";
356
357 r = parse_env_file(NULL, p, NEWLINE, variable, &s, NULL);
358 if (r == -ENOENT)
359 return 0;
360 if (r < 0)
361 return r;
362 if (isempty(s))
363 return 0;
364
365 if (asprintf(&t, UID_FMT, uid) < 0)
366 return -ENOMEM;
367
368 FOREACH_WORD(word, l, s, state)
369 if (strneq(t, word, l))
370 return 1;
371
372 return 0;
373 }
374
375 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
376 _cleanup_free_ char *p = NULL, *s = NULL;
377 char **a;
378 int r;
379
380 assert(variable);
381
382 r = file_of_uid(uid, &p);
383 if (r < 0)
384 return r;
385
386 r = parse_env_file(NULL, p, NEWLINE, variable, &s, NULL);
387 if (r == -ENOENT || (r >= 0 && isempty(s))) {
388 if (array)
389 *array = NULL;
390 return 0;
391 }
392 if (r < 0)
393 return r;
394
395 a = strv_split(s, " ");
396 if (!a)
397 return -ENOMEM;
398
399 strv_uniq(a);
400 r = (int) strv_length(a);
401
402 if (array)
403 *array = a;
404 else
405 strv_free(a);
406
407 return r;
408 }
409
410 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
411 return uid_get_array(
412 uid,
413 require_active == 0 ? "ONLINE_SESSIONS" :
414 require_active > 0 ? "ACTIVE_SESSIONS" :
415 "SESSIONS",
416 sessions);
417 }
418
419 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
420 return uid_get_array(
421 uid,
422 require_active == 0 ? "ONLINE_SEATS" :
423 require_active > 0 ? "ACTIVE_SEATS" :
424 "SEATS",
425 seats);
426 }
427
428 static int file_of_session(const char *session, char **_p) {
429 char *p;
430 int r;
431
432 assert(_p);
433
434 if (session) {
435 if (!session_id_valid(session))
436 return -EINVAL;
437
438 p = strappend("/run/systemd/sessions/", session);
439 } else {
440 _cleanup_free_ char *buf = NULL;
441
442 r = sd_pid_get_session(0, &buf);
443 if (r < 0)
444 return r;
445
446 p = strappend("/run/systemd/sessions/", buf);
447 }
448
449 if (!p)
450 return -ENOMEM;
451
452 *_p = p;
453 return 0;
454 }
455
456 _public_ int sd_session_is_active(const char *session) {
457 _cleanup_free_ char *p = NULL, *s = NULL;
458 int r;
459
460 r = file_of_session(session, &p);
461 if (r < 0)
462 return r;
463
464 r = parse_env_file(NULL, p, NEWLINE, "ACTIVE", &s, NULL);
465 if (r == -ENOENT)
466 return -ENXIO;
467 if (r < 0)
468 return r;
469 if (isempty(s))
470 return -EIO;
471
472 return parse_boolean(s);
473 }
474
475 _public_ int sd_session_is_remote(const char *session) {
476 _cleanup_free_ char *p = NULL, *s = NULL;
477 int r;
478
479 r = file_of_session(session, &p);
480 if (r < 0)
481 return r;
482
483 r = parse_env_file(NULL, p, NEWLINE, "REMOTE", &s, NULL);
484 if (r == -ENOENT)
485 return -ENXIO;
486 if (r < 0)
487 return r;
488 if (isempty(s))
489 return -ENODATA;
490
491 return parse_boolean(s);
492 }
493
494 _public_ int sd_session_get_state(const char *session, char **state) {
495 _cleanup_free_ char *p = NULL, *s = NULL;
496 int r;
497
498 assert_return(state, -EINVAL);
499
500 r = file_of_session(session, &p);
501 if (r < 0)
502 return r;
503
504 r = parse_env_file(NULL, p, NEWLINE, "STATE", &s, NULL);
505 if (r == -ENOENT)
506 return -ENXIO;
507 if (r < 0)
508 return r;
509 if (isempty(s))
510 return -EIO;
511
512 *state = TAKE_PTR(s);
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(NULL, 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(NULL, 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 = TAKE_PTR(s);
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(NULL, 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 = TAKE_PTR(s);
664
665 return 0;
666 }
667
668 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
669 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
670 _cleanup_strv_free_ char **a = NULL;
671 _cleanup_free_ uid_t *b = NULL;
672 unsigned n = 0;
673 int r;
674
675 r = file_of_seat(seat, &p);
676 if (r < 0)
677 return r;
678
679 r = parse_env_file(NULL, p, NEWLINE,
680 "SESSIONS", &s,
681 "UIDS", &t,
682 NULL);
683 if (r == -ENOENT)
684 return -ENXIO;
685 if (r < 0)
686 return r;
687
688 if (s) {
689 a = strv_split(s, " ");
690 if (!a)
691 return -ENOMEM;
692 }
693
694 if (uids && t) {
695 const char *word, *state;
696 size_t l;
697
698 FOREACH_WORD(word, l, t, state)
699 n++;
700
701 if (n > 0) {
702 unsigned i = 0;
703
704 b = new(uid_t, n);
705 if (!b)
706 return -ENOMEM;
707
708 FOREACH_WORD(word, l, t, state) {
709 _cleanup_free_ char *k = NULL;
710
711 k = strndup(word, l);
712 if (!k)
713 return -ENOMEM;
714
715 r = parse_uid(k, b + i);
716 if (r < 0)
717 return r;
718
719 i++;
720 }
721 }
722 }
723
724 r = (int) strv_length(a);
725
726 if (sessions)
727 *sessions = TAKE_PTR(a);
728
729 if (uids)
730 *uids = TAKE_PTR(b);
731
732 if (n_uids)
733 *n_uids = n;
734
735 return r;
736 }
737
738 static int seat_get_can(const char *seat, const char *variable) {
739 _cleanup_free_ char *p = NULL, *s = NULL;
740 int r;
741
742 assert(variable);
743
744 r = file_of_seat(seat, &p);
745 if (r < 0)
746 return r;
747
748 r = parse_env_file(NULL, p, NEWLINE,
749 variable, &s,
750 NULL);
751 if (r == -ENOENT)
752 return -ENXIO;
753 if (r < 0)
754 return r;
755 if (isempty(s))
756 return -ENODATA;
757
758 return parse_boolean(s);
759 }
760
761 _public_ int sd_seat_can_multi_session(const char *seat) {
762 return seat_get_can(seat, "CAN_MULTI_SESSION");
763 }
764
765 _public_ int sd_seat_can_tty(const char *seat) {
766 return seat_get_can(seat, "CAN_TTY");
767 }
768
769 _public_ int sd_seat_can_graphical(const char *seat) {
770 return seat_get_can(seat, "CAN_GRAPHICAL");
771 }
772
773 _public_ int sd_get_seats(char ***seats) {
774 int r;
775
776 r = get_files_in_directory("/run/systemd/seats/", seats);
777 if (r == -ENOENT) {
778 if (seats)
779 *seats = NULL;
780 return 0;
781 }
782 return r;
783 }
784
785 _public_ int sd_get_sessions(char ***sessions) {
786 int r;
787
788 r = get_files_in_directory("/run/systemd/sessions/", sessions);
789 if (r == -ENOENT) {
790 if (sessions)
791 *sessions = NULL;
792 return 0;
793 }
794 return r;
795 }
796
797 _public_ int sd_get_uids(uid_t **users) {
798 _cleanup_closedir_ DIR *d;
799 struct dirent *de;
800 int r = 0;
801 unsigned n = 0;
802 _cleanup_free_ uid_t *l = NULL;
803
804 d = opendir("/run/systemd/users/");
805 if (!d) {
806 if (errno == ENOENT) {
807 if (users)
808 *users = NULL;
809 return 0;
810 }
811 return -errno;
812 }
813
814 FOREACH_DIRENT_ALL(de, d, return -errno) {
815 int k;
816 uid_t uid;
817
818 dirent_ensure_type(d, de);
819
820 if (!dirent_is_file(de))
821 continue;
822
823 k = parse_uid(de->d_name, &uid);
824 if (k < 0)
825 continue;
826
827 if (users) {
828 if ((unsigned) r >= n) {
829 uid_t *t;
830
831 n = MAX(16, 2*r);
832 t = realloc(l, sizeof(uid_t) * n);
833 if (!t)
834 return -ENOMEM;
835
836 l = t;
837 }
838
839 assert((unsigned) r < n);
840 l[r++] = uid;
841 } else
842 r++;
843 }
844
845 if (users)
846 *users = TAKE_PTR(l);
847
848 return r;
849 }
850
851 _public_ int sd_get_machine_names(char ***machines) {
852 _cleanup_strv_free_ char **l = NULL;
853 char **a, **b;
854 int r;
855
856 r = get_files_in_directory("/run/systemd/machines/", &l);
857 if (r == -ENOENT) {
858 if (machines)
859 *machines = NULL;
860 return 0;
861 }
862 if (r < 0)
863 return r;
864
865 if (l) {
866 r = 0;
867
868 /* Filter out the unit: symlinks */
869 for (a = b = l; *a; a++) {
870 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
871 free(*a);
872 else {
873 *b = *a;
874 b++;
875 r++;
876 }
877 }
878
879 *b = NULL;
880 }
881
882 if (machines)
883 *machines = TAKE_PTR(l);
884
885 return r;
886 }
887
888 _public_ int sd_machine_get_class(const char *machine, char **class) {
889 _cleanup_free_ char *c = NULL;
890 const char *p;
891 int r;
892
893 assert_return(class, -EINVAL);
894
895 if (streq(machine, ".host")) {
896 c = strdup("host");
897 if (!c)
898 return -ENOMEM;
899 } else {
900 if (!machine_name_is_valid(machine))
901 return -EINVAL;
902
903 p = strjoina("/run/systemd/machines/", machine);
904 r = parse_env_file(NULL, p, NEWLINE, "CLASS", &c, NULL);
905 if (r == -ENOENT)
906 return -ENXIO;
907 if (r < 0)
908 return r;
909 if (!c)
910 return -EIO;
911 }
912
913 *class = TAKE_PTR(c);
914 return 0;
915 }
916
917 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
918 _cleanup_free_ char *netif = NULL;
919 size_t l, allocated = 0, nr = 0;
920 int *ni = NULL;
921 const char *p, *word, *state;
922 int r;
923
924 assert_return(machine_name_is_valid(machine), -EINVAL);
925 assert_return(ifindices, -EINVAL);
926
927 p = strjoina("/run/systemd/machines/", machine);
928 r = parse_env_file(NULL, p, NEWLINE, "NETIF", &netif, NULL);
929 if (r == -ENOENT)
930 return -ENXIO;
931 if (r < 0)
932 return r;
933 if (!netif) {
934 *ifindices = NULL;
935 return 0;
936 }
937
938 FOREACH_WORD(word, l, netif, state) {
939 char buf[l+1];
940 int ifi;
941
942 *(char*) (mempcpy(buf, word, l)) = 0;
943
944 if (parse_ifindex(buf, &ifi) < 0)
945 continue;
946
947 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
948 free(ni);
949 return -ENOMEM;
950 }
951
952 ni[nr++] = ifi;
953 }
954
955 *ifindices = ni;
956 return nr;
957 }
958
959 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
960 return (int) (unsigned long) m - 1;
961 }
962
963 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
964 return (sd_login_monitor*) (unsigned long) (fd + 1);
965 }
966
967 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
968 _cleanup_close_ int fd = -1;
969 bool good = false;
970 int k;
971
972 assert_return(m, -EINVAL);
973
974 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
975 if (fd < 0)
976 return -errno;
977
978 if (!category || streq(category, "seat")) {
979 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
980 if (k < 0)
981 return -errno;
982
983 good = true;
984 }
985
986 if (!category || streq(category, "session")) {
987 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
988 if (k < 0)
989 return -errno;
990
991 good = true;
992 }
993
994 if (!category || streq(category, "uid")) {
995 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
996 if (k < 0)
997 return -errno;
998
999 good = true;
1000 }
1001
1002 if (!category || streq(category, "machine")) {
1003 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1004 if (k < 0)
1005 return -errno;
1006
1007 good = true;
1008 }
1009
1010 if (!good)
1011 return -EINVAL;
1012
1013 *m = FD_TO_MONITOR(fd);
1014 fd = -1;
1015
1016 return 0;
1017 }
1018
1019 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1020 int fd;
1021
1022 if (!m)
1023 return NULL;
1024
1025 fd = MONITOR_TO_FD(m);
1026 close_nointr(fd);
1027
1028 return NULL;
1029 }
1030
1031 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1032 int r;
1033
1034 assert_return(m, -EINVAL);
1035
1036 r = flush_fd(MONITOR_TO_FD(m));
1037 if (r < 0)
1038 return r;
1039
1040 return 0;
1041 }
1042
1043 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1044
1045 assert_return(m, -EINVAL);
1046
1047 return MONITOR_TO_FD(m);
1048 }
1049
1050 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1051
1052 assert_return(m, -EINVAL);
1053
1054 /* For now we will only return POLLIN here, since we don't
1055 * need anything else ever for inotify. However, let's have
1056 * this API to keep our options open should we later on need
1057 * it. */
1058 return POLLIN;
1059 }
1060
1061 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1062
1063 assert_return(m, -EINVAL);
1064 assert_return(timeout_usec, -EINVAL);
1065
1066 /* For now we will only return (uint64_t) -1, since we don't
1067 * need any timeout. However, let's have this API to keep our
1068 * options open should we later on need it. */
1069 *timeout_usec = (uint64_t) -1;
1070 return 0;
1071 }