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