chiark / gitweb /
logind: remove redundant check in manager_new()
[elogind.git] / src / 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 <sys/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 "sd-login.h"
35
36 _public_ int sd_pid_get_session(pid_t pid, char **session) {
37
38         assert_return(pid >= 0, -EINVAL);
39         assert_return(session, -EINVAL);
40
41         return cg_pid_get_session(pid, session);
42 }
43
44 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
45
46         assert_return(pid >= 0, -EINVAL);
47         assert_return(unit, -EINVAL);
48
49         return cg_pid_get_unit(pid, unit);
50 }
51
52 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
53
54         assert_return(pid >= 0, -EINVAL);
55         assert_return(unit, -EINVAL);
56
57         return cg_pid_get_user_unit(pid, unit);
58 }
59
60 _public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
61
62         assert_return(pid >= 0, -EINVAL);
63         assert_return(name, -EINVAL);
64
65         return cg_pid_get_machine_name(pid, name);
66 }
67
68 _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
69
70         assert_return(pid >= 0, -EINVAL);
71         assert_return(slice, -EINVAL);
72
73         return cg_pid_get_slice(pid, slice);
74 }
75
76 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
77
78         assert_return(pid >= 0, -EINVAL);
79         assert_return(uid, -EINVAL);
80
81         return cg_pid_get_owner_uid(pid, uid);
82 }
83
84 _public_ int sd_uid_get_state(uid_t uid, char**state) {
85         char *p, *s = NULL;
86         int r;
87
88         assert_return(state, -EINVAL);
89
90         if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
91                 return -ENOMEM;
92
93         r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
94         free(p);
95
96         if (r == -ENOENT) {
97                 free(s);
98                 s = strdup("offline");
99                 if (!s)
100                         return -ENOMEM;
101
102                 *state = s;
103                 return 0;
104         } else if (r < 0) {
105                 free(s);
106                 return r;
107         } else if (!s)
108                 return -EIO;
109
110         *state = s;
111         return 0;
112 }
113
114 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
115         char *w, *state;
116         _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
117         size_t l;
118         int r;
119         const char *variable;
120
121         assert_return(seat, -EINVAL);
122
123         variable = require_active ? "ACTIVE_UID" : "UIDS";
124
125         p = strappend("/run/systemd/seats/", seat);
126         if (!p)
127                 return -ENOMEM;
128
129         r = parse_env_file(p, NEWLINE, variable, &s, NULL);
130
131         if (r < 0)
132                 return r;
133
134         if (!s)
135                 return -EIO;
136
137         if (asprintf(&t, "%lu", (unsigned long) uid) < 0)
138                 return -ENOMEM;
139
140         FOREACH_WORD(w, l, s, state) {
141                 if (strneq(t, w, l))
142                         return 1;
143         }
144
145         return 0;
146 }
147
148 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
149         _cleanup_free_ char *p = NULL, *s = NULL;
150         char **a;
151         int r;
152
153         if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
154                 return -ENOMEM;
155
156         r = parse_env_file(p, NEWLINE,
157                            variable, &s,
158                            NULL);
159         if (r < 0) {
160                 if (r == -ENOENT) {
161                         if (array)
162                                 *array = NULL;
163                         return 0;
164                 }
165
166                 return r;
167         }
168
169         if (!s) {
170                 if (array)
171                         *array = NULL;
172                 return 0;
173         }
174
175         a = strv_split(s, " ");
176
177         if (!a)
178                 return -ENOMEM;
179
180         strv_uniq(a);
181         r = strv_length(a);
182
183         if (array)
184                 *array = a;
185         else
186                 strv_free(a);
187
188         return r;
189 }
190
191 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
192         return uid_get_array(
193                         uid,
194                         require_active == 0 ? "ONLINE_SESSIONS" :
195                         require_active > 0  ? "ACTIVE_SESSIONS" :
196                                               "SESSIONS",
197                         sessions);
198 }
199
200 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
201         return uid_get_array(
202                         uid,
203                         require_active == 0 ? "ONLINE_SEATS" :
204                         require_active > 0  ? "ACTIVE_SEATS" :
205                                               "SEATS",
206                         seats);
207 }
208
209 static int file_of_session(const char *session, char **_p) {
210         char *p;
211         int r;
212
213         assert(_p);
214
215         if (session) {
216                 if (!session_id_valid(session))
217                         return -EINVAL;
218
219                 p = strappend("/run/systemd/sessions/", session);
220         } else {
221                 _cleanup_free_ char *buf = NULL;
222
223                 r = sd_pid_get_session(0, &buf);
224                 if (r < 0)
225                         return r;
226
227                 p = strappend("/run/systemd/sessions/", buf);
228         }
229
230         if (!p)
231                 return -ENOMEM;
232
233         *_p = p;
234         return 0;
235 }
236
237 _public_ int sd_session_is_active(const char *session) {
238         int r;
239         _cleanup_free_ char *p = NULL, *s = NULL;
240
241         r = file_of_session(session, &p);
242         if (r < 0)
243                 return r;
244
245         r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
246         if (r < 0)
247                 return r;
248
249         if (!s)
250                 return -EIO;
251
252         r = parse_boolean(s);
253
254         return r;
255 }
256
257 _public_ int sd_session_is_remote(const char *session) {
258         int r;
259         _cleanup_free_ char *p = NULL, *s = NULL;
260
261         r = file_of_session(session, &p);
262         if (r < 0)
263                 return r;
264
265         r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
266         if (r < 0)
267                 return r;
268
269         if (!s)
270                 return -EIO;
271
272         r = parse_boolean(s);
273
274         return r;
275 }
276
277 _public_ int sd_session_get_state(const char *session, char **state) {
278         _cleanup_free_ char *p = NULL, *s = NULL;
279         int r;
280
281         assert_return(state, -EINVAL);
282
283         r = file_of_session(session, &p);
284         if (r < 0)
285                 return r;
286
287         r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
288
289         if (r < 0)
290                 return r;
291         else if (!s)
292                 return -EIO;
293
294         *state = s;
295         s = NULL;
296
297         return 0;
298 }
299
300 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
301         int r;
302         _cleanup_free_ char *p = NULL, *s = NULL;
303
304         assert_return(uid, -EINVAL);
305
306         r = file_of_session(session, &p);
307         if (r < 0)
308                 return r;
309
310         r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
311
312         if (r < 0)
313                 return r;
314
315         if (!s)
316                 return -EIO;
317
318         r = parse_uid(s, uid);
319
320         return r;
321 }
322
323 static int session_get_string(const char *session, const char *field, char **value) {
324         _cleanup_free_ char *p = NULL, *s = NULL;
325         int r;
326
327         assert_return(value, -EINVAL);
328
329         r = file_of_session(session, &p);
330         if (r < 0)
331                 return r;
332
333         r = parse_env_file(p, NEWLINE, field, &s, NULL);
334
335         if (r < 0)
336                 return r;
337
338         if (isempty(s))
339                 return -ENOENT;
340
341         *value = s;
342         s = NULL;
343         return 0;
344 }
345
346 _public_ int sd_session_get_seat(const char *session, char **seat) {
347         return session_get_string(session, "SEAT", seat);
348 }
349
350 _public_ int sd_session_get_tty(const char *session, char **tty) {
351         return session_get_string(session, "TTY", tty);
352 }
353
354 _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
355         _cleanup_free_ char *vtnr_string = NULL;
356         unsigned u;
357         int r;
358
359         r = session_get_string(session, "VTNR", &vtnr_string);
360         if (r < 0)
361                 return r;
362
363         r = safe_atou(vtnr_string, &u);
364         if (r < 0)
365                 return r;
366
367         *vtnr = u;
368         return 0;
369 }
370
371 _public_ int sd_session_get_service(const char *session, char **service) {
372         return session_get_string(session, "SERVICE", service);
373 }
374
375 _public_ int sd_session_get_type(const char *session, char **type) {
376         return session_get_string(session, "TYPE", type);
377 }
378
379 _public_ int sd_session_get_class(const char *session, char **class) {
380         return session_get_string(session, "CLASS", class);
381 }
382
383 _public_ int sd_session_get_display(const char *session, char **display) {
384         return session_get_string(session, "DISPLAY", display);
385 }
386
387 _public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
388         return session_get_string(session, "REMOTE_USER", remote_user);
389 }
390
391 _public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
392         return session_get_string(session, "REMOTE_HOST", remote_host);
393 }
394
395 static int file_of_seat(const char *seat, char **_p) {
396         char *p;
397         int r;
398
399         assert(_p);
400
401         if (seat)
402                 p = strappend("/run/systemd/seats/", seat);
403         else {
404                 _cleanup_free_ char *buf = NULL;
405
406                 r = sd_session_get_seat(NULL, &buf);
407                 if (r < 0)
408                         return r;
409
410                 p = strappend("/run/systemd/seats/", buf);
411         }
412
413         if (!p)
414                 return -ENOMEM;
415
416         *_p = p;
417         p = NULL;
418         return 0;
419 }
420
421 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
422         _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
423         int r;
424
425         assert_return(session || uid, -EINVAL);
426
427         r = file_of_seat(seat, &p);
428         if (r < 0)
429                 return r;
430
431         r = parse_env_file(p, NEWLINE,
432                            "ACTIVE", &s,
433                            "ACTIVE_UID", &t,
434                            NULL);
435         if (r < 0)
436                 return r;
437
438         if (session && !s)
439                 return -ENOENT;
440
441         if (uid && !t)
442                 return -ENOENT;
443
444         if (uid && t) {
445                 r = parse_uid(t, uid);
446                 if (r < 0)
447                         return r;
448         }
449
450         if (session && s) {
451                 *session = s;
452                 s = NULL;
453         }
454
455         return 0;
456 }
457
458 _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
459         _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
460         _cleanup_strv_free_ char **a = NULL;
461         _cleanup_free_ uid_t *b = NULL;
462         unsigned n = 0;
463         int r;
464
465         r = file_of_seat(seat, &p);
466         if (r < 0)
467                 return r;
468
469         r = parse_env_file(p, NEWLINE,
470                            "SESSIONS", &s,
471                            "ACTIVE_SESSIONS", &t,
472                            NULL);
473
474         if (r < 0)
475                 return r;
476
477         if (s) {
478                 a = strv_split(s, " ");
479                 if (!a)
480                         return -ENOMEM;
481         }
482
483         if (uids && t) {
484                 char *w, *state;
485                 size_t l;
486
487                 FOREACH_WORD(w, l, t, state)
488                         n++;
489
490                 if (n > 0) {
491                         unsigned i = 0;
492
493                         b = new(uid_t, n);
494                         if (!b)
495                                 return -ENOMEM;
496
497                         FOREACH_WORD(w, l, t, state) {
498                                 _cleanup_free_ char *k = NULL;
499
500                                 k = strndup(w, l);
501                                 if (!k)
502                                         return -ENOMEM;
503
504                                 r = parse_uid(k, b + i);
505
506                                 if (r < 0)
507                                         continue;
508
509                                 i++;
510                         }
511                 }
512         }
513
514         r = strv_length(a);
515
516         if (sessions) {
517                 *sessions = a;
518                 a = NULL;
519         }
520
521         if (uids) {
522                 *uids = b;
523                 b = NULL;
524         }
525
526         if (n_uids)
527                 *n_uids = n;
528
529         return r;
530 }
531
532 static int seat_get_can(const char *seat, const char *variable) {
533         _cleanup_free_ char *p = NULL, *s = NULL;
534         int r;
535
536         r = file_of_seat(seat, &p);
537         if (r < 0)
538                 return r;
539
540         r = parse_env_file(p, NEWLINE,
541                            variable, &s,
542                            NULL);
543         if (r < 0)
544                 return r;
545
546         if (s)
547                 r = parse_boolean(s);
548         else
549                 r = 0;
550
551         return r;
552 }
553
554 _public_ int sd_seat_can_multi_session(const char *seat) {
555         return seat_get_can(seat, "CAN_MULTI_SESSION");
556 }
557
558 _public_ int sd_seat_can_tty(const char *seat) {
559         return seat_get_can(seat, "CAN_TTY");
560 }
561
562 _public_ int sd_seat_can_graphical(const char *seat) {
563         return seat_get_can(seat, "CAN_GRAPHICAL");
564 }
565
566 _public_ int sd_get_seats(char ***seats) {
567         return get_files_in_directory("/run/systemd/seats/", seats);
568 }
569
570 _public_ int sd_get_sessions(char ***sessions) {
571         return get_files_in_directory("/run/systemd/sessions/", sessions);
572 }
573
574 _public_ int sd_get_uids(uid_t **users) {
575         _cleanup_closedir_ DIR *d;
576         int r = 0;
577         unsigned n = 0;
578         _cleanup_free_ uid_t *l = NULL;
579
580         d = opendir("/run/systemd/users/");
581         if (!d)
582                 return -errno;
583
584         for (;;) {
585                 struct dirent *de;
586                 int k;
587                 uid_t uid;
588
589                 errno = 0;
590                 de = readdir(d);
591                 if (!de && errno != 0)
592                         return -errno;
593
594                 if (!de)
595                         break;
596
597                 dirent_ensure_type(d, de);
598
599                 if (!dirent_is_file(de))
600                         continue;
601
602                 k = parse_uid(de->d_name, &uid);
603                 if (k < 0)
604                         continue;
605
606                 if (users) {
607                         if ((unsigned) r >= n) {
608                                 uid_t *t;
609
610                                 n = MAX(16, 2*r);
611                                 t = realloc(l, sizeof(uid_t) * n);
612                                 if (!t)
613                                         return -ENOMEM;
614
615                                 l = t;
616                         }
617
618                         assert((unsigned) r < n);
619                         l[r++] = uid;
620                 } else
621                         r++;
622         }
623
624         if (users) {
625                 *users = l;
626                 l = NULL;
627         }
628
629         return r;
630 }
631
632 _public_ int sd_get_machine_names(char ***machines) {
633         char **l = NULL, **a, **b;
634         int r;
635
636         r = get_files_in_directory("/run/systemd/machines/", &l);
637         if (r < 0)
638                 return r;
639
640         if (l) {
641                 r = 0;
642
643                 /* Filter out the unit: symlinks */
644                 for (a = l, b = l; *a; a++) {
645                         if (startswith(*a, "unit:"))
646                                 free(*a);
647                         else {
648                                 *b = *a;
649                                 b++;
650                                 r++;
651                         }
652                 }
653
654                 *b = NULL;
655         }
656
657         *machines = l;
658         return r;
659 }
660
661 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
662         return (int) (unsigned long) m - 1;
663 }
664
665 static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
666         return (sd_login_monitor*) (unsigned long) (fd + 1);
667 }
668
669 _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
670         int fd, k;
671         bool good = false;
672
673         assert_return(m, -EINVAL);
674
675         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
676         if (fd < 0)
677                 return -errno;
678
679         if (!category || streq(category, "seat")) {
680                 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
681                 if (k < 0) {
682                         close_nointr_nofail(fd);
683                         return -errno;
684                 }
685
686                 good = true;
687         }
688
689         if (!category || streq(category, "session")) {
690                 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
691                 if (k < 0) {
692                         close_nointr_nofail(fd);
693                         return -errno;
694                 }
695
696                 good = true;
697         }
698
699         if (!category || streq(category, "uid")) {
700                 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
701                 if (k < 0) {
702                         close_nointr_nofail(fd);
703                         return -errno;
704                 }
705
706                 good = true;
707         }
708
709         if (!category || streq(category, "machine")) {
710                 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
711                 if (k < 0) {
712                         close_nointr_nofail(fd);
713                         return -errno;
714                 }
715
716                 good = true;
717         }
718
719         if (!good) {
720                 close_nointr(fd);
721                 return -EINVAL;
722         }
723
724         *m = FD_TO_MONITOR(fd);
725         return 0;
726 }
727
728 _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
729         int fd;
730
731         assert_return(m, NULL);
732
733         fd = MONITOR_TO_FD(m);
734         close_nointr(fd);
735
736         return NULL;
737 }
738
739 _public_ int sd_login_monitor_flush(sd_login_monitor *m) {
740
741         assert_return(m, -EINVAL);
742
743         return flush_fd(MONITOR_TO_FD(m));
744 }
745
746 _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
747
748         assert_return(m, -EINVAL);
749
750         return MONITOR_TO_FD(m);
751 }
752
753 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
754
755         assert_return(m, -EINVAL);
756
757         /* For now we will only return POLLIN here, since we don't
758          * need anything else ever for inotify.  However, let's have
759          * this API to keep our options open should we later on need
760          * it. */
761         return POLLIN;
762 }
763
764 _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
765
766         assert_return(m, -EINVAL);
767         assert_return(timeout_usec, -EINVAL);
768
769         /* For now we will only return (uint64_t) -1, since we don't
770          * need any timeout. However, let's have this API to keep our
771          * options open should we later on need it. */
772         *timeout_usec = (uint64_t) -1;
773         return 0;
774 }