chiark / gitweb /
systemctl: for switch-root check, if we switch to a systemd init
authorHarald Hoyer <harald@redhat.com>
Thu, 6 Mar 2014 15:35:02 +0000 (16:35 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 11 Mar 2014 03:45:33 +0000 (04:45 +0100)
If "systemctl switch-root" is called with a specific "INIT" or
/proc/cmdline contains "init=", then systemd would not serialize
itsself.

Let systemctl check, if the new init is in the standard systemd
installation path and if so, clear the INIT parameter,
to let systemd serialize itsself.

src/shared/util.h
src/systemctl/systemctl.c

index 11d28665b6ba5144d5b81fae22124ace9e1ceda5..cc52ae750387371ae2dbc0d74b02b613fa393f32 100644 (file)
@@ -813,6 +813,19 @@ int unlink_noerrno(const char *path);
                 _c_;                                    \
         })
 
+#define strappenda3(a, b, c)                                    \
+        ({                                                      \
+                const char *_a_ = (a), *_b_ = (b), *_c_ = (c);  \
+                char *_d_;                                      \
+                size_t _x_, _y_, _z_;                           \
+                _x_ = strlen(_a_);                              \
+                _y_ = strlen(_b_);                              \
+                _z_ = strlen(_c_);                              \
+                _d_ = alloca(_x_ + _y_ + _z_ + 1);              \
+                strcpy(stpcpy(stpcpy(_d_, _a_), _b_), _c_);     \
+                _d_;                                            \
+        })
+
 #define procfs_file_alloca(pid, field)                                  \
         ({                                                              \
                 pid_t _pid_ = (pid);                                    \
index f3952653e153698352bae410bc6cb9f6a565eef4..17ad7f0462c3e0ec4c0a05154f07b7d4155a4143 100644 (file)
@@ -4282,8 +4282,8 @@ static int show_environment(sd_bus *bus, char **args) {
 
 static int switch_root(sd_bus *bus, char **args) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_free_ char *init = NULL;
-        const char *root;
+        _cleanup_free_ char *cmdline_init = NULL;
+        const char *root, *init;
         unsigned l;
         int r;
 
@@ -4296,20 +4296,33 @@ static int switch_root(sd_bus *bus, char **args) {
         root = args[1];
 
         if (l >= 3)
-                init = strdup(args[2]);
+                init = args[2];
         else {
-                parse_env_file("/proc/cmdline", WHITESPACE,
-                               "init", &init,
-                               NULL);
+                r = parse_env_file("/proc/cmdline", WHITESPACE,
+                                   "init", &cmdline_init,
+                                   NULL);
+                if (r < 0)
+                        log_debug("Failed to parse /proc/cmdline: %s", strerror(-r));
 
-                if (!init)
-                        init = strdup("");
+                init = cmdline_init;
         }
 
-        if (!init)
-                return log_oom();
+        if (isempty(init))
+                init = NULL;
+
+        if (init) {
+                const char *root_systemd_path = NULL, *root_init_path = NULL;
+
+                root_systemd_path = strappenda(root, "/" SYSTEMD_BINARY_PATH);
+                root_init_path = strappenda3(root, "/", init);
+
+                /* If the passed init is actually the same as the
+                 * systemd binary, then let's suppress it. */
+                if (files_same(root_init_path, root_systemd_path) > 0)
+                        init = NULL;
+        }
 
-        log_debug("switching root - root: %s; init: %s", root, init);
+        log_debug("Switching root - root: %s; init: %s", root, strna(init));
 
         r = sd_bus_call_method(
                         bus,