chiark / gitweb /
systemctl: accept -f as short for --force
[elogind.git] / src / systemctl.c
index 1f2b43be032148a7f004af985100946115aa5924..555c171b0e4831a0bca47be23c482645fe360292 100644 (file)
@@ -31,6 +31,7 @@
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#include <stddef.h>
 
 #include <dbus/dbus.h>
 
@@ -53,6 +54,7 @@
 #include "exit-status.h"
 #include "bus-errors.h"
 #include "build.h"
+#include "unit-name.h"
 
 static const char *arg_type = NULL;
 static char **arg_property = NULL;
@@ -79,6 +81,8 @@ static enum action {
         ACTION_HALT,
         ACTION_POWEROFF,
         ACTION_REBOOT,
+        ACTION_KEXEC,
+        ACTION_EXIT,
         ACTION_RUNLEVEL2,
         ACTION_RUNLEVEL3,
         ACTION_RUNLEVEL4,
@@ -191,6 +195,7 @@ static void warn_wall(enum action action) {
                 [ACTION_HALT]      = "The system is going down for system halt NOW!",
                 [ACTION_REBOOT]    = "The system is going down for reboot NOW!",
                 [ACTION_POWEROFF]  = "The system is going down for power-off NOW!",
+                [ACTION_KEXEC]     = "The system is going down for kexec reboot NOW!",
                 [ACTION_RESCUE]    = "The system is going down to rescue mode NOW!",
                 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!"
         };
@@ -295,7 +300,8 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
                 if (!output_show_job(u))
                         continue;
 
-                if (!streq(u->load_state, "loaded")) {
+                if (!streq(u->load_state, "loaded") &&
+                    !streq(u->load_state, "banned")) {
                         on_loaded = ansi_highlight(true);
                         off_loaded = ansi_highlight(false);
                 } else
@@ -1217,12 +1223,16 @@ static enum action verb_to_action(const char *verb) {
                 return ACTION_POWEROFF;
         else if (streq(verb, "reboot"))
                 return ACTION_REBOOT;
+        else if (streq(verb, "kexec"))
+                return ACTION_KEXEC;
         else if (streq(verb, "rescue"))
                 return ACTION_RESCUE;
         else if (streq(verb, "emergency"))
                 return ACTION_EMERGENCY;
         else if (streq(verb, "default"))
                 return ACTION_DEFAULT;
+        else if (streq(verb, "exit"))
+                return ACTION_EXIT;
         else
                 return ACTION_INVALID;
 }
@@ -1233,13 +1243,15 @@ static int start_unit(DBusConnection *bus, char **args, unsigned n) {
                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
+                [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
-                [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET
+                [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
+                [ACTION_EXIT] = SPECIAL_EXIT_TARGET
         };
 
         int r, ret = 0;
@@ -1334,6 +1346,14 @@ static int start_special(DBusConnection *bus, char **args, unsigned n) {
         assert(bus);
         assert(args);
 
+        if (arg_force &&
+            (streq(args[0], "halt") ||
+             streq(args[0], "poweroff") ||
+             streq(args[0], "reboot") ||
+             streq(args[0], "kexec") ||
+             streq(args[0], "exit")))
+                return daemon_reload(bus, args, n);
+
         r = start_unit(bus, args, n);
 
         if (r >= 0)
@@ -1565,6 +1585,7 @@ typedef struct UnitStatusInfo {
         const char *sub_state;
 
         const char *description;
+        const char *following;
 
         const char *path;
         const char *default_control_group;
@@ -1626,7 +1647,11 @@ static void print_status_info(UnitStatusInfo *i) {
 
         printf("\n");
 
-        if (streq_ptr(i->load_state, "failed")) {
+        if (i->following)
+                printf("\t  Follow: unit currently follows state of %s\n", i->following);
+
+        if (streq_ptr(i->load_state, "failed") ||
+            streq_ptr(i->load_state, "banned")) {
                 on = ansi_highlight(true);
                 off = ansi_highlight(false);
         } else
@@ -1671,9 +1696,9 @@ static void print_status_info(UnitStatusInfo *i) {
         s2 = format_timestamp(since2, sizeof(since2), timestamp);
 
         if (s1)
-                printf(" since [%s; %s]\n", s2, s1);
+                printf(" since %s; %s\n", s2, s1);
         else if (s2)
-                printf(" since [%s]\n", s2);
+                printf(" since %s\n", s2);
         else
                 printf("\n");
 
@@ -1837,6 +1862,8 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
                                 i->where = s;
                         else if (streq(name, "What"))
                                 i->what = s;
+                        else if (streq(name, "Following"))
+                                i->following = s;
                 }
 
                 break;
@@ -2958,12 +2985,16 @@ static int daemon_reload(DBusConnection *bus, char **args, unsigned n) {
                 assert(arg_action == ACTION_SYSTEMCTL);
 
                 method =
-                        streq(args[0], "clear-jobs")        ||
-                        streq(args[0], "cancel")            ? "ClearJobs" :
-                        streq(args[0], "daemon-reexec")     ? "Reexecute" :
-                        streq(args[0], "reset-failed")      ? "ResetFailed" :
-                        streq(args[0], "daemon-exit")       ? "Exit" :
-                                                              "Reload";
+                        streq(args[0], "clear-jobs")    ||
+                        streq(args[0], "cancel")        ? "ClearJobs" :
+                        streq(args[0], "daemon-reexec") ? "Reexecute" :
+                        streq(args[0], "reset-failed")  ? "ResetFailed" :
+                        streq(args[0], "halt")          ? "Halt" :
+                        streq(args[0], "poweroff")      ? "PowerOff" :
+                        streq(args[0], "reboot")        ? "Reboot" :
+                        streq(args[0], "kexec")         ? "KExec" :
+                        streq(args[0], "exit")          ? "Exit" :
+                                    /* "daemon-reload" */ "Reload";
         }
 
         if (!(m = dbus_message_new_method_call(
@@ -3217,6 +3248,7 @@ typedef struct {
 
 static Hashmap *will_install = NULL, *have_installed = NULL;
 static Set *remove_symlinks_to = NULL;
+static unsigned n_symlinks = 0;
 
 static void install_info_free(InstallInfo *i) {
         assert(i);
@@ -3237,28 +3269,16 @@ static void install_info_hashmap_free(Hashmap *m) {
         hashmap_free(m);
 }
 
-static bool unit_name_valid(const char *name) {
-
-        /* This is a minimal version of unit_name_valid() from
-         * unit-name.c */
-
-        if (!*name)
-                return false;
-
-        if (ignore_file(name))
-                return false;
-
-        return true;
-}
-
 static int install_info_add(const char *name) {
         InstallInfo *i;
         int r;
 
         assert(will_install);
 
-        if (!unit_name_valid(name))
+        if (!unit_name_is_valid_no_type(name, true)) {
+                log_warning("Unit name %s is not a valid unit name.", name);
                 return -EINVAL;
+        }
 
         if (hashmap_get(have_installed, name) ||
             hashmap_get(will_install, name))
@@ -3310,11 +3330,13 @@ static int config_parse_also(
                 if (!(n = strndup(w, l)))
                         return -ENOMEM;
 
-                r = install_info_add(n);
-                free(n);
-
-                if (r < 0)
+                if ((r = install_info_add(n)) < 0) {
+                        log_warning("Cannot install unit %s: %s", n, strerror(-r));
+                        free(n);
                         return r;
+                }
+
+                free(n);
         }
 
         return 0;
@@ -3639,12 +3661,6 @@ static int install_info_symlink_alias(const char *verb, InstallInfo *i, const ch
 
         STRV_FOREACH(s, i->aliases) {
 
-                if (!unit_name_valid(*s)) {
-                        log_error("Invalid name %s.", *s);
-                        r = -EINVAL;
-                        goto finish;
-                }
-
                 free(alias_path);
                 if (!(alias_path = path_make_absolute(*s, config_path))) {
                         log_error("Out of memory");
@@ -3658,7 +3674,6 @@ static int install_info_symlink_alias(const char *verb, InstallInfo *i, const ch
                 if (streq(verb, "disable"))
                         rmdir_parents(alias_path, config_path);
         }
-
         r = 0;
 
 finish:
@@ -3677,7 +3692,7 @@ static int install_info_symlink_wants(const char *verb, InstallInfo *i, const ch
         assert(config_path);
 
         STRV_FOREACH(s, i->wanted_by) {
-                if (!unit_name_valid(*s)) {
+                if (!unit_name_is_valid_no_type(*s, true)) {
                         log_error("Invalid name %s.", *s);
                         r = -EINVAL;
                         goto finish;
@@ -3766,6 +3781,9 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo
                 return r;
         }
 
+        n_symlinks += strv_length(i->aliases);
+        n_symlinks += strv_length(i->wanted_by);
+
         fclose(f);
 
         if ((r = install_info_symlink_alias(verb, i, config_path)) != 0)
@@ -3840,8 +3858,10 @@ static int enable_unit(DBusConnection *bus, char **args, unsigned n) {
                 }
 
         for (j = 1; j < n; j++)
-                if ((r = install_info_add(args[j])) < 0)
+                if ((r = install_info_add(args[j])) < 0) {
+                        log_warning("Cannot install unit %s: %s", args[j], strerror(-r));
                         goto finish;
+                }
 
         while ((i = hashmap_first(will_install))) {
                 int q;
@@ -3864,19 +3884,24 @@ static int enable_unit(DBusConnection *bus, char **args, unsigned n) {
 
         if (streq(verb, "is-enabled"))
                 r = r > 0 ? 0 : -ENOENT;
-        else if (bus &&
-                 /* Don't try to reload anything if the user asked us to not do this */
-                 !arg_no_reload &&
-                 /* Don't try to reload anything when updating a unit globally */
-                 !arg_global &&
-                 /* Don't try to reload anything if we are called for system changes but the system wasn't booted with systemd */
-                 (arg_session || sd_booted() > 0) &&
-                 /* Don't try to reload anything if we are running in a chroot environment */
-                 (arg_session || running_in_chroot() <= 0) ) {
-                int q;
+        else {
+                if (n_symlinks <= 0)
+                        log_warning("Unit files contain no applicable installation information. Ignoring.");
+
+                if (bus &&
+                    /* Don't try to reload anything if the user asked us to not do this */
+                    !arg_no_reload &&
+                    /* Don't try to reload anything when updating a unit globally */
+                    !arg_global &&
+                    /* Don't try to reload anything if we are called for system changes but the system wasn't booted with systemd */
+                    (arg_session || sd_booted() > 0) &&
+                    /* Don't try to reload anything if we are running in a chroot environment */
+                    (arg_session || running_in_chroot() <= 0) ) {
+                        int q;
 
-                if ((q = daemon_reload(bus, args, n)) < 0)
-                        r = q;
+                        if ((q = daemon_reload(bus, args, n)) < 0)
+                                r = q;
+                }
         }
 
 finish:
@@ -3914,7 +3939,8 @@ static int systemctl_help(void) {
                "     --global        Enable/disable unit files globally\n"
                "     --no-reload     When enabling/disabling unit files, don't reload daemon\n"
                "                     configuration\n"
-               "     --force         When enabling unit files, override existing symlinks\n"
+               "  -f --force         When enabling unit files, override existing symlinks\n"
+               "                     When shutting down, execute action immediately\n"
                "     --defaults      When disabling unit files, remove default symlinks only\n\n"
                "Commands:\n"
                "  list-units                      List units\n"
@@ -3947,16 +3973,17 @@ static int systemctl_help(void) {
                "  delete [NAME...]                Remove one or more snapshots\n"
                "  daemon-reload                   Reload systemd manager configuration\n"
                "  daemon-reexec                   Reexecute systemd manager\n"
-               "  daemon-exit                     Ask the systemd manager to quit\n"
                "  show-environment                Dump environment\n"
                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
                "  unset-environment [NAME...]     Unset one or more environment variables\n"
+               "  default                         Enter system default mode\n"
+               "  rescue                          Enter system rescue mode\n"
+               "  emergency                       Enter system emergency mode\n"
                "  halt                            Shut down and halt the system\n"
                "  poweroff                        Shut down and power-off the system\n"
                "  reboot                          Shut down and reboot the system\n"
-               "  rescue                          Enter system rescue mode\n"
-               "  emergency                       Enter system emergency mode\n"
-               "  default                         Enter system default mode\n",
+               "  kexec                           Shut down and reboot the system with kexec\n"
+               "  exit                            Ask for session termination\n",
                program_invocation_short_name);
 
         return 0;
@@ -4041,7 +4068,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_ORDER,
                 ARG_REQUIRE,
                 ARG_FULL,
-                ARG_FORCE,
                 ARG_NO_RELOAD,
                 ARG_DEFAULTS
         };
@@ -4062,7 +4088,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "quiet",     no_argument,       NULL, 'q'           },
                 { "order",     no_argument,       NULL, ARG_ORDER     },
                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
-                { "force",     no_argument,       NULL, ARG_FORCE     },
+                { "force",     no_argument,       NULL, 'f'           },
                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
                 { "defaults",  no_argument,       NULL, ARG_DEFAULTS  },
                 { NULL,        0,                 NULL, 0             }
@@ -4073,7 +4099,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "ht:p:aq", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "ht:p:aqf", options, NULL)) >= 0) {
 
                 switch (c) {
 
@@ -4147,7 +4173,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_quiet = true;
                         break;
 
-                case ARG_FORCE:
+                case 'f':
                         arg_force = true;
                         break;
 
@@ -4768,16 +4794,17 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "delete",                MORE,  2, delete_snapshot   },
                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
-                { "daemon-exit",           EQUAL, 1, daemon_reload     },
                 { "show-environment",      EQUAL, 1, show_enviroment   },
                 { "set-environment",       MORE,  2, set_environment   },
                 { "unset-environment",     MORE,  2, set_environment   },
                 { "halt",                  EQUAL, 1, start_special     },
                 { "poweroff",              EQUAL, 1, start_special     },
                 { "reboot",                EQUAL, 1, start_special     },
+                { "kexec",                 EQUAL, 1, start_special     },
                 { "default",               EQUAL, 1, start_special     },
                 { "rescue",                EQUAL, 1, start_special     },
                 { "emergency",             EQUAL, 1, start_special     },
+                { "exit",                  EQUAL, 1, start_special     },
                 { "reset-failed",          MORE,  1, reset_failed      },
                 { "enable",                MORE,  2, enable_unit       },
                 { "disable",               MORE,  2, enable_unit       },
@@ -4883,7 +4910,7 @@ static int send_shutdownd(usec_t t, char mode, bool warn, const char *message) {
 
         zero(msghdr);
         msghdr.msg_name = &sockaddr;
-        msghdr.msg_namelen = sizeof(sa_family_t) + 1 + sizeof("/org/freedesktop/systemd1/shutdownd") - 1;
+        msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + 1 + sizeof("/org/freedesktop/systemd1/shutdownd") - 1;
 
         msghdr.msg_iov = &iovec;
         msghdr.msg_iovlen = 1;