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