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