X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=0034c553840514c805f400672baa764ffd8e8b97;hp=d80eb94af15fd5ffab855ee31e1144d7a6fe12e1;hb=957eb8cab28dc83aa4b800d033031e53cd0a9e00;hpb=06dab8e18aebf822392c7ca66c5bf3c1200fdec8 diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index d80eb94af..0034c5538 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -45,6 +45,7 @@ #include "utmp-wtmp.h" #include "special.h" #include "initreq.h" +#include "path-util.h" #include "strv.h" #include "dbus-common.h" #include "cgroup-show.h" @@ -61,6 +62,7 @@ #include "spawn-polkit-agent.h" #include "install.h" #include "logs-show.h" +#include "path-util.h" static const char *arg_type = NULL; static char **arg_property = NULL; @@ -95,6 +97,8 @@ static enum action { ACTION_REBOOT, ACTION_KEXEC, ACTION_EXIT, + ACTION_SUSPEND, + ACTION_HIBERNATE, ACTION_RUNLEVEL2, ACTION_RUNLEVEL3, ACTION_RUNLEVEL4, @@ -560,7 +564,7 @@ static int compare_unit_file_list(const void *a, const void *b) { return r; } - return strcasecmp(file_name_from_path(u->path), file_name_from_path(v->path)); + return strcasecmp(path_get_file_name(u->path), path_get_file_name(v->path)); } static bool output_show_unit_file(const UnitFileList *u) { @@ -579,7 +583,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { if (!output_show_unit_file(u)) continue; - max_id_len = MAX(max_id_len, strlen(file_name_from_path(u->path))); + max_id_len = MAX(max_id_len, strlen(path_get_file_name(u->path))); state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state))); } @@ -616,7 +620,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { } else on = off = ""; - id = file_name_from_path(u->path); + id = path_get_file_name(u->path); e = arg_full ? NULL : ellipsize(id, id_cols, 33); @@ -1603,6 +1607,10 @@ static enum action verb_to_action(const char *verb) { 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; } @@ -1621,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_EXIT] = SPECIAL_EXIT_TARGET + [ACTION_EXIT] = SPECIAL_EXIT_TARGET, + [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET, + [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET }; int r, ret = 0; @@ -1740,6 +1750,14 @@ static int reboot_with_logind(DBusConnection *bus, enum action a) { method = "PowerOff"; break; + case ACTION_SUSPEND: + method = "Suspend"; + break; + + case ACTION_HIBERNATE: + method = "Hibernate"; + break; + default: return -EINVAL; } @@ -1829,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 || - a == ACTION_REBOOT)) { + a == ACTION_REBOOT || + a == ACTION_SUSPEND || + a == ACTION_HIBERNATE)) { r = reboot_with_logind(bus, a); if (r >= 0) return r; @@ -3560,6 +3580,65 @@ finish: 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; @@ -3721,7 +3800,7 @@ static int enable_sysv_units(char **args) { if (!isempty(arg_root)) argv[c++] = q = strappend("--root=", arg_root); - argv[c++] = file_name_from_path(p); + argv[c++] = path_get_file_name(p); argv[c++] = streq(verb, "enable") ? "on" : streq(verb, "disable") ? "off" : "--level=5"; @@ -4199,7 +4278,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" - " 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; @@ -5133,6 +5215,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 }, + { "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 }, @@ -5145,7 +5229,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 }, - { "link", MORE, 2, enable_unit } + { "link", MORE, 2, enable_unit }, + { "switch-root", MORE, 2, switch_root }, }; int left; @@ -5224,8 +5309,8 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError } if (((!streq(verbs[i].verb, "reboot") && - !streq(verbs[i].verb, "halt") && - !streq(verbs[i].verb, "reboot")) || arg_force <= 0) && !bus) { + !streq(verbs[i].verb, "halt") && + !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) { log_error("Failed to get D-Bus connection: %s", dbus_error_is_set(error) ? error->message : "No connection to service manager."); return -EIO;