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