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