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