X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flogin%2Flogind-dbus.c;h=f35185971bb777c5bf612a2061321b47fc8a876d;hp=3cde83166f21208424f87fa1fd8e43255e8c441c;hb=314b4b0a68d9ab35de981923a088fc8c8820caa5;hpb=2154761fbbc931e3e3d83100fa42609c99cd2536 diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 3cde83166..f35185971 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -31,6 +31,8 @@ #include "path-util.h" #include "polkit.h" #include "special.h" +#include "systemd/sd-id128.h" +#include "systemd/sd-messages.h" #define BUS_MANAGER_INTERFACE \ " \n" \ @@ -81,6 +83,7 @@ " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -98,6 +101,8 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -141,6 +146,9 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -153,6 +161,9 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -207,8 +218,13 @@ " \n" \ " \n" \ " \n" \ - " \n" \ + " \n" \ + " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" #define INTROSPECTION_BEGIN \ @@ -273,12 +289,28 @@ static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property return 0; } +static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) { + Manager *m = data; + dbus_bool_t b; + + assert(i); + assert(property); + + if (streq(property, "PreparingForShutdown")) + b = !!(m->action_what & INHIBIT_SHUTDOWN); + else + b = !!(m->action_what & INHIBIT_SLEEP); + + dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b); + return 0; +} + static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) { Session *session = NULL; User *user = NULL; const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service; uint32_t uid, leader, audit_id = 0; - dbus_bool_t remote, kill_processes; + dbus_bool_t remote, kill_processes, exists; char **controllers = NULL, **reset_controllers = NULL; SessionType t; SessionClass c; @@ -386,8 +418,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess if (vtnr != 0) return -EINVAL; - } else if (!isempty(tty) && s && seat_is_vtconsole(s)) - return -EINVAL; + } if (s) { if (seat_can_multi_session(s)) { @@ -496,6 +527,8 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess seat = session->seat ? session->seat->id : ""; vtnr = session->vtnr; + exists = true; + b = dbus_message_append_args( reply, DBUS_TYPE_STRING, &session->id, @@ -504,6 +537,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess DBUS_TYPE_UNIX_FD, &fifo_fd, DBUS_TYPE_STRING, &seat, DBUS_TYPE_UINT32, &vtnr, + DBUS_TYPE_BOOLEAN, &exists, DBUS_TYPE_INVALID); free(p); @@ -620,6 +654,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess } seat = s ? s->id : ""; + exists = false; b = dbus_message_append_args( reply, DBUS_TYPE_STRING, &session->id, @@ -628,6 +663,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess DBUS_TYPE_UNIX_FD, &fifo_fd, DBUS_TYPE_STRING, &seat, DBUS_TYPE_UINT32, &vtnr, + DBUS_TYPE_BOOLEAN, &exists, DBUS_TYPE_INVALID); free(p); @@ -660,7 +696,13 @@ fail: return r; } -static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) { +static int bus_manager_inhibit( + Manager *m, + DBusConnection *connection, + DBusMessage *message, + DBusError *error, + DBusMessage **_reply) { + Inhibitor *i = NULL; char *id = NULL; const char *who, *why, *what, *mode; @@ -701,10 +743,30 @@ static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessa goto fail; } + /* Delay is only supported for shutdown/sleep */ + if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) { + r = -EINVAL; + goto fail; + } + + /* Don't allow taking delay locks while we are already + * executing the operation. We shouldn't create the impression + * that the lock was successful if the machine is about to go + * down/suspend any moment. */ + if (m->action_what & w) { + r = -EALREADY; + goto fail; + } + r = verify_polkit(connection, message, - m == INHIBIT_BLOCK ? - "org.freedesktop.login1.inhibit-block" : - "org.freedesktop.login1.inhibit-delay", false, NULL, error); + w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") : + w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") : + w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" : + w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" : + w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" : + w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" : + "org.freedesktop.login1.inhibit-handle-lid-switch", + false, NULL, error); if (r < 0) goto fail; @@ -925,105 +987,124 @@ static int flush_devices(Manager *m) { } static int have_multiple_sessions( - DBusConnection *connection, Manager *m, - DBusMessage *message, - DBusError *error) { + uid_t uid) { Session *session; Iterator i; - unsigned long ul; assert(m); - ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error); - if (ul == (unsigned long) -1) - return -EIO; - - /* Check for other users' sessions. Greeter sessions do not count. */ + /* Check for other users' sessions. Greeter sessions do not + * count, and non-login sessions do not count either. */ HASHMAP_FOREACH(session, m->sessions, i) - if (session->class == SESSION_USER && session->user->uid != ul) + if (session->class == SESSION_USER && + (session->type == SESSION_TTY || session->type == SESSION_X11) && + session->user->uid != uid) return true; return false; } -static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) { - DBusMessage *message, *reply; - const char *mode = "replace"; +static int bus_manager_log_shutdown( + Manager *m, + InhibitWhat w, + const char *unit_name) { - assert(connection); + const char *p, *q; + + assert(m); assert(unit_name); - message = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "StartUnit"); - if (!message) - return -ENOMEM; + if (w != INHIBIT_SHUTDOWN) + return 0; - if (!dbus_message_append_args(message, - DBUS_TYPE_STRING, &unit_name, - DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID)) { - dbus_message_unref(message); - return -ENOMEM; + 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_KEXEC_TARGET)) { + p = "MESSAGE=System is rebooting with kexec."; + q = "SHUTDOWN=kexec"; + } else { + p = "MESSAGE=System is shutting down."; + q = NULL; } - reply = dbus_connection_send_with_reply_and_block(connection, message, -1, error); - dbus_message_unref(message); - - if (!reply) - return -EIO; - - dbus_message_unref(reply); - return 0; + return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN), + p, + q, NULL); } -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" - }; +static int execute_shutdown_or_sleep( + Manager *m, + InhibitWhat w, + const char *unit_name, + DBusError *error) { - dbus_bool_t active = _active; - DBusMessage *message; - int r = 0; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; + const char *mode = "replace", *p; + int r; + char *c; assert(m); assert(w >= 0); assert(w < _INHIBIT_WHAT_MAX); - assert(signal_name[w]); + assert(unit_name); - message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]); - if (!message) + bus_manager_log_shutdown(m, w, unit_name); + + r = bus_method_call_with_reply( + m->bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartUnit", + &reply, + error, + DBUS_TYPE_STRING, &unit_name, + DBUS_TYPE_STRING, &mode, + DBUS_TYPE_INVALID); + if (r < 0) + return r; + + if (!dbus_message_get_args( + reply, + error, + DBUS_TYPE_OBJECT_PATH, &p, + DBUS_TYPE_INVALID)) + return -EINVAL; + + c = strdup(p); + if (!c) return -ENOMEM; - if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) || - !dbus_connection_send(m->bus, message, NULL)) - r = -ENOMEM; + m->action_unit = unit_name; + free(m->action_job); + m->action_job = c; + m->action_what = w; - dbus_message_unref(message); - return r; + return 0; } -static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) { +static int delay_shutdown_or_sleep( + Manager *m, + InhibitWhat w, + const char *unit_name) { + assert(m); assert(w >= 0); assert(w < _INHIBIT_WHAT_MAX); + assert(unit_name); - /* Tell everybody to prepare for shutdown/sleep */ - send_prepare_for(m, w, true); - - /* Update timestamp for timeout */ - if (!m->delayed_unit) - m->delayed_timestamp = now(CLOCK_MONOTONIC); - - /* Remember what we want to do, possibly overriding what kind - * of unit we previously queued. */ - m->delayed_unit = unit_name; - m->delayed_what = w; + m->action_timestamp = now(CLOCK_MONOTONIC); + m->action_unit = unit_name; + m->action_what = w; return 0; } @@ -1037,6 +1118,7 @@ static int bus_manager_can_shutdown_or_sleep( const char *action_multiple_sessions, const char *action_ignore_inhibit, const char *sleep_type, + const char *sleep_disk_type, DBusError *error, DBusMessage **_reply) { @@ -1044,6 +1126,7 @@ static int bus_manager_can_shutdown_or_sleep( const char *result; DBusMessage *reply = NULL; int r; + unsigned long ul; assert(m); assert(connection); @@ -1067,12 +1150,27 @@ static int bus_manager_can_shutdown_or_sleep( } } - r = have_multiple_sessions(connection, m, message, error); + if (sleep_disk_type) { + r = can_sleep_disk(sleep_disk_type); + if (r < 0) + return r; + + if (r == 0) { + result = "na"; + goto finish; + } + } + + ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error); + if (ul == (unsigned long) -1) + return -EIO; + + r = have_multiple_sessions(m, (uid_t) ul); if (r < 0) return r; multiple_sessions = r > 0; - blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL); + blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul); if (multiple_sessions) { r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error); @@ -1134,6 +1232,31 @@ finish: 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" + }; + + dbus_bool_t active = _active; + _cleanup_dbus_message_unref_ DBusMessage *message = NULL; + + assert(m); + assert(w >= 0); + assert(w < _INHIBIT_WHAT_MAX); + assert(signal_name[w]); + + message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]); + if (!message) + return -ENOMEM; + + if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) || + !dbus_connection_send(m->bus, message, NULL)) + return -ENOMEM; + + return 0; +} + int bus_manager_shutdown_or_sleep_now_or_later( Manager *m, const char *unit_name, @@ -1147,10 +1270,14 @@ int bus_manager_shutdown_or_sleep_now_or_later( assert(unit_name); assert(w >= 0); assert(w <= _INHIBIT_WHAT_MAX); + assert(!m->action_job); + + /* Tell everybody to prepare for shutdown/sleep */ + send_prepare_for(m, w, true); delayed = m->inhibit_delay_max > 0 && - manager_is_inhibited(m, w, INHIBIT_DELAY, NULL); + manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0); if (delayed) /* Shutdown is delayed, keep in mind what we @@ -1159,7 +1286,7 @@ int bus_manager_shutdown_or_sleep_now_or_later( else /* Shutdown is not delayed, execute it * immediately */ - r = send_start_unit(m->bus, unit_name, error); + r = execute_shutdown_or_sleep(m, w, unit_name, error); return r; } @@ -1174,6 +1301,7 @@ static int bus_manager_do_shutdown_or_sleep( const char *action_multiple_sessions, const char *action_ignore_inhibit, const char *sleep_type, + const char *sleep_disk_type, DBusError *error, DBusMessage **_reply) { @@ -1181,6 +1309,7 @@ static int bus_manager_do_shutdown_or_sleep( bool multiple_sessions, blocked; DBusMessage *reply = NULL; int r; + unsigned long ul; assert(m); assert(connection); @@ -1194,6 +1323,10 @@ static int bus_manager_do_shutdown_or_sleep( assert(error); assert(_reply); + /* Don't allow multiple jobs being executed at the same time */ + if (m->action_what) + return -EALREADY; + if (!dbus_message_get_args( message, error, @@ -1210,12 +1343,25 @@ static int bus_manager_do_shutdown_or_sleep( return -ENOTSUP; } - r = have_multiple_sessions(connection, m, message, error); + if (sleep_disk_type) { + r = can_sleep_disk(sleep_disk_type); + if (r < 0) + return r; + + if (r == 0) + return -ENOTSUP; + } + + ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error); + if (ul == (unsigned long) -1) + return -EIO; + + r = have_multiple_sessions(m, (uid_t) ul); if (r < 0) return r; multiple_sessions = r > 0; - blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL); + blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul); if (multiple_sessions) { r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error); @@ -1247,7 +1393,7 @@ static int bus_manager_do_shutdown_or_sleep( return 0; } -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton); +static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction); static const BusProperty bus_login_manager_properties[] = { { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true }, @@ -1263,9 +1409,14 @@ static const BusProperty bus_login_manager_properties[] = { { "BlockInhibited", bus_manager_append_inhibited, "s", 0 }, { "DelayInhibited", bus_manager_append_inhibited, "s", 0 }, { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) }, - { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) }, - { "HandleSleepKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_sleep_key) }, - { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) }, + { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) }, + { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) }, + { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)}, + { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) }, + { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) }, + { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) }, + { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 }, + { "PreparingForSleep", bus_manager_append_preparing, "b", 0 }, { NULL, } }; @@ -1716,7 +1867,7 @@ static DBusHandlerResult manager_message_handler( session = hashmap_get(m->sessions, name); if (!session) - return bus_send_error_reply(connection, message, &error, -ENOENT); + return bus_send_error_reply(connection, message, NULL, -ENOENT); if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0) goto oom; @@ -1725,6 +1876,17 @@ static DBusHandlerResult manager_message_handler( if (!reply) goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") || + dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) { + + r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions")); + if (r < 0) + bus_send_error_reply(connection, message, NULL, r); + + reply = dbus_message_new_method_return(message); + if (!reply) + goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) { const char *swho; int32_t signo; @@ -1985,7 +2147,7 @@ static DBusHandlerResult manager_message_handler( "org.freedesktop.login1.power-off", "org.freedesktop.login1.power-off-multiple-sessions", "org.freedesktop.login1.power-off-ignore-inhibit", - NULL, + NULL, NULL, &error, &reply); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -1997,7 +2159,7 @@ static DBusHandlerResult manager_message_handler( "org.freedesktop.login1.reboot", "org.freedesktop.login1.reboot-multiple-sessions", "org.freedesktop.login1.reboot-ignore-inhibit", - NULL, + NULL, NULL, &error, &reply); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -2010,7 +2172,7 @@ static DBusHandlerResult manager_message_handler( "org.freedesktop.login1.suspend", "org.freedesktop.login1.suspend-multiple-sessions", "org.freedesktop.login1.suspend-ignore-inhibit", - "mem", + "mem", NULL, &error, &reply); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -2022,7 +2184,20 @@ static DBusHandlerResult manager_message_handler( "org.freedesktop.login1.hibernate", "org.freedesktop.login1.hibernate-multiple-sessions", "org.freedesktop.login1.hibernate-ignore-inhibit", - "disk", + "disk", NULL, + &error, &reply); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) { + r = bus_manager_do_shutdown_or_sleep( + m, connection, message, + SPECIAL_HYBRID_SLEEP_TARGET, + INHIBIT_SLEEP, + "org.freedesktop.login1.hibernate", + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + "disk", "suspend", &error, &reply); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -2035,7 +2210,7 @@ static DBusHandlerResult manager_message_handler( "org.freedesktop.login1.power-off", "org.freedesktop.login1.power-off-multiple-sessions", "org.freedesktop.login1.power-off-ignore-inhibit", - NULL, + NULL, NULL, &error, &reply); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -2046,7 +2221,7 @@ static DBusHandlerResult manager_message_handler( "org.freedesktop.login1.reboot", "org.freedesktop.login1.reboot-multiple-sessions", "org.freedesktop.login1.reboot-ignore-inhibit", - NULL, + NULL, NULL, &error, &reply); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -2058,7 +2233,7 @@ static DBusHandlerResult manager_message_handler( "org.freedesktop.login1.suspend", "org.freedesktop.login1.suspend-multiple-sessions", "org.freedesktop.login1.suspend-ignore-inhibit", - "mem", + "mem", NULL, &error, &reply); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -2070,7 +2245,19 @@ static DBusHandlerResult manager_message_handler( "org.freedesktop.login1.hibernate", "org.freedesktop.login1.hibernate-multiple-sessions", "org.freedesktop.login1.hibernate-ignore-inhibit", - "disk", + "disk", NULL, + &error, &reply); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) { + r = bus_manager_can_shutdown_or_sleep( + m, connection, message, + INHIBIT_SLEEP, + "org.freedesktop.login1.hibernate", + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + "disk", "suspend", &error, &reply); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -2147,8 +2334,8 @@ static DBusHandlerResult manager_message_handler( } if (reply) { - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; + if (!bus_maybe_send_reply(connection, message, reply)) + goto oom; dbus_message_unref(reply); } @@ -2191,6 +2378,31 @@ DBusHandlerResult bus_message_filter( log_error("Failed to parse Released message: %s", bus_error_message(&error)); else manager_cgroup_notify_empty(m, cgroup); + + } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) { + uint32_t id; + const char *path, *result, *unit; + + if (!dbus_message_get_args(message, &error, + DBUS_TYPE_UINT32, &id, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_STRING, &unit, + DBUS_TYPE_STRING, &result, + DBUS_TYPE_INVALID)) + log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error)); + + else if (m->action_job && streq(m->action_job, path)) { + + log_info("Operation finished."); + + /* Tell people that they now may take a lock again */ + send_prepare_for(m, m->action_what, false); + + free(m->action_job); + m->action_job = NULL; + m->action_unit = NULL; + m->action_what = 0; + } } dbus_error_free(&error); @@ -2221,38 +2433,34 @@ finish: } int manager_dispatch_delayed(Manager *manager) { - const char *unit_name; DBusError error; - bool delayed; int r; assert(manager); - if (!manager->delayed_unit) + if (!manager->action_unit || manager->action_job) return 0; /* Continue delay? */ - delayed = - manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) && - manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL); - if (delayed) - return 0; + if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) { + + if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC)) + return 0; - /* Reset delay data */ - unit_name = manager->delayed_unit; - manager->delayed_unit = NULL; + log_info("Delay lock is active but inhibitor timeout is reached."); + } - /* Actually do the shutdown */ + /* Actually do the operation */ dbus_error_init(&error); - r = send_start_unit(manager->bus, unit_name, &error); + 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_or_strerror(&error, -r)); dbus_error_free(&error); + + manager->action_unit = NULL; + manager->action_what = 0; return r; } - /* Tell people about it */ - send_prepare_for(manager, manager->delayed_what, false); - return 1; }