chiark / gitweb /
systemctl: make shutdown operations use irreversible jobs
[elogind.git] / src / systemctl / systemctl.c
index becd68ff6e8215dcd33ad4572e24b92a65651958..3d59a8bb1d3b6a01918aff79e5cefc4ba65ee58a 100644 (file)
@@ -1336,7 +1336,9 @@ static void check_triggering_units(
         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
         DBusMessageIter iter, sub;
         const char *interface = "org.freedesktop.systemd1.Unit",
-                   *triggered_by_property = "TriggeredBy";
+                   *load_state_property = "LoadState",
+                   *triggered_by_property = "TriggeredBy",
+                   *state;
         char _cleanup_free_ *unit_path = NULL, *n = NULL;
         bool print_warning_label = true;
         int r;
@@ -1353,6 +1355,41 @@ static void check_triggering_units(
                 return;
         }
 
+        r = bus_method_call_with_reply(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        unit_path,
+                        "org.freedesktop.DBus.Properties",
+                        "Get",
+                        &reply,
+                        NULL,
+                        DBUS_TYPE_STRING, &interface,
+                        DBUS_TYPE_STRING, &load_state_property,
+                        DBUS_TYPE_INVALID);
+        if (r < 0)
+                return;
+
+        if (!dbus_message_iter_init(reply, &iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
+                log_error("Failed to parse reply.");
+                return;
+        }
+
+        dbus_message_iter_recurse(&iter, &sub);
+
+        if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
+            log_error("Failed to parse reply.");
+            return;
+        }
+
+        dbus_message_iter_get_basic(&sub, &state);
+
+        if (streq(state, "masked"))
+            return;
+
+        dbus_message_unref(reply);
+        reply = NULL;
+
         r = bus_method_call_with_reply(
                         bus,
                         "org.freedesktop.systemd1",
@@ -1558,10 +1595,22 @@ static int start_unit(DBusConnection *bus, char **args) {
                         streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
                                                                   "StartUnit";
 
-                mode =
-                        (streq(args[0], "isolate") ||
-                         streq(args[0], "rescue")  ||
-                         streq(args[0], "emergency")) ? "isolate" : arg_job_mode;
+                if (streq(args[0], "isolate") ||
+                    streq(args[0], "rescue")  ||
+                    streq(args[0], "emergency") ||
+                    streq(args[0], "default"))
+                        mode = "isolate";
+                else if (streq(args[0], "halt") ||
+                         streq(args[0], "poweroff") ||
+                         streq(args[0], "reboot") ||
+                         streq(args[0], "kexec") ||
+                         streq(args[0], "exit") ||
+                         streq(args[0], "suspend") ||
+                         streq(args[0], "hibernate") ||
+                         streq(args[0], "hybrid-sleep"))
+                        mode = "replace-irreversibly";
+                else
+                        mode = arg_job_mode;
 
                 one_name = table[verb_to_action(args[0])];
 
@@ -1576,7 +1625,7 @@ static int start_unit(DBusConnection *bus, char **args) {
                         arg_action == ACTION_RUNLEVEL2 ||
                         arg_action == ACTION_RUNLEVEL3 ||
                         arg_action == ACTION_RUNLEVEL4 ||
-                        arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
+                        arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace-irreversibly";
 
                 one_name = table[arg_action];
         }
@@ -4268,6 +4317,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
 
         enum {
                 ARG_FAIL = 0x100,
+                ARG_IRREVERSIBLE,
                 ARG_IGNORE_DEPENDENCIES,
                 ARG_VERSION,
                 ARG_USER,
@@ -4296,6 +4346,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "failed",    no_argument,       NULL, ARG_FAILED    },
                 { "full",      no_argument,       NULL, ARG_FULL      },
                 { "fail",      no_argument,       NULL, ARG_FAIL      },
+                { "irreversible", no_argument,    NULL, ARG_IRREVERSIBLE },
                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
                 { "ignore-inhibitors", no_argument, NULL, 'i'         },
                 { "user",      no_argument,       NULL, ARG_USER      },
@@ -4357,18 +4408,33 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         log_info("Use -t help to see a list of allowed values.");
                         return -EINVAL;
                 case 'p': {
-                        char **l;
+                        char *word, *state;
+                        size_t size;
+                        /* Make sure that if the empty property list
+                           was specified, we won't show any properties. */
+                        const char *source = isempty(optarg) ? " " : optarg;
+
+                        FOREACH_WORD_SEPARATOR(word, size, source, ",", state) {
+                                char _cleanup_free_ *prop;
+                                char **tmp;
+
+                                prop = strndup(word, size);
+                                if (!prop)
+                                        return -ENOMEM;
 
-                        if (!(l = strv_append(arg_property, optarg)))
-                                return -ENOMEM;
+                                tmp = strv_append(arg_property, prop);
+                                if (!tmp)
+                                        return -ENOMEM;
 
-                        strv_free(arg_property);
-                        arg_property = l;
+                                strv_free(arg_property);
+                                arg_property = tmp;
+                        }
 
                         /* If the user asked for a particular
                          * property, show it to him, even if it is
                          * empty. */
                         arg_all = true;
+
                         break;
                 }
 
@@ -4380,6 +4446,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_job_mode = "fail";
                         break;
 
+                case ARG_IRREVERSIBLE:
+                        arg_job_mode = "replace-irreversibly";
+                        break;
+
                 case ARG_IGNORE_DEPENDENCIES:
                         arg_job_mode = "ignore-dependencies";
                         break;