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