chiark / gitweb /
systemctl: fix race in --block
[elogind.git] / src / systemctl.c
index 8a7a2de4031c6d1cd22563f9b1bcebdedd580516..b0fb7b24ae83ff2d6d668ebda6fb55ccce288d9a 100644 (file)
@@ -447,13 +447,12 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
-static int wait_for_jobs(DBusConnection *bus, Set *s) {
+static int enable_wait_for_jobs(DBusConnection *bus) {
         DBusError error;
         DBusMessage *m = NULL, *reply = NULL;
         int r;
 
         assert(bus);
-        assert(s);
 
         dbus_error_init(&error);
 
@@ -471,12 +470,6 @@ static int wait_for_jobs(DBusConnection *bus, Set *s) {
                 goto finish;
         }
 
-        if (!dbus_connection_add_filter(bus, wait_filter, s, NULL)) {
-                log_error("Failed to add filter.");
-                r = -ENOMEM;
-                goto finish;
-        }
-
         if (!(m = dbus_message_new_method_call(
                               "org.freedesktop.systemd1",
                               "/org/freedesktop/systemd1",
@@ -493,14 +486,10 @@ static int wait_for_jobs(DBusConnection *bus, Set *s) {
                 goto finish;
         }
 
-        while (!set_isempty(s) &&
-               dbus_connection_read_write_dispatch(bus, -1))
-                ;
-
         r = 0;
 
 finish:
-        /* This is slightly dirty, since we don't undo the filter or the matches. */
+        /* This is slightly dirty, since we don't undo the match registrations. */
 
         if (m)
                 dbus_message_unref(m);
@@ -513,6 +502,30 @@ finish:
         return r;
 }
 
+static int wait_for_jobs(DBusConnection *bus, Set *s) {
+        int r;
+
+        assert(bus);
+        assert(s);
+
+        if (!dbus_connection_add_filter(bus, wait_filter, s, NULL)) {
+                log_error("Failed to add filter.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        while (!set_isempty(s) &&
+               dbus_connection_read_write_dispatch(bus, -1))
+                ;
+
+        r = 0;
+
+finish:
+        /* This is slightly dirty, since we don't undo the filter registration. */
+
+        return r;
+}
+
 static int start_unit(DBusConnection *bus, char **args, unsigned n) {
         DBusMessage *m = NULL, *reply = NULL;
         DBusError error;
@@ -532,6 +545,13 @@ static int start_unit(DBusConnection *bus, char **args, unsigned n) {
 
         mode = arg_replace ? "replace" : "fail";
 
+        if (arg_block) {
+                if ((r = enable_wait_for_jobs(bus)) < 0) {
+                        log_error("Could not watch jobs: %s", strerror(-r));
+                        goto finish;
+                }
+        }
+
         for (i = 1; i < n; i++) {
 
                 if (!(m = dbus_message_new_method_call(
@@ -628,6 +648,13 @@ static int isolate_unit(DBusConnection *bus, char **args, unsigned n) {
 
         dbus_error_init(&error);
 
+        if (arg_block) {
+                if ((r = enable_wait_for_jobs(bus)) < 0) {
+                        log_error("Could not watch jobs: %s", strerror(-r));
+                        goto finish;
+                }
+        }
+
         if (!(m = dbus_message_new_method_call(
                               "org.freedesktop.systemd1",
                               "/org/freedesktop/systemd1",