+static bool prepare_new_root(void) {
+ int r = false;
+ const char *dirs[] = { "/run/initramfs/oldroot",
+ "/run/initramfs/proc",
+ "/run/initramfs/sys",
+ "/run/initramfs/dev",
+ "/run/initramfs/run",
+ NULL };
+ const char **dir;
+ const char *msg;
+
+ msg = "Failed to mount bind /run/initramfs on /run/initramfs";
+ if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) != 0)
+ goto out;
+
+ msg="Failed to make /run/initramfs private mount %m:";
+ if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) != 0)
+ goto out;
+
+ for (dir = &dirs[0]; *dir != NULL; dir++) {
+ asprintf((char **) &msg, "mkdir %s: %%m", *dir);
+ if (mkdir(*dir, 0755) != 0) {
+ if (errno != EEXIST)
+ goto out;
+ }
+ free((char *) msg);
+ }
+
+ msg = "Failed to mount bind /sys on /run/initramfs/sys";
+ if (mount("/sys", "/run/initramfs/sys", NULL, MS_BIND, NULL) != 0)
+ goto out;
+ msg = "Failed to mount bind /proc on /run/initramfs/proc";
+ if (mount("/proc", "/run/initramfs/proc", NULL, MS_BIND, NULL) != 0)
+ goto out;
+ msg = "Failed to mount bind /dev on /run/initramfs/dev";
+ if (mount("/dev", "/run/initramfs/dev", NULL, MS_BIND, NULL) != 0)
+ goto out;
+ msg = "Failed to mount bind /run on /run/initramfs/run";
+ if (mount("/run", "/run/initramfs/run", NULL, MS_BIND, NULL) != 0)
+ goto out;
+
+ r = true;
+ out:
+ if (!r)
+ log_error("%s: %m", msg);
+ return r;
+}
+
+static bool pivot_to_new_root(void) {
+ int fd;
+ int r = 0;
+ chdir("/run/initramfs");
+
+ /*
+ In case some evil process made "/" MS_SHARED
+ It works for pivot_root, but the ref count for the root device
+ is not decreasing :-/
+ */
+ if (mount(NULL, "/", NULL, MS_PRIVATE, NULL) != 0) {
+ log_error("Failed to make \"/\" private mount %m: ");
+ return false;
+ }
+
+ r = pivot_root(".", "oldroot");
+ if (r!=0) {
+ log_error("pivot failed: %m");
+ /* only chroot, if pivot root succeded */
+ return false;
+ }
+ chroot(".");
+ log_info("pivot rooted");
+
+ fd = open("dev/console", O_RDONLY);
+ dup2(fd, STDIN_FILENO);
+ close_nointr_nofail(fd);
+ fd = open("dev/console", O_WRONLY);
+ dup2(fd, STDOUT_FILENO);
+ close_nointr_nofail(fd);
+ fd = open("dev/console", O_WRONLY);
+ dup2(fd, STDERR_FILENO);
+ close_nointr_nofail(fd);
+ return true;
+}
+