chiark / gitweb /
Prep v236 : Add missing SPDX-License-Identifier (4/9) src/libelogind
[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 = s;
359         s = NULL;
360
361         return 0;
362 }
363
364 static int file_of_seat(const char *seat, char **_p) {
365         char *p;
366         int r;
367
368         assert(_p);
369
370         if (seat) {
371                 if (!filename_is_valid(seat))
372                         return -EINVAL;
373
374                 p = strappend("/run/systemd/seats/", seat);
375         } else {
376                 _cleanup_free_ char *buf = NULL;
377
378                 r = sd_session_get_seat(NULL, &buf);
379                 if (r < 0)
380                         return r;
381
382                 p = strappend("/run/systemd/seats/", buf);
383         }
384
385         if (!p)
386                 return -ENOMEM;
387
388         *_p = p;
389         p = NULL;
390         return 0;
391 }
392
393 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
394         _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
395         size_t l;
396         int r;
397         const char *word, *variable, *state;
398
399         assert_return(uid_is_valid(uid), -EINVAL);
400
401         r = file_of_seat(seat, &p);
402         if (r < 0)
403                 return r;
404
405         variable = require_active ? "ACTIVE_UID" : "UIDS";
406
407         r = parse_env_file(p, NEWLINE, variable, &s, NULL);
408         if (r == -ENOENT)
409                 return 0;
410         if (r < 0)
411                 return r;
412         if (isempty(s))
413                 return 0;
414
415         if (asprintf(&t, UID_FMT, uid) < 0)
416                 return -ENOMEM;
417
418         FOREACH_WORD(word, l, s, state)
419                 if (strneq(t, word, l))
420                         return 1;
421
422         return 0;
423 }
424
425 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
426         _cleanup_free_ char *p = NULL, *s = NULL;
427         char **a;
428         int r;
429
430         assert(variable);
431
432         r = file_of_uid(uid, &p);
433         if (r < 0)
434                 return r;
435
436         r = parse_env_file(p, NEWLINE, variable, &s, NULL);
437         if (r == -ENOENT || (r >= 0 && isempty(s))) {
438                 if (array)
439                         *array = NULL;
440                 return 0;
441         }
442         if (r < 0)
443                 return r;
444
445         a = strv_split(s, " ");
446         if (!a)
447                 return -ENOMEM;
448
449         strv_uniq(a);
450         r = strv_length(a);
451
452         if (array)
453                 *array = a;
454         else
455                 strv_free(a);
456
457         return r;
458 }
459
460 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
461         return uid_get_array(
462                         uid,
463                         require_active == 0 ? "ONLINE_SESSIONS" :
464                         require_active > 0  ? "ACTIVE_SESSIONS" :
465                                               "SESSIONS",
466                         sessions);
467 }
468
469 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
470         return uid_get_array(
471                         uid,
472                         require_active == 0 ? "ONLINE_SEATS" :
473                         require_active > 0  ? "ACTIVE_SEATS" :
474                                               "SEATS",
475                         seats);
476 }
477
478 static int file_of_session(const char *session, char **_p) {
479         char *p;
480         int r;
481
482         assert(_p);
483
484         if (session) {
485                 if (!session_id_valid(session))
486                         return -EINVAL;
487
488                 p = strappend("/run/systemd/sessions/", session);
489         } else {
490                 _cleanup_free_ char *buf = NULL;
491
492                 r = sd_pid_get_session(0, &buf);
493                 if (r < 0)
494                         return r;
495
496                 p = strappend("/run/systemd/sessions/", buf);
497         }
498
499         if (!p)
500                 return -ENOMEM;
501
502         *_p = p;
503         return 0;
504 }
505
506 _public_ int sd_session_is_active(const char *session) {
507         _cleanup_free_ char *p = NULL, *s = NULL;
508         int r;
509
510         r = file_of_session(session, &p);
511         if (r < 0)
512                 return r;
513
514         r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
515         if (r == -ENOENT)
516                 return -ENXIO;
517         if (r < 0)
518                 return r;
519         if (isempty(s))
520                 return -EIO;
521
522         return parse_boolean(s);
523 }
524
525 _public_ int sd_session_is_remote(const char *session) {
526         _cleanup_free_ char *p = NULL, *s = NULL;
527         int r;
528
529         r = file_of_session(session, &p);
530         if (r < 0)
531                 return r;
532
533         r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
534         if (r == -ENOENT)
535                 return -ENXIO;
536         if (r < 0)
537                 return r;
538         if (isempty(s))
539                 return -ENODATA;
540
541         return parse_boolean(s);
542 }
543
544 _public_ int sd_session_get_state(const char *session, char **state) {
545         _cleanup_free_ char *p = NULL, *s = NULL;
546         int r;
547
548         assert_return(state, -EINVAL);
549
550         r = file_of_session(session, &p);
551         if (r < 0)
552                 return r;
553
554         r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
555         if (r == -ENOENT)
556                 return -ENXIO;
557         if (r < 0)
558                 return r;
559         if (isempty(s))
560                 return -EIO;
561
562         *state = s;
563         s = NULL;
564
565         return 0;
566 }
567
568 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
569         int r;
570         _cleanup_free_ char *p = NULL, *s = NULL;
571
572         assert_return(uid, -EINVAL);
573
574         r = file_of_session(session, &p);
575         if (r < 0)
576                 return r;
577
578         r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
579         if (r == -ENOENT)
580                 return -ENXIO;
581         if (r < 0)
582                 return r;
583         if (isempty(s))
584                 return -EIO;
585
586         return parse_uid(s, uid);
587 }
588
589 static int session_get_string(const char *session, const char *field, char **value) {
590         _cleanup_free_ char *p = NULL, *s = NULL;
591         int r;
592
593         assert_return(value, -EINVAL);
594         assert(field);
595
596         r = file_of_session(session, &p);
597         if (r < 0)
598                 return r;
599
600         r = parse_env_file(p, NEWLINE, field, &s, NULL);
601         if (r == -ENOENT)
602                 return -ENXIO;
603         if (r < 0)
604                 return r;
605         if (isempty(s))
606                 return -ENODATA;
607
608         *value = s;
609         s = NULL;
610         return 0;
611 }
612
613 _public_ int sd_session_get_seat(const char *session, char **seat) {
614         return session_get_string(session, "SEAT", seat);
615 }
616
617 _public_ int sd_session_get_tty(const char *session, char **tty) {
618         return session_get_string(session, "TTY", tty);
619 }
620
621 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
622         _cleanup_free_ char *vtnr_string = NULL;
623         unsigned u;
624         int r;
625
626         assert_return(vtnr, -EINVAL);
627
628         r = session_get_string(session, "VTNR", &vtnr_string);
629         if (r < 0)
630                 return r;
631
632         r = safe_atou(vtnr_string, &u);
633         if (r < 0)
634                 return r;
635
636         *vtnr = u;
637         return 0;
638 }
639
640 _public_ int sd_session_get_service(const char *session, char **service) {
641         return session_get_string(session, "SERVICE", service);
642 }
643
644 _public_ int sd_session_get_type(const char *session, char **type) {
645         return session_get_string(session, "TYPE", type);
646 }
647
648 _public_ int sd_session_get_class(const char *session, char **class) {
649         return session_get_string(session, "CLASS", class);
650 }
651
652 _public_ int sd_session_get_desktop(const char *session, char **desktop) {
653         _cleanup_free_ char *escaped = NULL;
654         char *t;
655         int r;
656
657         assert_return(desktop, -EINVAL);
658
659         r = session_get_string(session, "DESKTOP", &escaped);
660         if (r < 0)
661                 return r;
662
663         r = cunescape(escaped, 0, &t);
664         if (r < 0)
665                 return r;
666
667         *desktop = t;
668         return 0;
669 }
670
671 _public_ int sd_session_get_display(const char *session, char **display) {
672         return session_get_string(session, "DISPLAY", display);
673 }
674
675 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
676         return session_get_string(session, "REMOTE_USER", remote_user);
677 }
678
679 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
680         return session_get_string(session, "REMOTE_HOST", remote_host);
681 }
682
683 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
684         _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
685         int r;
686
687         assert_return(session || uid, -EINVAL);
688
689         r = file_of_seat(seat, &p);
690         if (r < 0)
691                 return r;
692
693         r = parse_env_file(p, NEWLINE,
694                            "ACTIVE", &s,
695                            "ACTIVE_UID", &t,
696                            NULL);
697         if (r == -ENOENT)
698                 return -ENXIO;
699         if (r < 0)
700                 return r;
701
702         if (session && !s)
703                 return -ENODATA;
704
705         if (uid && !t)
706                 return -ENODATA;
707
708         if (uid && t) {
709                 r = parse_uid(t, uid);
710                 if (r < 0)
711                         return r;
712         }
713
714         if (session && s) {
715                 *session = s;
716                 s = NULL;
717         }
718
719         return 0;
720 }
721
722 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
723         _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
724         _cleanup_strv_free_ char **a = NULL;
725         _cleanup_free_ uid_t *b = NULL;
726         unsigned n = 0;
727         int r;
728
729         r = file_of_seat(seat, &p);
730         if (r < 0)
731                 return r;
732
733         r = parse_env_file(p, NEWLINE,
734                            "SESSIONS", &s,
735                            "UIDS", &t,
736                            NULL);
737         if (r == -ENOENT)
738                 return -ENXIO;
739         if (r < 0)
740                 return r;
741
742         if (s) {
743                 a = strv_split(s, " ");
744                 if (!a)
745                         return -ENOMEM;
746         }
747
748         if (uids && t) {
749                 const char *word, *state;
750                 size_t l;
751
752                 FOREACH_WORD(word, l, t, state)
753                         n++;
754
755                 if (n > 0) {
756                         unsigned i = 0;
757
758                         b = new(uid_t, n);
759                         if (!b)
760                                 return -ENOMEM;
761
762                         FOREACH_WORD(word, l, t, state) {
763                                 _cleanup_free_ char *k = NULL;
764
765                                 k = strndup(word, l);
766                                 if (!k)
767                                         return -ENOMEM;
768
769                                 r = parse_uid(k, b + i);
770                                 if (r < 0)
771                                         return r;
772
773                                 i++;
774                         }
775                 }
776         }
777
778         r = strv_length(a);
779
780         if (sessions) {
781                 *sessions = a;
782                 a = NULL;
783         }
784
785         if (uids) {
786                 *uids = b;
787                 b = NULL;
788         }
789
790         if (n_uids)
791                 *n_uids = n;
792
793         return r;
794 }
795
796 static int seat_get_can(const char *seat, const char *variable) {
797         _cleanup_free_ char *p = NULL, *s = NULL;
798         int r;
799
800         assert(variable);
801
802         r = file_of_seat(seat, &p);
803         if (r < 0)
804                 return r;
805
806         r = parse_env_file(p, NEWLINE,
807                            variable, &s,
808                            NULL);
809         if (r == -ENOENT)
810                 return -ENXIO;
811         if (r < 0)
812                 return r;
813         if (isempty(s))
814                 return -ENODATA;
815
816         return parse_boolean(s);
817 }
818
819 _public_ int sd_seat_can_multi_session(const char *seat) {
820         return seat_get_can(seat, "CAN_MULTI_SESSION");
821 }
822
823 _public_ int sd_seat_can_tty(const char *seat) {
824         return seat_get_can(seat, "CAN_TTY");
825 }
826
827 _public_ int sd_seat_can_graphical(const char *seat) {
828         return seat_get_can(seat, "CAN_GRAPHICAL");
829 }
830
831 _public_ int sd_get_seats(char ***seats) {
832         int r;
833
834         r = get_files_in_directory("/run/systemd/seats/", seats);
835         if (r == -ENOENT) {
836                 if (seats)
837                         *seats = NULL;
838                 return 0;
839         }
840         return r;
841 }
842
843 _public_ int sd_get_sessions(char ***sessions) {
844         int r;
845
846         r = get_files_in_directory("/run/systemd/sessions/", sessions);
847         if (r == -ENOENT) {
848                 if (sessions)
849                         *sessions = NULL;
850                 return 0;
851         }
852         return r;
853 }
854
855 _public_ int sd_get_uids(uid_t **users) {
856         _cleanup_closedir_ DIR *d;
857         struct dirent *de;
858         int r = 0;
859         unsigned n = 0;
860         _cleanup_free_ uid_t *l = NULL;
861
862         d = opendir("/run/systemd/users/");
863         if (!d) {
864                 if (errno == ENOENT) {
865                         if (users)
866                                 *users = NULL;
867                         return 0;
868                 }
869                 return -errno;
870         }
871
872         FOREACH_DIRENT_ALL(de, d, return -errno) {
873                 int k;
874                 uid_t uid;
875
876                 dirent_ensure_type(d, de);
877
878                 if (!dirent_is_file(de))
879                         continue;
880
881                 k = parse_uid(de->d_name, &uid);
882                 if (k < 0)
883                         continue;
884
885                 if (users) {
886                         if ((unsigned) r >= n) {
887                                 uid_t *t;
888
889                                 n = MAX(16, 2*r);
890                                 t = realloc(l, sizeof(uid_t) * n);
891                                 if (!t)
892                                         return -ENOMEM;
893
894                                 l = t;
895                         }
896
897                         assert((unsigned) r < n);
898                         l[r++] = uid;
899                 } else
900                         r++;
901         }
902
903         if (users) {
904                 *users = l;
905                 l = NULL;
906         }
907
908         return r;
909 }
910
911 _public_ int sd_get_machine_names(char ***machines) {
912         _cleanup_strv_free_ char **l = NULL;
913         char **a, **b;
914         int r;
915
916         r = get_files_in_directory("/run/systemd/machines/", &l);
917         if (r == -ENOENT) {
918                 if (machines)
919                         *machines = NULL;
920                 return 0;
921         }
922         if (r < 0)
923                 return r;
924
925         if (l) {
926                 r = 0;
927
928                 /* Filter out the unit: symlinks */
929                 for (a = b = l; *a; a++) {
930                         if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
931                                 free(*a);
932                         else {
933                                 *b = *a;
934                                 b++;
935                                 r++;
936                         }
937                 }
938
939                 *b = NULL;
940         }
941
942         if (machines) {
943                 *machines = l;
944                 l = NULL;
945         }
946         return r;
947 }
948
949 _public_ int sd_machine_get_class(const char *machine, char **class) {
950         _cleanup_free_ char *c = NULL;
951         const char *p;
952         int r;
953
954         assert_return(machine_name_is_valid(machine), -EINVAL);
955         assert_return(class, -EINVAL);
956
957         p = strjoina("/run/systemd/machines/", machine);
958         r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
959         if (r == -ENOENT)
960                 return -ENXIO;
961         if (r < 0)
962                 return r;
963         if (!c)
964                 return -EIO;
965
966         *class = c;
967         c = NULL;
968
969         return 0;
970 }
971
972 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
973         _cleanup_free_ char *netif = NULL;
974         size_t l, allocated = 0, nr = 0;
975         int *ni = NULL;
976         const char *p, *word, *state;
977         int r;
978
979         assert_return(machine_name_is_valid(machine), -EINVAL);
980         assert_return(ifindices, -EINVAL);
981
982         p = strjoina("/run/systemd/machines/", machine);
983         r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
984         if (r == -ENOENT)
985                 return -ENXIO;
986         if (r < 0)
987                 return r;
988         if (!netif) {
989                 *ifindices = NULL;
990                 return 0;
991         }
992
993         FOREACH_WORD(word, l, netif, state) {
994                 char buf[l+1];
995                 int ifi;
996
997                 *(char*) (mempcpy(buf, word, l)) = 0;
998
999                 if (parse_ifindex(buf, &ifi) < 0)
1000                         continue;
1001
1002                 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
1003                         free(ni);
1004                         return -ENOMEM;
1005                 }
1006
1007                 ni[nr++] = ifi;
1008         }
1009
1010         *ifindices = ni;
1011         return nr;
1012 }
1013
1014 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
1015         return (int) (unsigned long) m - 1;
1016 }
1017
1018 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
1019         return (sd_login_monitor*) (unsigned long) (fd + 1);
1020 }
1021
1022 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
1023         int fd, k;
1024         bool good = false;
1025
1026         assert_return(m, -EINVAL);
1027
1028         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1029         if (fd < 0)
1030                 return -errno;
1031
1032         if (!category || streq(category, "seat")) {
1033                 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
1034                 if (k < 0) {
1035                         safe_close(fd);
1036                         return -errno;
1037                 }
1038
1039                 good = true;
1040         }
1041
1042         if (!category || streq(category, "session")) {
1043                 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
1044                 if (k < 0) {
1045                         safe_close(fd);
1046                         return -errno;
1047                 }
1048
1049                 good = true;
1050         }
1051
1052         if (!category || streq(category, "uid")) {
1053                 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1054                 if (k < 0) {
1055                         safe_close(fd);
1056                         return -errno;
1057                 }
1058
1059                 good = true;
1060         }
1061
1062         if (!category || streq(category, "machine")) {
1063                 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1064                 if (k < 0) {
1065                         safe_close(fd);
1066                         return -errno;
1067                 }
1068
1069                 good = true;
1070         }
1071
1072         if (!good) {
1073                 close_nointr(fd);
1074                 return -EINVAL;
1075         }
1076
1077         *m = FD_TO_MONITOR(fd);
1078         return 0;
1079 }
1080
1081 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1082         int fd;
1083
1084         if (!m)
1085                 return NULL;
1086
1087         fd = MONITOR_TO_FD(m);
1088         close_nointr(fd);
1089
1090         return NULL;
1091 }
1092
1093 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1094
1095         assert_return(m, -EINVAL);
1096
1097         return flush_fd(MONITOR_TO_FD(m));
1098 }
1099
1100 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1101
1102         assert_return(m, -EINVAL);
1103
1104         return MONITOR_TO_FD(m);
1105 }
1106
1107 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1108
1109         assert_return(m, -EINVAL);
1110
1111         /* For now we will only return POLLIN here, since we don't
1112          * need anything else ever for inotify.  However, let's have
1113          * this API to keep our options open should we later on need
1114          * it. */
1115         return POLLIN;
1116 }
1117
1118 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1119
1120         assert_return(m, -EINVAL);
1121         assert_return(timeout_usec, -EINVAL);
1122
1123         /* For now we will only return (uint64_t) -1, since we don't
1124          * need any timeout. However, let's have this API to keep our
1125          * options open should we later on need it. */
1126         *timeout_usec = (uint64_t) -1;
1127         return 0;
1128 }