chiark / gitweb /
Merge pull request #7 from elogind/dev_v228-r1
[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 <errno.h>
23 #include <poll.h>
24 #include <string.h>
25 #include <sys/inotify.h>
26 #include <unistd.h>
27
28 #include "sd-login.h"
29
30 #include "alloc-util.h"
31 #include "cgroup-util.h"
32 #include "dirent-util.h"
33 #include "escape.h"
34 #include "fd-util.h"
35 #include "fileio.h"
36 #include "formats-util.h"
37 #include "fs-util.h"
38 #include "hostname-util.h"
39 #include "io-util.h"
40 #include "login-util.h"
41 #include "macro.h"
42 #include "parse-util.h"
43 #include "path-util.h"
44 #include "socket-util.h"
45 #include "string-util.h"
46 #include "strv.h"
47 #include "user-util.h"
48 #include "util.h"
49
50 /* Error codes:
51  *
52  *    invalid input parameters                → -EINVAL
53  *    invalid fd                              → -EBADF
54  *    process does not exist                  → -ESRCH
55  *    cgroup does not exist                   → -ENOENT
56  *    machine, session does not exist         → -ENXIO
57  *    requested metadata on object is missing → -ENODATA
58  */
59
60 _public_ int sd_pid_get_session(pid_t pid, char **session) {
61
62         assert_return(pid >= 0, -EINVAL);
63         assert_return(session, -EINVAL);
64
65         return cg_pid_get_session(pid, session);
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 ambigious 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                            "ACTIVE_SESSIONS", &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                                         continue;
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         int r = 0;
851         unsigned n = 0;
852         _cleanup_free_ uid_t *l = NULL;
853
854         d = opendir("/run/systemd/users/");
855         if (!d)
856                 return -errno;
857
858         for (;;) {
859                 struct dirent *de;
860                 int k;
861                 uid_t uid;
862
863                 errno = 0;
864                 de = readdir(d);
865                 if (!de && errno != 0)
866                         return -errno;
867
868                 if (!de)
869                         break;
870
871                 dirent_ensure_type(d, de);
872
873                 if (!dirent_is_file(de))
874                         continue;
875
876                 k = parse_uid(de->d_name, &uid);
877                 if (k < 0)
878                         continue;
879
880                 if (users) {
881                         if ((unsigned) r >= n) {
882                                 uid_t *t;
883
884                                 n = MAX(16, 2*r);
885                                 t = realloc(l, sizeof(uid_t) * n);
886                                 if (!t)
887                                         return -ENOMEM;
888
889                                 l = t;
890                         }
891
892                         assert((unsigned) r < n);
893                         l[r++] = uid;
894                 } else
895                         r++;
896         }
897
898         if (users) {
899                 *users = l;
900                 l = NULL;
901         }
902
903         return r;
904 }
905
906 _public_ int sd_get_machine_names(char ***machines) {
907         char **l = NULL, **a, **b;
908         int r;
909
910         assert_return(machines, -EINVAL);
911
912         r = get_files_in_directory("/run/systemd/machines/", &l);
913         if (r < 0)
914                 return r;
915
916         if (l) {
917                 r = 0;
918
919                 /* Filter out the unit: symlinks */
920                 for (a = l, b = l; *a; a++) {
921                         if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
922                                 free(*a);
923                         else {
924                                 *b = *a;
925                                 b++;
926                                 r++;
927                         }
928                 }
929
930                 *b = NULL;
931         }
932
933         *machines = l;
934         return r;
935 }
936
937 _public_ int sd_machine_get_class(const char *machine, char **class) {
938         _cleanup_free_ char *c = NULL;
939         const char *p;
940         int r;
941
942         assert_return(machine_name_is_valid(machine), -EINVAL);
943         assert_return(class, -EINVAL);
944
945         p = strjoina("/run/systemd/machines/", machine);
946         r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
947         if (r == -ENOENT)
948                 return -ENXIO;
949         if (r < 0)
950                 return r;
951         if (!c)
952                 return -EIO;
953
954         *class = c;
955         c = NULL;
956
957         return 0;
958 }
959
960 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
961         _cleanup_free_ char *netif = NULL;
962         size_t l, allocated = 0, nr = 0;
963         int *ni = NULL;
964         const char *p, *word, *state;
965         int r;
966
967         assert_return(machine_name_is_valid(machine), -EINVAL);
968         assert_return(ifindices, -EINVAL);
969
970         p = strjoina("/run/systemd/machines/", machine);
971         r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
972         if (r == -ENOENT)
973                 return -ENXIO;
974         if (r < 0)
975                 return r;
976         if (!netif) {
977                 *ifindices = NULL;
978                 return 0;
979         }
980
981         FOREACH_WORD(word, l, netif, state) {
982                 char buf[l+1];
983                 int ifi;
984
985                 *(char*) (mempcpy(buf, word, l)) = 0;
986
987                 if (parse_ifindex(buf, &ifi) < 0)
988                         continue;
989
990                 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
991                         free(ni);
992                         return -ENOMEM;
993                 }
994
995                 ni[nr++] = ifi;
996         }
997
998         *ifindices = ni;
999         return nr;
1000 }
1001
1002 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
1003         return (int) (unsigned long) m - 1;
1004 }
1005
1006 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
1007         return (sd_login_monitor*) (unsigned long) (fd + 1);
1008 }
1009
1010 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
1011         int fd, k;
1012         bool good = false;
1013
1014         assert_return(m, -EINVAL);
1015
1016         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1017         if (fd < 0)
1018                 return -errno;
1019
1020         if (!category || streq(category, "seat")) {
1021                 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
1022                 if (k < 0) {
1023                         safe_close(fd);
1024                         return -errno;
1025                 }
1026
1027                 good = true;
1028         }
1029
1030         if (!category || streq(category, "session")) {
1031                 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
1032                 if (k < 0) {
1033                         safe_close(fd);
1034                         return -errno;
1035                 }
1036
1037                 good = true;
1038         }
1039
1040         if (!category || streq(category, "uid")) {
1041                 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1042                 if (k < 0) {
1043                         safe_close(fd);
1044                         return -errno;
1045                 }
1046
1047                 good = true;
1048         }
1049
1050         if (!category || streq(category, "machine")) {
1051                 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1052                 if (k < 0) {
1053                         safe_close(fd);
1054                         return -errno;
1055                 }
1056
1057                 good = true;
1058         }
1059
1060         if (!good) {
1061                 close_nointr(fd);
1062                 return -EINVAL;
1063         }
1064
1065         *m = FD_TO_MONITOR(fd);
1066         return 0;
1067 }
1068
1069 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1070         int fd;
1071
1072         assert_return(m, NULL);
1073
1074         fd = MONITOR_TO_FD(m);
1075         close_nointr(fd);
1076
1077         return NULL;
1078 }
1079
1080 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1081
1082         assert_return(m, -EINVAL);
1083
1084         return flush_fd(MONITOR_TO_FD(m));
1085 }
1086
1087 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1088
1089         assert_return(m, -EINVAL);
1090
1091         return MONITOR_TO_FD(m);
1092 }
1093
1094 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1095
1096         assert_return(m, -EINVAL);
1097
1098         /* For now we will only return POLLIN here, since we don't
1099          * need anything else ever for inotify.  However, let's have
1100          * this API to keep our options open should we later on need
1101          * it. */
1102         return POLLIN;
1103 }
1104
1105 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1106
1107         assert_return(m, -EINVAL);
1108         assert_return(timeout_usec, -EINVAL);
1109
1110         /* For now we will only return (uint64_t) -1, since we don't
1111          * need any timeout. However, let's have this API to keep our
1112          * options open should we later on need it. */
1113         *timeout_usec = (uint64_t) -1;
1114         return 0;
1115 }