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