chiark / gitweb /
util: make use of get_user_creds() and get_group_creds() wherever applicable
[elogind.git] / src / logind.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 General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <pwd.h>
24 #include <libudev.h>
25 #include <fcntl.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/epoll.h>
29 #include <sys/ioctl.h>
30 #include <linux/vt.h>
31
32 #include "logind.h"
33 #include "dbus-common.h"
34 #include "dbus-loop.h"
35 #include "strv.h"
36 #include "conf-parser.h"
37
38 Manager *manager_new(void) {
39         Manager *m;
40
41         m = new0(Manager, 1);
42         if (!m)
43                 return NULL;
44
45         m->console_active_fd = -1;
46         m->bus_fd = -1;
47         m->udev_seat_fd = -1;
48         m->udev_vcsa_fd = -1;
49         m->epoll_fd = -1;
50         m->n_autovts = 6;
51
52         m->devices = hashmap_new(string_hash_func, string_compare_func);
53         m->seats = hashmap_new(string_hash_func, string_compare_func);
54         m->sessions = hashmap_new(string_hash_func, string_compare_func);
55         m->users = hashmap_new(trivial_hash_func, trivial_compare_func);
56         m->cgroups = hashmap_new(string_hash_func, string_compare_func);
57         m->fifo_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
58
59         if (!m->devices || !m->seats || !m->sessions || !m->users || !m->cgroups || !m->fifo_fds) {
60                 manager_free(m);
61                 return NULL;
62         }
63
64         m->reset_controllers = strv_new("cpu", NULL);
65         m->kill_exclude_users = strv_new("root", NULL);
66         if (!m->reset_controllers || !m->kill_exclude_users) {
67                 manager_free(m);
68                 return NULL;
69         }
70
71         m->udev = udev_new();
72         if (!m->udev) {
73                 manager_free(m);
74                 return NULL;
75         }
76
77         if (cg_get_user_path(&m->cgroup_path) < 0) {
78                 manager_free(m);
79                 return NULL;
80         }
81
82         return m;
83 }
84
85 void manager_free(Manager *m) {
86         Session *session;
87         User *u;
88         Device *d;
89         Seat *s;
90
91         assert(m);
92
93         while ((session = hashmap_first(m->sessions)))
94                 session_free(session);
95
96         while ((u = hashmap_first(m->users)))
97                 user_free(u);
98
99         while ((d = hashmap_first(m->devices)))
100                 device_free(d);
101
102         while ((s = hashmap_first(m->seats)))
103                 seat_free(s);
104
105         hashmap_free(m->sessions);
106         hashmap_free(m->users);
107         hashmap_free(m->devices);
108         hashmap_free(m->seats);
109         hashmap_free(m->cgroups);
110         hashmap_free(m->fifo_fds);
111
112         if (m->console_active_fd >= 0)
113                 close_nointr_nofail(m->console_active_fd);
114
115         if (m->udev_seat_monitor)
116                 udev_monitor_unref(m->udev_seat_monitor);
117
118         if (m->udev_vcsa_monitor)
119                 udev_monitor_unref(m->udev_vcsa_monitor);
120
121         if (m->udev)
122                 udev_unref(m->udev);
123
124         if (m->bus) {
125                 dbus_connection_flush(m->bus);
126                 dbus_connection_close(m->bus);
127                 dbus_connection_unref(m->bus);
128         }
129
130         if (m->bus_fd >= 0)
131                 close_nointr_nofail(m->bus_fd);
132
133         if (m->epoll_fd >= 0)
134                 close_nointr_nofail(m->epoll_fd);
135
136         strv_free(m->controllers);
137         strv_free(m->reset_controllers);
138         strv_free(m->kill_only_users);
139         strv_free(m->kill_exclude_users);
140
141         free(m->cgroup_path);
142         free(m);
143 }
144
145 int manager_add_device(Manager *m, const char *sysfs, Device **_device) {
146         Device *d;
147
148         assert(m);
149         assert(sysfs);
150
151         d = hashmap_get(m->devices, sysfs);
152         if (d) {
153                 if (_device)
154                         *_device = d;
155
156                 return 0;
157         }
158
159         d = device_new(m, sysfs);
160         if (!d)
161                 return -ENOMEM;
162
163         if (_device)
164                 *_device = d;
165
166         return 0;
167 }
168
169 int manager_add_seat(Manager *m, const char *id, Seat **_seat) {
170         Seat *s;
171
172         assert(m);
173         assert(id);
174
175         s = hashmap_get(m->seats, id);
176         if (s) {
177                 if (_seat)
178                         *_seat = s;
179
180                 return 0;
181         }
182
183         s = seat_new(m, id);
184         if (!s)
185                 return -ENOMEM;
186
187         if (_seat)
188                 *_seat = s;
189
190         return 0;
191 }
192
193 int manager_add_session(Manager *m, User *u, const char *id, Session **_session) {
194         Session *s;
195
196         assert(m);
197         assert(id);
198
199         s = hashmap_get(m->sessions, id);
200         if (s) {
201                 if (_session)
202                         *_session = s;
203
204                 return 0;
205         }
206
207         s = session_new(m, u, id);
208         if (!s)
209                 return -ENOMEM;
210
211         if (_session)
212                 *_session = s;
213
214         return 0;
215 }
216
217 int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
218         User *u;
219
220         assert(m);
221         assert(name);
222
223         u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
224         if (u) {
225                 if (_user)
226                         *_user = u;
227
228                 return 0;
229         }
230
231         u = user_new(m, uid, gid, name);
232         if (!u)
233                 return -ENOMEM;
234
235         if (_user)
236                 *_user = u;
237
238         return 0;
239 }
240
241 int manager_add_user_by_name(Manager *m, const char *name, User **_user) {
242         uid_t uid;
243         gid_t gid;
244         int r;
245
246         assert(m);
247         assert(name);
248
249         r = get_user_creds(&name, &uid, &gid, NULL);
250         if (r < 0)
251                 return r;
252
253         return manager_add_user(m, uid, gid, name, _user);
254 }
255
256 int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
257         struct passwd *p;
258
259         assert(m);
260
261         errno = 0;
262         p = getpwuid(uid);
263         if (!p)
264                 return errno ? -errno : -ENOENT;
265
266         return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
267 }
268
269 int manager_process_seat_device(Manager *m, struct udev_device *d) {
270         Device *device;
271         int r;
272
273         assert(m);
274
275         if (streq_ptr(udev_device_get_action(d), "remove")) {
276
277                 /* FIXME: use syspath instead of sysname here, as soon as fb driver is fixed */
278                 device = hashmap_get(m->devices, udev_device_get_sysname(d));
279                 if (!device)
280                         return 0;
281
282                 seat_add_to_gc_queue(device->seat);
283                 device_free(device);
284
285         } else {
286                 const char *sn;
287                 Seat *seat;
288
289                 sn = udev_device_get_property_value(d, "ID_SEAT");
290                 if (isempty(sn))
291                         sn = "seat0";
292
293                 if (!seat_name_is_valid(sn)) {
294                         log_warning("Device with invalid seat name %s found, ignoring.", sn);
295                         return 0;
296                 }
297
298                 r = manager_add_device(m, udev_device_get_sysname(d), &device);
299                 if (r < 0)
300                         return r;
301
302                 r = manager_add_seat(m, sn, &seat);
303                 if (r < 0) {
304                         if (!device->seat)
305                                 device_free(device);
306
307                         return r;
308                 }
309
310                 device_attach(device, seat);
311                 seat_start(seat);
312         }
313
314         return 0;
315 }
316
317 int manager_enumerate_devices(Manager *m) {
318         struct udev_list_entry *item = NULL, *first = NULL;
319         struct udev_enumerate *e;
320         int r;
321
322         assert(m);
323
324         /* Loads devices from udev and creates seats for them as
325          * necessary */
326
327         e = udev_enumerate_new(m->udev);
328         if (!e) {
329                 r = -ENOMEM;
330                 goto finish;
331         }
332
333         r = udev_enumerate_add_match_subsystem(e, "graphics");
334         if (r < 0)
335                 goto finish;
336
337         r = udev_enumerate_add_match_tag(e, "seat");
338         if (r < 0)
339                 goto finish;
340
341         r = udev_enumerate_scan_devices(e);
342         if (r < 0)
343                 goto finish;
344
345         first = udev_enumerate_get_list_entry(e);
346         udev_list_entry_foreach(item, first) {
347                 struct udev_device *d;
348                 int k;
349
350                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
351                 if (!d) {
352                         r = -ENOMEM;
353                         goto finish;
354                 }
355
356                 k = manager_process_seat_device(m, d);
357                 udev_device_unref(d);
358
359                 if (k < 0)
360                         r = k;
361         }
362
363 finish:
364         if (e)
365                 udev_enumerate_unref(e);
366
367         return r;
368 }
369
370 int manager_enumerate_seats(Manager *m) {
371         DIR *d;
372         struct dirent *de;
373         int r = 0;
374
375         assert(m);
376
377         /* This loads data about seats stored on disk, but does not
378          * actually create any seats. Removes data of seats that no
379          * longer exist. */
380
381         d = opendir("/run/systemd/seats");
382         if (!d) {
383                 if (errno == ENOENT)
384                         return 0;
385
386                 log_error("Failed to open /run/systemd/seats: %m");
387                 return -errno;
388         }
389
390         while ((de = readdir(d))) {
391                 Seat *s;
392                 int k;
393
394                 if (!dirent_is_file(de))
395                         continue;
396
397                 s = hashmap_get(m->seats, de->d_name);
398                 if (!s) {
399                         unlinkat(dirfd(d), de->d_name, 0);
400                         continue;
401                 }
402
403                 k = seat_load(s);
404                 if (k < 0)
405                         r = k;
406         }
407
408         closedir(d);
409
410         return r;
411 }
412
413 static int manager_enumerate_users_from_cgroup(Manager *m) {
414         int r = 0;
415         char *name;
416         DIR *d;
417
418         r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &d);
419         if (r < 0) {
420                 if (r == -ENOENT)
421                         return 0;
422
423                 log_error("Failed to open %s: %s", m->cgroup_path, strerror(-r));
424                 return r;
425         }
426
427         while ((r = cg_read_subgroup(d, &name)) > 0) {
428                 User *user;
429                 int k;
430
431                 k = manager_add_user_by_name(m, name, &user);
432                 if (k < 0) {
433                         free(name);
434                         r = k;
435                         continue;
436                 }
437
438                 user_add_to_gc_queue(user);
439
440                 if (!user->cgroup_path)
441                         if (asprintf(&user->cgroup_path, "%s/%s", m->cgroup_path, name) < 0) {
442                                 r = -ENOMEM;
443                                 free(name);
444                                 break;
445                         }
446
447                 free(name);
448         }
449
450         closedir(d);
451
452         return r;
453 }
454
455 static int manager_enumerate_linger_users(Manager *m) {
456         DIR *d;
457         struct dirent *de;
458         int r = 0;
459
460         d = opendir("/var/lib/systemd/linger");
461         if (!d) {
462                 if (errno == ENOENT)
463                         return 0;
464
465                 log_error("Failed to open /var/lib/systemd/linger/: %m");
466                 return -errno;
467         }
468
469         while ((de = readdir(d))) {
470                 int k;
471
472                 if (!dirent_is_file(de))
473                         continue;
474
475                 k = manager_add_user_by_name(m, de->d_name, NULL);
476                 if (k < 0) {
477                         log_notice("Couldn't add lingering user %s: %s", de->d_name, strerror(-k));
478                         r = k;
479                 }
480         }
481
482         closedir(d);
483
484         return r;
485 }
486
487 int manager_enumerate_users(Manager *m) {
488         DIR *d;
489         struct dirent *de;
490         int r, k;
491
492         assert(m);
493
494         /* First, enumerate user cgroups */
495         r = manager_enumerate_users_from_cgroup(m);
496
497         /* Second, add lingering users on top */
498         k = manager_enumerate_linger_users(m);
499         if (k < 0)
500                 r = k;
501
502         /* Third, read in user data stored on disk */
503         d = opendir("/run/systemd/users");
504         if (!d) {
505                 if (errno == ENOENT)
506                         return 0;
507
508                 log_error("Failed to open /run/systemd/users: %m");
509                 return -errno;
510         }
511
512         while ((de = readdir(d))) {
513                 uid_t uid;
514                 User *u;
515
516                 if (!dirent_is_file(de))
517                         continue;
518
519                 k = parse_uid(de->d_name, &uid);
520                 if (k < 0) {
521                         log_error("Failed to parse file name %s: %s", de->d_name, strerror(-k));
522                         continue;
523                 }
524
525                 u = hashmap_get(m->users, ULONG_TO_PTR(uid));
526                 if (!u) {
527                         unlinkat(dirfd(d), de->d_name, 0);
528                         continue;
529                 }
530
531                 k = user_load(u);
532                 if (k < 0)
533                         r = k;
534         }
535
536         closedir(d);
537
538         return r;
539 }
540
541 static int manager_enumerate_sessions_from_cgroup(Manager *m) {
542         User *u;
543         Iterator i;
544         int r = 0;
545
546         HASHMAP_FOREACH(u, m->users, i) {
547                 DIR *d;
548                 char *name;
549                 int k;
550
551                 if (!u->cgroup_path)
552                         continue;
553
554                 k = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &d);
555                 if (k < 0) {
556                         if (k == -ENOENT)
557                                 continue;
558
559                         log_error("Failed to open %s: %s", u->cgroup_path, strerror(-k));
560                         r = k;
561                         continue;
562                 }
563
564                 while ((k = cg_read_subgroup(d, &name)) > 0) {
565                         Session *session;
566
567                         if (streq(name, "shared"))
568                                 continue;
569
570                         k = manager_add_session(m, u, name, &session);
571                         if (k < 0) {
572                                 free(name);
573                                 break;
574                         }
575
576                         session_add_to_gc_queue(session);
577
578                         if (!session->cgroup_path)
579                                 if (asprintf(&session->cgroup_path, "%s/%s", u->cgroup_path, name) < 0) {
580                                         k = -ENOMEM;
581                                         free(name);
582                                         break;
583                                 }
584
585                         free(name);
586                 }
587
588                 closedir(d);
589
590                 if (k < 0)
591                         r = k;
592         }
593
594         return r;
595 }
596
597 int manager_enumerate_sessions(Manager *m) {
598         DIR *d;
599         struct dirent *de;
600         int r = 0;
601
602         assert(m);
603
604         /* First enumerate session cgroups */
605         r = manager_enumerate_sessions_from_cgroup(m);
606
607         /* Second, read in session data stored on disk */
608         d = opendir("/run/systemd/sessions");
609         if (!d) {
610                 if (errno == ENOENT)
611                         return 0;
612
613                 log_error("Failed to open /run/systemd/sessions: %m");
614                 return -errno;
615         }
616
617         while ((de = readdir(d))) {
618                 struct Session *s;
619                 int k;
620
621                 if (!dirent_is_file(de))
622                         continue;
623
624                 s = hashmap_get(m->sessions, de->d_name);
625                 if (!s) {
626                         unlinkat(dirfd(d), de->d_name, 0);
627                         continue;
628                 }
629
630                 k = session_load(s);
631                 if (k < 0)
632                         r = k;
633         }
634
635         closedir(d);
636
637         return r;
638 }
639
640 int manager_dispatch_seat_udev(Manager *m) {
641         struct udev_device *d;
642         int r;
643
644         assert(m);
645
646         d = udev_monitor_receive_device(m->udev_seat_monitor);
647         if (!d)
648                 return -ENOMEM;
649
650         r = manager_process_seat_device(m, d);
651         udev_device_unref(d);
652
653         return r;
654 }
655
656
657 int manager_dispatch_vcsa_udev(Manager *m) {
658         struct udev_device *d;
659         int r = 0;
660         const char *name;
661
662         assert(m);
663
664         d = udev_monitor_receive_device(m->udev_vcsa_monitor);
665         if (!d)
666                 return -ENOMEM;
667
668         name = udev_device_get_sysname(d);
669
670         /* Whenever a VCSA device is removed try to reallocate our
671          * VTs, to make sure our auto VTs never go away. */
672
673         if (name && startswith(name, "vcsa") && streq_ptr(udev_device_get_action(d), "remove"))
674                 r = seat_preallocate_vts(m->vtconsole);
675
676         udev_device_unref(d);
677
678         return r;
679 }
680
681 int manager_dispatch_console(Manager *m) {
682         assert(m);
683
684         if (m->vtconsole)
685                 seat_read_active_vt(m->vtconsole);
686
687         return 0;
688 }
689
690 static int vt_is_busy(int vtnr) {
691         struct vt_stat vt_stat;
692         int r = 0, fd;
693
694         assert(vtnr >= 1);
695
696         /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
697          * we'd open the latter we'd open the foreground tty which
698          * hence would be unconditionally busy. By opening /dev/tty1
699          * we avoid this. Since tty1 is special and needs to be an
700          * explicitly loaded getty or DM this is safe. */
701
702         fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
703         if (fd < 0)
704                 return -errno;
705
706         if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
707                 r = -errno;
708         else
709                 r = !!(vt_stat.v_state & (1 << vtnr));
710
711         close_nointr_nofail(fd);
712
713         return r;
714 }
715
716 int manager_spawn_autovt(Manager *m, int vtnr) {
717         int r;
718         DBusMessage *message = NULL, *reply = NULL;
719         char *name = NULL;
720         const char *mode = "fail";
721         DBusError error;
722
723         assert(m);
724         assert(vtnr >= 1);
725
726         dbus_error_init(&error);
727
728         if ((unsigned) vtnr > m->n_autovts)
729                 return 0;
730
731         r = vt_is_busy(vtnr);
732         if (r < 0)
733                 return r;
734         else if (r > 0)
735                 return -EBUSY;
736
737         message = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit");
738         if (!message) {
739                 log_error("Could not allocate message.");
740                 r = -ENOMEM;
741                 goto finish;
742         }
743
744         if (asprintf(&name, "autovt@tty%i.service", vtnr) < 0) {
745                 log_error("Could not allocate service name.");
746                 r = -ENOMEM;
747                 goto finish;
748         }
749
750         if (!dbus_message_append_args(message,
751                                       DBUS_TYPE_STRING, &name,
752                                       DBUS_TYPE_STRING, &mode,
753                                       DBUS_TYPE_INVALID)) {
754                 log_error("Could not attach target and flag information to message.");
755                 r = -ENOMEM;
756                 goto finish;
757         }
758
759         reply = dbus_connection_send_with_reply_and_block(m->bus, message, -1, &error);
760         if (!reply) {
761                 log_error("Failed to start unit: %s", bus_error_message(&error));
762                 goto finish;
763         }
764
765         r = 0;
766
767 finish:
768         free(name);
769
770         if (message)
771                 dbus_message_unref(message);
772
773         if (reply)
774                 dbus_message_unref(reply);
775
776         dbus_error_free(&error);
777
778         return r;
779 }
780
781 void manager_cgroup_notify_empty(Manager *m, const char *cgroup) {
782         Session *s;
783         char *p;
784
785         assert(m);
786         assert(cgroup);
787
788         p = strdup(cgroup);
789         if (!p) {
790                 log_error("Out of memory.");
791                 return;
792         }
793
794         for (;;) {
795                 char *e;
796
797                 if (isempty(p) || streq(p, "/"))
798                         break;
799
800                 s = hashmap_get(m->cgroups, p);
801                 if (s)
802                         session_add_to_gc_queue(s);
803
804                 assert_se(e = strrchr(p, '/'));
805                 *e = 0;
806         }
807
808         free(p);
809 }
810
811 static void manager_pipe_notify_eof(Manager *m, int fd) {
812         Session *s;
813
814         assert_se(m);
815         assert_se(fd >= 0);
816
817         assert_se(s = hashmap_get(m->fifo_fds, INT_TO_PTR(fd + 1)));
818         assert(s->fifo_fd == fd);
819         session_remove_fifo(s);
820
821         session_stop(s);
822 }
823
824 static int manager_connect_bus(Manager *m) {
825         DBusError error;
826         int r;
827         struct epoll_event ev;
828
829         assert(m);
830         assert(!m->bus);
831         assert(m->bus_fd < 0);
832
833         dbus_error_init(&error);
834
835         m->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
836         if (!m->bus) {
837                 log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error));
838                 r = -ECONNREFUSED;
839                 goto fail;
840         }
841
842         if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/login1", &bus_manager_vtable, m) ||
843             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/seat", &bus_seat_vtable, m) ||
844             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/session", &bus_session_vtable, m) ||
845             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/user", &bus_user_vtable, m) ||
846             !dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL)) {
847                 log_error("Not enough memory");
848                 r = -ENOMEM;
849                 goto fail;
850         }
851
852         dbus_bus_add_match(m->bus,
853                            "type='signal',"
854                            "interface='org.freedesktop.systemd1.Agent',"
855                            "member='Released',"
856                            "path='/org/freedesktop/systemd1/agent'",
857                            &error);
858
859         if (dbus_error_is_set(&error)) {
860                 log_error("Failed to register match: %s", bus_error_message(&error));
861                 r = -EIO;
862                 goto fail;
863         }
864
865         r = dbus_bus_request_name(m->bus, "org.freedesktop.login1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
866         if (dbus_error_is_set(&error)) {
867                 log_error("Failed to register name on bus: %s", bus_error_message(&error));
868                 r = -EIO;
869                 goto fail;
870         }
871
872         if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)  {
873                 log_error("Failed to acquire name.");
874                 r = -EEXIST;
875                 goto fail;
876         }
877
878         m->bus_fd = bus_loop_open(m->bus);
879         if (m->bus_fd < 0) {
880                 r = m->bus_fd;
881                 goto fail;
882         }
883
884         zero(ev);
885         ev.events = EPOLLIN;
886         ev.data.u32 = FD_BUS;
887
888         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0)
889                 goto fail;
890
891         return 0;
892
893 fail:
894         dbus_error_free(&error);
895
896         return r;
897 }
898
899 static int manager_connect_console(Manager *m) {
900         struct epoll_event ev;
901
902         assert(m);
903         assert(m->console_active_fd < 0);
904
905         m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC);
906         if (m->console_active_fd < 0) {
907                 log_error("Failed to open /sys/class/tty/tty0/active: %m");
908                 return -errno;
909         }
910
911         zero(ev);
912         ev.events = 0;
913         ev.data.u32 = FD_CONSOLE;
914
915         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->console_active_fd, &ev) < 0)
916                 return -errno;
917
918         return 0;
919 }
920
921 static int manager_connect_udev(Manager *m) {
922         struct epoll_event ev;
923         int r;
924
925         assert(m);
926         assert(!m->udev_seat_monitor);
927         assert(!m->udev_vcsa_monitor);
928
929         m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
930         if (!m->udev_seat_monitor)
931                 return -ENOMEM;
932
933         r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "seat");
934         if (r < 0)
935                 return r;
936
937         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_seat_monitor, "graphics", NULL);
938         if (r < 0)
939                 return r;
940
941         r = udev_monitor_enable_receiving(m->udev_seat_monitor);
942         if (r < 0)
943                 return r;
944
945         m->udev_seat_fd = udev_monitor_get_fd(m->udev_seat_monitor);
946
947         zero(ev);
948         ev.events = EPOLLIN;
949         ev.data.u32 = FD_SEAT_UDEV;
950
951         if (m->n_autovts <= 0)
952                 return 0;
953
954         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_seat_fd, &ev) < 0)
955                 return -errno;
956
957         m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
958         if (!m->udev_vcsa_monitor)
959                 return -ENOMEM;
960
961         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL);
962         if (r < 0)
963                 return r;
964
965         r = udev_monitor_enable_receiving(m->udev_vcsa_monitor);
966         if (r < 0)
967                 return r;
968
969         m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor);
970
971         zero(ev);
972         ev.events = EPOLLIN;
973         ev.data.u32 = FD_VCSA_UDEV;
974
975         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_vcsa_fd, &ev) < 0)
976                 return -errno;
977
978         return 0;
979 }
980
981 void manager_gc(Manager *m, bool drop_not_started) {
982         Seat *seat;
983         Session *session;
984         User *user;
985
986         assert(m);
987
988         while ((seat = m->seat_gc_queue)) {
989                 LIST_REMOVE(Seat, gc_queue, m->seat_gc_queue, seat);
990                 seat->in_gc_queue = false;
991
992                 if (seat_check_gc(seat, drop_not_started) == 0) {
993                         seat_stop(seat);
994                         seat_free(seat);
995                 }
996         }
997
998         while ((session = m->session_gc_queue)) {
999                 LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session);
1000                 session->in_gc_queue = false;
1001
1002                 if (session_check_gc(session, drop_not_started) == 0) {
1003                         session_stop(session);
1004                         session_free(session);
1005                 }
1006         }
1007
1008         while ((user = m->user_gc_queue)) {
1009                 LIST_REMOVE(User, gc_queue, m->user_gc_queue, user);
1010                 user->in_gc_queue = false;
1011
1012                 if (user_check_gc(user, drop_not_started) == 0) {
1013                         user_stop(user);
1014                         user_free(user);
1015                 }
1016         }
1017 }
1018
1019 int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
1020         Session *s;
1021         bool idle_hint = true;
1022         dual_timestamp ts = { 0, 0 };
1023         Iterator i;
1024
1025         assert(m);
1026
1027         HASHMAP_FOREACH(s, m->sessions, i) {
1028                 dual_timestamp k;
1029                 int ih;
1030
1031                 ih = session_get_idle_hint(s, &k);
1032                 if (ih < 0)
1033                         return ih;
1034
1035                 if (!ih) {
1036                         if (!idle_hint) {
1037                                 if (k.monotonic < ts.monotonic)
1038                                         ts = k;
1039                         } else {
1040                                 idle_hint = false;
1041                                 ts = k;
1042                         }
1043                 } else if (idle_hint) {
1044
1045                         if (k.monotonic > ts.monotonic)
1046                                 ts = k;
1047                 }
1048         }
1049
1050         if (t)
1051                 *t = ts;
1052
1053         return idle_hint;
1054 }
1055
1056 int manager_startup(Manager *m) {
1057         int r;
1058         Seat *seat;
1059         Session *session;
1060         User *user;
1061         Iterator i;
1062
1063         assert(m);
1064         assert(m->epoll_fd <= 0);
1065
1066         m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
1067         if (m->epoll_fd < 0)
1068                 return -errno;
1069
1070         /* Connect to udev */
1071         r = manager_connect_udev(m);
1072         if (r < 0)
1073                 return r;
1074
1075         /* Connect to console */
1076         r = manager_connect_console(m);
1077         if (r < 0)
1078                 return r;
1079
1080         /* Connect to the bus */
1081         r = manager_connect_bus(m);
1082         if (r < 0)
1083                 return r;
1084
1085         /* Instantiate magic seat 0 */
1086         r = manager_add_seat(m, "seat0", &m->vtconsole);
1087         if (r < 0)
1088                 return r;
1089
1090         /* Deserialize state */
1091         manager_enumerate_devices(m);
1092         manager_enumerate_seats(m);
1093         manager_enumerate_users(m);
1094         manager_enumerate_sessions(m);
1095
1096         /* Remove stale objects before we start them */
1097         manager_gc(m, false);
1098
1099         /* And start everything */
1100         HASHMAP_FOREACH(seat, m->seats, i)
1101                 seat_start(seat);
1102
1103         HASHMAP_FOREACH(user, m->users, i)
1104                 user_start(user);
1105
1106         HASHMAP_FOREACH(session, m->sessions, i)
1107                 session_start(session);
1108
1109         return 0;
1110 }
1111
1112 int manager_run(Manager *m) {
1113         assert(m);
1114
1115         for (;;) {
1116                 struct epoll_event event;
1117                 int n;
1118
1119                 manager_gc(m, true);
1120
1121                 if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
1122                         continue;
1123
1124                 manager_gc(m, true);
1125
1126                 n = epoll_wait(m->epoll_fd, &event, 1, -1);
1127                 if (n < 0) {
1128                         if (errno == EINTR || errno == EAGAIN)
1129                                 continue;
1130
1131                         log_error("epoll() failed: %m");
1132                         return -errno;
1133                 }
1134
1135                 switch (event.data.u32) {
1136
1137                 case FD_SEAT_UDEV:
1138                         manager_dispatch_seat_udev(m);
1139                         break;
1140
1141                 case FD_VCSA_UDEV:
1142                         manager_dispatch_vcsa_udev(m);
1143                         break;
1144
1145                 case FD_CONSOLE:
1146                         manager_dispatch_console(m);
1147                         break;
1148
1149                 case FD_BUS:
1150                         bus_loop_dispatch(m->bus_fd);
1151                         break;
1152
1153                 default:
1154                         if (event.data.u32 >= FD_FIFO_BASE)
1155                                 manager_pipe_notify_eof(m, event.data.u32 - FD_FIFO_BASE);
1156                 }
1157         }
1158
1159         return 0;
1160 }
1161
1162 static int manager_parse_config_file(Manager *m) {
1163
1164         const ConfigItem items[] = {
1165                 { "NAutoVTs",          config_parse_unsigned, 0, &m->n_autovts,           "Login" },
1166                 { "KillUserProcesses", config_parse_bool,     0, &m->kill_user_processes, "Login" },
1167                 { "KillOnlyUsers",     config_parse_strv,     0, &m->kill_only_users,     "Login" },
1168                 { "KillExcludeUsers",  config_parse_strv,     0, &m->kill_exclude_users,  "Login" },
1169                 { "Controllers",       config_parse_strv,     0, &m->controllers,         "Login" },
1170                 { "ResetControllers",  config_parse_strv,     0, &m->reset_controllers,   "Login" },
1171                 { NULL, NULL, 0, NULL, NULL }
1172         };
1173
1174         static const char * const sections[] = {
1175                 "Login",
1176                 NULL
1177         };
1178
1179         FILE *f;
1180         const char *fn;
1181         int r;
1182
1183         assert(m);
1184
1185         fn = "/etc/systemd/systemd-logind.conf";
1186         f = fopen(fn, "re");
1187         if (!f) {
1188                 if (errno == ENOENT)
1189                         return 0;
1190
1191                 log_warning("Failed to open configuration file %s: %m", fn);
1192                 return -errno;
1193         }
1194
1195         r = config_parse(fn, f, sections, items, false, NULL);
1196         if (r < 0)
1197                 log_warning("Failed to parse configuration file: %s", strerror(-r));
1198
1199         fclose(f);
1200
1201         return r;
1202 }
1203
1204 int main(int argc, char *argv[]) {
1205         Manager *m = NULL;
1206         int r;
1207
1208         log_set_target(LOG_TARGET_AUTO);
1209         log_parse_environment();
1210         log_open();
1211
1212         if (argc != 1) {
1213                 log_error("This program takes no arguments.");
1214                 r = -EINVAL;
1215                 goto finish;
1216         }
1217
1218         umask(0022);
1219
1220         m = manager_new();
1221         if (!m) {
1222                 log_error("Out of memory");
1223                 r = -ENOMEM;
1224                 goto finish;
1225         }
1226
1227         manager_parse_config_file(m);
1228
1229         r = manager_startup(m);
1230         if (r < 0) {
1231                 log_error("Failed to fully start up daemon: %s", strerror(-r));
1232                 goto finish;
1233         }
1234
1235         r = manager_run(m);
1236
1237 finish:
1238         if (m)
1239                 manager_free(m);
1240
1241         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1242 }