X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flogin%2Flogind.c;h=66a786a3f8fab020dc2d281ea32330853b52c483;hp=9cce481340043bd7ccb402be278711ebf7b07db5;hb=e8e581bf256b8c0fbd430935af79fa0e8ee570a1;hpb=8e7fd6ade44ce5dde0867ba748c7978ed1206865 diff --git a/src/login/logind.c b/src/login/logind.c index 9cce48134..66a786a3f 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -36,6 +37,7 @@ #include "dbus-loop.h" #include "strv.h" #include "conf-parser.h" +#include "mkdir.h" Manager *manager_new(void) { Manager *m; @@ -61,6 +63,11 @@ Manager *manager_new(void) { m->handle_lid_switch = HANDLE_SUSPEND; m->lid_switch_ignore_inhibited = true; + m->idle_action_fd = -1; + m->idle_action_usec = 30 * USEC_PER_MINUTE; + m->idle_action = HANDLE_IGNORE; + m->idle_action_not_before_usec = now(CLOCK_MONOTONIC); + m->devices = hashmap_new(string_hash_func, string_compare_func); m->seats = hashmap_new(string_hash_func, string_compare_func); m->sessions = hashmap_new(string_hash_func, string_compare_func); @@ -173,11 +180,16 @@ void manager_free(Manager *m) { if (m->reserve_vt_fd >= 0) close_nointr_nofail(m->reserve_vt_fd); + if (m->idle_action_fd >= 0) + close_nointr_nofail(m->idle_action_fd); + strv_free(m->controllers); strv_free(m->reset_controllers); strv_free(m->kill_only_users); strv_free(m->kill_exclude_users); + free(m->action_job); + free(m->cgroup_path); free(m); } @@ -450,11 +462,7 @@ int manager_enumerate_devices(Manager *m) { goto finish; } - r = udev_enumerate_add_match_subsystem(e, "graphics"); - if (r < 0) - goto finish; - - r = udev_enumerate_add_match_tag(e, "seat"); + r = udev_enumerate_add_match_tag(e, "master-of-seat"); if (r < 0) goto finish; @@ -1033,16 +1041,13 @@ int manager_get_session_by_cgroup(Manager *m, const char *cgroup, Session **sess return 1; } - p = strdup(cgroup); - if (!p) - return log_oom(); + p = strdupa(cgroup); for (;;) { char *e; e = strrchr(p, '/'); if (!e || e == p) { - free(p); *session = NULL; return 0; } @@ -1051,7 +1056,6 @@ int manager_get_session_by_cgroup(Manager *m, const char *cgroup, Session **sess s = hashmap_get(m->session_cgroups, p); if (s) { - free(p); *session = s; return 1; } @@ -1072,7 +1076,7 @@ int manager_get_user_by_cgroup(Manager *m, const char *cgroup, User **user) { return 1; } - p = strdup(cgroup); + p = strdupa(cgroup); if (!p) return log_oom(); @@ -1081,7 +1085,6 @@ int manager_get_user_by_cgroup(Manager *m, const char *cgroup, User **user) { e = strrchr(p, '/'); if (!e || e == p) { - free(p); *user = NULL; return 0; } @@ -1090,7 +1093,6 @@ int manager_get_user_by_cgroup(Manager *m, const char *cgroup, User **user) { u = hashmap_get(m->user_cgroups, p); if (u) { - free(p); *user = u; return 1; } @@ -1098,21 +1100,18 @@ int manager_get_user_by_cgroup(Manager *m, const char *cgroup, User **user) { } int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) { - char *p; + _cleanup_free_ char *p = NULL; int r; assert(m); assert(pid >= 1); assert(session); - r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &p); + r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &p); if (r < 0) return r; - r = manager_get_session_by_cgroup(m, p, session); - free(p); - - return r; + return manager_get_session_by_cgroup(m, p, session); } void manager_cgroup_notify_empty(Manager *m, const char *cgroup) { @@ -1166,7 +1165,10 @@ static void manager_dispatch_other(Manager *m, int fd) { static int manager_connect_bus(Manager *m) { DBusError error; int r; - struct epoll_event ev; + struct epoll_event ev = { + .events = EPOLLIN, + .data.u32 = FD_BUS, + }; assert(m); assert(!m->bus); @@ -1222,10 +1224,6 @@ static int manager_connect_bus(Manager *m) { goto fail; } - zero(ev); - ev.events = EPOLLIN; - ev.data.u32 = FD_BUS; - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0) goto fail; @@ -1238,7 +1236,10 @@ fail: } static int manager_connect_console(Manager *m) { - struct epoll_event ev; + struct epoll_event ev = { + .events = 0, + .data.u32 = FD_CONSOLE, + }; assert(m); assert(m->console_active_fd < 0); @@ -1263,10 +1264,6 @@ static int manager_connect_console(Manager *m) { return -errno; } - zero(ev); - ev.events = 0; - ev.data.u32 = FD_CONSOLE; - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->console_active_fd, &ev) < 0) return -errno; @@ -1274,8 +1271,11 @@ static int manager_connect_console(Manager *m) { } static int manager_connect_udev(Manager *m) { - struct epoll_event ev; int r; + struct epoll_event ev = { + .events = EPOLLIN, + .data.u32 = FD_SEAT_UDEV, + }; assert(m); assert(!m->udev_seat_monitor); @@ -1286,11 +1286,7 @@ static int manager_connect_udev(Manager *m) { if (!m->udev_seat_monitor) return -ENOMEM; - r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "seat"); - if (r < 0) - return r; - - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_seat_monitor, "graphics", NULL); + r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "master-of-seat"); if (r < 0) return r; @@ -1300,9 +1296,6 @@ static int manager_connect_udev(Manager *m) { m->udev_seat_fd = udev_monitor_get_fd(m->udev_seat_monitor); - zero(ev); - ev.events = EPOLLIN; - ev.data.u32 = FD_SEAT_UDEV; if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_seat_fd, &ev) < 0) return -errno; @@ -1441,6 +1434,77 @@ int manager_get_idle_hint(Manager *m, dual_timestamp *t) { return idle_hint; } +int manager_dispatch_idle_action(Manager *m) { + struct dual_timestamp since; + struct itimerspec its = {}; + int r; + usec_t n; + + assert(m); + + if (m->idle_action == HANDLE_IGNORE || + m->idle_action_usec <= 0) { + r = 0; + goto finish; + } + + n = now(CLOCK_MONOTONIC); + + r = manager_get_idle_hint(m, &since); + if (r <= 0) + /* Not idle. Let's check if after a timeout it might be idle then. */ + timespec_store(&its.it_value, n + m->idle_action_usec); + else { + /* Idle! Let's see if it's time to do something, or if + * we shall sleep for longer. */ + + if (n >= since.monotonic + m->idle_action_usec && + (m->idle_action_not_before_usec <= 0 || n >= m->idle_action_not_before_usec + m->idle_action_usec)) { + log_info("System idle. Taking action."); + + manager_handle_action(m, 0, m->idle_action, false, false); + m->idle_action_not_before_usec = n; + } + + timespec_store(&its.it_value, MAX(since.monotonic, m->idle_action_not_before_usec) + m->idle_action_usec); + } + + if (m->idle_action_fd < 0) { + struct epoll_event ev = { + .events = EPOLLIN, + .data.u32 = FD_IDLE_ACTION, + }; + + m->idle_action_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC); + if (m->idle_action_fd < 0) { + log_error("Failed to create idle action timer: %m"); + r = -errno; + goto finish; + } + + if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->idle_action_fd, &ev) < 0) { + log_error("Failed to add idle action timer to epoll: %m"); + r = -errno; + goto finish; + } + } + + if (timerfd_settime(m->idle_action_fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { + log_error("Failed to reset timerfd: %m"); + r = -errno; + goto finish; + } + + return 0; + +finish: + if (m->idle_action_fd >= 0) { + close_nointr_nofail(m->idle_action_fd); + m->idle_action_fd = -1; + } + + return r; +} int manager_startup(Manager *m) { int r; Seat *seat; @@ -1506,6 +1570,8 @@ int manager_startup(Manager *m) { HASHMAP_FOREACH(inhibitor, m->inhibitors, i) inhibitor_start(inhibitor); + manager_dispatch_idle_action(m); + return 0; } @@ -1550,11 +1616,11 @@ int manager_run(Manager *m) { manager_gc(m, true); - if (m->delayed_unit) { + if (m->action_what != 0) { usec_t x, y; x = now(CLOCK_MONOTONIC); - y = m->delayed_timestamp + m->inhibit_delay_max; + y = m->action_timestamp + m->inhibit_delay_max; msec = x >= y ? 0 : (int) ((y - x) / USEC_PER_MSEC); } @@ -1589,6 +1655,10 @@ int manager_run(Manager *m) { manager_dispatch_console(m); break; + case FD_IDLE_ACTION: + manager_dispatch_idle_action(m); + break; + case FD_BUS: bus_loop_dispatch(m->bus_fd); break; @@ -1619,7 +1689,7 @@ static int manager_parse_config_file(Manager *m) { return -errno; } - r = config_parse(fn, f, "Login\0", config_item_perf_lookup, (void*) logind_gperf_lookup, false, m); + r = config_parse(NULL, fn, f, "Login\0", config_item_perf_lookup, (void*) logind_gperf_lookup, false, m); if (r < 0) log_warning("Failed to parse configuration file: %s", strerror(-r)); @@ -1645,6 +1715,15 @@ int main(int argc, char *argv[]) { goto finish; } + /* Always create the directories people can create inotify + * watches in. Note that some applications might check for the + * existence of /run/systemd/seats/ to determine whether + * logind is available, so please always make sure this check + * stays in. */ + mkdir_label("/run/systemd/seats", 0755); + mkdir_label("/run/systemd/users", 0755); + mkdir_label("/run/systemd/sessions", 0755); + m = manager_new(); if (!m) { r = log_oom();