chiark / gitweb /
794136304b7a26ec0e91525e7045e0b909b65251
[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 < 0)
914                 return r;
915
916         if (l) {
917                 r = 0;
918
919                 /* Filter out the unit: symlinks */
920                 for (a = l, b = l; *a; a++) {
921                         if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
922                                 free(*a);
923                         else {
924                                 *b = *a;
925                                 b++;
926                                 r++;
927                         }
928                 }
929
930                 *b = NULL;
931         }
932
933         *machines = l;
934         return r;
935 }
936
937 _public_ int sd_machine_get_class(const char *machine, char **class) {
938         _cleanup_free_ char *c = NULL;
939         const char *p;
940         int r;
941
942         assert_return(machine_name_is_valid(machine), -EINVAL);
943         assert_return(class, -EINVAL);
944
945         p = strjoina("/run/systemd/machines/", machine);
946         r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
947         if (r == -ENOENT)
948                 return -ENXIO;
949         if (r < 0)
950                 return r;
951         if (!c)
952                 return -EIO;
953
954         *class = c;
955         c = NULL;
956
957         return 0;
958 }
959
960 _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
961         _cleanup_free_ char *netif = NULL;
962         size_t l, allocated = 0, nr = 0;
963         int *ni = NULL;
964         const char *p, *word, *state;
965         int r;
966
967         assert_return(machine_name_is_valid(machine), -EINVAL);
968         assert_return(ifindices, -EINVAL);
969
970         p = strjoina("/run/systemd/machines/", machine);
971         r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
972         if (r == -ENOENT)
973                 return -ENXIO;
974         if (r < 0)
975                 return r;
976         if (!netif) {
977                 *ifindices = NULL;
978                 return 0;
979         }
980
981         FOREACH_WORD(word, l, netif, state) {
982                 char buf[l+1];
983                 int ifi;
984
985                 *(char*) (mempcpy(buf, word, l)) = 0;
986
987                 if (parse_ifindex(buf, &ifi) < 0)
988                         continue;
989
990                 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
991                         free(ni);
992                         return -ENOMEM;
993                 }
994
995                 ni[nr++] = ifi;
996         }
997
998         *ifindices = ni;
999         return nr;
1000 }
1001
1002 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
1003         return (int) (unsigned long) m - 1;
1004 }
1005
1006 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
1007         return (sd_login_monitor*) (unsigned long) (fd + 1);
1008 }
1009
1010 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
1011         int fd, k;
1012         bool good = false;
1013
1014         assert_return(m, -EINVAL);
1015
1016         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1017         if (fd < 0)
1018                 return -errno;
1019
1020         if (!category || streq(category, "seat")) {
1021                 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
1022                 if (k < 0) {
1023                         safe_close(fd);
1024                         return -errno;
1025                 }
1026
1027                 good = true;
1028         }
1029
1030         if (!category || streq(category, "session")) {
1031                 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
1032                 if (k < 0) {
1033                         safe_close(fd);
1034                         return -errno;
1035                 }
1036
1037                 good = true;
1038         }
1039
1040         if (!category || streq(category, "uid")) {
1041                 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
1042                 if (k < 0) {
1043                         safe_close(fd);
1044                         return -errno;
1045                 }
1046
1047                 good = true;
1048         }
1049
1050         if (!category || streq(category, "machine")) {
1051                 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
1052                 if (k < 0) {
1053                         safe_close(fd);
1054                         return -errno;
1055                 }
1056
1057                 good = true;
1058         }
1059
1060         if (!good) {
1061                 close_nointr(fd);
1062                 return -EINVAL;
1063         }
1064
1065         *m = FD_TO_MONITOR(fd);
1066         return 0;
1067 }
1068
1069 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1070         int fd;
1071
1072         if (!m)
1073                 return NULL;
1074
1075         fd = MONITOR_TO_FD(m);
1076         close_nointr(fd);
1077
1078         return NULL;
1079 }
1080
1081 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1082
1083         assert_return(m, -EINVAL);
1084
1085         return flush_fd(MONITOR_TO_FD(m));
1086 }
1087
1088 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1089
1090         assert_return(m, -EINVAL);
1091
1092         return MONITOR_TO_FD(m);
1093 }
1094
1095 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1096
1097         assert_return(m, -EINVAL);
1098
1099         /* For now we will only return POLLIN here, since we don't
1100          * need anything else ever for inotify.  However, let's have
1101          * this API to keep our options open should we later on need
1102          * it. */
1103         return POLLIN;
1104 }
1105
1106 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1107
1108         assert_return(m, -EINVAL);
1109         assert_return(timeout_usec, -EINVAL);
1110
1111         /* For now we will only return (uint64_t) -1, since we don't
1112          * need any timeout. However, let's have this API to keep our
1113          * options open should we later on need it. */
1114         *timeout_usec = (uint64_t) -1;
1115         return 0;
1116 }