9fc0f6
From cad8ec5980d63253586d9f884649c45eed0667a1 Mon Sep 17 00:00:00 2001
9fc0f6
From: Harald Hoyer <harald@redhat.com>
9fc0f6
Date: Thu, 6 Mar 2014 16:35:02 +0100
9fc0f6
Subject: [PATCH] systemctl: for switch-root check, if we switch to a systemd
9fc0f6
 init
9fc0f6
9fc0f6
If "systemctl switch-root" is called with a specific "INIT" or
9fc0f6
/proc/cmdline contains "init=", then systemd would not serialize
9fc0f6
itsself.
9fc0f6
9fc0f6
Let systemctl check, if the new init is in the standard systemd
9fc0f6
installation path and if so, clear the INIT parameter,
9fc0f6
to let systemd serialize itsself.
9fc0f6
9fc0f6
Conflicts:
9fc0f6
	src/systemctl/systemctl.c
9fc0f6
9fc0f6
(cherry picked from commit f39d4a08e746e703d562076a0f622eb91dbdcd3e)
9fc0f6
9fc0f6
Related: #1111199
9fc0f6
---
9fc0f6
 src/shared/util.h         | 13 +++++++++++++
9fc0f6
 src/systemctl/systemctl.c | 35 ++++++++++++++++++++++++++---------
9fc0f6
 2 files changed, 39 insertions(+), 9 deletions(-)
9fc0f6
9fc0f6
diff --git a/src/shared/util.h b/src/shared/util.h
9fc0f6
index 631a385..d11fa07 100644
9fc0f6
--- a/src/shared/util.h
9fc0f6
+++ b/src/shared/util.h
9fc0f6
@@ -726,6 +726,19 @@ int unlink_noerrno(const char *path);
9fc0f6
                 _c_;                                    \
9fc0f6
         })
9fc0f6
 
9fc0f6
+#define strappenda3(a, b, c)                                    \
9fc0f6
+        ({                                                      \
9fc0f6
+                const char *_a_ = (a), *_b_ = (b), *_c_ = (c);  \
9fc0f6
+                char *_d_;                                      \
9fc0f6
+                size_t _x_, _y_, _z_;                           \
9fc0f6
+                _x_ = strlen(_a_);                              \
9fc0f6
+                _y_ = strlen(_b_);                              \
9fc0f6
+                _z_ = strlen(_c_);                              \
9fc0f6
+                _d_ = alloca(_x_ + _y_ + _z_ + 1);              \
9fc0f6
+                strcpy(stpcpy(stpcpy(_d_, _a_), _b_), _c_);     \
9fc0f6
+                _d_;                                            \
9fc0f6
+        })
9fc0f6
+
9fc0f6
 #define procfs_file_alloca(pid, field)                                  \
9fc0f6
         ({                                                              \
9fc0f6
                 pid_t _pid_ = (pid);                                    \
9fc0f6
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
9fc0f6
index c738daf..1ca4fd3 100644
9fc0f6
--- a/src/systemctl/systemctl.c
9fc0f6
+++ b/src/systemctl/systemctl.c
9fc0f6
@@ -4143,9 +4143,10 @@ static int show_enviroment(DBusConnection *bus, char **args) {
9fc0f6
 }
9fc0f6
 
9fc0f6
 static int switch_root(DBusConnection *bus, char **args) {
9fc0f6
+        _cleanup_free_ char *cmdline_init = NULL;
9fc0f6
+        const char *root, *init;
9fc0f6
         unsigned l;
9fc0f6
-        const char *root;
9fc0f6
-        _cleanup_free_ char *init = NULL;
9fc0f6
+        int r;
9fc0f6
 
9fc0f6
         l = strv_length(args);
9fc0f6
         if (l < 2 || l > 3) {
9fc0f6
@@ -4156,19 +4157,35 @@ static int switch_root(DBusConnection *bus, char **args) {
9fc0f6
         root = args[1];
9fc0f6
 
9fc0f6
         if (l >= 3)
9fc0f6
-                init = strdup(args[2]);
9fc0f6
+                init = args[2];
9fc0f6
         else {
9fc0f6
-                parse_env_file("/proc/cmdline", WHITESPACE,
9fc0f6
-                               "init", &init,
9fc0f6
-                               NULL);
9fc0f6
+                r = parse_env_file("/proc/cmdline", WHITESPACE,
9fc0f6
+                                   "init", &cmdline_init,
9fc0f6
+                                   NULL);
9fc0f6
+                if (r < 0)
9fc0f6
+                        log_debug("Failed to parse /proc/cmdline: %s", strerror(-r));
9fc0f6
 
9fc0f6
-                if (!init)
9fc0f6
-                        init = strdup("");
9fc0f6
+                init = cmdline_init;
9fc0f6
         }
9fc0f6
         if (!init)
9fc0f6
                 return log_oom();
9fc0f6
 
9fc0f6
-        log_debug("switching root - root: %s; init: %s", root, init);
9fc0f6
+        if (isempty(init))
9fc0f6
+                init = NULL;
9fc0f6
+
9fc0f6
+        if (init) {
9fc0f6
+                const char *root_systemd_path = NULL, *root_init_path = NULL;
9fc0f6
+
9fc0f6
+                root_systemd_path = strappenda(root, "/" SYSTEMD_BINARY_PATH);
9fc0f6
+                root_init_path = strappenda3(root, "/", init);
9fc0f6
+
9fc0f6
+                /* If the passed init is actually the same as the
9fc0f6
+                 * systemd binary, then let's suppress it. */
9fc0f6
+                if (files_same(root_init_path, root_systemd_path) > 0)
9fc0f6
+                        init = NULL;
9fc0f6
+        }
9fc0f6
+
9fc0f6
+        log_debug("Switching root - root: %s; init: %s", root, strna(init));
9fc0f6
 
9fc0f6
         return bus_method_call_with_reply(
9fc0f6
                         bus,