chiark / gitweb /
4633a5ef29109c9cf51538dfdc99deb5de96a4fb
[elogind.git] / src / login / 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                 device = hashmap_get(m->devices, udev_device_get_syspath(d));
278                 if (!device)
279                         return 0;
280
281                 seat_add_to_gc_queue(device->seat);
282                 device_free(device);
283
284         } else {
285                 const char *sn;
286                 Seat *seat;
287
288                 sn = udev_device_get_property_value(d, "ID_SEAT");
289                 if (isempty(sn))
290                         sn = "seat0";
291
292                 if (!seat_name_is_valid(sn)) {
293                         log_warning("Device with invalid seat name %s found, ignoring.", sn);
294                         return 0;
295                 }
296
297                 r = manager_add_device(m, udev_device_get_syspath(d), &device);
298                 if (r < 0)
299                         return r;
300
301                 r = manager_add_seat(m, sn, &seat);
302                 if (r < 0) {
303                         if (!device->seat)
304                                 device_free(device);
305
306                         return r;
307                 }
308
309                 device_attach(device, seat);
310                 seat_start(seat);
311         }
312
313         return 0;
314 }
315
316 int manager_enumerate_devices(Manager *m) {
317         struct udev_list_entry *item = NULL, *first = NULL;
318         struct udev_enumerate *e;
319         int r;
320
321         assert(m);
322
323         /* Loads devices from udev and creates seats for them as
324          * necessary */
325
326         e = udev_enumerate_new(m->udev);
327         if (!e) {
328                 r = -ENOMEM;
329                 goto finish;
330         }
331
332         r = udev_enumerate_add_match_subsystem(e, "graphics");
333         if (r < 0)
334                 goto finish;
335
336         r = udev_enumerate_add_match_tag(e, "seat");
337         if (r < 0)
338                 goto finish;
339
340         r = udev_enumerate_scan_devices(e);
341         if (r < 0)
342                 goto finish;
343
344         first = udev_enumerate_get_list_entry(e);
345         udev_list_entry_foreach(item, first) {
346                 struct udev_device *d;
347                 int k;
348
349                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
350                 if (!d) {
351                         r = -ENOMEM;
352                         goto finish;
353                 }
354
355                 k = manager_process_seat_device(m, d);
356                 udev_device_unref(d);
357
358                 if (k < 0)
359                         r = k;
360         }
361
362 finish:
363         if (e)
364                 udev_enumerate_unref(e);
365
366         return r;
367 }
368
369 int manager_enumerate_seats(Manager *m) {
370         DIR *d;
371         struct dirent *de;
372         int r = 0;
373
374         assert(m);
375
376         /* This loads data about seats stored on disk, but does not
377          * actually create any seats. Removes data of seats that no
378          * longer exist. */
379
380         d = opendir("/run/systemd/seats");
381         if (!d) {
382                 if (errno == ENOENT)
383                         return 0;
384
385                 log_error("Failed to open /run/systemd/seats: %m");
386                 return -errno;
387         }
388
389         while ((de = readdir(d))) {
390                 Seat *s;
391                 int k;
392
393                 if (!dirent_is_file(de))
394                         continue;
395
396                 s = hashmap_get(m->seats, de->d_name);
397                 if (!s) {
398                         unlinkat(dirfd(d), de->d_name, 0);
399                         continue;
400                 }
401
402                 k = seat_load(s);
403                 if (k < 0)
404                         r = k;
405         }
406
407         closedir(d);
408
409         return r;
410 }
411
412 static int manager_enumerate_users_from_cgroup(Manager *m) {
413         int r = 0;
414         char *name;
415         DIR *d;
416         int k;
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 ((k = cg_read_subgroup(d, &name)) > 0) {
428                 User *user;
429
430                 k = manager_add_user_by_name(m, name, &user);
431                 if (k < 0) {
432                         free(name);
433                         r = k;
434                         continue;
435                 }
436
437                 user_add_to_gc_queue(user);
438
439                 if (!user->cgroup_path)
440                         if (asprintf(&user->cgroup_path, "%s/%s", m->cgroup_path, name) < 0) {
441                                 r = -ENOMEM;
442                                 free(name);
443                                 break;
444                         }
445
446                 free(name);
447         }
448
449         if (r >= 0 && k < 0)
450                 r = k;
451
452         closedir(d);
453
454         return r;
455 }
456
457 static int manager_enumerate_linger_users(Manager *m) {
458         DIR *d;
459         struct dirent *de;
460         int r = 0;
461
462         d = opendir("/var/lib/systemd/linger");
463         if (!d) {
464                 if (errno == ENOENT)
465                         return 0;
466
467                 log_error("Failed to open /var/lib/systemd/linger/: %m");
468                 return -errno;
469         }
470
471         while ((de = readdir(d))) {
472                 int k;
473
474                 if (!dirent_is_file(de))
475                         continue;
476
477                 k = manager_add_user_by_name(m, de->d_name, NULL);
478                 if (k < 0) {
479                         log_notice("Couldn't add lingering user %s: %s", de->d_name, strerror(-k));
480                         r = k;
481                 }
482         }
483
484         closedir(d);
485
486         return r;
487 }
488
489 int manager_enumerate_users(Manager *m) {
490         DIR *d;
491         struct dirent *de;
492         int r, k;
493
494         assert(m);
495
496         /* First, enumerate user cgroups */
497         r = manager_enumerate_users_from_cgroup(m);
498
499         /* Second, add lingering users on top */
500         k = manager_enumerate_linger_users(m);
501         if (k < 0)
502                 r = k;
503
504         /* Third, read in user data stored on disk */
505         d = opendir("/run/systemd/users");
506         if (!d) {
507                 if (errno == ENOENT)
508                         return 0;
509
510                 log_error("Failed to open /run/systemd/users: %m");
511                 return -errno;
512         }
513
514         while ((de = readdir(d))) {
515                 uid_t uid;
516                 User *u;
517
518                 if (!dirent_is_file(de))
519                         continue;
520
521                 k = parse_uid(de->d_name, &uid);
522                 if (k < 0) {
523                         log_error("Failed to parse file name %s: %s", de->d_name, strerror(-k));
524                         continue;
525                 }
526
527                 u = hashmap_get(m->users, ULONG_TO_PTR(uid));
528                 if (!u) {
529                         unlinkat(dirfd(d), de->d_name, 0);
530                         continue;
531                 }
532
533                 k = user_load(u);
534                 if (k < 0)
535                         r = k;
536         }
537
538         closedir(d);
539
540         return r;
541 }
542
543 static int manager_enumerate_sessions_from_cgroup(Manager *m) {
544         User *u;
545         Iterator i;
546         int r = 0;
547
548         HASHMAP_FOREACH(u, m->users, i) {
549                 DIR *d;
550                 char *name;
551                 int k;
552
553                 if (!u->cgroup_path)
554                         continue;
555
556                 k = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &d);
557                 if (k < 0) {
558                         if (k == -ENOENT)
559                                 continue;
560
561                         log_error("Failed to open %s: %s", u->cgroup_path, strerror(-k));
562                         r = k;
563                         continue;
564                 }
565
566                 while ((k = cg_read_subgroup(d, &name)) > 0) {
567                         Session *session;
568
569                         if (streq(name, "shared"))
570                                 continue;
571
572                         k = manager_add_session(m, u, name, &session);
573                         if (k < 0) {
574                                 free(name);
575                                 break;
576                         }
577
578                         session_add_to_gc_queue(session);
579
580                         if (!session->cgroup_path)
581                                 if (asprintf(&session->cgroup_path, "%s/%s", u->cgroup_path, name) < 0) {
582                                         k = -ENOMEM;
583                                         free(name);
584                                         break;
585                                 }
586
587                         free(name);
588                 }
589
590                 closedir(d);
591
592                 if (k < 0)
593                         r = k;
594         }
595
596         return r;
597 }
598
599 int manager_enumerate_sessions(Manager *m) {
600         DIR *d;
601         struct dirent *de;
602         int r = 0;
603
604         assert(m);
605
606         /* First enumerate session cgroups */
607         r = manager_enumerate_sessions_from_cgroup(m);
608
609         /* Second, read in session data stored on disk */
610         d = opendir("/run/systemd/sessions");
611         if (!d) {
612                 if (errno == ENOENT)
613                         return 0;
614
615                 log_error("Failed to open /run/systemd/sessions: %m");
616                 return -errno;
617         }
618
619         while ((de = readdir(d))) {
620                 struct Session *s;
621                 int k;
622
623                 if (!dirent_is_file(de))
624                         continue;
625
626                 s = hashmap_get(m->sessions, de->d_name);
627                 if (!s) {
628                         unlinkat(dirfd(d), de->d_name, 0);
629                         continue;
630                 }
631
632                 k = session_load(s);
633                 if (k < 0)
634                         r = k;
635         }
636
637         closedir(d);
638
639         return r;
640 }
641
642 int manager_dispatch_seat_udev(Manager *m) {
643         struct udev_device *d;
644         int r;
645
646         assert(m);
647
648         d = udev_monitor_receive_device(m->udev_seat_monitor);
649         if (!d)
650                 return -ENOMEM;
651
652         r = manager_process_seat_device(m, d);
653         udev_device_unref(d);
654
655         return r;
656 }
657
658
659 int manager_dispatch_vcsa_udev(Manager *m) {
660         struct udev_device *d;
661         int r = 0;
662         const char *name;
663
664         assert(m);
665
666         d = udev_monitor_receive_device(m->udev_vcsa_monitor);
667         if (!d)
668                 return -ENOMEM;
669
670         name = udev_device_get_sysname(d);
671
672         /* Whenever a VCSA device is removed try to reallocate our
673          * VTs, to make sure our auto VTs never go away. */
674
675         if (name && startswith(name, "vcsa") && streq_ptr(udev_device_get_action(d), "remove"))
676                 r = seat_preallocate_vts(m->vtconsole);
677
678         udev_device_unref(d);
679
680         return r;
681 }
682
683 int manager_dispatch_console(Manager *m) {
684         assert(m);
685
686         if (m->vtconsole)
687                 seat_read_active_vt(m->vtconsole);
688
689         return 0;
690 }
691
692 static int vt_is_busy(int vtnr) {
693         struct vt_stat vt_stat;
694         int r = 0, fd;
695
696         assert(vtnr >= 1);
697
698         /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
699          * we'd open the latter we'd open the foreground tty which
700          * hence would be unconditionally busy. By opening /dev/tty1
701          * we avoid this. Since tty1 is special and needs to be an
702          * explicitly loaded getty or DM this is safe. */
703
704         fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
705         if (fd < 0)
706                 return -errno;
707
708         if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
709                 r = -errno;
710         else
711                 r = !!(vt_stat.v_state & (1 << vtnr));
712
713         close_nointr_nofail(fd);
714
715         return r;
716 }
717
718 int manager_spawn_autovt(Manager *m, int vtnr) {
719         int r;
720         DBusMessage *message = NULL, *reply = NULL;
721         char *name = NULL;
722         const char *mode = "fail";
723         DBusError error;
724
725         assert(m);
726         assert(vtnr >= 1);
727
728         dbus_error_init(&error);
729
730         if ((unsigned) vtnr > m->n_autovts)
731                 return 0;
732
733         r = vt_is_busy(vtnr);
734         if (r < 0)
735                 return r;
736         else if (r > 0)
737                 return -EBUSY;
738
739         message = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit");
740         if (!message) {
741                 log_error("Could not allocate message.");
742                 r = -ENOMEM;
743                 goto finish;
744         }
745
746         if (asprintf(&name, "autovt@tty%i.service", vtnr) < 0) {
747                 log_error("Could not allocate service name.");
748                 r = -ENOMEM;
749                 goto finish;
750         }
751
752         if (!dbus_message_append_args(message,
753                                       DBUS_TYPE_STRING, &name,
754                                       DBUS_TYPE_STRING, &mode,
755                                       DBUS_TYPE_INVALID)) {
756                 log_error("Could not attach target and flag information to message.");
757                 r = -ENOMEM;
758                 goto finish;
759         }
760
761         reply = dbus_connection_send_with_reply_and_block(m->bus, message, -1, &error);
762         if (!reply) {
763                 log_error("Failed to start unit: %s", bus_error_message(&error));
764                 goto finish;
765         }
766
767         r = 0;
768
769 finish:
770         free(name);
771
772         if (message)
773                 dbus_message_unref(message);
774
775         if (reply)
776                 dbus_message_unref(reply);
777
778         dbus_error_free(&error);
779
780         return r;
781 }
782
783 void manager_cgroup_notify_empty(Manager *m, const char *cgroup) {
784         Session *s;
785         char *p;
786
787         assert(m);
788         assert(cgroup);
789
790         p = strdup(cgroup);
791         if (!p) {
792                 log_error("Out of memory.");
793                 return;
794         }
795
796         for (;;) {
797                 char *e;
798
799                 if (isempty(p) || streq(p, "/"))
800                         break;
801
802                 s = hashmap_get(m->cgroups, p);
803                 if (s)
804                         session_add_to_gc_queue(s);
805
806                 assert_se(e = strrchr(p, '/'));
807                 *e = 0;
808         }
809
810         free(p);
811 }
812
813 static void manager_pipe_notify_eof(Manager *m, int fd) {
814         Session *s;
815
816         assert_se(m);
817         assert_se(fd >= 0);
818
819         assert_se(s = hashmap_get(m->fifo_fds, INT_TO_PTR(fd + 1)));
820         assert(s->fifo_fd == fd);
821         session_remove_fifo(s);
822
823         session_stop(s);
824 }
825
826 static int manager_connect_bus(Manager *m) {
827         DBusError error;
828         int r;
829         struct epoll_event ev;
830
831         assert(m);
832         assert(!m->bus);
833         assert(m->bus_fd < 0);
834
835         dbus_error_init(&error);
836
837         m->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
838         if (!m->bus) {
839                 log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error));
840                 r = -ECONNREFUSED;
841                 goto fail;
842         }
843
844         if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/login1", &bus_manager_vtable, m) ||
845             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/seat", &bus_seat_vtable, m) ||
846             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/session", &bus_session_vtable, m) ||
847             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/user", &bus_user_vtable, m) ||
848             !dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL)) {
849                 log_error("Not enough memory");
850                 r = -ENOMEM;
851                 goto fail;
852         }
853
854         dbus_bus_add_match(m->bus,
855                            "type='signal',"
856                            "interface='org.freedesktop.systemd1.Agent',"
857                            "member='Released',"
858                            "path='/org/freedesktop/systemd1/agent'",
859                            &error);
860
861         if (dbus_error_is_set(&error)) {
862                 log_error("Failed to register match: %s", bus_error_message(&error));
863                 r = -EIO;
864                 goto fail;
865         }
866
867         r = dbus_bus_request_name(m->bus, "org.freedesktop.login1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
868         if (dbus_error_is_set(&error)) {
869                 log_error("Failed to register name on bus: %s", bus_error_message(&error));
870                 r = -EIO;
871                 goto fail;
872         }
873
874         if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)  {
875                 log_error("Failed to acquire name.");
876                 r = -EEXIST;
877                 goto fail;
878         }
879
880         m->bus_fd = bus_loop_open(m->bus);
881         if (m->bus_fd < 0) {
882                 r = m->bus_fd;
883                 goto fail;
884         }
885
886         zero(ev);
887         ev.events = EPOLLIN;
888         ev.data.u32 = FD_BUS;
889
890         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0)
891                 goto fail;
892
893         return 0;
894
895 fail:
896         dbus_error_free(&error);
897
898         return r;
899 }
900
901 static int manager_connect_console(Manager *m) {
902         struct epoll_event ev;
903
904         assert(m);
905         assert(m->console_active_fd < 0);
906
907         m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC);
908         if (m->console_active_fd < 0) {
909                 log_error("Failed to open /sys/class/tty/tty0/active: %m");
910                 return -errno;
911         }
912
913         zero(ev);
914         ev.events = 0;
915         ev.data.u32 = FD_CONSOLE;
916
917         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->console_active_fd, &ev) < 0)
918                 return -errno;
919
920         return 0;
921 }
922
923 static int manager_connect_udev(Manager *m) {
924         struct epoll_event ev;
925         int r;
926
927         assert(m);
928         assert(!m->udev_seat_monitor);
929         assert(!m->udev_vcsa_monitor);
930
931         m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
932         if (!m->udev_seat_monitor)
933                 return -ENOMEM;
934
935         r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "seat");
936         if (r < 0)
937                 return r;
938
939         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_seat_monitor, "graphics", NULL);
940         if (r < 0)
941                 return r;
942
943         r = udev_monitor_enable_receiving(m->udev_seat_monitor);
944         if (r < 0)
945                 return r;
946
947         m->udev_seat_fd = udev_monitor_get_fd(m->udev_seat_monitor);
948
949         zero(ev);
950         ev.events = EPOLLIN;
951         ev.data.u32 = FD_SEAT_UDEV;
952
953         if (m->n_autovts <= 0)
954                 return 0;
955
956         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_seat_fd, &ev) < 0)
957                 return -errno;
958
959         m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
960         if (!m->udev_vcsa_monitor)
961                 return -ENOMEM;
962
963         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL);
964         if (r < 0)
965                 return r;
966
967         r = udev_monitor_enable_receiving(m->udev_vcsa_monitor);
968         if (r < 0)
969                 return r;
970
971         m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor);
972
973         zero(ev);
974         ev.events = EPOLLIN;
975         ev.data.u32 = FD_VCSA_UDEV;
976
977         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_vcsa_fd, &ev) < 0)
978                 return -errno;
979
980         return 0;
981 }
982
983 void manager_gc(Manager *m, bool drop_not_started) {
984         Seat *seat;
985         Session *session;
986         User *user;
987
988         assert(m);
989
990         while ((seat = m->seat_gc_queue)) {
991                 LIST_REMOVE(Seat, gc_queue, m->seat_gc_queue, seat);
992                 seat->in_gc_queue = false;
993
994                 if (seat_check_gc(seat, drop_not_started) == 0) {
995                         seat_stop(seat);
996                         seat_free(seat);
997                 }
998         }
999
1000         while ((session = m->session_gc_queue)) {
1001                 LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session);
1002                 session->in_gc_queue = false;
1003
1004                 if (session_check_gc(session, drop_not_started) == 0) {
1005                         session_stop(session);
1006                         session_free(session);
1007                 }
1008         }
1009
1010         while ((user = m->user_gc_queue)) {
1011                 LIST_REMOVE(User, gc_queue, m->user_gc_queue, user);
1012                 user->in_gc_queue = false;
1013
1014                 if (user_check_gc(user, drop_not_started) == 0) {
1015                         user_stop(user);
1016                         user_free(user);
1017                 }
1018         }
1019 }
1020
1021 int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
1022         Session *s;
1023         bool idle_hint = true;
1024         dual_timestamp ts = { 0, 0 };
1025         Iterator i;
1026
1027         assert(m);
1028
1029         HASHMAP_FOREACH(s, m->sessions, i) {
1030                 dual_timestamp k;
1031                 int ih;
1032
1033                 ih = session_get_idle_hint(s, &k);
1034                 if (ih < 0)
1035                         return ih;
1036
1037                 if (!ih) {
1038                         if (!idle_hint) {
1039                                 if (k.monotonic < ts.monotonic)
1040                                         ts = k;
1041                         } else {
1042                                 idle_hint = false;
1043                                 ts = k;
1044                         }
1045                 } else if (idle_hint) {
1046
1047                         if (k.monotonic > ts.monotonic)
1048                                 ts = k;
1049                 }
1050         }
1051
1052         if (t)
1053                 *t = ts;
1054
1055         return idle_hint;
1056 }
1057
1058 int manager_startup(Manager *m) {
1059         int r;
1060         Seat *seat;
1061         Session *session;
1062         User *user;
1063         Iterator i;
1064
1065         assert(m);
1066         assert(m->epoll_fd <= 0);
1067
1068         m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
1069         if (m->epoll_fd < 0)
1070                 return -errno;
1071
1072         /* Connect to udev */
1073         r = manager_connect_udev(m);
1074         if (r < 0)
1075                 return r;
1076
1077         /* Connect to console */
1078         r = manager_connect_console(m);
1079         if (r < 0)
1080                 return r;
1081
1082         /* Connect to the bus */
1083         r = manager_connect_bus(m);
1084         if (r < 0)
1085                 return r;
1086
1087         /* Instantiate magic seat 0 */
1088         r = manager_add_seat(m, "seat0", &m->vtconsole);
1089         if (r < 0)
1090                 return r;
1091
1092         /* Deserialize state */
1093         manager_enumerate_devices(m);
1094         manager_enumerate_seats(m);
1095         manager_enumerate_users(m);
1096         manager_enumerate_sessions(m);
1097
1098         /* Remove stale objects before we start them */
1099         manager_gc(m, false);
1100
1101         /* And start everything */
1102         HASHMAP_FOREACH(seat, m->seats, i)
1103                 seat_start(seat);
1104
1105         HASHMAP_FOREACH(user, m->users, i)
1106                 user_start(user);
1107
1108         HASHMAP_FOREACH(session, m->sessions, i)
1109                 session_start(session);
1110
1111         return 0;
1112 }
1113
1114 int manager_run(Manager *m) {
1115         assert(m);
1116
1117         for (;;) {
1118                 struct epoll_event event;
1119                 int n;
1120
1121                 manager_gc(m, true);
1122
1123                 if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
1124                         continue;
1125
1126                 manager_gc(m, true);
1127
1128                 n = epoll_wait(m->epoll_fd, &event, 1, -1);
1129                 if (n < 0) {
1130                         if (errno == EINTR || errno == EAGAIN)
1131                                 continue;
1132
1133                         log_error("epoll() failed: %m");
1134                         return -errno;
1135                 }
1136
1137                 switch (event.data.u32) {
1138
1139                 case FD_SEAT_UDEV:
1140                         manager_dispatch_seat_udev(m);
1141                         break;
1142
1143                 case FD_VCSA_UDEV:
1144                         manager_dispatch_vcsa_udev(m);
1145                         break;
1146
1147                 case FD_CONSOLE:
1148                         manager_dispatch_console(m);
1149                         break;
1150
1151                 case FD_BUS:
1152                         bus_loop_dispatch(m->bus_fd);
1153                         break;
1154
1155                 default:
1156                         if (event.data.u32 >= FD_FIFO_BASE)
1157                                 manager_pipe_notify_eof(m, event.data.u32 - FD_FIFO_BASE);
1158                 }
1159         }
1160
1161         return 0;
1162 }
1163
1164 static int manager_parse_config_file(Manager *m) {
1165         FILE *f;
1166         const char *fn;
1167         int r;
1168
1169         assert(m);
1170
1171         fn = "/etc/systemd/systemd-logind.conf";
1172         f = fopen(fn, "re");
1173         if (!f) {
1174                 if (errno == ENOENT)
1175                         return 0;
1176
1177                 log_warning("Failed to open configuration file %s: %m", fn);
1178                 return -errno;
1179         }
1180
1181         r = config_parse(fn, f, "Login\0", config_item_perf_lookup, (void*) logind_gperf_lookup, false, m);
1182         if (r < 0)
1183                 log_warning("Failed to parse configuration file: %s", strerror(-r));
1184
1185         fclose(f);
1186
1187         return r;
1188 }
1189
1190 int main(int argc, char *argv[]) {
1191         Manager *m = NULL;
1192         int r;
1193
1194         log_set_target(LOG_TARGET_AUTO);
1195         log_parse_environment();
1196         log_open();
1197
1198         umask(0022);
1199
1200         if (argc != 1) {
1201                 log_error("This program takes no arguments.");
1202                 r = -EINVAL;
1203                 goto finish;
1204         }
1205
1206         m = manager_new();
1207         if (!m) {
1208                 log_error("Out of memory");
1209                 r = -ENOMEM;
1210                 goto finish;
1211         }
1212
1213         manager_parse_config_file(m);
1214
1215         r = manager_startup(m);
1216         if (r < 0) {
1217                 log_error("Failed to fully start up daemon: %s", strerror(-r));
1218                 goto finish;
1219         }
1220
1221         r = manager_run(m);
1222
1223 finish:
1224         if (m)
1225                 manager_free(m);
1226
1227         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1228 }