chiark / gitweb /
2665ab910d95f08c20b29d529ff6fae6dd651b30
[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
36 enum {
37         FD_UDEV,
38         FD_CONSOLE,
39         FD_BUS
40 };
41
42 Manager *manager_new(void) {
43         Manager *m;
44
45         m = new0(Manager, 1);
46         if (!m)
47                 return NULL;
48
49         m->console_active_fd = -1;
50         m->bus_fd = -1;
51         m->udev_fd = -1;
52         m->epoll_fd = -1;
53         m->n_autovts = 6;
54
55         m->devices = hashmap_new(string_hash_func, string_compare_func);
56         m->seats = hashmap_new(string_hash_func, string_compare_func);
57         m->sessions = hashmap_new(string_hash_func, string_compare_func);
58         m->users = hashmap_new(trivial_hash_func, trivial_compare_func);
59         m->cgroups = hashmap_new(string_hash_func, string_compare_func);
60
61         if (!m->devices || !m->seats || !m->sessions || !m->users) {
62                 manager_free(m);
63                 return NULL;
64         }
65
66         m->udev = udev_new();
67         if (!m->udev) {
68                 manager_free(m);
69                 return NULL;
70         }
71
72         if (cg_get_user_path(&m->cgroup_path) < 0) {
73                 manager_free(m);
74                 return NULL;
75         }
76
77         return m;
78 }
79
80 void manager_free(Manager *m) {
81         Session *session;
82         User *u;
83         Device *d;
84         Seat *s;
85
86         assert(m);
87
88         while ((session = hashmap_first(m->sessions)))
89                 session_free(session);
90
91         while ((u = hashmap_first(m->users)))
92                 user_free(u);
93
94         while ((d = hashmap_first(m->devices)))
95                 device_free(d);
96
97         while ((s = hashmap_first(m->seats)))
98                 seat_free(s);
99
100         hashmap_free(m->sessions);
101         hashmap_free(m->users);
102         hashmap_free(m->devices);
103         hashmap_free(m->seats);
104         hashmap_free(m->cgroups);
105
106         if (m->console_active_fd >= 0)
107                 close_nointr_nofail(m->console_active_fd);
108
109         if (m->udev_monitor)
110                 udev_monitor_unref(m->udev_monitor);
111
112         if (m->udev)
113                 udev_unref(m->udev);
114
115         if (m->bus) {
116                 dbus_connection_flush(m->bus);
117                 dbus_connection_close(m->bus);
118                 dbus_connection_unref(m->bus);
119         }
120
121         if (m->bus_fd >= 0)
122                 close_nointr_nofail(m->bus_fd);
123
124         if (m->epoll_fd >= 0)
125                 close_nointr_nofail(m->epoll_fd);
126
127         free(m->cgroup_path);
128         free(m);
129 }
130
131 int manager_add_device(Manager *m, const char *sysfs, Device **_device) {
132         Device *d;
133
134         assert(m);
135         assert(sysfs);
136
137         d = hashmap_get(m->devices, sysfs);
138         if (d) {
139                 if (_device)
140                         *_device = d;
141
142                 return 0;
143         }
144
145         d = device_new(m, sysfs);
146         if (!d)
147                 return -ENOMEM;
148
149         if (_device)
150                 *_device = d;
151
152         return 0;
153 }
154
155 int manager_add_seat(Manager *m, const char *id, Seat **_seat) {
156         Seat *s;
157
158         assert(m);
159         assert(id);
160
161         s = hashmap_get(m->seats, id);
162         if (s) {
163                 if (_seat)
164                         *_seat = s;
165
166                 return 0;
167         }
168
169         s = seat_new(m, id);
170         if (!s)
171                 return -ENOMEM;
172
173         if (_seat)
174                 *_seat = s;
175
176         return 0;
177 }
178
179 int manager_add_session(Manager *m, User *u, const char *id, Session **_session) {
180         Session *s;
181
182         assert(m);
183         assert(id);
184
185         s = hashmap_get(m->sessions, id);
186         if (s) {
187                 if (_session)
188                         *_session = s;
189
190                 return 0;
191         }
192
193         s = session_new(m, u, id);
194         if (!s)
195                 return -ENOMEM;
196
197         if (_session)
198                 *_session = s;
199
200         return 0;
201 }
202
203 int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
204         User *u;
205
206         assert(m);
207         assert(name);
208
209         u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
210         if (u) {
211                 if (_user)
212                         *_user = u;
213
214                 return 0;
215         }
216
217         u = user_new(m, uid, gid, name);
218         if (!u)
219                 return -ENOMEM;
220
221         if (_user)
222                 *_user = u;
223
224         return 0;
225 }
226
227 int manager_add_user_by_name(Manager *m, const char *name, User **_user) {
228         struct passwd *p;
229
230         assert(m);
231         assert(name);
232
233         errno = 0;
234         p = getpwnam(name);
235         if (!p)
236                 return errno ? -errno : -ENOENT;
237
238         return manager_add_user(m, p->pw_uid, p->pw_gid, name, _user);
239 }
240
241 int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
242         struct passwd *p;
243
244         assert(m);
245
246         errno = 0;
247         p = getpwuid(uid);
248         if (!p)
249                 return errno ? -errno : -ENOENT;
250
251         return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
252 }
253
254 int manager_process_device(Manager *m, struct udev_device *d) {
255         Device *device;
256         int r;
257
258         assert(m);
259
260         /* FIXME: drop this check as soon as libudev's enum support
261          * honours tags and subsystem matches at the same time */
262         if (!streq_ptr(udev_device_get_subsystem(d), "graphics"))
263                 return 0;
264
265         if (streq_ptr(udev_device_get_action(d), "remove")) {
266
267                 /* FIXME: use syspath instead of sysname here, as soon as fb driver is fixed */
268                 device = hashmap_get(m->devices, udev_device_get_sysname(d));
269                 if (!device)
270                         return 0;
271
272                 seat_add_to_gc_queue(device->seat);
273                 device_free(device);
274
275         } else {
276                 const char *sn;
277                 Seat *seat;
278
279                 sn = udev_device_get_property_value(d, "ID_SEAT");
280                 if (!sn)
281                         sn = "seat0";
282
283                 if (!seat_name_is_valid(sn)) {
284                         log_warning("Device with invalid seat name %s found, ignoring.", sn);
285                         return 0;
286                 }
287
288                 r = manager_add_device(m, udev_device_get_sysname(d), &device);
289                 if (r < 0)
290                         return r;
291
292                 r = manager_add_seat(m, sn, &seat);
293                 if (r < 0) {
294                         if (!device->seat)
295                                 device_free(device);
296
297                         return r;
298                 }
299
300                 device_attach(device, seat);
301                 seat_start(seat);
302         }
303
304         return 0;
305 }
306
307 int manager_enumerate_devices(Manager *m) {
308         struct udev_list_entry *item = NULL, *first = NULL;
309         struct udev_enumerate *e;
310         int r;
311
312         assert(m);
313
314         /* Loads devices from udev and creates seats for them as
315          * necessary */
316
317         e = udev_enumerate_new(m->udev);
318         if (!e) {
319                 r = -ENOMEM;
320                 goto finish;
321         }
322
323         r = udev_enumerate_add_match_subsystem(e, "graphics");
324         if (r < 0)
325                 goto finish;
326
327         r = udev_enumerate_add_match_tag(e, "seat");
328         if (r < 0)
329                 goto finish;
330
331         r = udev_enumerate_scan_devices(e);
332         if (r < 0)
333                 goto finish;
334
335         first = udev_enumerate_get_list_entry(e);
336         udev_list_entry_foreach(item, first) {
337                 struct udev_device *d;
338                 int k;
339
340                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
341                 if (!d) {
342                         r = -ENOMEM;
343                         goto finish;
344                 }
345
346                 k = manager_process_device(m, d);
347                 udev_device_unref(d);
348
349                 if (k < 0)
350                         r = k;
351         }
352
353 finish:
354         if (e)
355                 udev_enumerate_unref(e);
356
357         return r;
358 }
359
360 int manager_enumerate_seats(Manager *m) {
361         DIR *d;
362         struct dirent *de;
363         int r = 0;
364
365         assert(m);
366
367         /* This loads data about seats stored on disk, but does not
368          * actually create any seats. Removes data of seats that no
369          * longer exist. */
370
371         d = opendir("/run/systemd/seats");
372         if (!d) {
373                 if (errno == ENOENT)
374                         return 0;
375
376                 log_error("Failed to open /run/systemd/seats: %m");
377                 return -errno;
378         }
379
380         while ((de = readdir(d))) {
381                 Seat *s;
382                 int k;
383
384                 if (!dirent_is_file(de))
385                         continue;
386
387                 s = hashmap_get(m->seats, de->d_name);
388                 if (!s) {
389                         unlinkat(dirfd(d), de->d_name, 0);
390                         continue;
391                 }
392
393                 k = seat_load(s);
394                 if (k < 0)
395                         r = k;
396         }
397
398         closedir(d);
399
400         return r;
401 }
402
403 static int manager_enumerate_users_from_cgroup(Manager *m) {
404         int r = 0;
405         char *name;
406         DIR *d;
407
408         r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &d);
409         if (r < 0) {
410                 if (r == -ENOENT)
411                         return 0;
412
413                 log_error("Failed to open %s: %s", m->cgroup_path, strerror(-r));
414                 return r;
415         }
416
417         while ((r = cg_read_subgroup(d, &name)) > 0) {
418                 User *user;
419                 int k;
420
421                 k = manager_add_user_by_name(m, name, &user);
422                 if (k < 0) {
423                         free(name);
424                         r = k;
425                         continue;
426                 }
427
428                 user_add_to_gc_queue(user);
429
430                 if (!user->cgroup_path)
431                         if (asprintf(&user->cgroup_path, "%s/%s", m->cgroup_path, name) < 0) {
432                                 r = -ENOMEM;
433                                 free(name);
434                                 break;
435                         }
436
437                 free(name);
438         }
439
440         closedir(d);
441
442         return r;
443 }
444
445
446 static int manager_enumerate_linger_users(Manager *m) {
447         DIR *d;
448         struct dirent *de;
449         int r = 0;
450
451         d = opendir("/var/lib/systemd/linger");
452         if (!d) {
453                 if (errno == ENOENT)
454                         return 0;
455
456                 log_error("Failed to open /var/lib/systemd/linger/: %m");
457                 return -errno;
458         }
459
460         while ((de = readdir(d))) {
461                 int k;
462
463                 if (!dirent_is_file(de))
464                         continue;
465
466                 k = manager_add_user_by_name(m, de->d_name, NULL);
467                 if (k < 0) {
468                         log_notice("Couldn't add lingering user %s: %s", de->d_name, strerror(-k));
469                         r = k;
470                 }
471         }
472
473         closedir(d);
474
475         return r;
476 }
477
478 int manager_enumerate_users(Manager *m) {
479         DIR *d;
480         struct dirent *de;
481         int r, k;
482
483         assert(m);
484
485         /* First, enumerate user cgroups */
486         r = manager_enumerate_users_from_cgroup(m);
487
488         /* Second, add lingering users on top */
489         k = manager_enumerate_linger_users(m);
490         if (k < 0)
491                 r = k;
492
493         /* Third, read in user data stored on disk */
494         d = opendir("/run/systemd/users");
495         if (!d) {
496                 if (errno == ENOENT)
497                         return 0;
498
499                 log_error("Failed to open /run/systemd/users: %m");
500                 return -errno;
501         }
502
503         while ((de = readdir(d))) {
504                 unsigned long ul;
505                 User *u;
506
507                 if (!dirent_is_file(de))
508                         continue;
509
510                 k = safe_atolu(de->d_name, &ul);
511                 if (k < 0) {
512                         log_error("Failed to parse file name %s: %s", de->d_name, strerror(-k));
513                         continue;
514                 }
515
516                 u = hashmap_get(m->users, ULONG_TO_PTR(ul));
517                 if (!u) {
518                         unlinkat(dirfd(d), de->d_name, 0);
519                         continue;
520                 }
521
522                 k = user_load(u);
523                 if (k < 0)
524                         r = k;
525         }
526
527         closedir(d);
528
529         return r;
530 }
531
532 static int manager_enumerate_sessions_from_cgroup(Manager *m) {
533         User *u;
534         Iterator i;
535         int r = 0;
536
537         HASHMAP_FOREACH(u, m->users, i) {
538                 DIR *d;
539                 char *name;
540                 int k;
541
542                 if (!u->cgroup_path)
543                         continue;
544
545                 k = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &d);
546                 if (k < 0) {
547                         if (k == -ENOENT)
548                                 continue;
549
550                         log_error("Failed to open %s: %s", u->cgroup_path, strerror(-k));
551                         r = k;
552                         continue;
553                 }
554
555                 while ((k = cg_read_subgroup(d, &name)) > 0) {
556                         Session *session;
557
558                         k = manager_add_session(m, u, name, &session);
559                         if (k < 0) {
560                                 free(name);
561                                 break;
562                         }
563
564                         session_add_to_gc_queue(session);
565
566                         if (!session->cgroup_path)
567                                 if (asprintf(&session->cgroup_path, "%s/%s", u->cgroup_path, name) < 0) {
568                                         k = -ENOMEM;
569                                         free(name);
570                                         break;
571                                 }
572
573                         free(name);
574                 }
575
576                 closedir(d);
577
578                 if (k < 0)
579                         r = k;
580         }
581
582         return r;
583 }
584
585 int manager_enumerate_sessions(Manager *m) {
586         DIR *d;
587         struct dirent *de;
588         int r = 0;
589
590         assert(m);
591
592         /* First enumerate session cgroups */
593         r = manager_enumerate_sessions_from_cgroup(m);
594
595         /* Second, read in session data stored on disk */
596         d = opendir("/run/systemd/sessions");
597         if (!d) {
598                 if (errno == ENOENT)
599                         return 0;
600
601                 log_error("Failed to open /run/systemd/sessions: %m");
602                 return -errno;
603         }
604
605         while ((de = readdir(d))) {
606                 struct Session *s;
607                 int k;
608
609                 if (!dirent_is_file(de))
610                         continue;
611
612                 s = hashmap_get(m->sessions, de->d_name);
613                 if (!s) {
614                         unlinkat(dirfd(d), de->d_name, 0);
615                         continue;
616                 }
617
618                 k = session_load(s);
619                 if (k < 0)
620                         r = k;
621         }
622
623         closedir(d);
624
625         return r;
626 }
627
628 int manager_dispatch_udev(Manager *m) {
629         struct udev_device *d;
630         int r;
631
632         assert(m);
633
634         d = udev_monitor_receive_device(m->udev_monitor);
635         if (!d)
636                 return -ENOMEM;
637
638         r = manager_process_device(m, d);
639         udev_device_unref(d);
640
641         return r;
642 }
643
644 int manager_dispatch_console(Manager *m) {
645         assert(m);
646
647         if (m->vtconsole)
648                 seat_read_active_vt(m->vtconsole);
649
650         return 0;
651 }
652
653 static int vt_is_busy(int vtnr) {
654         struct vt_stat vt_stat;
655         int r = 0, fd;
656
657         assert(vtnr >= 1);
658
659         fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
660         if (fd < 0)
661                 return -errno;
662
663         if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
664                 r = -errno;
665         else
666                 r = !!(vt_stat.v_state & (1 << vtnr));
667
668         close_nointr_nofail(fd);
669
670         return r;
671 }
672
673 int manager_spawn_autovt(Manager *m, int vtnr) {
674         int r;
675
676         assert(m);
677
678         r = vt_is_busy(vtnr);
679         if (r != 0)
680                 return r;
681
682         /* ... */
683
684         return 0;
685 }
686
687 void manager_cgroup_notify_empty(Manager *m, const char *cgroup) {
688         Session *s;
689         char *p;
690
691         assert(m);
692         assert(cgroup);
693
694         p = strdup(cgroup);
695         if (!p) {
696                 log_error("Out of memory.");
697                 return;
698         }
699
700         for (;;) {
701                 char *e;
702
703                 if (isempty(p) || streq(p, "/"))
704                         break;
705
706                 s = hashmap_get(m->cgroups, p);
707                 if (s)
708                         session_add_to_gc_queue(s);
709
710                 assert_se(e = strrchr(p, '/'));
711                 *e = 0;
712         }
713
714         free(p);
715 }
716
717 static int manager_connect_bus(Manager *m) {
718         DBusError error;
719         int r;
720         struct epoll_event ev;
721
722         assert(m);
723         assert(!m->bus);
724         assert(m->bus_fd < 0);
725
726         dbus_error_init(&error);
727
728         m->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
729         if (!m->bus) {
730                 log_error("Failed to get system D-Bus connection: %s", error.message);
731                 r = -ECONNREFUSED;
732                 goto fail;
733         }
734
735         if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/login1", &bus_manager_vtable, m) ||
736             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/seat", &bus_seat_vtable, m) ||
737             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/session", &bus_session_vtable, m) ||
738             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/user", &bus_user_vtable, m) ||
739             !dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL)) {
740                 log_error("Not enough memory");
741                 r = -ENOMEM;
742                 goto fail;
743         }
744
745         dbus_bus_add_match(m->bus,
746                            "type='signal',"
747                            "interface='org.freedesktop.systemd1.Agent',"
748                            "member='Released',"
749                            "path='/org/freedesktop/systemd1/agent'",
750                            &error);
751
752         if (dbus_error_is_set(&error)) {
753                 log_error("Failed to register match: %s", error.message);
754                 r = -EIO;
755                 goto fail;
756         }
757
758         if (dbus_bus_request_name(m->bus, "org.freedesktop.login1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) < 0) {
759                 log_error("Failed to register name on bus: %s", error.message);
760                 r = -EEXIST;
761                 goto fail;
762         }
763
764         m->bus_fd = bus_loop_open(m->bus);
765         if (m->bus_fd < 0) {
766                 r = m->bus_fd;
767                 goto fail;
768         }
769
770         zero(ev);
771         ev.events = EPOLLIN;
772         ev.data.u32 = FD_BUS;
773
774         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0)
775                 goto fail;
776
777         return 0;
778
779 fail:
780         dbus_error_free(&error);
781
782         return r;
783 }
784
785 static int manager_connect_console(Manager *m) {
786         struct epoll_event ev;
787
788         assert(m);
789         assert(m->console_active_fd < 0);
790
791         m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC);
792         if (m->console_active_fd < 0) {
793                 log_error("Failed to open /sys/class/tty/tty0/active: %m");
794                 return -errno;
795         }
796
797         zero(ev);
798         ev.events = 0;
799         ev.data.u32 = FD_CONSOLE;
800
801         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->console_active_fd, &ev) < 0)
802                 return -errno;
803
804         return 0;
805 }
806
807 static int manager_connect_udev(Manager *m) {
808         struct epoll_event ev;
809         int r;
810
811         assert(m);
812         assert(!m->udev_monitor);
813
814         m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
815         if (!m->udev_monitor)
816                 return -ENOMEM;
817
818         r = udev_monitor_filter_add_match_tag(m->udev_monitor, "seat");
819         if (r < 0)
820                 return r;
821
822         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "graphics", NULL);
823         if (r < 0)
824                 return r;
825
826         r = udev_monitor_enable_receiving(m->udev_monitor);
827         if (r < 0)
828                 return r;
829
830         m->udev_fd = udev_monitor_get_fd(m->udev_monitor);
831
832         zero(ev);
833         ev.events = EPOLLIN;
834         ev.data.u32 = FD_UDEV;
835
836         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_fd, &ev) < 0)
837                 return -errno;
838
839         return 0;
840 }
841
842 void manager_gc(Manager *m) {
843         Seat *seat;
844         Session *session;
845         User *user;
846
847         assert(m);
848
849         while ((seat = m->seat_gc_queue)) {
850                 LIST_REMOVE(Seat, gc_queue, m->seat_gc_queue, seat);
851                 seat->in_gc_queue = false;
852
853                 if (seat_check_gc(seat) == 0) {
854                         seat_stop(seat);
855                         seat_free(seat);
856                 }
857         }
858
859         while ((session = m->session_gc_queue)) {
860                 LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session);
861                 session->in_gc_queue = false;
862
863                 if (session_check_gc(session) == 0) {
864                         session_stop(session);
865                         session_free(session);
866                 }
867         }
868
869         while ((user = m->user_gc_queue)) {
870                 LIST_REMOVE(User, gc_queue, m->user_gc_queue, user);
871                 user->in_gc_queue = false;
872
873                 if (user_check_gc(user) == 0) {
874                         user_stop(user);
875                         user_free(user);
876                 }
877         }
878 }
879
880 int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
881         Session *s;
882         bool idle_hint = true;
883         dual_timestamp ts = { 0, 0 };
884         Iterator i;
885
886         assert(m);
887
888         HASHMAP_FOREACH(s, m->sessions, i) {
889                 dual_timestamp k;
890                 int ih;
891
892                 ih = session_get_idle_hint(s, &k);
893                 if (ih < 0)
894                         return ih;
895
896                 if (!ih) {
897                         if (!idle_hint) {
898                                 if (k.monotonic < ts.monotonic)
899                                         ts = k;
900                         } else {
901                                 idle_hint = false;
902                                 ts = k;
903                         }
904                 } else if (idle_hint) {
905
906                         if (k.monotonic > ts.monotonic)
907                                 ts = k;
908                 }
909         }
910
911         if (t)
912                 *t = ts;
913
914         return idle_hint;
915 }
916
917 int manager_startup(Manager *m) {
918         int r;
919         Seat *seat;
920         Session *session;
921         User *user;
922         Iterator i;
923
924         assert(m);
925         assert(m->epoll_fd <= 0);
926
927         m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
928         if (m->epoll_fd < 0)
929                 return -errno;
930
931         /* Connect to udev */
932         r = manager_connect_udev(m);
933         if (r < 0)
934                 return r;
935
936         /* Connect to console */
937         r = manager_connect_console(m);
938         if (r < 0)
939                 return r;
940
941         /* Connect to the bus */
942         r = manager_connect_bus(m);
943         if (r < 0)
944                 return r;
945
946         /* Instantiate magic seat 0 */
947         r = manager_add_seat(m, "seat0", &m->vtconsole);
948         if (r < 0)
949                 return r;
950
951         /* Deserialize state */
952         manager_enumerate_devices(m);
953         manager_enumerate_seats(m);
954         manager_enumerate_users(m);
955         manager_enumerate_sessions(m);
956
957         /* Get rid of objects that are no longer used */
958         manager_gc(m);
959
960         /* And start everything */
961         HASHMAP_FOREACH(seat, m->seats, i)
962                 seat_start(seat);
963
964         HASHMAP_FOREACH(user, m->users, i)
965                 user_start(user);
966
967         HASHMAP_FOREACH(session, m->sessions, i)
968                 session_start(session);
969
970         return 0;
971 }
972
973 int manager_run(Manager *m) {
974         assert(m);
975
976         for (;;) {
977                 struct epoll_event event;
978                 int n;
979
980                 manager_gc(m);
981
982                 if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
983                         continue;
984
985                 manager_gc(m);
986
987                 n = epoll_wait(m->epoll_fd, &event, 1, -1);
988                 if (n < 0) {
989                         if (errno == EINTR || errno == EAGAIN)
990                                 continue;
991
992                         log_error("epoll() failed: %m");
993                         return -errno;
994                 }
995
996                 switch (event.data.u32) {
997
998                 case FD_UDEV:
999                         manager_dispatch_udev(m);
1000                         break;
1001
1002                 case FD_CONSOLE:
1003                         manager_dispatch_console(m);
1004                         break;
1005
1006                 case FD_BUS:
1007                         bus_loop_dispatch(m->bus_fd);
1008                         break;
1009                 }
1010         }
1011
1012         return 0;
1013 }
1014
1015 int main(int argc, char *argv[]) {
1016         Manager *m = NULL;
1017         int r;
1018
1019         log_set_target(LOG_TARGET_AUTO);
1020         log_parse_environment();
1021         log_open();
1022
1023         if (argc != 1) {
1024                 log_error("This program takes no arguments.");
1025                 r = -EINVAL;
1026                 goto finish;
1027         }
1028
1029         umask(0022);
1030
1031         m = manager_new();
1032         if (!m) {
1033                 log_error("Out of memory");
1034                 r = -ENOMEM;
1035                 goto finish;
1036         }
1037
1038         r = manager_startup(m);
1039         if (r < 0) {
1040                 log_error("Failed to fully start up daemon: %s", strerror(-r));
1041                 goto finish;
1042         }
1043
1044         r = manager_run(m);
1045
1046 finish:
1047         if (m)
1048                 manager_free(m);
1049
1050         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1051 }