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