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