chiark / gitweb /
delta: fix spelling of overridden
[elogind.git] / src / systemctl / systemctl.c
index acede4e765959ce32a2d136b6cc911de2e74b6ab..b4253a45b183e4f5027eca9c83b10623ac911d1a 100644 (file)
@@ -97,6 +97,8 @@ static enum action {
         ACTION_REBOOT,
         ACTION_KEXEC,
         ACTION_EXIT,
         ACTION_REBOOT,
         ACTION_KEXEC,
         ACTION_EXIT,
+        ACTION_SUSPEND,
+        ACTION_HIBERNATE,
         ACTION_RUNLEVEL2,
         ACTION_RUNLEVEL3,
         ACTION_RUNLEVEL4,
         ACTION_RUNLEVEL2,
         ACTION_RUNLEVEL3,
         ACTION_RUNLEVEL4,
@@ -1605,6 +1607,10 @@ static enum action verb_to_action(const char *verb) {
                 return ACTION_DEFAULT;
         else if (streq(verb, "exit"))
                 return ACTION_EXIT;
                 return ACTION_DEFAULT;
         else if (streq(verb, "exit"))
                 return ACTION_EXIT;
+        else if (streq(verb, "suspend"))
+                return ACTION_SUSPEND;
+        else if (streq(verb, "hibernate"))
+                return ACTION_HIBERNATE;
         else
                 return ACTION_INVALID;
 }
         else
                 return ACTION_INVALID;
 }
@@ -1623,7 +1629,9 @@ static int start_unit(DBusConnection *bus, char **args) {
                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
-                [ACTION_EXIT] = SPECIAL_EXIT_TARGET
+                [ACTION_EXIT] = SPECIAL_EXIT_TARGET,
+                [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
+                [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET
         };
 
         int r, ret = 0;
         };
 
         int r, ret = 0;
@@ -1742,6 +1750,14 @@ static int reboot_with_logind(DBusConnection *bus, enum action a) {
                 method = "PowerOff";
                 break;
 
                 method = "PowerOff";
                 break;
 
+        case ACTION_SUSPEND:
+                method = "Suspend";
+                break;
+
+        case ACTION_HIBERNATE:
+                method = "Hibernate";
+                break;
+
         default:
                 return -EINVAL;
         }
         default:
                 return -EINVAL;
         }
@@ -1831,7 +1847,9 @@ static int start_special(DBusConnection *bus, char **args) {
         /* first try logind, to allow authentication with polkit */
         if (geteuid() != 0 &&
             (a == ACTION_POWEROFF ||
         /* first try logind, to allow authentication with polkit */
         if (geteuid() != 0 &&
             (a == ACTION_POWEROFF ||
-             a == ACTION_REBOOT)) {
+             a == ACTION_REBOOT ||
+             a == ACTION_SUSPEND ||
+             a == ACTION_HIBERNATE)) {
                 r = reboot_with_logind(bus, a);
                 if (r >= 0)
                         return r;
                 r = reboot_with_logind(bus, a);
                 if (r >= 0)
                         return r;
@@ -2140,6 +2158,8 @@ typedef struct UnitStatusInfo {
         const char *description;
         const char *following;
 
         const char *description;
         const char *following;
 
+        char **documentation;
+
         const char *path;
         const char *default_control_group;
 
         const char *path;
         const char *default_control_group;
 
@@ -2285,6 +2305,19 @@ static void print_status_info(UnitStatusInfo *i) {
         if (i->what)
                 printf("\t    What: %s\n", i->what);
 
         if (i->what)
                 printf("\t    What: %s\n", i->what);
 
+        if (!strv_isempty(i->documentation)) {
+                char **t;
+                bool first = true;
+
+                STRV_FOREACH(t, i->documentation) {
+                        if (first) {
+                                printf("\t    Docs: %s\n", *t);
+                                first = false;
+                        } else
+                                printf("\t          %s\n", *t);
+                }
+        }
+
         if (i->accept)
                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
 
         if (i->accept)
                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
 
@@ -2589,6 +2622,27 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
 
                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
 
 
                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
 
+                                dbus_message_iter_next(&sub);
+                        }
+                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
+                           streq(name, "Documentation")) {
+
+                        DBusMessageIter sub;
+
+                        dbus_message_iter_recurse(iter, &sub);
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
+                                const char *s;
+                                char **l;
+
+                                dbus_message_iter_get_basic(&sub, &s);
+
+                                l = strv_append(i->documentation, s);
+                                if (!l)
+                                        return -ENOMEM;
+
+                                strv_free(i->documentation);
+                                i->documentation = l;
+
                                 dbus_message_iter_next(&sub);
                         }
                 }
                                 dbus_message_iter_next(&sub);
                         }
                 }
