]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-login/sd-login.c
macro: introduce TAKE_PTR() macro
[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 = TAKE_PTR(s);
329
330 return 0;
331 }
332
333 static int file_of_seat(const char *seat, char **_p) {
334 char *p;
335 int r;
336
337 assert(_p);
338
339 if (seat) {
340 if (!filename_is_valid(seat))
341 return -EINVAL;
342
343 p = strappend("/run/systemd/seats/", seat);
344 } else {
345 _cleanup_free_ char *buf = NULL;
346
347 r = sd_session_get_seat(NULL, &buf);
348 if (r < 0)
349 return r;
350
351 p = strappend("/run/systemd/seats/", buf);
352 }
353
354 if (!p)
355 return -ENOMEM;
356
357 *_p = TAKE_PTR(p);
358 return 0;
359 }
360
361 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
362 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
363 size_t l;
364 int r;
365 const char *word, *variable, *state;
366
367 assert_return(uid_is_valid(uid), -EINVAL);
368
369 r = file_of_seat(seat, &p);
370 if (r < 0)
371 return r;
372
373 variable = require_active ? "ACTIVE_UID" : "UIDS";
374
375 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
376 if (r == -ENOENT)
377 return 0;
378 if (r < 0)
379 return r;
380 if (isempty(s))
381 return 0;
382
383 if (asprintf(&t, UID_FMT, uid) < 0)
384 return -ENOMEM;
385
386 FOREACH_WORD(word, l, s, state)
387 if (strneq(t, word, l))
388 return 1;
389
390 return 0;
391 }
392
393 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
394 _cleanup_free_ char *p = NULL, *s = NULL;
395 char **a;
396 int r;
397
398 assert(variable);
399
400 r = file_of_uid(uid, &p);
401 if (r < 0)
402 return r;
403
404 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
405 if (r == -ENOENT || (r >= 0 && isempty(s))) {
406 if (array)
407 *array = NULL;
408 return 0;
409 }
410 if (r < 0)
411 return r;
412
413 a = strv_split(s, " ");
414 if (!a)
415 return -ENOMEM;
416
417 strv_uniq(a);
418 r = strv_length(a);
419
420 if (array)
421 *array = a;
422 else
423 strv_free(a);
424
425 return r;
426 }
427
428 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
429 return uid_get_array(
430 uid,
431 require_active == 0 ? "ONLINE_SESSIONS" :
432 require_active > 0 ? "ACTIVE_SESSIONS" :
433 "SESSIONS",
434 sessions);
435 }
436
437 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
438 return uid_get_array(
439 uid,
440 require_active == 0 ? "ONLINE_SEATS" :
441 require_active > 0 ? "ACTIVE_SEATS" :
442 "SEATS",
443 seats);
444 }
445
446 static int file_of_session(const char *session, char **_p) {
447 char *p;
448 int r;
449
450 assert(_p);
451
452 if (session) {
453 if (!session_id_valid(session))
454 return -EINVAL;
455
456 p = strappend("/run/systemd/sessions/", session);
457 } else {
458 _cleanup_free_ char *buf = NULL;
459
460 r = sd_pid_get_session(0, &buf);
461 if (r < 0)
462 return r;
463
464 p = strappend("/run/systemd/sessions/", buf);
465 }
466
467 if (!p)
468 return -ENOMEM;
469
470 *_p = p;
471 return 0;
472 }
473
474 _public_ int sd_session_is_active(const char *session) {
475 _cleanup_free_ char *p = NULL, *s = NULL;
476 int r;
477
478 r = file_of_session(session, &p);
479 if (r < 0)
480 return r;
481
482 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
483 if (r == -ENOENT)
484 return -ENXIO;
485 if (r < 0)
486 return r;
487 if (isempty(s))
488 return -EIO;
489
490 return parse_boolean(s);
491 }
492
493 _public_ int sd_session_is_remote(const char *session) {
494 _cleanup_free_ char *p = NULL, *s = NULL;
495 int r;
496
497 r = file_of_session(session, &p);
498 if (r < 0)
499 return r;
500
501 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
502 if (r == -ENOENT)
503 return -ENXIO;
504 if (r < 0)
505 return r;
506 if (isempty(s))
507 return -ENODATA;
508
509 return parse_boolean(s);
510 }
511
512 _public_ int sd_session_get_state(const char *session, char **state) {
513 _cleanup_free_ char *p = NULL, *s = NULL;
514 int r;
515
516 assert_return(state, -EINVAL);
517
518 r = file_of_session(session, &p);
519 if (r < 0)
520 return r;
521
522 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
523 if (r == -ENOENT)
524 return -ENXIO;
525 if (r < 0)
526 return r;
527 if (isempty(s))
528 return -EIO;
529
530 *state = TAKE_PTR(s);
531
532 return 0;
533 }
534
535 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
536 int r;
537 _cleanup_free_ char *p = NULL, *s = NULL;
538
539 assert_return(uid, -EINVAL);
540
541 r = file_of_session(session, &p);
542 if (r < 0)
543 return r;
544
545 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
546 if (r == -ENOENT)
547 return -ENXIO;
548 if (r < 0)
549 return r;
550 if (isempty(s))
551 return -EIO;
552
553 return parse_uid(s, uid);
554 }
555
556 static int session_get_string(const char *session, const char *field, char **value) {
557 _cleanup_free_ char *p = NULL, *s = NULL;
558 int r;
559
560 assert_return(value, -EINVAL);
561 assert(field);
562
563 r = file_of_session(session, &p);
564 if (r < 0)
565 return r;
566
567 r = parse_env_file(p, NEWLINE, field, &s, NULL);
568 if (r == -ENOENT)
569 return -ENXIO;
570 if (r < 0)
571 return r;
572 if (isempty(s))
573 return -ENODATA;
574
575 *value = TAKE_PTR(s);
576 return 0;
577 }
578
579 _public_ int sd_session_get_seat(const char *session, char **seat) {
580 return session_get_string(session, "SEAT", seat);
581 }
582
583 _public_ int sd_session_get_tty(const char *session, char **tty) {
584 return session_get_string(session, "TTY", tty);
585 }
586
587 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
588 _cleanup_free_ char *vtnr_string = NULL;
589 unsigned u;
590 int r;
591
592 assert_return(vtnr, -EINVAL);
593
594 r = session_get_string(session, "VTNR", &vtnr_string);
595 if (r < 0)
596 return r;
597
598 r = safe_atou(vtnr_string, &u);
599 if (r < 0)
600 return r;
601
602 *vtnr = u;
603 return 0;
604 }
605
606 _public_ int sd_session_get_service(const char *session, char **service) {
607 return session_get_string(session, "SERVICE", service);
608 }
609
610 _public_ int sd_session_get_type(const char *session, char **type) {
611 return session_get_string(session, "TYPE", type);
612 }
613
614 _public_ int sd_session_get_class(const char *session, char **class) {
615 return session_get_string(session, "CLASS", class);
616 }
617
618 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
619 _cleanup_free_ char *escaped = NULL;
620 char *t;
621 int r;
622
623 assert_return(desktop, -EINVAL);
624
625 r = session_get_string(session, "DESKTOP", &escaped);
626 if (r < 0)
627 return r;
628
629 r = cunescape(escaped, 0, &t);
630 if (r < 0)
631 return r;
632
633 *desktop = t;
634 return 0;
635 }
636
637 _public_ int sd_session_get_display(const char *session, char **display) {
638 return session_get_string(session, "DISPLAY", display);
639 }
640
641 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
642 return session_get_string(session, "REMOTE_USER", remote_user);
643 }
644
645 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
646 return session_get_string(session, "REMOTE_HOST", remote_host);
647 }
648
649 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
650 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
651 int r;
652
653 assert_return(session || uid, -EINVAL);
654
655 r = file_of_seat(seat, &p);
656 if (r < 0)
657 return r;
658
659 r = parse_env_file(p, NEWLINE,
660 "ACTIVE", &s,
661 "ACTIVE_UID", &t,
662 NULL);
663 if (r == -ENOENT)
664 return -ENXIO;
665 if (r < 0)
666 return r;
667
668 if (session && !s)
669 return -ENODATA;
670
671 if (uid && !t)
672 return -ENODATA;
673
674 if (uid && t) {
675 r = parse_uid(t, uid);
676 if (r < 0)
677 return r;
678 }
679
680 if (session && s)
681 *session = TAKE_PTR(s);
682
683 return 0;
684 }
685
686 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
687 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
688 _cleanup_strv_free_ char **a = NULL;
689 _cleanup_free_ uid_t *b = NULL;
690 unsigned n = 0;
691 int r;
692
693 r = file_of_seat(seat, &p);
694 if (r < 0)
695 return r;
696
697 r = parse_env_file(p, NEWLINE,
698 "SESSIONS", &s,
699 "UIDS", &t,
700 NULL);
701 if (r == -ENOENT)
702 return -ENXIO;
703 if (r < 0)
704 return r;
705
706 if (s) {
707 a = strv_split(s, " ");
708 if (!a)
709 return -ENOMEM;
710 }
711
712 if (uids && t) {
713 const char *word, *state;
714 size_t l;
715
716 FOREACH_WORD(word, l, t, state)
717 n++;
718
719 if (n > 0) {
720 unsigned i = 0;
721
722 b = new(uid_t, n);
723 if (!b)
724 return -ENOMEM;
725
726 FOREACH_WORD(word, l, t, state) {
727 _cleanup_free_ char *k = NULL;
728
729 k = strndup(word, l);
730 if (!k)
731 return -ENOMEM;
732
733 r = parse_uid(k, b + i);
734 if (r < 0)
735 return r;
736
737 i++;
738 }
739 }
740 }
741
742 r = strv_length(a);
743
744 if (sessions) {
745 *sessions = a;
746 a = NULL;
747 }
748
749 if (uids) {
750 *uids = b;
751 b = NULL;
752 }
753
754 if (n_uids)
755 *n_uids = n;
756
757 return r;
758 }
759
760 static int seat_get_can(const char *seat, const char *variable) {
761 _cleanup_free_ char *p = NULL, *s = NULL;
762 int r;
763
764 assert(variable);
765
766 r = file_of_seat(seat, &p);
767 if (r < 0)
768 return r;
769
770 r = parse_env_file(p, NEWLINE,
771 variable, &s,
772 NULL);
773 if (r == -ENOENT)
774 return -ENXIO;
775 if (r < 0)
776 return r;
777 if (isempty(s))
778 return -ENODATA;
779
780 return parse_boolean(s);
781 }
782
783 _public_ int sd_seat_can_multi_session(const char *seat) {
784 return seat_get_can(seat, "CAN_MULTI_SESSION");
785 }
786
787 _public_ int sd_seat_can_tty(const char *seat) {
788 return seat_get_can(seat, "CAN_TTY");
789 }
790
791 _public_ int sd_seat_can_graphical(const char *seat) {
792 return seat_get_can(seat, "CAN_GRAPHICAL");
793 }
794
795 _public_ int sd_get_seats(char ***seats) {
796 int r;
797
798 r = get_files_in_directory("/run/systemd/seats/", seats);
799 if (r == -ENOENT) {
800 if (seats)
801 *seats = NULL;
802 return 0;
803 }
804 return r;
805 }
806
807 _public_ int sd_get_sessions(char ***sessions) {
808 int r;
809
810 r = get_files_in_directory("/run/systemd/sessions/", sessions);
811 if (r == -ENOENT) {
812 if (sessions)
813 *sessions = NULL;
814 return 0;
815 }
816 return r;
817 }
818
819 _public_ int sd_get_uids(uid_t **users) {
820 _cleanup_closedir_ DIR *d;
821 struct dirent *de;
822 int r = 0;
823 unsigned n = 0;
824 _cleanup_free_ uid_t *l = NULL;
825
826 d = opendir("/run/systemd/users/");
827 if (!d) {
828 if (errno == ENOENT) {
829 if (users)
830 *users = NULL;
831 return 0;
832 }
833 return -errno;
834 }
835
836 FOREACH_DIRENT_ALL(de, d, return -errno) {
837 int k;
838 uid_t uid;
839
840 dirent_ensure_type(d, de);
841
842 if (!dirent_is_file(de))
843 continue;
844
845 k = parse_uid(de->d_name, &uid);
846 if (k < 0)
847 continue;
848
849 if (users) {
850 if ((unsigned) r >= n) {
851 uid_t *t;
852
853 n = MAX(16, 2*r);
854 t = realloc(l, sizeof(uid_t) * n);
855 if (!t)
856 return -ENOMEM;
857
858 l = t;
859 }
860
861 assert((unsigned) r < n);
862 l[r++] = uid;
863 } else
864 r++;
865 }
866
867 if (users) {
868 *users = l;
869 l = NULL;
870 }
871
872 return r;
873 }
874
875 _public_ int sd_get_machine_names(char ***machines) {
876 _cleanup_strv_free_ char **l = NULL;
877 char **a, **b;
878 int r;
879
880 r = get_files_in_directory("/run/systemd/machines/", &l);
881 if (r == -ENOENT) {
882 if (machines)
883 *machines = NULL;
884 return 0;
885 }
886 if (r < 0)
887 return r;
888
889 if (l) {
890 r = 0;
891
892 /* Filter out the unit: symlinks */
893 for (a = b = l; *a; a++) {
894 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
895 free(*a);
896 else {
897 *b = *a;
898 b++;
899 r++;
900 }
901 }
902
903 *b = NULL;
904 }
905
906 if (machines)
907 *machines = TAKE_PTR(l);
908
909 return r;
910 }
911
912 _public_ int sd_machine_get_class(const char *machine, char **class) {
913 _cleanup_free_ char *c = NULL;
914 const char *p;
915 int r;
916
917 assert_return(machine_name_is_valid(machine), -EINVAL);
918 assert_return(class, -EINVAL);
919
920 p = strjoina("/run/systemd/machines/", machine);
921 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
922 if (r == -ENOENT)
923 return -ENXIO;
924 if (r < 0)
925 return r;
926 if (!c)
927 return -EIO;
928
929 *class = TAKE_PTR(c);
930
931 return 0;
932 }
933
934 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
935 _cleanup_free_ char *netif = NULL;
936 size_t l, allocated = 0, nr = 0;
937 int *ni = NULL;
938 const char *p, *word, *state;
939 int r;
940
941 assert_return(machine_name_is_valid(machine), -EINVAL);
942 assert_return(ifindices, -EINVAL);
943
944 p = strjoina("/run/systemd/machines/", machine);
945 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
946 if (r == -ENOENT)
947 return -ENXIO;
948 if (r < 0)
949 return r;
950 if (!netif) {
951 *ifindices = NULL;
952 return 0;
953 }
954
955 FOREACH_WORD(word, l, netif, state) {
956 char buf[l+1];
957 int ifi;
958
959 *(char*) (mempcpy(buf, word, l)) = 0;
960
961 if (parse_ifindex(buf, &ifi) < 0)
962 continue;
963
964 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
965 free(ni);
966 return -ENOMEM;
967 }
968
969 ni[nr++] = ifi;
970 }
971
972 *ifindices = ni;
973 return nr;
974 }
975
976 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
977 return (int) (unsigned long) m - 1;
978 }
979
980 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
981 return (sd_login_monitor*) (unsigned long) (fd + 1);
982 }
983
984 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
985 _cleanup_close_ int fd = -1;
986 bool good = false;
987 int k;
988
989 assert_return(m, -EINVAL);
990
991 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
992 if (fd < 0)
993 return -errno;
994
995 if (!category || streq(category, "seat")) {
996 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
997 if (k < 0)
998 return -errno;
999
1000 good = true;
1001 }
1002
1003 if (!category || streq(category, "session")) {
1004 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
1005 if (k < 0)
1006 return -errno;
1007
1008 good = true;
1009 }
1010
1011 if (!category || streq(category, "uid")) {
1012 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1013 if (k < 0)
1014 return -errno;
1015
1016 good = true;
1017 }
1018
1019 if (!category || streq(category, "machine")) {
1020 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1021 if (k < 0)
1022 return -errno;
1023
1024 good = true;
1025 }
1026
1027 if (!good)
1028 return -EINVAL;
1029
1030 *m = FD_TO_MONITOR(fd);
1031 fd = -1;
1032
1033 return 0;
1034 }
1035
1036 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1037 int fd;
1038
1039 if (!m)
1040 return NULL;
1041
1042 fd = MONITOR_TO_FD(m);
1043 close_nointr(fd);
1044
1045 return NULL;
1046 }
1047
1048 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1049 int r;
1050
1051 assert_return(m, -EINVAL);
1052
1053 r = flush_fd(MONITOR_TO_FD(m));
1054 if (r < 0)
1055 return r;
1056
1057 return 0;
1058 }
1059
1060 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1061
1062 assert_return(m, -EINVAL);
1063
1064 return MONITOR_TO_FD(m);
1065 }
1066
1067 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1068
1069 assert_return(m, -EINVAL);
1070
1071 /* For now we will only return POLLIN here, since we don't
1072 * need anything else ever for inotify. However, let's have
1073 * this API to keep our options open should we later on need
1074 * it. */
1075 return POLLIN;
1076 }
1077
1078 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1079
1080 assert_return(m, -EINVAL);
1081 assert_return(timeout_usec, -EINVAL);
1082
1083 /* For now we will only return (uint64_t) -1, since we don't
1084 * need any timeout. However, let's have this API to keep our
1085 * options open should we later on need it. */
1086 *timeout_usec = (uint64_t) -1;
1087 return 0;
1088 }