chiark / gitweb /
Pass log config from systemd to systemd-shutdown
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sat, 15 Feb 2014 23:13:46 +0000 (18:13 -0500)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 17 Feb 2014 07:26:22 +0000 (02:26 -0500)
If PID 1 debug logging is enabled, it is nice to keep those settings
when switching to systemd-shutdown binary, independently of whether
this was done through /proc/cmdline options, or through runtime
manipulations.

src/core/main.c
src/core/shutdown.c
src/shared/log.c
src/shared/log.h

index dd67d08a0b2e517443989fcaa3163a10c46c3267..ed64dd167b924de9b639299f36e1a40d57898ffa 100644 (file)
@@ -1881,14 +1881,42 @@ finish:
 #endif
 
         if (shutdown_verb) {
-                const char * command_line[] = {
+                char log_level[DECIMAL_STR_MAX(int) + 1];
+                const char* command_line[9] = {
                         SYSTEMD_SHUTDOWN_BINARY_PATH,
                         shutdown_verb,
-                        NULL
+                        "--log-level", log_level,
+                        "--log-target",
                 };
+                unsigned pos = 5;
+                assert(command_line[pos] == NULL);
+
                 _cleanup_strv_free_ char **env_block = NULL;
                 env_block = strv_copy(environ);
 
+                snprintf(log_level, sizeof(log_level), "%d", log_get_max_level());
+
+                switch (log_get_target()) {
+                case LOG_TARGET_KMSG:
+                case LOG_TARGET_JOURNAL_OR_KMSG:
+                case LOG_TARGET_SYSLOG_OR_KMSG:
+                        command_line[pos++] = "kmsg";
+                        break;
+
+                case LOG_TARGET_CONSOLE:
+                default:
+                        command_line[pos++] = "console";
+                        break;
+                };
+
+                if (log_get_show_color())
+                        command_line[pos++] = "--log-color";
+
+                if (log_get_show_location())
+                        command_line[pos++] = "--log-location";
+
+                assert(pos + 1 < ELEMENTSOF(command_line));
+
                 if (arm_reboot_watchdog && arg_shutdown_watchdog > 0) {
                         char *e;
 
@@ -1911,7 +1939,8 @@ finish:
                         cg_uninstall_release_agent(SYSTEMD_CGROUP_CONTROLLER);
 
                 execve(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line, env_block);
-                log_error("Failed to execute shutdown binary, freezing: %m");
+                log_error("Failed to execute shutdown binary, %s: %m",
+                          getpid() == 1 ? "freezing" : "quitting");
         }
 
         if (getpid() == 1)
index 8420a6753552ae7302566fcc0bab3c9df115a53e..9189cfb1ade3eed754249518501bb374be09c075 100644 (file)
@@ -35,6 +35,7 @@
 #include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
+#include <getopt.h>
 
 #include "missing.h"
 #include "log.h"
 
 #define FINALIZE_ATTEMPTS 50
 
+static char* arg_verb;
+
+static int parse_argv(int argc, char *argv[]) {
+        enum {
+                ARG_LOG_LEVEL = 0x100,
+                ARG_LOG_TARGET,
+                ARG_LOG_COLOR,
+                ARG_LOG_LOCATION,
+        };
+
+        static const struct option options[] = {
+                { "log-level",     required_argument, NULL, ARG_LOG_LEVEL    },
+                { "log-target",    required_argument, NULL, ARG_LOG_TARGET   },
+                { "log-color",     optional_argument, NULL, ARG_LOG_COLOR    },
+                { "log-location",  optional_argument, NULL, ARG_LOG_LOCATION },
+                {}
+        };
+
+        int c, r;
+
+        assert(argc >= 1);
+        assert(argv);
+
+        opterr = 0;
+
+        while ((c = getopt_long(argc, argv, ":", options, NULL)) >= 0)
+                switch (c) {
+
+                case ARG_LOG_LEVEL:
+                        r = log_set_max_level_from_string(optarg);
+                        if (r < 0)
+                                log_error("Failed to parse log level %s, ignoring.", optarg);
+
+                        break;
+
+                case ARG_LOG_TARGET:
+                        r = log_set_target_from_string(optarg);
+                        if (r < 0)
+                                log_error("Failed to parse log target %s, ignoring", optarg);
+
+                        break;
+
+                case ARG_LOG_COLOR:
+
+                        if (optarg) {
+                                r = log_show_color_from_string(optarg);
+                                if (r < 0)
+                                        log_error("Failed to parse log color setting %s, ignoring", optarg);
+                        } else
+                                log_show_color(true);
+
+                        break;
+
+                case ARG_LOG_LOCATION:
+                        if (optarg) {
+                                r = log_show_location_from_string(optarg);
+                                if (r < 0)
+                                        log_error("Failed to parse log location setting %s, ignoring", optarg);
+                        } else
+                                log_show_location(true);
+
+                        break;
+
+                case '?':
+                        log_error("Unknown option %s.", argv[optind-1]);
+                        return -EINVAL;
+
+                case ':':
+                        log_error("Missing argument to %s.", argv[optind-1]);
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unhandled option code.");
+                }
+
+        if (optind >= argc) {
+                log_error("Verb argument missing.");
+                return -EINVAL;
+        }
+
+        arg_verb = argv[optind];
+
+        if (optind + 1 < argc)
+                log_error("Excess arguments, ignoring");
+        return 0;
+}
+
 static int prepare_new_root(void) {
         static const char dirs[] =
                 "/run/initramfs/oldroot\0"
@@ -139,52 +227,38 @@ int main(int argc, char *argv[]) {
         unsigned retries;
         int cmd, r;
 
-        /* suppress shutdown status output if 'quiet' is used  */
-        r = proc_cmdline(&line);
-        if (r > 0) {
-                char *w, *state;
-                size_t l;
+        log_parse_environment();
+        r = parse_argv(argc, argv);
+        if (r < 0)
+                goto error;
 
-                FOREACH_WORD_QUOTED(w, l, line, state) {
-                        if (l == 5 && memcmp(w, "quiet", 5) == 0) {
-                                log_set_max_level(LOG_WARNING);
-                                break;
-                        }
-                }
-        }
+        /* journald will die if not gone yet. The log target defaults
+         * to console, but may have been changed by commandline options. */
 
-        log_parse_environment();
-        log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */
         log_close_console(); /* force reopen of /dev/console */
         log_open();
 
         umask(0022);
 
         if (getpid() != 1) {
-                log_error("Not executed by init (pid 1).");
+                log_error("Not executed by init (PID 1).");
                 r = -EPERM;
                 goto error;
         }
 
-        if (argc != 2) {
-                log_error("Invalid number of arguments.");
-                r = -EINVAL;
-                goto error;
-        }
-
         in_container = detect_container(NULL) > 0;
 
-        if (streq(argv[1], "reboot"))
+        if (streq(arg_verb, "reboot"))
                 cmd = RB_AUTOBOOT;
-        else if (streq(argv[1], "poweroff"))
+        else if (streq(arg_verb, "poweroff"))
                 cmd = RB_POWER_OFF;
-        else if (streq(argv[1], "halt"))
+        else if (streq(arg_verb, "halt"))
                 cmd = RB_HALT_SYSTEM;
-        else if (streq(argv[1], "kexec"))
+        else if (streq(arg_verb, "kexec"))
                 cmd = LINUX_REBOOT_CMD_KEXEC;
         else {
-                log_error("Unknown action '%s'.", argv[1]);
                 r = -EINVAL;
+                log_error("Unknown action '%s'.", arg_verb);
                 goto error;
         }
 
@@ -292,7 +366,7 @@ int main(int argc, char *argv[]) {
                 log_info("Storage is finalized.");
 
         arguments[0] = NULL;
-        arguments[1] = argv[1];
+        arguments[1] = arg_verb;
         arguments[2] = NULL;
         execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, arguments);
 
@@ -301,10 +375,11 @@ int main(int argc, char *argv[]) {
 
                 if (prepare_new_root() >= 0 &&
                     pivot_to_new_root() >= 0) {
+                        arguments[0] = (char*) "/shutdown";
 
                         log_info("Returning to initrd...");
 
-                        execv("/shutdown", argv);
+                        execv("/shutdown", arguments);
                         log_error("Failed to execute shutdown binary: %m");
                 }
         }
@@ -389,5 +464,4 @@ int main(int argc, char *argv[]) {
         log_error("Critical error while doing system shutdown: %s", strerror(-r));
 
         freeze();
-        return EXIT_FAILURE;
 }
index ee20921f7843845e3479a04cb2400b43f8f1cc5b..3e48b3ccc24f303e41229a3f198942bcd09aa05a 100644 (file)
@@ -927,10 +927,18 @@ void log_show_color(bool b) {
         show_color = b;
 }
 
+bool log_get_show_color(void) {
+        return show_color;
+}
+
 void log_show_location(bool b) {
         show_location = b;
 }
 
+bool log_get_show_location(void) {
+        return show_location;
+}
+
 int log_show_color_from_string(const char *e) {
         int t;
 
index 6a0f6735c5a2e6f0151af764d5f8a65937d45ed1..794af7be6af64aa004424d01131e558d418546bc 100644 (file)
@@ -52,7 +52,9 @@ int log_set_target_from_string(const char *e);
 int log_set_max_level_from_string(const char *e);
 
 void log_show_color(bool b);
+bool log_get_show_color(void) _pure_;
 void log_show_location(bool b);
+bool log_get_show_location(void) _pure_;
 
 int log_show_color_from_string(const char *e);
 int log_show_location_from_string(const char *e);