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