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