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