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