chiark / gitweb /
96d7e447af1118969867d8bc65404becbcc16270
[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 r == -ENXIO ? -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 r == -ENXIO ? -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 r == -ENXIO ? -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
102         assert_return(pid >= 0, -EINVAL);
103         assert_return(name, -EINVAL);
104
105 #if 0 /// elogind does not support systemd units
106         return cg_pid_get_machine_name(pid, name);
107 #else
108         return -ESRCH;
109 #endif // 0
110 }
111
112 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
113
114         assert_return(pid >= 0, -EINVAL);
115         assert_return(slice, -EINVAL);
116
117 #if 0 /// elogind does not support systemd slices
118         return cg_pid_get_slice(pid, slice);
119 #else
120         return -ESRCH;
121 #endif // 0
122 }
123
124 _public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
125
126         assert_return(pid >= 0, -EINVAL);
127         assert_return(slice, -EINVAL);
128
129 #if 0 /// elogind does not support systemd slices
130         return cg_pid_get_user_slice(pid, slice);
131 #else
132         return -ESRCH;
133 #endif // 0
134 }
135
136 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
137
138         assert_return(pid >= 0, -EINVAL);
139         assert_return(uid, -EINVAL);
140
141 #if 0 /// elogind does not support systemd slices
142         return cg_pid_get_owner_uid(pid, uid);
143 #else
144         return -ESRCH;
145 #endif // 0
146 }
147
148 _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
149         char *c;
150         int r;
151
152         assert_return(pid >= 0, -EINVAL);
153         assert_return(cgroup, -EINVAL);
154
155         r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c);
156         if (r < 0)
157                 return r;
158
159         /* The internal APIs return the empty string for the root
160          * cgroup, let's return the "/" in the public APIs instead, as
161          * that's easier and less ambiguous for people to grok. */
162         if (isempty(c)) {
163                 free(c);
164                 c = strdup("/");
165                 if (!c)
166                         return -ENOMEM;
167
168         }
169
170         *cgroup = c;
171         return 0;
172 }
173
174 _public_ int sd_peer_get_session(int fd, char **session) {
175         struct ucred ucred = {};
176         int r;
177
178         assert_return(fd >= 0, -EBADF);
179         assert_return(session, -EINVAL);
180
181         r = getpeercred(fd, &ucred);
182         if (r < 0)
183                 return r;
184
185 #if 0 /// elogind does not support systemd scopes
186         return cg_pid_get_session(ucred.pid, session);
187 #else
188         return -ESRCH;
189 #endif // 0
190 }
191
192 _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
193         struct ucred ucred;
194         int r;
195
196         assert_return(fd >= 0, -EBADF);
197         assert_return(uid, -EINVAL);
198
199         r = getpeercred(fd, &ucred);
200         if (r < 0)
201                 return r;
202
203 #if 0 /// elogind does not support systemd units
204         return cg_pid_get_owner_uid(ucred.pid, uid);
205 #else
206         return -ESRCH;
207 #endif // 0
208 }
209
210 _public_ int sd_peer_get_unit(int fd, char **unit) {
211         struct ucred ucred;
212         int r;
213
214         assert_return(fd >= 0, -EBADF);
215         assert_return(unit, -EINVAL);
216
217         r = getpeercred(fd, &ucred);
218         if (r < 0)
219                 return r;
220
221 #if 0 /// elogind does not support systemd units
222         return cg_pid_get_unit(ucred.pid, unit);
223 #else
224         return -ESRCH;
225 #endif // 0
226 }
227
228 _public_ int sd_peer_get_user_unit(int fd, char **unit) {
229         struct ucred ucred;
230         int r;
231
232         assert_return(fd >= 0, -EBADF);
233         assert_return(unit, -EINVAL);
234
235         r = getpeercred(fd, &ucred);
236         if (r < 0)
237                 return r;
238
239 #if 0 /// elogind does not support systemd units
240         return cg_pid_get_user_unit(ucred.pid, unit);
241 #else
242         return -ESRCH;
243 #endif // 0
244 }
245
246 _public_ int sd_peer_get_machine_name(int fd, char **machine) {
247         struct ucred ucred;
248         int r;
249
250         assert_return(fd >= 0, -EBADF);
251         assert_return(machine, -EINVAL);
252
253         r = getpeercred(fd, &ucred);
254         if (r < 0)
255                 return r;
256
257 #if 0 /// elogind does not support systemd units
258         return cg_pid_get_machine_name(ucred.pid, machine);
259 #else
260         return -ESRCH;
261 #endif // 0
262 }
263
264 _public_ int sd_peer_get_slice(int fd, char **slice) {
265         struct ucred ucred;
266         int r;
267
268         assert_return(fd >= 0, -EBADF);
269         assert_return(slice, -EINVAL);
270
271         r = getpeercred(fd, &ucred);
272         if (r < 0)
273                 return r;
274
275 #if 0 /// elogind does not support systemd slices
276         return cg_pid_get_slice(ucred.pid, slice);
277 #else
278         return -ESRCH;
279 #endif // 0
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         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         return get_files_in_directory("/run/systemd/seats/", seats);
850 }
851
852 _public_ int sd_get_sessions(char ***sessions) {
853         return get_files_in_directory("/run/systemd/sessions/", sessions);
854 }
855
856 _public_ int sd_get_uids(uid_t **users) {
857         _cleanup_closedir_ DIR *d;
858         struct dirent *de;
859         int r = 0;
860         unsigned n = 0;
861         _cleanup_free_ uid_t *l = NULL;
862
863         d = opendir("/run/systemd/users/");
864         if (!d)
865                 return -errno;
866
867         FOREACH_DIRENT_ALL(de, d, return -errno) {
868                 int k;
869                 uid_t uid;
870
871                 dirent_ensure_type(d, de);
872
873                 if (!dirent_is_file(de))
874                         continue;
875
876                 k = parse_uid(de->d_name, &uid);
877                 if (k < 0)
878                         continue;
879
880                 if (users) {
881                         if ((unsigned) r >= n) {
882                                 uid_t *t;
883
884                                 n = MAX(16, 2*r);
885                                 t = realloc(l, sizeof(uid_t) * n);
886                                 if (!t)
887                                         return -ENOMEM;
888
889                                 l = t;
890                         }
891
892                         assert((unsigned) r < n);
893                         l[r++] = uid;
894                 } else
895                         r++;
896         }
897
898         if (users) {
899                 *users = l;
900                 l = NULL;
901         }
902
903         return r;
904 }
905
906 _public_ int sd_get_machine_names(char ***machines) {
907         char **l = NULL, **a, **b;
908         int r;
909
910         assert_return(machines, -EINVAL);
911
912         r = get_files_in_directory("/run/systemd/machines/", &l);
913         if (r == -ENOENT) {
914                 *machines = NULL;
915                 return 0;
916         }
917         if (r < 0)
918                 return r;
919
920         if (l) {
921                 r = 0;
922
923                 /* Filter out the unit: symlinks */
924                 for (a = l, b = l; *a; a++) {
925                         if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
926                                 free(*a);
927                         else {
928                                 *b = *a;
929                                 b++;
930                                 r++;
931                         }
932                 }
933
934                 *b = NULL;
935         }
936
937         *machines = l;
938         return r;
939 }
940
941 _public_ int sd_machine_get_class(const char *machine, char **class) {
942         _cleanup_free_ char *c = NULL;
943         const char *p;
944         int r;
945
946         assert_return(machine_name_is_valid(machine), -EINVAL);
947         assert_return(class, -EINVAL);
948
949         p = strjoina("/run/systemd/machines/", machine);
950         r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
951         if (r == -ENOENT)
952                 return -ENXIO;
953         if (r < 0)
954                 return r;
955         if (!c)
956                 return -EIO;
957
958         *class = c;
959         c = NULL;
960
961         return 0;
962 }
963
964 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
965         _cleanup_free_ char *netif = NULL;
966         size_t l, allocated = 0, nr = 0;
967         int *ni = NULL;
968         const char *p, *word, *state;
969         int r;
970
971         assert_return(machine_name_is_valid(machine), -EINVAL);
972         assert_return(ifindices, -EINVAL);
973
974         p = strjoina("/run/systemd/machines/", machine);
975         r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
976         if (r == -ENOENT)
977                 return -ENXIO;
978         if (r < 0)
979                 return r;
980         if (!netif) {
981                 *ifindices = NULL;
982                 return 0;
983         }
984
985         FOREACH_WORD(word, l, netif, state) {
986                 char buf[l+1];
987                 int ifi;
988
989                 *(char*) (mempcpy(buf, word, l)) = 0;
990
991                 if (parse_ifindex(buf, &ifi) < 0)
992                         continue;
993
994                 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
995                         free(ni);
996                         return -ENOMEM;
997                 }
998
999                 ni[nr++] = ifi;
1000         }
1001
1002         *ifindices = ni;
1003         return nr;
1004 }
1005
1006 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
1007         return (int) (unsigned long) m - 1;
1008 }
1009
1010 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
1011         return (sd_login_monitor*) (unsigned long) (fd + 1);
1012 }
1013
1014 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
1015         int fd, k;
1016         bool good = false;
1017
1018         assert_return(m, -EINVAL);
1019
1020         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1021         if (fd < 0)
1022                 return -errno;
1023
1024         if (!category || streq(category, "seat")) {
1025                 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
1026                 if (k < 0) {
1027                         safe_close(fd);
1028                         return -errno;
1029                 }
1030
1031                 good = true;
1032         }
1033
1034         if (!category || streq(category, "session")) {
1035                 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
1036                 if (k < 0) {
1037                         safe_close(fd);
1038                         return -errno;
1039                 }
1040
1041                 good = true;
1042         }
1043
1044         if (!category || streq(category, "uid")) {
1045                 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1046                 if (k < 0) {
1047                         safe_close(fd);
1048                         return -errno;
1049                 }
1050
1051                 good = true;
1052         }
1053
1054         if (!category || streq(category, "machine")) {
1055                 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1056                 if (k < 0) {
1057                         safe_close(fd);
1058                         return -errno;
1059                 }
1060
1061                 good = true;
1062         }
1063
1064         if (!good) {
1065                 close_nointr(fd);
1066                 return -EINVAL;
1067         }
1068
1069         *m = FD_TO_MONITOR(fd);
1070         return 0;
1071 }
1072
1073 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1074         int fd;
1075
1076         if (!m)
1077                 return NULL;
1078
1079         fd = MONITOR_TO_FD(m);
1080         close_nointr(fd);
1081
1082         return NULL;
1083 }
1084
1085 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1086
1087         assert_return(m, -EINVAL);
1088
1089         return flush_fd(MONITOR_TO_FD(m));
1090 }
1091
1092 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1093
1094         assert_return(m, -EINVAL);
1095
1096         return MONITOR_TO_FD(m);
1097 }
1098
1099 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1100
1101         assert_return(m, -EINVAL);
1102
1103         /* For now we will only return POLLIN here, since we don't
1104          * need anything else ever for inotify.  However, let's have
1105          * this API to keep our options open should we later on need
1106          * it. */
1107         return POLLIN;
1108 }
1109
1110 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1111
1112         assert_return(m, -EINVAL);
1113         assert_return(timeout_usec, -EINVAL);
1114
1115         /* For now we will only return (uint64_t) -1, since we don't
1116          * need any timeout. However, let's have this API to keep our
1117          * options open should we later on need it. */
1118         *timeout_usec = (uint64_t) -1;
1119         return 0;
1120 }