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