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