@@ -2914,6 +2968,8 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo
         if (!show_properties)
                 print_status_info(&info);
 
         if (!show_properties)
                 print_status_info(&info);
 
+        strv_free(info.documentation);
+
         if (!streq_ptr(info.active_state, "active") &&
             !streq_ptr(info.active_state, "reloading") &&
             streq(verb, "status"))
         if (!streq_ptr(info.active_state, "active") &&
             !streq_ptr(info.active_state, "reloading") &&
             streq(verb, "status"))
@@ -2937,18 +2993,70 @@ finish:
         return r;
 }
 
         return r;
 }
 
-static int show(DBusConnection *bus, char **args) {
+static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
         DBusMessage *m = NULL, *reply = NULL;
         DBusMessage *m = NULL, *reply = NULL;
-        int r, ret = 0;
+        const char *path = NULL;
         DBusError error;
         DBusError error;
+        int r;
+
+        dbus_error_init(&error);
+
+        m = dbus_message_new_method_call(
+                              "org.freedesktop.systemd1",
+                              "/org/freedesktop/systemd1",
+                              "org.freedesktop.systemd1.Manager",
+                              "GetUnitByPID");
+        if (!m) {
+                log_error("Could not allocate message.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_UINT32, &pid,
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Could not append arguments to message.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+        if (!reply) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
+                r = -EIO;
+                goto finish;
+        }
+
+        if (!dbus_message_get_args(reply, &error,
+                                   DBUS_TYPE_OBJECT_PATH, &path,
+                                   DBUS_TYPE_INVALID)) {
+                log_error("Failed to parse reply: %s", bus_error_message(&error));
+                r = -EIO;
+                goto finish;
+        }
+
+        r = show_one(verb, bus, path, false, new_line);
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return r;
+}
+
+static int show(DBusConnection *bus, char **args) {
+        int r, ret = 0;
         bool show_properties, new_line = false;
         char **name;
 
         assert(bus);
         assert(args);
 
         bool show_properties, new_line = false;
         char **name;
 
         assert(bus);
         assert(args);
 
-        dbus_error_init(&error);
-
         show_properties = !streq(args[0], "status");
 
         if (show_properties)
         show_properties = !streq(args[0], "status");
 
         if (show_properties)
@@ -2958,157 +3066,55 @@ static int show(DBusConnection *bus, char **args) {
                 /* If not argument is specified inspect the manager
                  * itself */
 
                 /* If not argument is specified inspect the manager
                  * itself */
 
-                ret = show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
-                goto finish;
+                return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
         }
 
         STRV_FOREACH(name, args+1) {
         }
 
         STRV_FOREACH(name, args+1) {
-                const char *path = NULL;
                 uint32_t id;
 
                 if (safe_atou32(*name, &id) < 0) {
 
                         /* Interpret as unit name */
 
                 uint32_t id;
 
                 if (safe_atou32(*name, &id) < 0) {
 
                         /* Interpret as unit name */
 
-                        if (!(m = dbus_message_new_method_call(
-                                              "org.freedesktop.systemd1",
-                                              "/org/freedesktop/systemd1",
-                                              "org.freedesktop.systemd1.Manager",
-                                              "LoadUnit"))) {
-                                log_error("Could not allocate message.");
-                                ret = -ENOMEM;
-                                goto finish;
-                        }
-
-                        if (!dbus_message_append_args(m,
-                                                      DBUS_TYPE_STRING, name,
-                                                      DBUS_TYPE_INVALID)) {
-                                log_error("Could not append arguments to message.");
-                                ret = -ENOMEM;
-                                goto finish;
-                        }
-
-                        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-
-                                if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
-                                        log_error("Failed to issue method call: %s", bus_error_message(&error));
-                                        ret = -EIO;
-                                        goto finish;
-                                }
-
-                                dbus_error_free(&error);
-
-                                dbus_message_unref(m);
-                                if (!(m = dbus_message_new_method_call(
-                                                      "org.freedesktop.systemd1",
-                                                      "/org/freedesktop/systemd1",
-                                                      "org.freedesktop.systemd1.Manager",
-                                                      "GetUnit"))) {
-                                        log_error("Could not allocate message.");
-                                        ret = -ENOMEM;
-                                        goto finish;
-                                }
-
-                                if (!dbus_message_append_args(m,
-                                                              DBUS_TYPE_STRING, name,
-                                                              DBUS_TYPE_INVALID)) {
-                                        log_error("Could not append arguments to message.");
-                                        ret = -ENOMEM;
-                                        goto finish;
-                                }
+                        char *e, *p;
+                        e = bus_path_escape(*name);
+                        if (!e)
+                                return -ENOMEM;
+                        p = strappend("/org/freedesktop/systemd1/unit/", e);
+                        free(e);
+                        if (!p)
+                                return -ENOMEM;
 
 
-                                if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                                        log_error("Failed to issue method call: %s", bus_error_message(&error));
+                        r = show_one(args[0], bus, p, show_properties, &new_line);
+                        free(p);
 
 
-                                        if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT))
-                                                ret = 4; /* According to LSB: "program or service status is unknown" */
-                                        else
-                                                ret = -EIO;
-                                        goto finish;
-                                }
-                        }
+                        if (r != 0)
+                                ret = r;
 
                 } else if (show_properties) {
 
                         /* Interpret as job id */
 
 
                 } else if (show_properties) {
 
                         /* Interpret as job id */
 
-                        if (!(m = dbus_message_new_method_call(
-                                              "org.freedesktop.systemd1",
-                                              "/org/freedesktop/systemd1",
-                                              "org.freedesktop.systemd1.Manager",
-                                              "GetJob"))) {
-                                log_error("Could not allocate message.");
-                                ret = -ENOMEM;
-                                goto finish;
-                        }
+                        char *p;
+                        if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
+                                return -ENOMEM;
 
 
-                        if (!dbus_message_append_args(m,
-                                                      DBUS_TYPE_UINT32, &id,
-                                                      DBUS_TYPE_INVALID)) {
-                                log_error("Could not append arguments to message.");
-                                ret = -ENOMEM;
-                                goto finish;
-                        }
+                        r = show_one(args[0], bus, p, show_properties, &new_line);
+                        free(p);
+
+                        if (r != 0)
+                                ret = r;
 
 
-                        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                                log_error("Failed to issue method call: %s", bus_error_message(&error));
-                                ret = -EIO;
-                                goto finish;
-                        }
                 } else {
 
                         /* Interpret as PID */
 
                 } else {
 
                         /* Interpret as PID */
 
-                        if (!(m = dbus_message_new_method_call(
-                                              "org.freedesktop.systemd1",
-                                              "/org/freedesktop/systemd1",
-                                              "org.freedesktop.systemd1.Manager",
-                                              "GetUnitByPID"))) {
-                                log_error("Could not allocate message.");
-                                ret = -ENOMEM;
-                                goto finish;
-                        }
-
-                        if (!dbus_message_append_args(m,
-                                                      DBUS_TYPE_UINT32, &id,
-                                                      DBUS_TYPE_INVALID)) {
-                                log_error("Could not append arguments to message.");
-                                ret = -ENOMEM;
-                                goto finish;
-                        }
-
-                        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                                log_error("Failed to issue method call: %s", bus_error_message(&error));
-                                ret = -EIO;
-                                goto finish;
-                        }
+                        r = show_one_by_pid(args[0], bus, id, &new_line);
+                        if (r != 0)
+                                ret = r;
                 }
                 }
