summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/login/logind-action.c9
-rw-r--r--src/login/logind-dbus.c65
-rw-r--r--src/login/logind.c2
-rw-r--r--src/login/logind.h4
4 files changed, 67 insertions, 13 deletions
diff --git a/src/login/logind-action.c b/src/login/logind-action.c
index e1517d6ac2..a796ebe9ec 100644
--- a/src/login/logind-action.c
+++ b/src/login/logind-action.c
@@ -56,10 +56,15 @@ int manager_handle_action(
DBusError error;
int r;
InhibitWhat inhibit_operation;
- bool supported = true;
+ bool supported;
assert(m);
+ if (m->action_job || m->delayed_unit) {
+ log_debug("Action already in progress, ignoring.");
+ return -EALREADY;
+ }
+
/* If the key handling is turned off, don't do anything */
if (handle == HANDLE_IGNORE) {
log_debug("Refusing operation, as it is turned off.");
@@ -74,6 +79,8 @@ int manager_handle_action(
supported = can_sleep("disk") > 0 && can_sleep_disk("suspend") > 0;
else if (handle == HANDLE_KEXEC)
supported = access("/sbin/kexec", X_OK) >= 0;
+ else
+ supported = true;
if (!supported) {
log_warning("Requested operation not supported, ignoring.");
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index d64debe51f..0ff20fabd5 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -990,22 +990,44 @@ static int have_multiple_sessions(
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, 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;
+
+ return 0;
}
static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
@@ -1226,6 +1248,7 @@ int bus_manager_shutdown_or_sleep_now_or_later(
assert(unit_name);
assert(w >= 0);
assert(w <= _INHIBIT_WHAT_MAX);
+ assert(!m->action_job);
delayed =
m->inhibit_delay_max > 0 &&
@@ -1240,7 +1263,7 @@ int bus_manager_shutdown_or_sleep_now_or_later(
/* Shutdown is not delayed, execute it
* immediately */
- r = send_start_unit(m->bus, unit_name, error);
+ r = send_start_unit(m, unit_name, error);
}
return r;
@@ -1278,6 +1301,9 @@ static int bus_manager_do_shutdown_or_sleep(
assert(error);
assert(_reply);
+ if (m->action_job || m->delayed_unit)
+ return -EALREADY;
+
if (!dbus_message_get_args(
message,
error,
@@ -2327,6 +2353,23 @@ 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("Action is complete, result is '%s'.", result);
+ free(m->action_job);
+ m->action_job = NULL;
+ }
}
dbus_error_free(&error);
@@ -2376,21 +2419,21 @@ int manager_dispatch_delayed(Manager *manager) {
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, &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;
}
diff --git a/src/login/logind.c b/src/login/logind.c
index 6776229ee7..ed0b7489b9 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -187,6 +187,8 @@ void manager_free(Manager *m) {
strv_free(m->kill_only_users);
strv_free(m->kill_exclude_users);
+ free(m->action_job);
+
free(m->cgroup_path);
free(m);
}
diff --git a/src/login/logind.h b/src/login/logind.h
index 816635dcfc..fe6ea0fd34 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -100,7 +100,9 @@ struct Manager {
usec_t inhibit_delay_max;
- int idle_action_fd;
+ char* action_job;
+
+ int idle_action_fd; /* the timer_fd */
usec_t idle_action_usec;
usec_t idle_action_not_before_usec;
HandleAction idle_action;