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