chiark / gitweb /
util: user parse_uid() 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         struct passwd *p;
243
244         assert(m);
245         assert(name);
246
247         errno = 0;
248         p = getpwnam(name);
249         if (!p)
250                 return errno ? -errno : -ENOENT;
251
252         return manager_add_user(m, p->pw_uid, p->pw_gid, name, _user);
253 }
254
255 int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
256         struct passwd *p;
257
258         assert(m);
259
260         errno = 0;
261         p = getpwuid(uid);
262         if (!p)
263                 return errno ? -errno : -ENOENT;
264
265         return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
266 }
267
268 int manager_process_seat_device(Manager *m, struct udev_device *d) {
269         Device *device;
270         int r;
271
272         assert(m);
273
274         if (streq_ptr(udev_device_get_action(d), "remove")) {
275
276                 /* FIXME: use syspath instead of sysname here, as soon as fb driver is fixed */
277                 device = hashmap_get(m->devices, udev_device_get_sysname(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_sysname(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
417         r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &d);
418         if (r < 0) {
419                 if (r == -ENOENT)
420                         return 0;
421
422                 log_error("Failed to open %s: %s", m->cgroup_path, strerror(-r));
423                 return r;
424         }
425
426         while ((r = cg_read_subgroup(d, &name)) > 0) {
427                 User *user;
428                 int k;
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         closedir(d);
450
451         return r;
452 }
453
454 static int manager_enumerate_linger_users(Manager *m) {
455         DIR *d;
456         struct dirent *de;
457         int r = 0;
458
459         d = opendir("/var/lib/systemd/linger");
460         if (!d) {
461                 if (errno == ENOENT)
462                         return 0;
463
464                 log_error("Failed to open /var/lib/systemd/linger/: %m");
465                 return -errno;
466         }
467
468         while ((de = readdir(d))) {
469                 int k;
470
471                 if (!dirent_is_file(de))
472                         continue;
473
474                 k = manager_add_user_by_name(m, de->d_name, NULL);
475                 if (k < 0) {
476                         log_notice("Couldn't add lingering user %s: %s", de->d_name, strerror(-k));
477                         r = k;
478                 }
479         }
480
481         closedir(d);
482
483         return r;
484 }
485
486 int manager_enumerate_users(Manager *m) {
487         DIR *d;
488         struct dirent *de;
489         int r, k;
490
491         assert(m);
492
493         /* First, enumerate user cgroups */
494         r = manager_enumerate_users_from_cgroup(m);
495
496         /* Second, add lingering users on top */
497         k = manager_enumerate_linger_users(m);
498         if (k < 0)
499                 r = k;
500
501         /* Third, read in user data stored on disk */
502         d = opendir("/run/systemd/users");
503         if (!d) {
504                 if (errno == ENOENT)
505                         return 0;
506
507                 log_error("Failed to open /run/systemd/users: %m");
508                 return -errno;
509         }
510
511         while ((de = readdir(d))) {
512                 uid_t uid;
513                 User *u;
514
515                 if (!dirent_is_file(de))
516                         continue;
517
518                 k = parse_uid(de->d_name, &uid);
519                 if (k < 0) {
520                         log_error("Failed to parse file name %s: %s", de->d_name, strerror(-k));
521                         continue;
522                 }
523
524                 u = hashmap_get(m->users, ULONG_TO_PTR(uid));
525                 if (!u) {
526                         unlinkat(dirfd(d), de->d_name, 0);
527                         continue;
528                 }
529
530                 k = user_load(u);
531                 if (k < 0)
532                         r = k;
533         }
534
535         closedir(d);
536
537         return r;
538 }
539
540 static int manager_enumerate_sessions_from_cgroup(Manager *m) {
541         User *u;
542         Iterator i;
543         int r = 0;
544
545         HASHMAP_FOREACH(u, m->users, i) {
546                 DIR *d;
547                 char *name;
548                 int k;
549
550                 if (!u->cgroup_path)
551                         continue;
552
553                 k = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &d);
554                 if (k < 0) {
555                         if (k == -ENOENT)
556                                 continue;
557
558                         log_error("Failed to open %s: %s", u->cgroup_path, strerror(-k));
559                         r = k;
560                         continue;
561                 }
562
563                 while ((k = cg_read_subgroup(d, &name)) > 0) {
564                         Session *session;
565
566                         if (streq(name, "shared"))
567                                 continue;
568
569                         k = manager_add_session(m, u, name, &session);
570                         if (k < 0) {
571                                 free(name);
572                                 break;
573                         }
574
575                         session_add_to_gc_queue(session);
576
577                         if (!session->cgroup_path)
578                                 if (asprintf(&session->cgroup_path, "%s/%s", u->cgroup_path, name) < 0) {
579                                         k = -ENOMEM;
580                                         free(name);
581                                         break;
582                                 }
583
584                         free(name);
585                 }
586
587                 closedir(d);
588
589                 if (k < 0)
590                         r = k;
591         }
592
593         return r;
594 }
595
596 int manager_enumerate_sessions(Manager *m) {
597         DIR *d;
598         struct dirent *de;
599         int r = 0;
600
601         assert(m);
602
603         /* First enumerate session cgroups */
604         r = manager_enumerate_sessions_from_cgroup(m);
605
606         /* Second, read in session data stored on disk */
607         d = opendir("/run/systemd/sessions");
608         if (!d) {
609                 if (errno == ENOENT)
610                         return 0;
611
612                 log_error("Failed to open /run/systemd/sessions: %m");
613                 return -errno;
614         }
615
616         while ((de = readdir(d))) {
617                 struct Session *s;
618                 int k;
619
620                 if (!dirent_is_file(de))
621                         continue;
622
623                 s = hashmap_get(m->sessions, de->d_name);
624                 if (!s) {
625                         unlinkat(dirfd(d), de->d_name, 0);
626                         continue;
627                 }
628
629                 k = session_load(s);
630                 if (k < 0)
631                         r = k;
632         }
633
634         closedir(d);
635
636         return r;
637 }
638
639 int manager_dispatch_seat_udev(Manager *m) {
640         struct udev_device *d;
641         int r;
642
643         assert(m);
644
645         d = udev_monitor_receive_device(m->udev_seat_monitor);
646         if (!d)
647                 return -ENOMEM;
648
649         r = manager_process_seat_device(m, d);
650         udev_device_unref(d);
651
652         return r;
653 }
654
655
656 int manager_dispatch_vcsa_udev(Manager *m) {
657         struct udev_device *d;
658         int r = 0;
659         const char *name;
660
661         assert(m);
662
663         d = udev_monitor_receive_device(m->udev_vcsa_monitor);
664         if (!d)
665                 return -ENOMEM;
666
667         name = udev_device_get_sysname(d);
668
669         /* Whenever a VCSA device is removed try to reallocate our
670          * VTs, to make sure our auto VTs never go away. */
671
672         if (name && startswith(name, "vcsa") && streq_ptr(udev_device_get_action(d), "remove"))
673                 r = seat_preallocate_vts(m->vtconsole);
674
675         udev_device_unref(d);
676
677         return r;
678 }
679
680 int manager_dispatch_console(Manager *m) {
681         assert(m);
682
683         if (m->vtconsole)
684                 seat_read_active_vt(m->vtconsole);
685
686         return 0;
687 }
688
689 static int vt_is_busy(int vtnr) {
690         struct vt_stat vt_stat;
691         int r = 0, fd;
692
693         assert(vtnr >= 1);
694
695         /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
696          * we'd open the latter we'd open the foreground tty which
697          * hence would be unconditionally busy. By opening /dev/tty1
698          * we avoid this. Since tty1 is special and needs to be an
699          * explicitly loaded getty or DM this is safe. */
700
701         fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
702         if (fd < 0)
703                 return -errno;
704
705         if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
706                 r = -errno;
707         else
708                 r = !!(vt_stat.v_state & (1 << vtnr));
709
710         close_nointr_nofail(fd);
711
712         return r;
713 }
714
715 int manager_spawn_autovt(Manager *m, int vtnr) {
716         int r;
717         DBusMessage *message = NULL, *reply = NULL;
718         char *name = NULL;
719         const char *mode = "fail";
720         DBusError error;
721
722         assert(m);
723         assert(vtnr >= 1);
724
725         dbus_error_init(&error);
726
727         if ((unsigned) vtnr > m->n_autovts)
728                 return 0;
729
730         r = vt_is_busy(vtnr);
731         if (r < 0)
732                 return r;
733         else if (r > 0)
734                 return -EBUSY;
735
736         message = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit");
737         if (!message) {
738                 log_error("Could not allocate message.");
739                 r = -ENOMEM;
740                 goto finish;
741         }
742
743         if (asprintf(&name, "autovt@tty%i.service", vtnr) < 0) {
744                 log_error("Could not allocate service name.");
745                 r = -ENOMEM;
746                 goto finish;
747         }
748
749         if (!dbus_message_append_args(message,
750                                       DBUS_TYPE_STRING, &name,
751                                       DBUS_TYPE_STRING, &mode,
752                                       DBUS_TYPE_INVALID)) {
753                 log_error("Could not attach target and flag information to message.");
754                 r = -ENOMEM;
755                 goto finish;
756         }
757
758         reply = dbus_connection_send_with_reply_and_block(m->bus, message, -1, &error);
759         if (!reply) {
760                 log_error("Failed to start unit: %s", bus_error_message(&error));
761                 goto finish;
762         }
763
764         r = 0;
765
766 finish:
767         free(name);
768
769         if (message)
770                 dbus_message_unref(message);
771
772         if (reply)
773                 dbus_message_unref(reply);
774
775         dbus_error_free(&error);
776
777         return r;
778 }
779
780 void manager_cgroup_notify_empty(Manager *m, const char *cgroup) {
781         Session *s;
782         char *p;
783
784         assert(m);
785         assert(cgroup);
786
787         p = strdup(cgroup);
788         if (!p) {
789                 log_error("Out of memory.");
790                 return;
791         }
792
793         for (;;) {
794                 char *e;
795
796                 if (isempty(p) || streq(p, "/"))
797                         break;
798
799                 s = hashmap_get(m->cgroups, p);
800                 if (s)
801                         session_add_to_gc_queue(s);
802
803                 assert_se(e = strrchr(p, '/'));
804                 *e = 0;
805         }
806
807         free(p);
808 }
809
810 static void manager_pipe_notify_eof(Manager *m, int fd) {
811         Session *s;
812
813         assert_se(m);
814         assert_se(fd >= 0);
815
816         assert_se(s = hashmap_get(m->fifo_fds, INT_TO_PTR(fd + 1)));
817         assert(s->fifo_fd == fd);
818         session_remove_fifo(s);
819
820         session_stop(s);
821 }
822
823 static int manager_connect_bus(Manager *m) {
824         DBusError error;
825         int r;
826         struct epoll_event ev;
827
828         assert(m);
829         assert(!m->bus);
830         assert(m->bus_fd < 0);
831
832         dbus_error_init(&error);
833
834         m->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
835         if (!m->bus) {
836                 log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error));
837                 r = -ECONNREFUSED;
838                 goto fail;
839         }
840
841         if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/login1", &bus_manager_vtable, m) ||
842             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/seat", &bus_seat_vtable, m) ||
843             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/session", &bus_session_vtable, m) ||
844             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/user", &bus_user_vtable, m) ||
845             !dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL)) {
846                 log_error("Not enough memory");
847                 r = -ENOMEM;
848                 goto fail;
849         }
850
851         dbus_bus_add_match(m->bus,
852                            "type='signal',"
853                            "interface='org.freedesktop.systemd1.Agent',"
854                            "member='Released',"
855                            "path='/org/freedesktop/systemd1/agent'",
856                            &error);
857
858         if (dbus_error_is_set(&error)) {
859                 log_error("Failed to register match: %s", bus_error_message(&error));
860                 r = -EIO;
861                 goto fail;
862         }
863
864         r = dbus_bus_request_name(m->bus, "org.freedesktop.login1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
865         if (dbus_error_is_set(&error)) {
866                 log_error("Failed to register name on bus: %s", bus_error_message(&error));
867                 r = -EIO;
868                 goto fail;
869         }
870
871         if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)  {
872                 log_error("Failed to acquire name.");
873                 r = -EEXIST;
874                 goto fail;
875         }
876
877         m->bus_fd = bus_loop_open(m->bus);
878         if (m->bus_fd < 0) {
879                 r = m->bus_fd;
880                 goto fail;
881         }
882
883         zero(ev);
884         ev.events = EPOLLIN;
885         ev.data.u32 = FD_BUS;
886
887         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0)
888                 goto fail;
889
890         return 0;
891
892 fail:
893         dbus_error_free(&error);
894
895         return r;
896 }
897
898 static int manager_connect_console(Manager *m) {
899         struct epoll_event ev;
900
901         assert(m);
902         assert(m->console_active_fd < 0);
903
904         m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC);
905         if (m->console_active_fd < 0) {
906                 log_error("Failed to open /sys/class/tty/tty0/active: %m");
907                 return -errno;
908         }
909
910         zero(ev);
911         ev.events = 0;
912         ev.data.u32 = FD_CONSOLE;
913
914         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->console_active_fd, &ev) < 0)
915                 return -errno;
916
917         return 0;
918 }
919
920 static int manager_connect_udev(Manager *m) {
921         struct epoll_event ev;
922         int r;
923
924         assert(m);
925         assert(!m->udev_seat_monitor);
926         assert(!m->udev_vcsa_monitor);
927
928         m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
929         if (!m->udev_seat_monitor)
930                 return -ENOMEM;
931
932         r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "seat");
933         if (r < 0)
934                 return r;
935
936         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_seat_monitor, "graphics", NULL);
937         if (r < 0)
938                 return r;
939
940         r = udev_monitor_enable_receiving(m->udev_seat_monitor);
941         if (r < 0)
942                 return r;
943
944         m->udev_seat_fd = udev_monitor_get_fd(m->udev_seat_monitor);
945
946         zero(ev);
947         ev.events = EPOLLIN;
948         ev.data.u32 = FD_SEAT_UDEV;
949
950         if (m->n_autovts <= 0)
951                 return 0;
952
953         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_seat_fd, &ev) < 0)
954                 return -errno;
955
956         m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
957         if (!m->udev_vcsa_monitor)
958                 return -ENOMEM;
959
960         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL);
961         if (r < 0)
962                 return r;
963
964         r = udev_monitor_enable_receiving(m->udev_vcsa_monitor);
965         if (r < 0)
966                 return r;
967
968         m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor);
969
970         zero(ev);
971         ev.events = EPOLLIN;
972         ev.data.u32 = FD_VCSA_UDEV;
973
974         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_vcsa_fd, &ev) < 0)
975                 return -errno;
976
977         return 0;
978 }
979
980 void manager_gc(Manager *m, bool drop_not_started) {
981         Seat *seat;
982         Session *session;
983         User *user;
984
985         assert(m);
986
987         while ((seat = m->seat_gc_queue)) {
988                 LIST_REMOVE(Seat, gc_queue, m->seat_gc_queue, seat);
989                 seat->in_gc_queue = false;
990
991                 if (seat_check_gc(seat, drop_not_started) == 0) {
992                         seat_stop(seat);
993                         seat_free(seat);
994                 }
995         }
996
997         while ((session = m->session_gc_queue)) {
998                 LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session);
999                 session->in_gc_queue = false;
1000
1001                 if (session_check_gc(session, drop_not_started) == 0) {
1002                         session_stop(session);
1003                         session_free(session);
1004                 }
1005         }
1006
1007         while ((user = m->user_gc_queue)) {
1008                 LIST_REMOVE(User, gc_queue, m->user_gc_queue, user);
1009                 user->in_gc_queue = false;
1010
1011                 if (user_check_gc(user, drop_not_started) == 0) {
1012                         user_stop(user);
1013                         user_free(user);
1014                 }
1015         }
1016 }
1017
1018 int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
1019         Session *s;
1020         bool idle_hint = true;
1021         dual_timestamp ts = { 0, 0 };
1022         Iterator i;
1023
1024         assert(m);
1025
1026         HASHMAP_FOREACH(s, m->sessions, i) {
1027                 dual_timestamp k;
1028                 int ih;
1029
1030                 ih = session_get_idle_hint(s, &k);
1031                 if (ih < 0)
1032                         return ih;
1033
1034                 if (!ih) {
1035                         if (!idle_hint) {
1036                                 if (k.monotonic < ts.monotonic)
1037                                         ts = k;
1038                         } else {
1039                                 idle_hint = false;
1040                                 ts = k;
1041                         }
1042                 } else if (idle_hint) {
1043
1044                         if (k.monotonic > ts.monotonic)
1045                                 ts = k;
1046                 }
1047         }
1048
1049         if (t)
1050                 *t = ts;
1051
1052         return idle_hint;
1053 }
1054
1055 int manager_startup(Manager *m) {
1056         int r;
1057         Seat *seat;
1058         Session *session;
1059         User *user;
1060         Iterator i;
1061
1062         assert(m);
1063         assert(m->epoll_fd <= 0);
1064
1065         m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
1066         if (m->epoll_fd < 0)
1067                 return -errno;
1068
1069         /* Connect to udev */
1070         r = manager_connect_udev(m);
1071         if (r < 0)
1072                 return r;
1073
1074         /* Connect to console */
1075         r = manager_connect_console(m);
1076         if (r < 0)
1077                 return r;
1078
1079         /* Connect to the bus */
1080         r = manager_connect_bus(m);
1081         if (r < 0)
1082                 return r;
1083
1084         /* Instantiate magic seat 0 */
1085         r = manager_add_seat(m, "seat0", &m->vtconsole);
1086         if (r < 0)
1087                 return r;
1088
1089         /* Deserialize state */
1090         manager_enumerate_devices(m);
1091         manager_enumerate_seats(m);
1092         manager_enumerate_users(m);
1093         manager_enumerate_sessions(m);
1094
1095         /* Remove stale objects before we start them */
1096         manager_gc(m, false);
1097
1098         /* And start everything */
1099         HASHMAP_FOREACH(seat, m->seats, i)
1100                 seat_start(seat);
1101
1102         HASHMAP_FOREACH(user, m->users, i)
1103                 user_start(user);
1104
1105         HASHMAP_FOREACH(session, m->sessions, i)
1106                 session_start(session);
1107
1108         return 0;
1109 }
1110
1111 int manager_run(Manager *m) {
1112         assert(m);
1113
1114         for (;;) {
1115                 struct epoll_event event;
1116                 int n;
1117
1118                 manager_gc(m, true);
1119
1120                 if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
1121                         continue;
1122
1123                 manager_gc(m, true);
1124
1125                 n = epoll_wait(m->epoll_fd, &event, 1, -1);
1126                 if (n < 0) {
1127                         if (errno == EINTR || errno == EAGAIN)
1128                                 continue;
1129
1130                         log_error("epoll() failed: %m");
1131                         return -errno;
1132                 }
1133
1134                 switch (event.data.u32) {
1135
1136                 case FD_SEAT_UDEV:
1137                         manager_dispatch_seat_udev(m);
1138                         break;
1139
1140                 case FD_VCSA_UDEV:
1141                         manager_dispatch_vcsa_udev(m);
1142                         break;
1143
1144                 case FD_CONSOLE:
1145                         manager_dispatch_console(m);
1146                         break;
1147
1148                 case FD_BUS:
1149                         bus_loop_dispatch(m->bus_fd);
1150                         break;
1151
1152                 default:
1153                         if (event.data.u32 >= FD_FIFO_BASE)
1154                                 manager_pipe_notify_eof(m, event.data.u32 - FD_FIFO_BASE);
1155                 }
1156         }
1157
1158         return 0;
1159 }
1160
1161 static int manager_parse_config_file(Manager *m) {
1162
1163         const ConfigItem items[] = {
1164                 { "NAutoVTs",          config_parse_unsigned, 0, &m->n_autovts,           "Login" },
1165                 { "KillUserProcesses", config_parse_bool,     0, &m->kill_user_processes, "Login" },
1166                 { "KillOnlyUsers",     config_parse_strv,     0, &m->kill_only_users,     "Login" },
1167                 { "KillExcludeUsers",  config_parse_strv,     0, &m->kill_exclude_users,  "Login" },
1168                 { "Controllers",       config_parse_strv,     0, &m->controllers,         "Login" },
1169                 { "ResetControllers",  config_parse_strv,     0, &m->reset_controllers,   "Login" },
1170                 { NULL, NULL, 0, NULL, NULL }
1171         };
1172
1173         static const char * const sections[] = {
1174                 "Login",
1175                 NULL
1176         };
1177
1178         FILE *f;
1179         const char *fn;
1180         int r;
1181
1182         assert(m);
1183
1184         fn = "/etc/systemd/systemd-logind.conf";
1185         f = fopen(fn, "re");
1186         if (!f) {
1187                 if (errno == ENOENT)
1188                         return 0;
1189
1190                 log_warning("Failed to open configuration file %s: %m", fn);
1191                 return -errno;
1192         }
1193
1194         r = config_parse(fn, f, sections, items, false, NULL);
1195         if (r < 0)
1196                 log_warning("Failed to parse configuration file: %s", strerror(-r));
1197
1198         fclose(f);
1199
1200         return r;
1201 }
1202
1203 int main(int argc, char *argv[]) {
1204         Manager *m = NULL;
1205         int r;
1206
1207         log_set_target(LOG_TARGET_AUTO);
1208         log_parse_environment();
1209         log_open();
1210
1211         if (argc != 1) {
1212                 log_error("This program takes no arguments.");
1213                 r = -EINVAL;
1214                 goto finish;
1215         }
1216
1217         umask(0022);
1218
1219         m = manager_new();
1220         if (!m) {
1221                 log_error("Out of memory");
1222                 r = -ENOMEM;
1223                 goto finish;
1224         }
1225
1226         manager_parse_config_file(m);
1227
1228         r = manager_startup(m);
1229         if (r < 0) {
1230                 log_error("Failed to fully start up daemon: %s", strerror(-r));
1231                 goto finish;
1232         }
1233
1234         r = manager_run(m);
1235
1236 finish:
1237         if (m)
1238                 manager_free(m);
1239
1240         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1241 }