#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
+#include <sys/wait.h>
#include <asm/byteorder.h>
cb(dir);
}
+static int find_overlay_mount(char *overlay)
+{
+ FILE *fp = fopen("/proc/mounts", "r");
+ static char line[256];
+ int ret = -1;
+
+ if(!fp)
+ return ret;
+
+ while (ret && fgets(line, sizeof(line), fp))
+ if (!strncmp(line, overlay, strlen(overlay)))
+ ret = 0;
+
+ fclose(fp);
+
+ return ret;
+}
+
+static char* find_mount(char *mp)
+{
+ FILE *fp = fopen("/proc/mounts", "r");
+ static char line[256];
+ char *point = NULL;
+
+ if(!fp)
+ return NULL;
+
+ while (fgets(line, sizeof(line), fp)) {
+ char *s, *t = strstr(line, " ");
+
+ if (!t)
+ return NULL;
+ t++;
+ s = strstr(t, " ");
+ if (!s)
+ return NULL;
+ *s = '\0';
+
+ if (!strcmp(t, mp)) {
+ fclose(fp);
+ return t;
+ }
+ }
+
+ fclose(fp);
+
+ return point;
+}
+
static char* find_mount_point(char *block, char *fs)
{
FILE *fp = fopen("/proc/mounts", "r");
return ret;
}
-static int mtd_erase(const char *mtd)
-{
- int fd = open(mtd, O_RDWR | O_SYNC);
- struct mtd_info_user i;
- struct erase_info_user e;
- int ret;
-
- if (!fd) {
- ERROR("failed to open %s: %s\n", mtd, strerror(errno));
- return -1;
- }
-
- ret = ioctl(fd, MEMGETINFO, &i);
- if (ret) {
- ERROR("ioctl(%s, MEMGETINFO) failed: %s\n", mtd, strerror(errno));
- return -1;
- }
-
- e.length = i.erasesize;
- for (e.start = 0; e.start < i.size; e.start += i.erasesize) {
- ioctl(fd, MEMUNLOCK, &e);
- if(ioctl(fd, MEMERASE, &e))
- ERROR("Failed to erase block on %s at 0x%x\n", mtd, e.start);
- }
-
- close(fd);
- return 0;
-}
-
-static int do_mount_jffs2(void)
+static int mtd_mount_jffs2(void)
{
char rootfs_data[32];
-
if (mkdir("/tmp/overlay", 0755)) {
ERROR("failed to mkdir /tmp/overlay: %s\n", strerror(errno));
return -1;
char newdir[64];
int ret;
- DEBUG(2, "%s %s\n", oldroot, dir);
+ DEBUG(2, "%s %s %s\n", oldroot, newroot, dir);
snprintf(olddir, sizeof(olddir), "%s%s", oldroot, dir);
snprintf(newdir, sizeof(newdir), "%s%s", newroot, dir);
return 0;
}
-
static int fopivot(char *rw_root, char *ro_root)
{
char overlay[64], lowerdir[64];
return 0;
}
-static int main_switch2jffs(int argc, char **argv)
+static int mtd_erase(const char *mtd)
{
- char mtd[32];
- char *mp;
- int ret = -1;
-
- if (check_fs_exists("overlay")) {
- ERROR("overlayfs not found\n");
- return ret;
- }
+ int fd = open(mtd, O_RDWR | O_SYNC);
+ struct mtd_info_user i;
+ struct erase_info_user e;
+ int ret;
- find_mtd_block("rootfs_data", mtd, sizeof(mtd));
- mp = find_mount_point(mtd, NULL);
- if (mp) {
- LOG("rootfs_data:%s is already mounted as %s\n", mtd, mp);
+ if (!fd) {
+ ERROR("failed to open %s: %s\n", mtd, strerror(errno));
return -1;
}
- if (find_mtd_char("rootfs_data", mtd, sizeof(mtd))) {
- ERROR("no rootfs_data was found\n");
- return ret;
+ ret = ioctl(fd, MEMGETINFO, &i);
+ if (ret) {
+ ERROR("ioctl(%s, MEMGETINFO) failed: %s\n", mtd, strerror(errno));
+ return -1;
}
- switch (jffs2_ready(mtd)) {
- case FS_NONE:
- ERROR("no jffs2 marker found\n");
- /* fall through */
-
- case FS_DEADCODE:
- ret = switch2jffs();
- if (!ret) {
- DEBUG(1, "doing fo cleanup\n");
- umount2("/tmp/root", MNT_DETACH);
- foreachdir("/overlay/", handle_whiteout);
- }
- break;
-
- case FS_JFFS2:
- ret = do_mount_jffs2();
- if (ret)
- break;
- if (mount_move("/tmp", "", "/overlay") || fopivot("/overlay", "/rom")) {
- ERROR("switching to jffs2 failed\n");
- ret = -1;
- }
- break;
+ e.length = i.erasesize;
+ for (e.start = 0; e.start < i.size; e.start += i.erasesize) {
+ ioctl(fd, MEMUNLOCK, &e);
+ if(ioctl(fd, MEMERASE, &e))
+ ERROR("Failed to erase block on %s at 0x%x\n", mtd, e.start);
}
- return ret;
+ close(fd);
+ return 0;
}
static int ask_user(int argc, char **argv)
}
return 0;
+ }
+static int main_switch2jffs(int argc, char **argv)
+{
+ char mtd[32];
+ char *mp;
+ int ret = -1;
+
+ if (find_overlay_mount("overlayfs:/tmp/root"))
+ return -1;
+
+ if (check_fs_exists("overlay")) {
+ ERROR("overlayfs not found\n");
+ return ret;
+ }
+
+ find_mtd_block("rootfs_data", mtd, sizeof(mtd));
+ mp = find_mount_point(mtd, NULL);
+ if (mp) {
+ LOG("rootfs_data:%s is already mounted as %s\n", mtd, mp);
+ return -1;
+ }
+
+ if (find_mtd_char("rootfs_data", mtd, sizeof(mtd))) {
+ ERROR("no rootfs_data was found\n");
+ return ret;
+ }
+
+ switch (jffs2_ready(mtd)) {
+ case FS_NONE:
+ ERROR("no jffs2 marker found\n");
+ /* fall through */
+
+ case FS_DEADCODE:
+ ret = switch2jffs();
+ if (!ret) {
+ DEBUG(1, "doing fo cleanup\n");
+ umount2("/tmp/root", MNT_DETACH);
+ foreachdir("/overlay/", handle_whiteout);
+ }
+ break;
+
+ case FS_JFFS2:
+ ret = mtd_mount_jffs2();
+ if (ret)
+ break;
+ if (mount_move("/tmp", "", "/overlay") || fopivot("/overlay", "/rom")) {
+ ERROR("switching to jffs2 failed\n");
+ ret = -1;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+static int extroot(const char *prefix)
+{
+ char block_path[32];
+ char kmod_loader[64];
+ struct stat s;
+ pid_t pid;
+
+ sprintf(block_path, "%s/sbin/block", prefix);
+
+ if (stat(block_path, &s))
+ return -1;
+
+ sprintf(kmod_loader, "/sbin/kmodloader %s/etc/modules-boot.d/ %s", prefix, 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")) {
+ ERROR("moving pivotroot failed - continue normal boot\n");
+ umount("/tmp/extroot/mnt");
+ } else if (pivot("/mnt", "/rom")) {
+ ERROR("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")) {
+ ERROR("moving extroot failed - continue normal boot\n");
+ umount("/tmp/extroot/overlay");
+ } else if (fopivot("/overlay", "/rom")) {
+ ERROR("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;
}
int main(int argc, char **argv)
argv0 = basename(*argv);
- if (!strcmp(basename(*argv), "switch2jffs"))
- return main_switch2jffs(argc, argv);
-
if (!strcmp(basename(*argv), "jffs2mark"))
return main_jffs2mark(argc, argv);
if (!strcmp(basename(*argv), "jffs2reset"))
return main_jffs2reset(argc, argv);
+ if (!strcmp(basename(*argv), "switch2jffs"))
+ return main_switch2jffs(argc, argv);
+
+ if (!getenv("PREINIT"))
+ return -1;
+
if (find_mtd_char("rootfs_data", mtd, sizeof(mtd))) {
if (!find_mtd_char("rootfs", mtd, sizeof(mtd)))
mtd_unlock(mtd);
LOG("mounting /dev/root\n");
mount("/dev/root", "/", NULL, MS_NOATIME | MS_REMOUNT, 0);
} else {
+ if (!extroot("")) {
+ fprintf(stderr, "mount_root: switched to extroot\n");
+ return 0;
+ }
+
switch (jffs2_ready(mtd)) {
case FS_NONE:
case FS_DEADCODE:
return -1;
}
- do_mount_jffs2();
+ mtd_mount_jffs2();
+
+ if (!extroot("/tmp/overlay")) {
+ fprintf(stderr, "mount_root: switched to extroot\n");
+ return 0;
+ }
+
DEBUG(1, "switching to jffs2\n");
if (mount_move("/tmp", "", "/overlay") || fopivot("/overlay", "/rom")) {
ERROR("switching to jffs2 failed - fallback to ramoverlay\n");