chiark / gitweb /
macro: introduce TAKE_PTR() macro
[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 = a;
776                 a = NULL;
777         }
778
779         if (uids) {
780                 *uids = b;
781                 b = NULL;
782         }
783
784         if (n_uids)
785                 *n_uids = n;
786
787         return r;
788 }
789
790 static int seat_get_can(const char *seat, const char *variable) {
791         _cleanup_free_ char *p = NULL, *s = NULL;
792         int r;
793
794         assert(variable);
795
796         r = file_of_seat(seat, &p);
797         if (r < 0)
798                 return r;
799
800         r = parse_env_file(p, NEWLINE,
801                            variable, &s,
802                            NULL);
803         if (r == -ENOENT)
804                 return -ENXIO;
805         if (r < 0)
806                 return r;
807         if (isempty(s))
808                 return -ENODATA;
809
810         return parse_boolean(s);
811 }
812
813 _public_ int sd_seat_can_multi_session(const char *seat) {
814         return seat_get_can(seat, "CAN_MULTI_SESSION");
815 }
816
817 _public_ int sd_seat_can_tty(const char *seat) {
818         return seat_get_can(seat, "CAN_TTY");
819 }
820
821 _public_ int sd_seat_can_graphical(const char *seat) {
822         return seat_get_can(seat, "CAN_GRAPHICAL");
823 }
824
825 _public_ int sd_get_seats(char ***seats) {
826         int r;
827
828         r = get_files_in_directory("/run/systemd/seats/", seats);
829         if (r == -ENOENT) {
830                 if (seats)
831                         *seats = NULL;
832                 return 0;
833         }
834         return r;
835 }
836
837 _public_ int sd_get_sessions(char ***sessions) {
838         int r;
839
840         r = get_files_in_directory("/run/systemd/sessions/", sessions);
841         if (r == -ENOENT) {
842                 if (sessions)
843                         *sessions = NULL;
844                 return 0;
845         }
846         return r;
847 }
848
849 _public_ int sd_get_uids(uid_t **users) {
850         _cleanup_closedir_ DIR *d;
851         struct dirent *de;
852         int r = 0;
853         unsigned n = 0;
854         _cleanup_free_ uid_t *l = NULL;
855
856         d = opendir("/run/systemd/users/");
857         if (!d) {
858                 if (errno == ENOENT) {
859                         if (users)
860                                 *users = NULL;
861                         return 0;
862                 }
863                 return -errno;
864         }
865
866         FOREACH_DIRENT_ALL(de, d, return -errno) {
867                 int k;
868                 uid_t uid;
869
870                 dirent_ensure_type(d, de);
871
872                 if (!dirent_is_file(de))
873                         continue;
874
875                 k = parse_uid(de->d_name, &uid);
876                 if (k < 0)
877                         continue;
878
879                 if (users) {
880                         if ((unsigned) r >= n) {
881                                 uid_t *t;
882
883                                 n = MAX(16, 2*r);
884                                 t = realloc(l, sizeof(uid_t) * n);
885                                 if (!t)
886                                         return -ENOMEM;
887
888                                 l = t;
889                         }
890
891                         assert((unsigned) r < n);
892                         l[r++] = uid;
893                 } else
894                         r++;
895         }
896
897         if (users) {
898                 *users = l;
899                 l = NULL;
900         }
901
902         return r;
903 }
904
905 _public_ int sd_get_machine_names(char ***machines) {
906         _cleanup_strv_free_ char **l = NULL;
907         char **a, **b;
908         int r;
909
910         r = get_files_in_directory("/run/systemd/machines/", &l);
911         if (r == -ENOENT) {
912                 if (machines)
913                         *machines = NULL;
914                 return 0;
915         }
916         if (r < 0)
917                 return r;
918
919         if (l) {
920                 r = 0;
921
922                 /* Filter out the unit: symlinks */
923                 for (a = b = l; *a; a++) {
924                         if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
925                                 free(*a);
926                         else {
927                                 *b = *a;
928                                 b++;
929                                 r++;
930                         }
931                 }
932
933                 *b = NULL;
934         }
935
936         if (machines)
937                 *machines = TAKE_PTR(l);
938
939         return r;
940 }
941
942 _public_ int sd_machine_get_class(const char *machine, char **class) {
943         _cleanup_free_ char *c = NULL;
944         const char *p;
945         int r;
946
947         assert_return(machine_name_is_valid(machine), -EINVAL);
948         assert_return(class, -EINVAL);
949
950         p = strjoina("/run/systemd/machines/", machine);
951         r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
952         if (r == -ENOENT)
953                 return -ENXIO;
954         if (r < 0)
955                 return r;
956         if (!c)
957                 return -EIO;
958
959         *class = TAKE_PTR(c);
960
961         return 0;
962 }
963
964 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
965         _cleanup_free_ char *netif = NULL;
966         size_t l, allocated = 0, nr = 0;
967         int *ni = NULL;
968         const char *p, *word, *state;
969         int r;
970
971         assert_return(machine_name_is_valid(machine), -EINVAL);
972         assert_return(ifindices, -EINVAL);
973
974         p = strjoina("/run/systemd/machines/", machine);
975         r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
976         if (r == -ENOENT)
977                 return -ENXIO;
978         if (r < 0)
979                 return r;
980         if (!netif) {
981                 *ifindices = NULL;
982                 return 0;
983         }
984
985         FOREACH_WORD(word, l, netif, state) {
986                 char buf[l+1];
987                 int ifi;
988
989                 *(char*) (mempcpy(buf, word, l)) = 0;
990
991                 if (parse_ifindex(buf, &ifi) < 0)
992                         continue;
993
994                 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
995                         free(ni);
996                         return -ENOMEM;
997                 }
998
999                 ni[nr++] = ifi;
1000         }
1001
1002         *ifindices = ni;
1003         return nr;
1004 }
1005
1006 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
1007         return (int) (unsigned long) m - 1;
1008 }
1009
1010 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
1011         return (sd_login_monitor*) (unsigned long) (fd + 1);
1012 }
1013
1014 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
1015         _cleanup_close_ int fd = -1;
1016         bool good = false;
1017         int k;
1018
1019         assert_return(m, -EINVAL);
1020
1021         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1022         if (fd < 0)
1023                 return -errno;
1024
1025         if (!category || streq(category, "seat")) {
1026                 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
1027                 if (k < 0)
1028                         return -errno;
1029
1030                 good = true;
1031         }
1032
1033         if (!category || streq(category, "session")) {
1034                 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
1035                 if (k < 0)
1036                         return -errno;
1037
1038                 good = true;
1039         }
1040
1041         if (!category || streq(category, "uid")) {
1042                 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1043                 if (k < 0)
1044                         return -errno;
1045
1046                 good = true;
1047         }
1048
1049         if (!category || streq(category, "machine")) {
1050                 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1051                 if (k < 0)
1052                         return -errno;
1053
1054                 good = true;
1055         }
1056
1057         if (!good)
1058                 return -EINVAL;
1059
1060         *m = FD_TO_MONITOR(fd);
1061         fd = -1;
1062
1063         return 0;
1064 }
1065
1066 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1067         int fd;
1068
1069         if (!m)
1070                 return NULL;
1071
1072         fd = MONITOR_TO_FD(m);
1073         close_nointr(fd);
1074
1075         return NULL;
1076 }
1077
1078 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1079         int r;
1080
1081         assert_return(m, -EINVAL);
1082
1083         r = flush_fd(MONITOR_TO_FD(m));
1084         if (r < 0)
1085                 return r;
1086
1087         return 0;
1088 }
1089
1090 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1091
1092         assert_return(m, -EINVAL);
1093
1094         return MONITOR_TO_FD(m);
1095 }
1096
1097 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1098
1099         assert_return(m, -EINVAL);
1100
1101         /* For now we will only return POLLIN here, since we don't
1102          * need anything else ever for inotify.  However, let's have
1103          * this API to keep our options open should we later on need
1104          * it. */
1105         return POLLIN;
1106 }
1107
1108 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1109
1110         assert_return(m, -EINVAL);
1111         assert_return(timeout_usec, -EINVAL);
1112
1113         /* For now we will only return (uint64_t) -1, since we don't
1114          * need any timeout. However, let's have this API to keep our
1115          * options open should we later on need it. */
1116         *timeout_usec = (uint64_t) -1;
1117         return 0;
1118 }