chiark / gitweb /
core/main.c: do_switch_root(): do not remove the old root if not in initrd
[elogind.git] / src / core / main.c
index ea06dc80146ee4a86eeec5151826b4084bd03c59..d7143edae2b5d062c51df61872fd3b0f8cab8897 100644 (file)
@@ -746,6 +746,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_SHOW_STATUS,
                 ARG_SYSV_CONSOLE,
                 ARG_DESERIALIZE,
+                ARG_SWITCHEDROOT,
                 ARG_INTROSPECT,
                 ARG_DEFAULT_STD_OUTPUT,
                 ARG_DEFAULT_STD_ERROR
@@ -770,6 +771,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "sysv-console",             optional_argument, NULL, ARG_SYSV_CONSOLE             },
 #endif
                 { "deserialize",              required_argument, NULL, ARG_DESERIALIZE              },
+                { "switchedroot",             no_argument,       NULL, ARG_SWITCHEDROOT             },
                 { "introspect",               optional_argument, NULL, ARG_INTROSPECT               },
                 { "default-standard-output",  required_argument, NULL, ARG_DEFAULT_STD_OUTPUT,      },
                 { "default-standard-error",   required_argument, NULL, ARG_DEFAULT_STD_ERROR,       },
@@ -941,6 +943,10 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
                 }
 
+                case ARG_SWITCHEDROOT:
+                        /* Nothing special yet */
+                        break;
+
                 case ARG_INTROSPECT: {
                         const char * const * i = NULL;
 
@@ -1174,6 +1180,7 @@ static int do_switch_root(const char *switch_root) {
         int i;
         int cfd = -1;
         struct stat switch_root_stat, sb;
+        bool remove_old_root;
 
         if (path_equal(switch_root, "/"))
                 return 0;
@@ -1184,6 +1191,8 @@ static int do_switch_root(const char *switch_root) {
                 goto fail;
         }
 
+        remove_old_root = in_initrd();
+
         for (i = 0; umounts[i] != NULL; i++) {
                 char newmount[PATH_MAX];
 
@@ -1209,7 +1218,8 @@ static int do_switch_root(const char *switch_root) {
                 goto fail;
         }
 
-        cfd = open("/", O_RDONLY);
+        if (remove_old_root)
+                cfd = open("/", O_RDONLY);
 
         if (mount(switch_root, "/", NULL, MS_MOVE, NULL) < 0) {
                 r = -errno;
@@ -1278,6 +1288,13 @@ int main(int argc, char *argv[]) {
                         break;
                 }
 
+        /* If we have switched root, do all the special things */
+        for (j = 1; j < argc; j++)
+                if (streq(argv[j], "--switchedroot")) {
+                        is_reexec = false;
+                        break;
+                }
+
         /* If we get started via the /sbin/init symlink then we are
            called 'init'. After a subsequent reexecution we are then
            called 'systemd'. That is confusing, hence let's call us
@@ -1693,7 +1710,7 @@ finish:
                 if (switch_root)
                         do_switch_root(switch_root);
 
-                args_size = MAX(5, argc+1);
+                args_size = MAX(6, argc+1);
                 args = newa(const char*, args_size);
 
                 if (!switch_root_init) {
@@ -1712,6 +1729,8 @@ finish:
 
                         i = 0;
                         args[i++] = SYSTEMD_BINARY_PATH;
+                        if (switch_root)
+                                args[i++] = "--switchedroot";
                         args[i++] = arg_running_as == MANAGER_SYSTEM ? "--system" : "--user";
                         args[i++] = "--deserialize";
                         args[i++] = sfd;