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