" <arg name=\"id\" type=\"s\"/>\n" \
" <arg name=\"path\" type=\"o\"/>\n" \
" </signal>\n" \
+ " <signal name=\"Resumed\"/>\n" \
" <signal name=\"PrepareForShutdown\">\n" \
" <arg name=\"active\" type=\"b\"/>\n" \
" </signal>\n" \
" <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
" <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
" </interface>\n"
assert(m);
- /* 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 != uid)
+ 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) {
- const char *mode = "replace";
+static int send_start_unit(Manager *m, const char *unit_name, bool send_resumed, DBusError *error) {
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+ const char *mode = "replace", *p;
+ int r;
+ char *c;
+ assert(m);
assert(unit_name);
- return bus_method_call_with_reply (
- connection,
+ r = bus_method_call_with_reply(
+ m->bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"StartUnit",
- NULL,
- NULL,
+ &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;
+
+ free(m->action_job);
+ m->action_job = c;
+ m->send_resumed_after_action_job = send_resumed;
+
+ return 0;
}
static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
};
dbus_bool_t active = _active;
- DBusMessage *message;
- int r = 0;
+ _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
assert(m);
assert(w >= 0);
if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
!dbus_connection_send(m->bus, message, NULL))
- r = -ENOMEM;
+ return -ENOMEM;
- dbus_message_unref(message);
- return r;
+ return 0;
}
static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
assert(unit_name);
assert(w >= 0);
assert(w <= _INHIBIT_WHAT_MAX);
+ assert(!m->action_job);
delayed =
m->inhibit_delay_max > 0 &&
/* Shutdown is not delayed, execute it
* immediately */
- r = send_start_unit(m->bus, unit_name, error);
+ r = send_start_unit(m, unit_name, w & INHIBIT_SLEEP, error);
}
return r;
assert(error);
assert(_reply);
+ if (m->action_job || m->delayed_unit)
+ return -EALREADY;
+
if (!dbus_message_get_args(
message,
error,
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 },
{ "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) },
- { "HandleSuspendKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_suspend_key) },
- { "HandleHibernateKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_hibernate_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, }
}
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);
}
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("Action is complete, result is '%s'.", result);
+ free(m->action_job);
+ m->action_job = NULL;
+
+ if (m->send_resumed_after_action_job) {
+ _cleanup_dbus_message_unref_ DBusMessage *s = NULL;
+
+ s = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", "Resumed");
+ if (s)
+ dbus_connection_send(m->bus, s, NULL);
+ }
+ }
}
dbus_error_free(&error);
bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
+ /* Tell people about it */
+ send_prepare_for(manager, manager->delayed_what, false);
+
/* Reset delay data */
unit_name = manager->delayed_unit;
manager->delayed_unit = NULL;
/* Actually do the shutdown */
dbus_error_init(&error);
- r = send_start_unit(manager->bus, unit_name, &error);
+ r = send_start_unit(manager, unit_name, manager->delayed_what & INHIBIT_SLEEP, &error);
if (r < 0) {
log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
dbus_error_free(&error);
return r;
}
- /* Tell people about it */
- send_prepare_for(manager, manager->delayed_what, false);
-
return 1;
}