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