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