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