diff options
Diffstat (limited to 'src/login/logind-dbus.c')
-rw-r--r-- | src/login/logind-dbus.c | 297 |
1 files changed, 180 insertions, 117 deletions
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index c9b7d99818..2342375f20 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -88,7 +88,7 @@ int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, assert(message); assert(ret); - if (uid == UID_INVALID) { + if (!uid_is_valid(uid)) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; /* Note that we get the owner UID of the session, not the actual client UID here! */ @@ -767,8 +767,8 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus if (hashmap_size(m->sessions) >= m->sessions_max) return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.", m->sessions_max); - audit_session_from_pid(leader, &audit_id); - if (audit_id > 0) { + (void) audit_session_from_pid(leader, &audit_id); + if (audit_session_is_valid(audit_id)) { /* Keep our session IDs and the audit session IDs in sync */ if (asprintf(&id, "%"PRIu32, audit_id) < 0) @@ -780,7 +780,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus * ID */ if (hashmap_get(m->sessions, id)) { log_warning("Existing logind session ID %s used by new audit session, ignoring", id); - audit_id = 0; + audit_id = AUDIT_SESSION_INVALID; id = mfree(id); } @@ -1132,7 +1132,7 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu if (r < 0) return r; - if (uid == UID_INVALID) { + if (!uid_is_valid(uid)) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; /* Note that we get the owner UID of the session, not the actual client UID here! */ @@ -1399,7 +1399,6 @@ static int have_multiple_sessions( static int bus_manager_log_shutdown( Manager *m, - InhibitWhat w, const char *unit_name) { const char *p, *q; @@ -1407,18 +1406,15 @@ static int bus_manager_log_shutdown( assert(m); assert(unit_name); - if (w != INHIBIT_SHUTDOWN) - return 0; - if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) { p = "MESSAGE=System is powering down"; q = "SHUTDOWN=power-off"; - } else if (streq(unit_name, SPECIAL_HALT_TARGET)) { - p = "MESSAGE=System is halting"; - q = "SHUTDOWN=halt"; } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) { p = "MESSAGE=System is rebooting"; q = "SHUTDOWN=reboot"; + } else if (streq(unit_name, SPECIAL_HALT_TARGET)) { + p = "MESSAGE=System is halting"; + q = "SHUTDOWN=halt"; } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) { p = "MESSAGE=System is rebooting with kexec"; q = "SHUTDOWN=kexec"; @@ -1484,18 +1480,26 @@ int manager_set_lid_switch_ignore(Manager *m, usec_t until) { return r; } -static void reset_scheduled_shutdown(Manager *m) { - m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source); - m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source); - m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source); - m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type); - m->scheduled_shutdown_timeout = 0; - m->shutdown_dry_run = false; +static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) { - if (m->unlink_nologin) { - (void) unlink("/run/nologin"); - m->unlink_nologin = false; - } + static const char * const signal_name[_INHIBIT_WHAT_MAX] = { + [INHIBIT_SHUTDOWN] = "PrepareForShutdown", + [INHIBIT_SLEEP] = "PrepareForSleep" + }; + + int active = _active; + + assert(m); + assert(w >= 0); + assert(w < _INHIBIT_WHAT_MAX); + assert(signal_name[w]); + + return sd_bus_emit_signal(m->bus, + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + signal_name[w], + "b", + active); } static int execute_shutdown_or_sleep( @@ -1510,35 +1514,33 @@ static int execute_shutdown_or_sleep( int r; assert(m); - assert(w >= 0); + assert(w > 0); assert(w < _INHIBIT_WHAT_MAX); assert(unit_name); - bus_manager_log_shutdown(m, w, unit_name); + if (w == INHIBIT_SHUTDOWN) + bus_manager_log_shutdown(m, unit_name); - if (m->shutdown_dry_run) { - log_info("Running in dry run, suppressing action."); - reset_scheduled_shutdown(m); - } else { - r = sd_bus_call_method( - m->bus, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "StartUnit", - error, - &reply, - "ss", unit_name, "replace-irreversibly"); - if (r < 0) - return r; + r = sd_bus_call_method( + m->bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartUnit", + error, + &reply, + "ss", unit_name, "replace-irreversibly"); + if (r < 0) + goto error; - r = sd_bus_message_read(reply, "o", &p); - if (r < 0) - return r; + r = sd_bus_message_read(reply, "o", &p); + if (r < 0) + goto error; - c = strdup(p); - if (!c) - return -ENOMEM; + c = strdup(p); + if (!c) { + r = -ENOMEM; + goto error; } m->action_unit = unit_name; @@ -1550,6 +1552,12 @@ static int execute_shutdown_or_sleep( manager_set_lid_switch_ignore(m, now(CLOCK_MONOTONIC) + m->holdoff_timeout_usec); return 0; + +error: + /* Tell people that they now may take a lock again */ + send_prepare_for(m, m->action_what, false); + + return r; } int manager_dispatch_delayed(Manager *manager, bool timeout) { @@ -1580,7 +1588,8 @@ int manager_dispatch_delayed(Manager *manager, bool timeout) { /* Actually do the operation */ r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error); if (r < 0) { - log_warning("Failed to send delayed message: %s", bus_error_message(&error, r)); + log_warning("Error during inhibitor-delayed operation (already returned success to client): %s", + bus_error_message(&error, r)); manager->action_unit = NULL; manager->action_what = 0; @@ -1641,28 +1650,6 @@ static int delay_shutdown_or_sleep( return 0; } -static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) { - - static const char * const signal_name[_INHIBIT_WHAT_MAX] = { - [INHIBIT_SHUTDOWN] = "PrepareForShutdown", - [INHIBIT_SLEEP] = "PrepareForSleep" - }; - - int active = _active; - - assert(m); - assert(w >= 0); - assert(w < _INHIBIT_WHAT_MAX); - assert(signal_name[w]); - - return sd_bus_emit_signal(m->bus, - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - signal_name[w], - "b", - active); -} - int bus_manager_shutdown_or_sleep_now_or_later( Manager *m, const char *unit_name, @@ -1674,7 +1661,7 @@ int bus_manager_shutdown_or_sleep_now_or_later( assert(m); assert(unit_name); - assert(w >= 0); + assert(w > 0); assert(w <= _INHIBIT_WHAT_MAX); assert(!m->action_job); @@ -1835,6 +1822,20 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error * error); } +static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_do_shutdown_or_sleep( + m, message, + SPECIAL_HALT_TARGET, + INHIBIT_SHUTDOWN, + "org.freedesktop.login1.halt", + "org.freedesktop.login1.halt-multiple-sessions", + "org.freedesktop.login1.halt-ignore-inhibit", + NULL, + error); +} + static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) { Manager *m = userdata; @@ -1849,6 +1850,34 @@ static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error error); } +static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_do_shutdown_or_sleep( + m, message, + SPECIAL_HIBERNATE_TARGET, + INHIBIT_SLEEP, + "org.freedesktop.login1.hibernate", + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + "hibernate", + error); +} + +static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_do_shutdown_or_sleep( + m, message, + SPECIAL_HYBRID_SLEEP_TARGET, + INHIBIT_SLEEP, + "org.freedesktop.login1.hibernate", + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + "hybrid-sleep", + error); +} + static int nologin_timeout_handler( sd_event_source *s, uint64_t usec, @@ -1923,6 +1952,25 @@ fail: return log_error_errno(r, "Failed to write information about scheduled shutdowns: %m"); } +static void reset_scheduled_shutdown(Manager *m) { + assert(m); + + m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source); + m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source); + m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source); + + m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type); + m->scheduled_shutdown_timeout = 0; + m->shutdown_dry_run = false; + + if (m->unlink_nologin) { + (void) unlink("/run/nologin"); + m->unlink_nologin = false; + } + + (void) unlink("/run/systemd/shutdown/scheduled"); +} + static int manager_scheduled_shutdown_handler( sd_event_source *s, uint64_t usec, @@ -1938,18 +1986,46 @@ static int manager_scheduled_shutdown_handler( if (isempty(m->scheduled_shutdown_type)) return 0; - if (streq(m->scheduled_shutdown_type, "halt")) - target = SPECIAL_HALT_TARGET; - else if (streq(m->scheduled_shutdown_type, "poweroff")) + if (streq(m->scheduled_shutdown_type, "poweroff")) target = SPECIAL_POWEROFF_TARGET; - else + else if (streq(m->scheduled_shutdown_type, "reboot")) target = SPECIAL_REBOOT_TARGET; + else if (streq(m->scheduled_shutdown_type, "halt")) + target = SPECIAL_HALT_TARGET; + else + assert_not_reached("unexpected shutdown type"); - r = execute_shutdown_or_sleep(m, 0, target, &error); - if (r < 0) - return log_error_errno(r, "Unable to execute transition to %s: %m", target); + /* Don't allow multiple jobs being executed at the same time */ + if (m->action_what) { + r = -EALREADY; + log_error("Scheduled shutdown to %s failed: shutdown or sleep operation already in progress", target); + goto error; + } + + if (m->shutdown_dry_run) { + /* We do not process delay inhibitors here. Otherwise, we + * would have to be considered "in progress" (like the check + * above) for some seconds after our admin has seen the final + * wall message. */ + + bus_manager_log_shutdown(m, target); + log_info("Running in dry run, suppressing action."); + reset_scheduled_shutdown(m); + + return 0; + } + + r = bus_manager_shutdown_or_sleep_now_or_later(m, target, INHIBIT_SHUTDOWN, &error); + if (r < 0) { + log_error_errno(r, "Scheduled shutdown to %s failed: %m", target); + goto error; + } return 0; + +error: + reset_scheduled_shutdown(m); + return r; } static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) { @@ -1961,6 +2037,7 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ uint64_t elapse; char *type; int r; + bool dry_run = false; assert(m); assert(message); @@ -1971,10 +2048,14 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ if (startswith(type, "dry-")) { type += 4; - m->shutdown_dry_run = true; + dry_run = true; } - if (streq(type, "reboot")) { + if (streq(type, "poweroff")) { + action = "org.freedesktop.login1.power-off"; + action_multiple_sessions = "org.freedesktop.login1.power-off-multiple-sessions"; + action_ignore_inhibit = "org.freedesktop.login1.power-off-ignore-inhibit"; + } else if (streq(type, "reboot")) { action = "org.freedesktop.login1.reboot"; action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions"; action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit"; @@ -1982,10 +2063,6 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ action = "org.freedesktop.login1.halt"; action_multiple_sessions = "org.freedesktop.login1.halt-multiple-sessions"; action_ignore_inhibit = "org.freedesktop.login1.halt-ignore-inhibit"; - } else if (streq(type, "poweroff")) { - action = "org.freedesktop.login1.power-off"; - action_multiple_sessions = "org.freedesktop.login1.power-off-multiple-sessions"; - action_ignore_inhibit = "org.freedesktop.login1.power-off-ignore-inhibit"; } else return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type"); @@ -2015,6 +2092,8 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ return log_oom(); } + m->shutdown_dry_run = dry_run; + if (m->nologin_timeout_source) { r = sd_event_source_set_time(m->nologin_timeout_source, elapse); if (r < 0) @@ -2050,12 +2129,9 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ if (r < 0) return r; - if (!isempty(type)) { - r = update_schedule_file(m); - if (r < 0) - return r; - } else - (void) unlink("/run/systemd/shutdown/scheduled"); + r = update_schedule_file(m); + if (r < 0) + return r; return sd_bus_reply_method_return(message, NULL); } @@ -2089,34 +2165,6 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd return sd_bus_reply_method_return(message, "b", cancelled); } -static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) { - Manager *m = userdata; - - return method_do_shutdown_or_sleep( - m, message, - SPECIAL_HIBERNATE_TARGET, - INHIBIT_SLEEP, - "org.freedesktop.login1.hibernate", - "org.freedesktop.login1.hibernate-multiple-sessions", - "org.freedesktop.login1.hibernate-ignore-inhibit", - "hibernate", - error); -} - -static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) { - Manager *m = userdata; - - return method_do_shutdown_or_sleep( - m, message, - SPECIAL_HYBRID_SLEEP_TARGET, - INHIBIT_SLEEP, - "org.freedesktop.login1.hibernate", - "org.freedesktop.login1.hibernate-multiple-sessions", - "org.freedesktop.login1.hibernate-ignore-inhibit", - "hybrid-sleep", - error); -} - static int method_can_shutdown_or_sleep( Manager *m, sd_bus_message *message, @@ -2235,6 +2283,19 @@ static int method_can_reboot(sd_bus_message *message, void *userdata, sd_bus_err error); } +static int method_can_halt(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_can_shutdown_or_sleep( + m, message, + INHIBIT_SHUTDOWN, + "org.freedesktop.login1.halt", + "org.freedesktop.login1.halt-multiple-sessions", + "org.freedesktop.login1.halt-ignore-inhibit", + NULL, + error); +} + static int method_can_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) { Manager *m = userdata; @@ -2587,11 +2648,13 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD("FlushDevices", "b", NULL, method_flush_devices, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Halt", "b", NULL, method_halt, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanReboot", NULL, "s", method_can_reboot, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CanHalt", NULL, "s", method_can_halt, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED), |