chiark / gitweb /
Merge pull request #7 from elogind/dev_v228-r1
[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 <fcntl.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "libudev.h"
28 #include "sd-daemon.h"
29
30 #include "alloc-util.h"
31 #include "bus-error.h"
32 #include "bus-util.h"
33 #include "conf-parser.h"
34 #include "def.h"
35 #include "dirent-util.h"
36 #include "fd-util.h"
37 #include "formats-util.h"
38 #include "logind.h"
39 #include "signal-util.h"
40 #include "strv.h"
41 #include "udev-util.h"
42
43 /// additional includes elogind needs
44 #include "cgroup.h"       // From src/core/
45 #include "label.h"
46 #include "mount-setup.h"  // From src/core
47 #include "musl_missing.h"
48
49 static void manager_free(Manager *m);
50
51 static Manager *manager_new(void) {
52         Manager *m;
53         int r;
54
55         m = new0(Manager, 1);
56         if (!m)
57                 return NULL;
58
59         m->pin_cgroupfs_fd = -1;
60
61         m->console_active_fd = -1;
62
63 #if 0 /// elogind does not support autospawning of vts
64         m->reserve_vt_fd = -1;
65
66         m->n_autovts = 6;
67         m->reserve_vt = 6;
68 #endif // 0
69         m->remove_ipc = true;
70         m->inhibit_delay_max = 5 * USEC_PER_SEC;
71         m->handle_power_key = HANDLE_POWEROFF;
72         m->handle_suspend_key = HANDLE_SUSPEND;
73         m->handle_hibernate_key = HANDLE_HIBERNATE;
74         m->handle_lid_switch = HANDLE_SUSPEND;
75         m->handle_lid_switch_docked = HANDLE_IGNORE;
76         m->lid_switch_ignore_inhibited = true;
77         m->holdoff_timeout_usec = 30 * USEC_PER_SEC;
78
79         m->idle_action_usec = 30 * USEC_PER_MINUTE;
80         m->idle_action = HANDLE_IGNORE;
81         m->idle_action_not_before_usec = now(CLOCK_MONOTONIC);
82
83         m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */
84         m->user_tasks_max = UINT64_C(4096);
85
86         m->devices = hashmap_new(&string_hash_ops);
87         m->seats = hashmap_new(&string_hash_ops);
88         m->sessions = hashmap_new(&string_hash_ops);
89         m->users = hashmap_new(NULL);
90         m->inhibitors = hashmap_new(&string_hash_ops);
91         m->buttons = hashmap_new(&string_hash_ops);
92
93         m->user_units = hashmap_new(&string_hash_ops);
94         m->session_units = hashmap_new(&string_hash_ops);
95
96         m->running_as = MANAGER_SYSTEM;
97         m->test_run   = false;
98
99         if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->user_units || !m->session_units)
100                 goto fail;
101
102         m->kill_exclude_users = strv_new("root", NULL);
103         if (!m->kill_exclude_users)
104                 goto fail;
105
106         /* If elogind should be its own controller, mount its cgroup */
107         if (streq(SYSTEMD_CGROUP_CONTROLLER, "name=elogind")) {
108                 r = mount_setup(true);
109                 if (r < 0)
110                         goto fail;
111         }
112
113         /* Make cgroups */
114         r = manager_setup_cgroup(m);
115         if (r < 0)
116                 goto fail;
117
118         m->suspend_mode = NULL;
119         m->suspend_state = strv_new("mem", "standby", "freeze", NULL);
120         if (!m->suspend_state)
121                 goto fail;
122         m->hibernate_mode = strv_new("platform", "shutdown", NULL);
123         if (!m->hibernate_mode)
124                 goto fail;
125         m->hibernate_state = strv_new("disk", NULL);
126         if (!m->hibernate_state)
127                 goto fail;
128         m->hybrid_sleep_mode = strv_new("suspend", "platform", "shutdown", NULL);
129         if (!m->hybrid_sleep_mode)
130                 goto fail;
131         m->hybrid_sleep_state = strv_new("disk", NULL);
132         if (!m->hybrid_sleep_state)
133                 goto fail;
134
135         m->udev = udev_new();
136         if (!m->udev)
137                 goto fail;
138
139         r = sd_event_default(&m->event);
140         if (r < 0)
141                 goto fail;
142
143         sd_event_set_watchdog(m->event, true);
144
145         return m;
146
147 fail:
148         manager_free(m);
149         return NULL;
150 }
151
152 static void manager_free(Manager *m) {
153         Session *session;
154         User *u;
155         Device *d;
156         Seat *s;
157         Inhibitor *i;
158         Button *b;
159
160         assert(m);
161
162         while ((session = hashmap_first(m->sessions)))
163                 session_free(session);
164
165         while ((u = hashmap_first(m->users)))
166                 user_free(u);
167
168         while ((d = hashmap_first(m->devices)))
169                 device_free(d);
170
171         while ((s = hashmap_first(m->seats)))
172                 seat_free(s);
173
174         while ((i = hashmap_first(m->inhibitors)))
175                 inhibitor_free(i);
176
177         while ((b = hashmap_first(m->buttons)))
178                 button_free(b);
179
180         hashmap_free(m->devices);
181         hashmap_free(m->seats);
182         hashmap_free(m->sessions);
183         hashmap_free(m->users);
184         hashmap_free(m->inhibitors);
185         hashmap_free(m->buttons);
186
187         hashmap_free(m->user_units);
188         hashmap_free(m->session_units);
189
190         sd_event_source_unref(m->idle_action_event_source);
191         sd_event_source_unref(m->inhibit_timeout_source);
192         sd_event_source_unref(m->scheduled_shutdown_timeout_source);
193         sd_event_source_unref(m->nologin_timeout_source);
194         sd_event_source_unref(m->wall_message_timeout_source);
195
196         sd_event_source_unref(m->console_active_event_source);
197         sd_event_source_unref(m->udev_seat_event_source);
198         sd_event_source_unref(m->udev_device_event_source);
199         sd_event_source_unref(m->udev_vcsa_event_source);
200         sd_event_source_unref(m->udev_button_event_source);
201         sd_event_source_unref(m->lid_switch_ignore_event_source);
202
203         safe_close(m->console_active_fd);
204
205                 udev_monitor_unref(m->udev_seat_monitor);
206                 udev_monitor_unref(m->udev_device_monitor);
207                 udev_monitor_unref(m->udev_vcsa_monitor);
208                 udev_monitor_unref(m->udev_button_monitor);
209
210                 udev_unref(m->udev);
211
212         if (m->unlink_nologin)
213                 (void) unlink("/run/nologin");
214
215         bus_verify_polkit_async_registry_free(m->polkit_registry);
216
217         sd_bus_unref(m->bus);
218         sd_event_unref(m->event);
219
220 #if 0 /// elogind does not support autospawning of vts
221         safe_close(m->reserve_vt_fd);
222 #endif // 0
223
224         manager_shutdown_cgroup(m, true);
225
226         strv_free(m->kill_only_users);
227         strv_free(m->kill_exclude_users);
228
229         free(m->scheduled_shutdown_type);
230         free(m->scheduled_shutdown_tty);
231         free(m->wall_message);
232
233         strv_free(m->suspend_mode);
234         strv_free(m->suspend_state);
235         strv_free(m->hibernate_mode);
236         strv_free(m->hibernate_state);
237         strv_free(m->hybrid_sleep_mode);
238         strv_free(m->hybrid_sleep_state);
239
240         free(m);
241 }
242
243 static int manager_enumerate_devices(Manager *m) {
244         struct udev_list_entry *item = NULL, *first = NULL;
245         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
246         int r;
247
248         assert(m);
249
250         /* Loads devices from udev and creates seats for them as
251          * necessary */
252
253         e = udev_enumerate_new(m->udev);
254         if (!e)
255                 return -ENOMEM;
256
257         r = udev_enumerate_add_match_tag(e, "master-of-seat");
258         if (r < 0)
259                 return r;
260
261         r = udev_enumerate_add_match_is_initialized(e);
262         if (r < 0)
263                 return r;
264
265         r = udev_enumerate_scan_devices(e);
266         if (r < 0)
267                 return r;
268
269         first = udev_enumerate_get_list_entry(e);
270         udev_list_entry_foreach(item, first) {
271                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
272                 int k;
273
274                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
275                 if (!d)
276                         return -ENOMEM;
277
278                 k = manager_process_seat_device(m, d);
279                 if (k < 0)
280                         r = k;
281         }
282
283         return r;
284 }
285
286 static int manager_enumerate_buttons(Manager *m) {
287         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
288         struct udev_list_entry *item = NULL, *first = NULL;
289         int r;
290
291         assert(m);
292
293         /* Loads buttons from udev */
294
295         if (m->handle_power_key == HANDLE_IGNORE &&
296             m->handle_suspend_key == HANDLE_IGNORE &&
297             m->handle_hibernate_key == HANDLE_IGNORE &&
298             m->handle_lid_switch == HANDLE_IGNORE &&
299             m->handle_lid_switch_docked == HANDLE_IGNORE)
300                 return 0;
301
302         e = udev_enumerate_new(m->udev);
303         if (!e)
304                 return -ENOMEM;
305
306         r = udev_enumerate_add_match_subsystem(e, "input");
307         if (r < 0)
308                 return r;
309
310         r = udev_enumerate_add_match_tag(e, "power-switch");
311         if (r < 0)
312                 return r;
313
314         r = udev_enumerate_add_match_is_initialized(e);
315         if (r < 0)
316                 return r;
317
318         r = udev_enumerate_scan_devices(e);
319         if (r < 0)
320                 return r;
321
322         first = udev_enumerate_get_list_entry(e);
323         udev_list_entry_foreach(item, first) {
324                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
325                 int k;
326
327                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
328                 if (!d)
329                         return -ENOMEM;
330
331                 k = manager_process_button_device(m, d);
332                 if (k < 0)
333                         r = k;
334         }
335
336         return r;
337 }
338
339 static int manager_enumerate_seats(Manager *m) {
340         _cleanup_closedir_ DIR *d = NULL;
341         struct dirent *de;
342         int r = 0;
343
344         assert(m);
345
346         /* This loads data about seats stored on disk, but does not
347          * actually create any seats. Removes data of seats that no
348          * longer exist. */
349
350         d = opendir("/run/systemd/seats");
351         if (!d) {
352                 if (errno == ENOENT)
353                         return 0;
354
355                 return log_error_errno(errno, "Failed to open /run/systemd/seats: %m");
356         }
357
358         FOREACH_DIRENT(de, d, return -errno) {
359                 Seat *s;
360                 int k;
361
362                 if (!dirent_is_file(de))
363                         continue;
364
365                 s = hashmap_get(m->seats, de->d_name);
366                 if (!s) {
367                         unlinkat(dirfd(d), de->d_name, 0);
368                         continue;
369                 }
370
371                 k = seat_load(s);
372                 if (k < 0)
373                         r = k;
374         }
375
376         return r;
377 }
378
379 static int manager_enumerate_linger_users(Manager *m) {
380         _cleanup_closedir_ DIR *d = NULL;
381         struct dirent *de;
382         int r = 0;
383
384         assert(m);
385
386         d = opendir("/var/lib/systemd/linger");
387         if (!d) {
388                 if (errno == ENOENT)
389                         return 0;
390
391                 return log_error_errno(errno, "Failed to open /var/lib/systemd/linger/: %m");
392         }
393
394         FOREACH_DIRENT(de, d, return -errno) {
395                 int k;
396
397                 if (!dirent_is_file(de))
398                         continue;
399
400                 k = manager_add_user_by_name(m, de->d_name, NULL);
401                 if (k < 0) {
402                         log_notice_errno(k, "Couldn't add lingering user %s: %m", de->d_name);
403                         r = k;
404                 }
405         }
406
407         return r;
408 }
409
410 static int manager_enumerate_users(Manager *m) {
411         _cleanup_closedir_ DIR *d = NULL;
412         struct dirent *de;
413         int r, k;
414
415         assert(m);
416
417         /* Add lingering users */
418         r = manager_enumerate_linger_users(m);
419
420         /* Read in user data stored on disk */
421         d = opendir("/run/systemd/users");
422         if (!d) {
423                 if (errno == ENOENT)
424                         return 0;
425
426                 return log_error_errno(errno, "Failed to open /run/systemd/users: %m");
427         }
428
429         FOREACH_DIRENT(de, d, return -errno) {
430                 User *u;
431
432                 if (!dirent_is_file(de))
433                         continue;
434
435                 k = manager_add_user_by_name(m, de->d_name, &u);
436                 if (k < 0) {
437                         log_error_errno(k, "Failed to add user by file name %s: %m", de->d_name);
438
439                         r = k;
440                         continue;
441                 }
442
443                 user_add_to_gc_queue(u);
444
445                 k = user_load(u);
446                 if (k < 0)
447                         r = k;
448         }
449
450         return r;
451 }
452
453 static int manager_enumerate_sessions(Manager *m) {
454         _cleanup_closedir_ DIR *d = NULL;
455         struct dirent *de;
456         int r = 0;
457
458         assert(m);
459
460         /* Read in session data stored on disk */
461         d = opendir("/run/systemd/sessions");
462         if (!d) {
463                 if (errno == ENOENT)
464                         return 0;
465
466                 return log_error_errno(errno, "Failed to open /run/systemd/sessions: %m");
467         }
468
469         FOREACH_DIRENT(de, d, return -errno) {
470                 struct Session *s;
471                 int k;
472
473                 if (!dirent_is_file(de))
474                         continue;
475
476                 if (!session_id_valid(de->d_name)) {
477                         log_warning("Invalid session file name '%s', ignoring.", de->d_name);
478                         r = -EINVAL;
479                         continue;
480                 }
481
482                 k = manager_add_session(m, de->d_name, &s);
483                 if (k < 0) {
484                         log_error_errno(k, "Failed to add session by file name %s: %m", de->d_name);
485
486                         r = k;
487                         continue;
488                 }
489
490                 session_add_to_gc_queue(s);
491
492                 k = session_load(s);
493                 if (k < 0)
494                         r = k;
495         }
496
497         return r;
498 }
499
500 static int manager_enumerate_inhibitors(Manager *m) {
501         _cleanup_closedir_ DIR *d = NULL;
502         struct dirent *de;
503         int r = 0;
504
505         assert(m);
506
507         d = opendir("/run/systemd/inhibit");
508         if (!d) {
509                 if (errno == ENOENT)
510                         return 0;
511
512                 return log_error_errno(errno, "Failed to open /run/systemd/inhibit: %m");
513         }
514
515         FOREACH_DIRENT(de, d, return -errno) {
516                 int k;
517                 Inhibitor *i;
518
519                 if (!dirent_is_file(de))
520                         continue;
521
522                 k = manager_add_inhibitor(m, de->d_name, &i);
523                 if (k < 0) {
524                         log_notice_errno(k, "Couldn't add inhibitor %s: %m", de->d_name);
525                         r = k;
526                         continue;
527                 }
528
529                 k = inhibitor_load(i);
530                 if (k < 0)
531                         r = k;
532         }
533
534         return r;
535 }
536
537 static int manager_dispatch_seat_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
538         _cleanup_udev_device_unref_ struct udev_device *d = NULL;
539         Manager *m = userdata;
540
541         assert(m);
542
543         d = udev_monitor_receive_device(m->udev_seat_monitor);
544         if (!d)
545                 return -ENOMEM;
546
547         manager_process_seat_device(m, d);
548         return 0;
549 }
550
551 static int manager_dispatch_device_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
552         _cleanup_udev_device_unref_ struct udev_device *d = NULL;
553         Manager *m = userdata;
554
555         assert(m);
556
557         d = udev_monitor_receive_device(m->udev_device_monitor);
558         if (!d)
559                 return -ENOMEM;
560
561         manager_process_seat_device(m, d);
562         return 0;
563 }
564
565 #if 0 /// UNNEEDED by elogind
566 static int manager_dispatch_vcsa_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
567         _cleanup_udev_device_unref_ struct udev_device *d = NULL;
568         Manager *m = userdata;
569         const char *name;
570
571         assert(m);
572
573         d = udev_monitor_receive_device(m->udev_vcsa_monitor);
574         if (!d)
575                 return -ENOMEM;
576
577         name = udev_device_get_sysname(d);
578
579         /* Whenever a VCSA device is removed try to reallocate our
580          * VTs, to make sure our auto VTs never go away. */
581
582         if (name && startswith(name, "vcsa") && streq_ptr(udev_device_get_action(d), "remove"))
583                 seat_preallocate_vts(m->seat0);
584
585         return 0;
586 }
587 #endif // 0
588
589 static int manager_dispatch_button_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
590         _cleanup_udev_device_unref_ struct udev_device *d = NULL;
591         Manager *m = userdata;
592
593         assert(m);
594
595         d = udev_monitor_receive_device(m->udev_button_monitor);
596         if (!d)
597                 return -ENOMEM;
598
599         manager_process_button_device(m, d);
600         return 0;
601 }
602
603 static int manager_dispatch_console(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
604         Manager *m = userdata;
605
606         assert(m);
607         assert(m->seat0);
608         assert(m->console_active_fd == fd);
609
610         seat_read_active_vt(m->seat0);
611         return 0;
612 }
613
614 #if 0 /// UNNEEDED by elogind
615 static int manager_reserve_vt(Manager *m) {
616         _cleanup_free_ char *p = NULL;
617
618         assert(m);
619
620         if (m->reserve_vt <= 0)
621                 return 0;
622
623         if (asprintf(&p, "/dev/tty%u", m->reserve_vt) < 0)
624                 return log_oom();
625
626         m->reserve_vt_fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
627         if (m->reserve_vt_fd < 0) {
628
629                 /* Don't complain on VT-less systems */
630                 if (errno != ENOENT)
631                         log_warning_errno(errno, "Failed to pin reserved VT: %m");
632                 return -errno;
633         }
634
635         return 0;
636 }
637 #endif // 0
638
639 static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus_error *error) {
640         Manager *m = userdata;
641         Session *s;
642         const char *cgroup;
643         int r;
644
645         assert(message);
646         assert(m);
647
648         r = sd_bus_message_read(message, "s", &cgroup);
649         if (r < 0) {
650                 bus_log_parse_error(r);
651                 return 0;
652         }
653
654         s = hashmap_get(m->sessions, cgroup);
655
656         if (!s) {
657                 log_warning("Session not found: %s", cgroup);
658                 return 0;
659         }
660
661         session_finalize(s);
662         session_free(s);
663
664         return 0;
665 }
666
667 static int manager_connect_bus(Manager *m) {
668         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
669         int r;
670
671         assert(m);
672         assert(!m->bus);
673
674         r = sd_bus_default_system(&m->bus);
675         if (r < 0)
676                 return log_error_errno(r, "Failed to connect to system bus: %m");
677
678         r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/login1", "org.freedesktop.login1.Manager", manager_vtable, m);
679         if (r < 0)
680                 return log_error_errno(r, "Failed to add manager object vtable: %m");
681
682         /* elogind relies on signals from its release agent */
683         r = sd_bus_add_match(m->bus, NULL,
684                              "type='signal',"
685                              "interface='org.freedesktop.elogind.Agent',"
686                              "member='Released',"
687                              "path='/org/freedesktop/elogind/agent'",
688                              signal_agent_released, m);
689
690         r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/seat", "org.freedesktop.login1.Seat", seat_vtable, seat_object_find, m);
691         if (r < 0)
692                 return log_error_errno(r, "Failed to add seat object vtable: %m");
693
694         r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/seat", seat_node_enumerator, m);
695         if (r < 0)
696                 return log_error_errno(r, "Failed to add seat enumerator: %m");
697
698         r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/session", "org.freedesktop.login1.Session", session_vtable, session_object_find, m);
699         if (r < 0)
700                 return log_error_errno(r, "Failed to add session object vtable: %m");
701
702         r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/session", session_node_enumerator, m);
703         if (r < 0)
704                 return log_error_errno(r, "Failed to add session enumerator: %m");
705
706         r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/user", "org.freedesktop.login1.User", user_vtable, user_object_find, m);
707         if (r < 0)
708                 return log_error_errno(r, "Failed to add user object vtable: %m");
709
710         r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/user", user_node_enumerator, m);
711         if (r < 0)
712                 return log_error_errno(r, "Failed to add user enumerator: %m");
713
714 #if 0 /// elogind does not support systemd as PID 1
715         r = sd_bus_add_match(m->bus,
716                              NULL,
717                              "type='signal',"
718                              "sender='org.freedesktop.systemd1',"
719                              "interface='org.freedesktop.systemd1.Manager',"
720                              "member='JobRemoved',"
721                              "path='/org/freedesktop/systemd1'",
722                              match_job_removed, m);
723         if (r < 0)
724                 return log_error_errno(r, "Failed to add match for JobRemoved: %m");
725
726         r = sd_bus_add_match(m->bus,
727                              NULL,
728                              "type='signal',"
729                              "sender='org.freedesktop.systemd1',"
730                              "interface='org.freedesktop.systemd1.Manager',"
731                              "member='UnitRemoved',"
732                              "path='/org/freedesktop/systemd1'",
733                              match_unit_removed, m);
734         if (r < 0)
735                 return log_error_errno(r, "Failed to add match for UnitRemoved: %m");
736
737         r = sd_bus_add_match(m->bus,
738                              NULL,
739                              "type='signal',"
740                              "sender='org.freedesktop.systemd1',"
741                              "interface='org.freedesktop.DBus.Properties',"
742                              "member='PropertiesChanged'",
743                              match_properties_changed, m);
744         if (r < 0)
745                 return log_error_errno(r, "Failed to add match for PropertiesChanged: %m");
746
747         r = sd_bus_add_match(m->bus,
748                              NULL,
749                              "type='signal',"
750                              "sender='org.freedesktop.systemd1',"
751                              "interface='org.freedesktop.systemd1.Manager',"
752                              "member='Reloading',"
753                              "path='/org/freedesktop/systemd1'",
754                              match_reloading, m);
755         if (r < 0)
756                 return log_error_errno(r, "Failed to add match for Reloading: %m");
757
758         r = sd_bus_call_method(
759                         m->bus,
760                         "org.freedesktop.systemd1",
761                         "/org/freedesktop/systemd1",
762                         "org.freedesktop.systemd1.Manager",
763                         "Subscribe",
764                         &error,
765                         NULL, NULL);
766         if (r < 0) {
767                 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
768                 return r;
769         }
770 #endif // 0
771
772         r = sd_bus_request_name(m->bus, "org.freedesktop.login1", 0);
773         if (r < 0)
774                 return log_error_errno(r, "Failed to register name: %m");
775
776         r = sd_bus_attach_event(m->bus, m->event, 0);
777         if (r < 0)
778                 return log_error_errno(r, "Failed to attach bus to event loop: %m");
779
780         return 0;
781 }
782
783 static int manager_vt_switch(sd_event_source *src, const struct signalfd_siginfo *si, void *data) {
784         Manager *m = data;
785         Session *active, *iter;
786
787         /*
788          * We got a VT-switch signal and we have to acknowledge it immediately.
789          * Preferably, we'd just use m->seat0->active->vtfd, but unfortunately,
790          * old user-space might run multiple sessions on a single VT, *sigh*.
791          * Therefore, we have to iterate all sessions and find one with a vtfd
792          * on the requested VT.
793          * As only VTs with active controllers have VT_PROCESS set, our current
794          * notion of the active VT might be wrong (for instance if the switch
795          * happens while we setup VT_PROCESS). Therefore, read the current VT
796          * first and then use s->active->vtnr as reference. Note that this is
797          * not racy, as no further VT-switch can happen as long as we're in
798          * synchronous VT_PROCESS mode.
799          */
800
801         assert(m->seat0);
802         seat_read_active_vt(m->seat0);
803
804         active = m->seat0->active;
805         if (!active || active->vtnr < 1) {
806                 log_warning("Received VT_PROCESS signal without a registered session on that VT.");
807                 return 0;
808         }
809
810         if (active->vtfd >= 0) {
811                 session_leave_vt(active);
812         } else {
813                 LIST_FOREACH(sessions_by_seat, iter, m->seat0->sessions) {
814                         if (iter->vtnr == active->vtnr && iter->vtfd >= 0) {
815                                 session_leave_vt(iter);
816                                 break;
817                         }
818                 }
819         }
820
821         return 0;
822 }
823
824 static int manager_connect_console(Manager *m) {
825         int r;
826
827         assert(m);
828         assert(m->console_active_fd < 0);
829
830         /* On certain architectures (S390 and Xen, and containers),
831            /dev/tty0 does not exist, so don't fail if we can't open
832            it. */
833         if (access("/dev/tty0", F_OK) < 0)
834                 return 0;
835
836         m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC);
837         if (m->console_active_fd < 0) {
838
839                 /* On some systems the device node /dev/tty0 may exist
840                  * even though /sys/class/tty/tty0 does not. */
841                 if (errno == ENOENT)
842                         return 0;
843
844                 return log_error_errno(errno, "Failed to open /sys/class/tty/tty0/active: %m");
845         }
846
847         r = sd_event_add_io(m->event, &m->console_active_event_source, m->console_active_fd, 0, manager_dispatch_console, m);
848         if (r < 0) {
849                 log_error("Failed to watch foreground console");
850                 return r;
851         }
852
853         /*
854          * SIGRTMIN is used as global VT-release signal, SIGRTMIN + 1 is used
855          * as VT-acquire signal. We ignore any acquire-events (yes, we still
856          * have to provide a valid signal-number for it!) and acknowledge all
857          * release events immediately.
858          */
859
860         if (SIGRTMIN + 1 > SIGRTMAX) {
861                 log_error("Not enough real-time signals available: %u-%u", SIGRTMIN, SIGRTMAX);
862                 return -EINVAL;
863         }
864
865         assert_se(ignore_signals(SIGRTMIN + 1, -1) >= 0);
866         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN, -1) >= 0);
867
868         r = sd_event_add_signal(m->event, NULL, SIGRTMIN, manager_vt_switch, m);
869         if (r < 0)
870                 return r;
871
872         return 0;
873 }
874
875 static int manager_connect_udev(Manager *m) {
876         int r;
877
878         assert(m);
879         assert(!m->udev_seat_monitor);
880         assert(!m->udev_device_monitor);
881         assert(!m->udev_vcsa_monitor);
882         assert(!m->udev_button_monitor);
883
884         m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
885         if (!m->udev_seat_monitor)
886                 return -ENOMEM;
887
888         r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "master-of-seat");
889         if (r < 0)
890                 return r;
891
892         r = udev_monitor_enable_receiving(m->udev_seat_monitor);
893         if (r < 0)
894                 return r;
895
896         r = sd_event_add_io(m->event, &m->udev_seat_event_source, udev_monitor_get_fd(m->udev_seat_monitor), EPOLLIN, manager_dispatch_seat_udev, m);
897         if (r < 0)
898                 return r;
899
900         m->udev_device_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
901         if (!m->udev_device_monitor)
902                 return -ENOMEM;
903
904         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "input", NULL);
905         if (r < 0)
906                 return r;
907
908         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "graphics", NULL);
909         if (r < 0)
910                 return r;
911
912         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "drm", NULL);
913         if (r < 0)
914                 return r;
915
916         r = udev_monitor_enable_receiving(m->udev_device_monitor);
917         if (r < 0)
918                 return r;
919
920         r = sd_event_add_io(m->event, &m->udev_device_event_source, udev_monitor_get_fd(m->udev_device_monitor), EPOLLIN, manager_dispatch_device_udev, m);
921         if (r < 0)
922                 return r;
923
924         /* Don't watch keys if nobody cares */
925         if (m->handle_power_key != HANDLE_IGNORE ||
926             m->handle_suspend_key != HANDLE_IGNORE ||
927             m->handle_hibernate_key != HANDLE_IGNORE ||
928             m->handle_lid_switch != HANDLE_IGNORE ||
929             m->handle_lid_switch_docked != HANDLE_IGNORE) {
930
931                 m->udev_button_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
932                 if (!m->udev_button_monitor)
933                         return -ENOMEM;
934
935                 r = udev_monitor_filter_add_match_tag(m->udev_button_monitor, "power-switch");
936                 if (r < 0)
937                         return r;
938
939                 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_button_monitor, "input", NULL);
940                 if (r < 0)
941                         return r;
942
943                 r = udev_monitor_enable_receiving(m->udev_button_monitor);
944                 if (r < 0)
945                         return r;
946
947                 r = sd_event_add_io(m->event, &m->udev_button_event_source, udev_monitor_get_fd(m->udev_button_monitor), EPOLLIN, manager_dispatch_button_udev, m);
948                 if (r < 0)
949                         return r;
950         }
951
952         /* Don't bother watching VCSA devices, if nobody cares */
953 #if 0 /// elogind does not support autospawning of vts
954         if (m->n_autovts > 0 && m->console_active_fd >= 0) {
955
956                 m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
957                 if (!m->udev_vcsa_monitor)
958                         return -ENOMEM;
959
960                 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL);
961                 if (r < 0)
962                         return r;
963
964                 r = udev_monitor_enable_receiving(m->udev_vcsa_monitor);
965                 if (r < 0)
966                         return r;
967
968                 r = sd_event_add_io(m->event, &m->udev_vcsa_event_source, udev_monitor_get_fd(m->udev_vcsa_monitor), EPOLLIN, manager_dispatch_vcsa_udev, m);
969                 if (r < 0)
970                         return r;
971         }
972 #endif // 0
973
974         return 0;
975 }
976
977 static void manager_gc(Manager *m, bool drop_not_started) {
978         Seat *seat;
979         Session *session;
980         User *user;
981
982         assert(m);
983
984         while ((seat = m->seat_gc_queue)) {
985                 LIST_REMOVE(gc_queue, m->seat_gc_queue, seat);
986                 seat->in_gc_queue = false;
987
988                 if (!seat_check_gc(seat, drop_not_started)) {
989                         seat_stop(seat, false);
990                         seat_free(seat);
991                 }
992         }
993
994         while ((session = m->session_gc_queue)) {
995                 LIST_REMOVE(gc_queue, m->session_gc_queue, session);
996                 session->in_gc_queue = false;
997
998                 /* First, if we are not closing yet, initiate stopping */
999                 if (!session_check_gc(session, drop_not_started) &&
1000                     session_get_state(session) != SESSION_CLOSING)
1001                         session_stop(session, false);
1002
1003                 /* Normally, this should make the session referenced
1004                  * again, if it doesn't then let's get rid of it
1005                  * immediately */
1006                 if (!session_check_gc(session, drop_not_started)) {
1007                         session_finalize(session);
1008                         session_free(session);
1009                 }
1010         }
1011
1012         while ((user = m->user_gc_queue)) {
1013                 LIST_REMOVE(gc_queue, m->user_gc_queue, user);
1014                 user->in_gc_queue = false;
1015
1016                 /* First step: queue stop jobs */
1017                 if (!user_check_gc(user, drop_not_started))
1018                         user_stop(user, false);
1019
1020                 /* Second step: finalize user */
1021                 if (!user_check_gc(user, drop_not_started)) {
1022                         user_finalize(user);
1023                         user_free(user);
1024                 }
1025         }
1026 }
1027
1028 static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *userdata) {
1029         Manager *m = userdata;
1030         struct dual_timestamp since;
1031         usec_t n, elapse;
1032         int r;
1033
1034         assert(m);
1035
1036         if (m->idle_action == HANDLE_IGNORE ||
1037             m->idle_action_usec <= 0)
1038                 return 0;
1039
1040         n = now(CLOCK_MONOTONIC);
1041
1042         r = manager_get_idle_hint(m, &since);
1043         if (r <= 0)
1044                 /* Not idle. Let's check if after a timeout it might be idle then. */
1045                 elapse = n + m->idle_action_usec;
1046         else {
1047                 /* Idle! Let's see if it's time to do something, or if
1048                  * we shall sleep for longer. */
1049
1050                 if (n >= since.monotonic + m->idle_action_usec &&
1051                     (m->idle_action_not_before_usec <= 0 || n >= m->idle_action_not_before_usec + m->idle_action_usec)) {
1052                         log_info("System idle. Taking action.");
1053
1054                         manager_handle_action(m, 0, m->idle_action, false, false);
1055                         m->idle_action_not_before_usec = n;
1056                 }
1057
1058                 elapse = MAX(since.monotonic, m->idle_action_not_before_usec) + m->idle_action_usec;
1059         }
1060
1061         if (!m->idle_action_event_source) {
1062
1063                 r = sd_event_add_time(
1064                                 m->event,
1065                                 &m->idle_action_event_source,
1066                                 CLOCK_MONOTONIC,
1067                                 elapse, USEC_PER_SEC*30,
1068                                 manager_dispatch_idle_action, m);
1069                 if (r < 0)
1070                         return log_error_errno(r, "Failed to add idle event source: %m");
1071
1072                 r = sd_event_source_set_priority(m->idle_action_event_source, SD_EVENT_PRIORITY_IDLE+10);
1073                 if (r < 0)
1074                         return log_error_errno(r, "Failed to set idle event source priority: %m");
1075         } else {
1076                 r = sd_event_source_set_time(m->idle_action_event_source, elapse);
1077                 if (r < 0)
1078                         return log_error_errno(r, "Failed to set idle event timer: %m");
1079
1080                 r = sd_event_source_set_enabled(m->idle_action_event_source, SD_EVENT_ONESHOT);
1081                 if (r < 0)
1082                         return log_error_errno(r, "Failed to enable idle event timer: %m");
1083         }
1084
1085         return 0;
1086 }
1087
1088 static int manager_startup(Manager *m) {
1089         int r;
1090         Seat *seat;
1091         Session *session;
1092         User *user;
1093         Button *button;
1094         Inhibitor *inhibitor;
1095         Iterator i;
1096
1097         assert(m);
1098
1099         /* Connect to console */
1100         r = manager_connect_console(m);
1101         if (r < 0)
1102                 return r;
1103
1104         /* Connect to udev */
1105         r = manager_connect_udev(m);
1106         if (r < 0)
1107                 return log_error_errno(r, "Failed to create udev watchers: %m");
1108
1109         /* Connect to the bus */
1110         r = manager_connect_bus(m);
1111         if (r < 0)
1112                 return r;
1113
1114         /* Instantiate magic seat 0 */
1115         r = manager_add_seat(m, "seat0", &m->seat0);
1116         if (r < 0)
1117                 return log_error_errno(r, "Failed to add seat0: %m");
1118
1119         r = manager_set_lid_switch_ignore(m, 0 + m->holdoff_timeout_usec);
1120         if (r < 0)
1121                 log_warning_errno(r, "Failed to set up lid switch ignore event source: %m");
1122
1123         /* Deserialize state */
1124         r = manager_enumerate_devices(m);
1125         if (r < 0)
1126                 log_warning_errno(r, "Device enumeration failed: %m");
1127
1128         r = manager_enumerate_seats(m);
1129         if (r < 0)
1130                 log_warning_errno(r, "Seat enumeration failed: %m");
1131
1132         r = manager_enumerate_users(m);
1133         if (r < 0)
1134                 log_warning_errno(r, "User enumeration failed: %m");
1135
1136         r = manager_enumerate_sessions(m);
1137         if (r < 0)
1138                 log_warning_errno(r, "Session enumeration failed: %m");
1139
1140         r = manager_enumerate_inhibitors(m);
1141         if (r < 0)
1142                 log_warning_errno(r, "Inhibitor enumeration failed: %m");
1143
1144         r = manager_enumerate_buttons(m);
1145         if (r < 0)
1146                 log_warning_errno(r, "Button enumeration failed: %m");
1147
1148         /* Remove stale objects before we start them */
1149         manager_gc(m, false);
1150
1151         /* Reserve the special reserved VT */
1152 #if 0 /// elogind does not support autospawning of vts
1153         manager_reserve_vt(m);
1154 #endif // 0
1155
1156         /* And start everything */
1157         HASHMAP_FOREACH(seat, m->seats, i)
1158                 seat_start(seat);
1159
1160         HASHMAP_FOREACH(user, m->users, i)
1161                 user_start(user);
1162
1163         HASHMAP_FOREACH(session, m->sessions, i)
1164                 session_start(session);
1165
1166         HASHMAP_FOREACH(inhibitor, m->inhibitors, i)
1167                 inhibitor_start(inhibitor);
1168
1169         HASHMAP_FOREACH(button, m->buttons, i)
1170                 button_check_switches(button);
1171
1172         manager_dispatch_idle_action(NULL, 0, m);
1173
1174         return 0;
1175 }
1176
1177 static int manager_run(Manager *m) {
1178         int r;
1179
1180         assert(m);
1181
1182         for (;;) {
1183                 r = sd_event_get_state(m->event);
1184                 if (r < 0)
1185                         return r;
1186                 if (r == SD_EVENT_FINISHED)
1187                         return 0;
1188
1189                 manager_gc(m, true);
1190
1191                 r = manager_dispatch_delayed(m, false);
1192                 if (r < 0)
1193                         return r;
1194                 if (r > 0)
1195                         continue;
1196
1197                 r = sd_event_run(m->event, (uint64_t) -1);
1198                 if (r < 0)
1199                         return r;
1200         }
1201 }
1202
1203 static int manager_parse_config_file(Manager *m) {
1204 #if 0 /// elogind parses its own config file
1205
1206         assert(m);
1207
1208         return config_parse_many(PKGSYSCONFDIR "/logind.conf",
1209                                  CONF_PATHS_NULSTR("systemd/logind.conf.d"),
1210                                  "Login\0",
1211                                  config_item_perf_lookup, logind_gperf_lookup,
1212                                  false, m);
1213 #else
1214         const char *unit = NULL, *logind_conf, *sections;
1215         FILE *file = NULL;
1216         bool relaxed = false, allow_include = false, warn = true;
1217
1218         assert(m);
1219
1220         logind_conf = getenv("ELOGIND_CONF_FILE");
1221         if (!logind_conf)
1222                 logind_conf = PKGSYSCONFDIR "/logind.conf";
1223         sections = "Login\0Sleep\0";
1224
1225         return config_parse(unit, logind_conf, file, sections,
1226                             config_item_perf_lookup, logind_gperf_lookup,
1227                             relaxed, allow_include, warn, m);
1228 #endif // 0
1229 }
1230
1231 int main(int argc, char *argv[]) {
1232         Manager *m = NULL;
1233         int r;
1234
1235         elogind_set_program_name(argv[0]);
1236         log_set_target(LOG_TARGET_AUTO);
1237         log_set_facility(LOG_AUTH);
1238         log_parse_environment();
1239         log_open();
1240
1241 #ifdef ENABLE_DEBUG_ELOGIND
1242         log_set_max_level(LOG_DEBUG);
1243 #endif // ENABLE_DEBUG_ELOGIND
1244
1245         umask(0022);
1246
1247         if (argc != 1) {
1248                 log_error("This program takes no arguments.");
1249                 r = -EINVAL;
1250                 goto finish;
1251         }
1252
1253         /* Always create the directories people can create inotify
1254          * watches in. Note that some applications might check for the
1255          * existence of /run/systemd/seats/ to determine whether
1256          * logind is available, so please always make sure this check
1257          * stays in. */
1258 #if 0 /// elogind can not rely on systemd to help, so we need a bit more effort than this
1259         mkdir_label("/run/systemd/seats", 0755);
1260         mkdir_label("/run/systemd/users", 0755);
1261         mkdir_label("/run/systemd/sessions", 0755);
1262 #else
1263         r = mkdir_label("/run/systemd", 0755);
1264         if ( (r < 0) && (-EEXIST != r) )
1265                 return log_error_errno(r, "Failed to create /run/systemd : %m");
1266         r = mkdir_label("/run/systemd/seats", 0755);
1267         if ( r < 0 && (-EEXIST != r) )
1268                 return log_error_errno(r, "Failed to create /run/systemd/seats : %m");
1269         r = mkdir_label("/run/systemd/users", 0755);
1270         if ( r < 0 && (-EEXIST != r) )
1271                 return log_error_errno(r, "Failed to create /run/systemd/users : %m");
1272         r = mkdir_label("/run/systemd/sessions", 0755);
1273         if ( r < 0 && (-EEXIST != r) )
1274                 return log_error_errno(r, "Failed to create /run/systemd/sessions : %m");
1275         r = mkdir_label("/run/systemd/machines", 0755);
1276         if ( r < 0 && (-EEXIST != r) )
1277                 return log_error_errno(r, "Failed to create /run/systemd/machines : %m");
1278 #endif // 0
1279
1280         m = manager_new();
1281         if (!m) {
1282                 r = log_oom();
1283                 goto finish;
1284         }
1285
1286         manager_parse_config_file(m);
1287
1288         r = manager_startup(m);
1289         if (r < 0) {
1290                 log_error_errno(r, "Failed to fully start up daemon: %m");
1291                 goto finish;
1292         }
1293
1294         log_debug("elogind running as pid "PID_FMT, getpid());
1295
1296         sd_notify(false,
1297                   "READY=1\n"
1298                   "STATUS=Processing requests...");
1299
1300         r = manager_run(m);
1301
1302         log_debug("elogind stopped as pid "PID_FMT, getpid());
1303
1304 finish:
1305         sd_notify(false,
1306                   "STOPPING=1\n"
1307                   "STATUS=Shutting down...");
1308
1309                 manager_free(m);
1310
1311         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1312 }