1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
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 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include <sys/epoll.h>
31 #include "dbus-common.h"
32 #include "dbus-loop.h"
40 Manager *manager_new(void) {
47 m->console_active_fd = -1;
53 m->devices = hashmap_new(string_hash_func, string_compare_func);
54 m->seats = hashmap_new(string_hash_func, string_compare_func);
55 m->sessions = hashmap_new(string_hash_func, string_compare_func);
56 m->users = hashmap_new(trivial_hash_func, trivial_compare_func);
58 if (!m->devices || !m->seats || !m->sessions || !m->users) {
69 if (cg_get_user_path(&m->cgroup_path) < 0) {
77 void manager_free(Manager *m) {
85 while ((session = hashmap_first(m->sessions)))
86 session_free(session);
88 while ((u = hashmap_first(m->users)))
91 while ((d = hashmap_first(m->devices)))
94 while ((s = hashmap_first(m->seats)))
97 hashmap_free(m->sessions);
98 hashmap_free(m->users);
99 hashmap_free(m->devices);
100 hashmap_free(m->seats);
102 if (m->console_active_fd >= 0)
103 close_nointr_nofail(m->console_active_fd);
106 udev_monitor_unref(m->udev_monitor);
112 dbus_connection_flush(m->bus);
113 dbus_connection_close(m->bus);
114 dbus_connection_unref(m->bus);
118 close_nointr_nofail(m->bus_fd);
120 if (m->epoll_fd >= 0)
121 close_nointr_nofail(m->epoll_fd);
123 free(m->cgroup_path);
127 int manager_add_device(Manager *m, const char *sysfs, Device **_device) {
133 d = hashmap_get(m->devices, sysfs);
141 d = device_new(m, sysfs);
151 int manager_add_seat(Manager *m, const char *id, Seat **_seat) {
157 s = hashmap_get(m->seats, id);
175 int manager_add_session(Manager *m, User *u, const char *id, Session **_session) {
181 s = hashmap_get(m->sessions, id);
189 s = session_new(m, u, id);
199 int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
206 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
214 u = user_new(m, uid, gid, name);
230 int manager_add_user_by_name(Manager *m, const char *name, User **_user) {
239 return errno ? -errno : -ENOENT;
241 return manager_add_user(m, p->pw_uid, p->pw_gid, name, _user);
244 int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
252 return errno ? -errno : -ENOENT;
254 return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
257 int manager_process_device(Manager *m, struct udev_device *d) {
265 sn = udev_device_get_property_value(d, "SEAT");
269 r = manager_add_device(m, udev_device_get_syspath(d), &device);
273 r = manager_add_seat(m, sn, &seat);
277 device_attach(device, seat);
281 int manager_enumerate_devices(Manager *m) {
282 struct udev_list_entry *item = NULL, *first = NULL;
283 struct udev_enumerate *e;
288 /* Loads devices from udev and creates seats for them as
291 e = udev_enumerate_new(m->udev);
295 if (udev_enumerate_add_match_subsystem(e, "graphics") < 0)
298 if (udev_enumerate_add_match_tag(e, "seat") < 0)
301 if (udev_enumerate_scan_devices(e) < 0)
304 first = udev_enumerate_get_list_entry(e);
305 udev_list_entry_foreach(item, first) {
306 struct udev_device *d;
309 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
313 k = manager_process_device(m, d);
314 udev_device_unref(d);
322 udev_enumerate_unref(e);
327 int manager_enumerate_seats(Manager *m) {
334 /* This loads data about seats stored on disk, but does not
335 * actually create any seats. Removes data of seats that no
338 d = opendir("/run/systemd/seats");
343 log_error("Failed to open /run/systemd/seats: %m");
347 while ((de = readdir(d))) {
351 if (!dirent_is_file(de))
354 s = hashmap_get(m->seats, de->d_name);
356 unlinkat(dirfd(d), de->d_name, 0);
370 static int manager_enumerate_users_from_cgroup(Manager *m) {
375 r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &d);
380 log_error("Failed to open %s: %s", m->cgroup_path, strerror(-r));
384 while ((r = cg_read_subgroup(d, &name)) > 0) {
387 r = manager_add_user_by_name(m, name, &user);
393 if (user->cgroup_path)
396 if (asprintf(&user->cgroup_path, "%s/%s", m->cgroup_path, name) < 0) {
408 int manager_enumerate_users(Manager *m) {
415 r = manager_enumerate_users_from_cgroup(m);
417 d = opendir("/run/systemd/users");
422 log_error("Failed to open /run/systemd/users: %m");
426 while ((de = readdir(d))) {
431 if (!dirent_is_file(de))
434 k = safe_atolu(de->d_name, &ul);
436 log_error("Failed to parse file name %s: %s", de->d_name, strerror(-k));
440 u = hashmap_get(m->users, ULONG_TO_PTR(ul));
442 unlinkat(dirfd(d), de->d_name, 0);
456 static int manager_enumerate_sessions_from_cgroup(Manager *m) {
461 HASHMAP_FOREACH(u, m->users, i) {
466 k = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &d);
471 log_error("Failed to open %s: %s", u->cgroup_path, strerror(-k));
476 while ((k = cg_read_subgroup(d, &name)) > 0) {
479 k = manager_add_session(m, u, name, &session);
485 if (session->cgroup_path)
488 if (asprintf(&session->cgroup_path, "%s/%s", u->cgroup_path, name) < 0) {
503 int manager_enumerate_sessions(Manager *m) {
510 r = manager_enumerate_sessions_from_cgroup(m);
512 d = opendir("/run/systemd/sessions");
517 log_error("Failed to open /run/systemd/sessions: %m");
521 while ((de = readdir(d))) {
525 if (!dirent_is_file(de))
528 s = hashmap_get(m->sessions, de->d_name);
530 unlinkat(dirfd(d), de->d_name, 0);
544 int manager_start_linger_users(Manager *m) {
549 d = opendir("/var/lib/systemd/linger");
554 log_error("Failed to open /var/lib/systemd/linger/: %m");
558 while ((de = readdir(d))) {
561 if (!dirent_is_file(de))
564 k = manager_add_user_by_name(m, de->d_name, NULL);
566 log_notice("Couldn't add lingering user %s: %s", de->d_name, strerror(-k));
576 int manager_dispatch_udev(Manager *m) {
577 struct udev_device *d;
582 d = udev_monitor_receive_device(m->udev_monitor);
586 r = manager_process_device(m, d);
587 udev_device_unref(d);
592 int manager_dispatch_console(Manager *m) {
599 lseek(m->console_active_fd, SEEK_SET, 0);
601 k = read(m->console_active_fd, t, sizeof(t)-1);
603 log_error("Failed to read current console: %s", k < 0 ? strerror(-errno) : "EOF");
604 return k < 0 ? -errno : -EIO;
608 if (!startswith(t, "tty")) {
609 log_error("Hm, /sys/class/tty/tty0/active is badly formatted.");
613 r = safe_atoi(t+3, &vtnr);
615 log_error("Failed to parse VT number %s", t+3);
620 log_error("VT number invalid: %s", t+3);
625 seat_active_vt_changed(m->vtconsole, vtnr);
630 int manager_spawn_autovt(Manager *m, int vtnr) {
636 static DBusHandlerResult login_message_handler(
637 DBusConnection *connection,
638 DBusMessage *message,
641 return DBUS_HANDLER_RESULT_HANDLED;
644 static DBusHandlerResult login_message_filter(
645 DBusConnection *connection,
646 DBusMessage *message,
649 return DBUS_HANDLER_RESULT_HANDLED;
652 static int manager_connect_bus(Manager *m) {
653 const DBusObjectPathVTable login_vtable = {
654 .message_function = login_message_handler
659 struct epoll_event ev;
663 assert(m->bus_fd < 0);
665 dbus_error_init(&error);
667 m->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
669 log_error("Failed to get system D-Bus connection: %s", error.message);
674 if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/login1", &login_vtable, NULL)) {
675 log_error("Not enough memory");
680 if (!dbus_connection_add_filter(m->bus, login_message_filter, m, NULL)) {
681 log_error("Not enough memory");
686 dbus_bus_add_match(m->bus,
688 "interface='org.freedesktop.systemd1.Agent',"
690 "path='/org/freedesktop/systemd1/agent'",
693 if (dbus_error_is_set(&error)) {
694 log_error("Failed to register match: %s", error.message);
699 if (dbus_bus_request_name(m->bus, "org.freedesktop.login1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) < 0) {
700 log_error("Failed to register name on bus: %s", error.message);
705 m->bus_fd = bus_loop_open(m->bus);
713 ev.data.u32 = FD_BUS;
715 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0)
721 dbus_error_free(&error);
726 static int manager_connect_console(Manager *m) {
727 struct epoll_event ev;
730 assert(m->console_active_fd < 0);
732 m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC);
733 if (m->console_active_fd < 0) {
734 log_error("Failed to open /sys/class/tty/tty0/active: %m");
740 ev.data.u32 = FD_CONSOLE;
742 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->console_active_fd, &ev) < 0)
748 static int manager_connect_udev(Manager *m) {
749 struct epoll_event ev;
752 assert(!m->udev_monitor);
754 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
755 if (!m->udev_monitor)
758 udev_monitor_filter_add_match_tag(m->udev_monitor, "seat");
760 if (udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "graphics", NULL) < 0)
763 if (udev_monitor_enable_receiving(m->udev_monitor) < 0)
766 m->udev_fd = udev_monitor_get_fd(m->udev_monitor);
770 ev.data.u32 = FD_UDEV;
772 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_fd, &ev) < 0)
778 int manager_startup(Manager *m) {
782 assert(m->epoll_fd <= 0);
784 m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
788 /* Connect to udev */
789 r = manager_connect_udev(m);
793 /* Connect to console */
794 r = manager_connect_console(m);
798 /* Connect to the bus */
799 r = manager_connect_bus(m);
803 /* Deserialize state */
804 manager_enumerate_devices(m);
805 manager_enumerate_seats(m);
806 manager_enumerate_users(m);
807 manager_enumerate_sessions(m);
809 /* Spawn lingering users */
810 manager_start_linger_users(m);
815 int manager_run(Manager *m) {
819 struct epoll_event event;
822 if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
825 n = epoll_wait(m->epoll_fd, &event, 1, -1);
827 log_error("epoll() failed: %m");
831 switch (event.data.u32) {
834 manager_dispatch_udev(m);
838 manager_dispatch_console(m);
842 bus_loop_dispatch(m->bus_fd);
850 int main(int argc, char *argv[]) {
854 log_set_target(LOG_TARGET_AUTO);
855 log_parse_environment();
859 log_error("This program takes no arguments.");
868 log_error("Out of memory");
873 r = manager_startup(m);
875 log_error("Failed to fully start up daemon: %s", strerror(-r));
885 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;