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