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