move files around
[project/fstools.git] / libfstools / extroot.c
diff --git a/libfstools/extroot.c b/libfstools/extroot.c
new file mode 100644 (file)
index 0000000..2ed9b37
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include "../fs-state.h"
+
+char const *extroot_prefix = NULL;
+
+static int mount_extroot(void)
+{
+       char block_path[32];
+       char kmod_loader[64];
+       struct stat s;
+       pid_t pid;
+
+       if (!extroot_prefix)
+               return -1;
+
+       sprintf(block_path, "%s/sbin/block", extroot_prefix);
+
+       if (stat(block_path, &s))
+               return -1;
+
+       sprintf(kmod_loader, "/sbin/kmodloader %s/etc/modules-boot.d/ %s", extroot_prefix, extroot_prefix);
+       system(kmod_loader);
+
+       pid = fork();
+       if (!pid) {
+               mkdir("/tmp/extroot", 0755);
+               execl(block_path, block_path, "extroot", NULL);
+               exit(-1);
+       } else if (pid > 0) {
+               int status;
+
+               waitpid(pid, &status, 0);
+               if (!WEXITSTATUS(status)) {
+                       if (find_mount("/tmp/extroot/mnt")) {
+                               mount("/dev/root", "/", NULL, MS_NOATIME | MS_REMOUNT | MS_RDONLY, 0);
+
+                               mkdir("/tmp/extroot/mnt/proc", 0755);
+                               mkdir("/tmp/extroot/mnt/dev", 0755);
+                               mkdir("/tmp/extroot/mnt/sys", 0755);
+                               mkdir("/tmp/extroot/mnt/tmp", 0755);
+                               mkdir("/tmp/extroot/mnt/rom", 0755);
+
+                               if (mount_move("/tmp/extroot", "", "/mnt")) {
+                                       fprintf(stderr, "moving pivotroot failed - continue normal boot\n");
+                                       umount("/tmp/extroot/mnt");
+                               } else if (pivot("/mnt", "/rom")) {
+                                       fprintf(stderr, "switching to pivotroot failed - continue normal boot\n");
+                                       umount("/mnt");
+                               } else {
+                                       umount("/tmp/overlay");
+                                       rmdir("/tmp/overlay");
+                                       rmdir("/tmp/extroot/mnt");
+                                       rmdir("/tmp/extroot");
+                                       return 0;
+                               }
+                       } else if (find_mount("/tmp/extroot/overlay")) {
+                               if (mount_move("/tmp/extroot", "", "/overlay")) {
+                                       fprintf(stderr, "moving extroot failed - continue normal boot\n");
+                                       umount("/tmp/extroot/overlay");
+                               } else if (fopivot("/overlay", "/rom")) {
+                                       fprintf(stderr, "switching to extroot failed - continue normal boot\n");
+                                       umount("/overlay");
+                               } else {
+                                       umount("/tmp/overlay");
+                                       rmdir("/tmp/overlay");
+                                       rmdir("/tmp/extroot/overlay");
+                                       rmdir("/tmp/extroot");
+                                       return 0;
+                               }
+                       }
+               }
+       }
+       return -1;
+}
+
+static struct backend extroot_backend = {
+       .name = "extroot",
+       .mount = mount_extroot,
+};
+BACKEND(extroot_backend);