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