X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fubox.git;a=blobdiff_plain;f=mount_root.c;h=bc236fe8e95b5751c1b3058f386b3de8ad93a311;hp=dc053686f21a52d81f9e22c787f375db193e9030;hb=b706806db4593c42bdc372af65543f4cb3e3b33f;hpb=fa4c1e81dae3ffb7711be38c64eacf8ac3856e42 diff --git a/mount_root.c b/mount_root.c index dc05368..bc236fe 100644 --- a/mount_root.c +++ b/mount_root.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -78,6 +79,55 @@ static void foreachdir(const char *dir, int (*cb)(const char*)) 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"); @@ -196,40 +246,10 @@ err_out: 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; @@ -321,7 +341,7 @@ static int mount_move(char *oldroot, char *newroot, char *dir) 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); @@ -367,7 +387,6 @@ static int pivot(char *new, char *old) return 0; } - static int fopivot(char *rw_root, char *ro_root) { char overlay[64], lowerdir[64]; @@ -471,55 +490,33 @@ static int handle_whiteout(const char *dir) 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) @@ -625,6 +622,111 @@ static int main_jffs2mark(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(void) +{ + struct stat s; + pid_t pid; + + if (stat("/sbin/block", &s)) + return -1; + + pid = fork(); + if (!pid) { + mkdir("/tmp/extroot", 0755); + execl("/sbin/block", "/sbin/block", "extroot", NULL); + exit(-1); + } else if (pid > 0) { + int status; + + waitpid(pid, &status, 0); + if (!WEXITSTATUS(status)) { + if (find_mount("/tmp/mnt")) { + mount("/dev/root", "/", NULL, MS_NOATIME | MS_REMOUNT | MS_RDONLY, 0); + + mkdir("/tmp/mnt/proc", 0755); + mkdir("/tmp/mnt/dev", 0755); + mkdir("/tmp/mnt/sys", 0755); + mkdir("/tmp/mnt/tmp", 0755); + mkdir("/tmp/mnt/rom", 0755); + + if (mount_move("/tmp", "", "/mnt")) { + ERROR("moving pivotroot failed - continue normal boot\n"); + umount("/tmp/mnt"); + } else if (pivot("/mnt", "/rom")) { + ERROR("switching to pivotroot failed - continue normal boot\n"); + umount("/mnt"); + } else { + return 0; + } + } else if (find_mount("/tmp/overlay")) { + if (mount_move("/tmp", "", "/overlay")) { + ERROR("moving extroot failed - continue normal boot\n"); + umount("/tmp/overlay"); + } else if (fopivot("/overlay", "/rom")) { + ERROR("switching to extroot failed - continue normal boot\n"); + umount("/overlay"); + } else { + return 0; + } + } + } + } + return -1; } int main(int argc, char **argv) @@ -634,21 +736,29 @@ 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: @@ -662,7 +772,7 @@ int main(int argc, char **argv) return -1; } - do_mount_jffs2(); + mtd_mount_jffs2(); DEBUG(1, "switching to jffs2\n"); if (mount_move("/tmp", "", "/overlay") || fopivot("/overlay", "/rom")) { ERROR("switching to jffs2 failed - fallback to ramoverlay\n");