-
-                if (!dbus_message_get_args(reply, &error,
-                                           DBUS_TYPE_OBJECT_PATH, &path,
-                                           DBUS_TYPE_INVALID)) {
-                        log_error("Failed to parse reply: %s", bus_error_message(&error));
-                        ret = -EIO;
-                        goto finish;
-                }
-
-                if ((r = show_one(args[0], bus, path, show_properties, &new_line)) != 0)
-                        ret = r;
-
-                dbus_message_unref(m);
-                dbus_message_unref(reply);
-                m = reply = NULL;
         }
 
         }
 
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
         return ret;
 }
 
         return ret;
 }
 
@@ -3562,6 +3568,65 @@ finish:
         return r;
 }
 
         return r;
 }
 
+static int switch_root(DBusConnection *bus, char **args) {
+        DBusMessage *m = NULL, *reply = NULL;
+        unsigned l;
+        const char *root, *init;
+        DBusError error;
+        int r;
+
+        dbus_error_init(&error);
+
+        l = strv_length(args);
+        if (l < 2 || l > 3) {
+                log_error("Wrong number of arguments.");
+                return -EINVAL;
+        }
+
+        root = args[1];
+        init = l >= 3 ? args[2] : "";
+
+        m = dbus_message_new_method_call(
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "SwitchRoot");
+        if (!m) {
+                log_error("Could not allocate message.");
+                return -ENOMEM;
+        }
+
+        if (!dbus_message_append_args(
+                            m,
+                            DBUS_TYPE_STRING, &root,
+                            DBUS_TYPE_STRING, &init,
+                            DBUS_TYPE_INVALID)) {
+                log_error("Could not append arguments to message.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+        if (!reply) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
+                r = -EIO;
+                goto finish;
+        }
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return r;
+}
+
 static int set_environment(DBusConnection *bus, char **args) {
         DBusMessage *m = NULL, *reply = NULL;
         DBusError error;
 static int set_environment(DBusConnection *bus, char **args) {
         DBusMessage *m = NULL, *reply = NULL;
         DBusError error;
@@ -4201,7 +4266,10 @@ static int systemctl_help(void) {
                "  poweroff                        Shut down and power-off the system\n"
                "  reboot                          Shut down and reboot the system\n"
                "  kexec                           Shut down and reboot the system with kexec\n"
                "  poweroff                        Shut down and power-off the system\n"
                "  reboot                          Shut down and reboot the system\n"
                "  kexec                           Shut down and reboot the system with kexec\n"
-               "  exit                            Ask for user instance termination\n",
+               "  exit                            Request user instance exit\n"
+               "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
+               "  suspend                         Suspend the system\n"
+               "  hibernate                       Hibernate the system\n",
                program_invocation_short_name);
 
         return 0;
                program_invocation_short_name);
 
         return 0;
@@ -4236,7 +4304,7 @@ static int shutdown_help(void) {
                "  -H --halt      Halt the machine\n"
                "  -P --poweroff  Power-off the machine\n"
                "  -r --reboot    Reboot the machine\n"
                "  -H --halt      Halt the machine\n"
                "  -P --poweroff  Power-off the machine\n"
                "  -r --reboot    Reboot the machine\n"
-               "  -h             Equivalent to --poweroff, overriden by --halt\n"
+               "  -h             Equivalent to --poweroff, overridden by --halt\n"
                "  -k             Don't halt/power-off/reboot, just send warnings\n"
                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
                "  -c             Cancel a pending shutdown\n",
                "  -k             Don't halt/power-off/reboot, just send warnings\n"
                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
                "  -c             Cancel a pending shutdown\n",
@@ -5135,6 +5203,8 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "poweroff",              EQUAL, 1, start_special     },
                 { "reboot",                EQUAL, 1, start_special     },
                 { "kexec",                 EQUAL, 1, start_special     },
                 { "poweroff",              EQUAL, 1, start_special     },
                 { "reboot",                EQUAL, 1, start_special     },
                 { "kexec",                 EQUAL, 1, start_special     },
+                { "suspend",               EQUAL, 1, start_special     },
+                { "hibernate",             EQUAL, 1, start_special     },
                 { "default",               EQUAL, 1, start_special     },
                 { "rescue",                EQUAL, 1, start_special     },
                 { "emergency",             EQUAL, 1, start_special     },
                 { "default",               EQUAL, 1, start_special     },
                 { "rescue",                EQUAL, 1, start_special     },
                 { "emergency",             EQUAL, 1, start_special     },
@@ -5147,7 +5217,8 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "preset",                MORE,  2, enable_unit       },
                 { "mask",                  MORE,  2, enable_unit       },
                 { "unmask",                MORE,  2, enable_unit       },
                 { "preset",                MORE,  2, enable_unit       },
                 { "mask",                  MORE,  2, enable_unit       },
                 { "unmask",                MORE,  2, enable_unit       },
-                { "link",                  MORE,  2, enable_unit       }
+                { "link",                  MORE,  2, enable_unit       },
+                { "switch-root",           MORE,  2, switch_root       },
         };
 
         int left;
         };
 
         int left;