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