X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fubox.git;a=blobdiff_plain;f=mount_root.c;h=8868e40c68203612f18e0a8e4da27f41d3ff8713;hp=dc053686f21a52d81f9e22c787f375db193e9030;hb=f8d43c5f222b99d5a7a0e2bd1fdc0d442e030e89;hpb=fa4c1e81dae3ffb7711be38c64eacf8ac3856e42 diff --git a/mount_root.c b/mount_root.c index dc05368..8868e40 100644 --- a/mount_root.c +++ b/mount_root.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -78,6 +79,59 @@ 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) { + fclose(fp); + return NULL; + } + t++; + s = strstr(t, " "); + if (!s) { + fclose(fp); + 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"); @@ -93,13 +147,16 @@ static char* find_mount_point(char *block, char *fs) char *p = &line[len + 1]; char *t = strstr(p, " "); - if (!t) + if (!t) { + fclose(fp); return NULL; + } *t = '\0'; t++; if (fs && strncmp(t, fs, strlen(fs))) { + fclose(fp); ERROR("block is mounted with wrong fs\n"); return NULL; } @@ -196,40 +253,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 +348,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 +394,6 @@ static int pivot(char *new, char *old) return 0; } - static int fopivot(char *rw_root, char *ro_root) { char overlay[64], lowerdir[64]; @@ -404,6 +430,9 @@ static int switch2jffs(void) { char mtd[32]; + if (!find_mtd_block("rootfs_patches", mtd, sizeof(mtd))) + return 0; + if (find_mtd_block("rootfs_data", mtd, sizeof(mtd))) { ERROR("no rootfs_data was found\n"); return -1; @@ -471,55 +500,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) @@ -582,7 +589,7 @@ static int main_jffs2reset(int argc, char **argv) mp = find_mount_point(mtd, "jffs2"); if (mp) { - LOG("%s is mounted as %s, only ereasing files\n", mtd, mp); + LOG("%s is mounted as %s, only erasing files\n", mtd, mp); foreachdir(mp, handle_rmdir); mount(mp, "/", NULL, MS_REMOUNT, 0); } else { @@ -625,6 +632,126 @@ 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(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) @@ -634,21 +761,31 @@ 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 (find_mtd_char("rootfs_data", mtd, sizeof(mtd))) { + if (!strcmp(basename(*argv), "switch2jffs")) + return main_switch2jffs(argc, argv); + + if (!getenv("PREINIT")) + return -1; + + if (!find_mtd_block("rootfs_patches", mtd, sizeof(mtd))) { + ramoverlay(); + } else 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 +799,13 @@ int main(int argc, char **argv) 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");