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