summaryrefslogtreecommitdiff
path: root/mount_root.c
diff options
context:
space:
mode:
Diffstat (limited to 'mount_root.c')
-rw-r--r--mount_root.c829
1 files changed, 0 insertions, 829 deletions
diff --git a/mount_root.c b/mount_root.c
deleted file mode 100644
index 1927efa..0000000
--- a/mount_root.c
+++ /dev/null
@@ -1,829 +0,0 @@
-/*
- * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
- * Copyright (C) 2013 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 <stdio.h>
-#include <string.h>
-#include <getopt.h>
-#include <syslog.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <libgen.h>
-#include <glob.h>
-#include <dirent.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/mount.h>
-#include <sys/wait.h>
-
-#include <asm/byteorder.h>
-
-#include <mtd/mtd-user.h>
-
-#define DEBUG(level, fmt, ...) do { \
- if (debug >= level) \
- fprintf(stderr, "%s %s(%d): " fmt, argv0, __func__, __LINE__, ## __VA_ARGS__); \
- } while (0)
-
-#define LOG(fmt, ...) do { \
- syslog(LOG_INFO, fmt, ## __VA_ARGS__); \
- fprintf(stderr, "%s: "fmt, argv0, ## __VA_ARGS__); \
- } while (0)
-
-#define ERROR(fmt, ...) do { \
- syslog(LOG_ERR, fmt, ## __VA_ARGS__); \
- fprintf(stderr, "%s: "fmt, argv0, ## __VA_ARGS__); \
- } while (0)
-
-enum {
- FS_NONE,
- FS_JFFS2,
- FS_DEADCODE,
-};
-
-static const char *argv0;
-
-/* this is a raw syscall - man 2 pivot_root */
-extern int pivot_root(const char *new_root, const char *put_old);
-
-static int debug = 0;
-
-static void foreachdir(const char *dir, int (*cb)(const char*))
-{
- char globdir[256];
- glob_t gl;
- int j;
-
- if (dir[strlen(dir) - 1] == '/')
- snprintf(globdir, 256, "%s*", dir);
- else
- snprintf(globdir, 256, "%s/*", dir);
-
- if (!glob(globdir, GLOB_NOESCAPE | GLOB_MARK | GLOB_ONLYDIR, NULL, &gl))
- for (j = 0; j < gl.gl_pathc; j++)
- foreachdir(gl.gl_pathv[j], cb);
-
- 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");
- static char line[256];
- int len = strlen(block);
- char *point = NULL;
-
- if(!fp)
- return NULL;
-
- while (fgets(line, sizeof(line), fp)) {
- if (!strncmp(line, block, len)) {
- char *p = &line[len + 1];
- char *t = strstr(p, " ");
-
- 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;
- }
- point = p;
- break;
- }
- }
-
- fclose(fp);
-
- return point;
-}
-
-static char* find_mtd_index(char *name)
-{
- FILE *fp = fopen("/proc/mtd", "r");
- static char line[256];
- char *index = NULL;
-
- if(!fp)
- return index;
-
- while (!index && fgets(line, sizeof(line), fp)) {
- if (strstr(line, name)) {
- char *eol = strstr(line, ":");
-
- if (!eol)
- continue;
-
- *eol = '\0';
- index = &line[3];
- DEBUG(1, "found %s -> index:%s\n", name, index);
- }
- }
-
- fclose(fp);
-
- return index;
-}
-
-static int find_mtd_block(char *name, char *part, int plen)
-{
- char *index = find_mtd_index(name);
-
- if (!index)
- return -1;
-
- snprintf(part, plen, "/dev/mtdblock%s", index);
- DEBUG(1, "found %s -> %s\n", name, part);
-
- return 0;
-}
-
-static int find_mtd_char(char *name, char *part, int plen)
-{
- char *index = find_mtd_index(name);
-
- if (!index)
- return -1;
-
- snprintf(part, plen, "/dev/mtd%s", index);
- DEBUG(1, "found %s -> %s\n", name, part);
-
- return 0;
-}
-
-static int mtd_unlock(char *mtd)
-{
- struct erase_info_user mtdlock;
- struct mtd_info_user mtdinfo;
- int fd = open(mtd, O_RDWR | O_SYNC);
- int ret = -1;
-
- DEBUG(1, "%s\n", mtd);
-
- if (!fd) {
- ERROR("failed to open %s: %s\n", mtd, strerror(errno));
- return -1;
- }
-
- ret = ioctl(fd, MEMGETINFO, &mtdinfo);
- if (ret) {
- ERROR("ioctl(%s, MEMGETINFO) failed: %s\n", mtd, strerror(errno));
- goto err_out;
- }
-
- mtdlock.start = 0;
- mtdlock.length = mtdinfo.size;
- ioctl(fd, MEMUNLOCK, &mtdlock);
-
-err_out:
- close(fd);
-
- return ret;
-}
-
-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;
- }
-
- if (find_mtd_block("rootfs_data", rootfs_data, sizeof(rootfs_data))) {
- ERROR("rootfs_data does not exist\n");
- return -1;
- }
-
- if (mount(rootfs_data, "/tmp/overlay", "jffs2", MS_NOATIME, NULL)) {
- ERROR("failed to mount -t jffs2 %s /tmp/overlay: %s\n", rootfs_data, strerror(errno));
- return -1;
- }
-
- find_mtd_char("rootfs_data", rootfs_data, sizeof(rootfs_data));
-
- return mtd_unlock(rootfs_data);
-}
-
-static int jffs2_ready(char *mtd)
-{
- FILE *fp = fopen(mtd, "r");
- __u32 deadc0de;
- __u16 jffs2;
- size_t sz;
-
- if (!fp) {
- ERROR("reading %s failed\n", mtd);
- exit(-1);
- }
-
- sz = fread(&deadc0de, sizeof(deadc0de), 1, fp);
- fclose(fp);
-
- if (sz != 1) {
- ERROR("reading %s failed: %s\n", mtd, strerror(errno));
- exit(-1);
- }
-
- deadc0de = __be32_to_cpu(deadc0de);
- jffs2 = __be16_to_cpu(deadc0de >> 16);
-
- if (jffs2 == 0x1985) {
- LOG("jffs2 is ready\n");
- return FS_JFFS2;
- }
-
- if (deadc0de == 0xdeadc0de) {
- LOG("jffs2 is not ready - marker found\n");
- return FS_DEADCODE;
- }
-
- ERROR("No jffs2 marker was found\n");
-
- return FS_NONE;
-}
-
-static int check_fs_exists(char *fs)
-{
- FILE *fp = fopen("/proc/filesystems", "r");
- static char line[256];
- int ret = -1;
-
- DEBUG(2, "%s\n", fs);
-
- if (!fp) {
- ERROR("opening /proc/filesystems failed: %s\n", strerror(errno));
- goto out;
- }
-
- while (ret && fgets(line, sizeof(line), fp))
- if (strstr(line, fs))
- ret = 0;
-
- fclose(fp);
-
-out:
- return ret;
-}
-
-static int mount_move(char *oldroot, char *newroot, char *dir)
-{
-#ifndef MS_MOVE
-#define MS_MOVE (1 << 13)
-#endif
- struct stat s;
- char olddir[64];
- char newdir[64];
- int ret;
-
- 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);
-
- if (stat(olddir, &s) || !S_ISDIR(s.st_mode))
- return -1;
-
- if (stat(newdir, &s) || !S_ISDIR(s.st_mode))
- return -1;
-
- ret = mount(olddir, newdir, NULL, MS_NOATIME | MS_MOVE, NULL);
-
- if (ret)
- DEBUG(1, "failed %s %s: %s\n", olddir, newdir, strerror(errno));
-
- return ret;
-}
-
-static int pivot(char *new, char *old)
-{
- char pivotdir[64];
- int ret;
-
- DEBUG(2, "%s %s\n", new, old);
-
- if (mount_move("", new, "/proc"))
- return -1;
-
- snprintf(pivotdir, sizeof(pivotdir), "%s%s", new, old);
-
- ret = pivot_root(new, pivotdir);
-
- if (ret < 0) {
- ERROR("pivot_root failed %s %s: %s\n", new, pivotdir, strerror(errno));
- return -1;
- }
-
- mount_move(old, "", "/dev");
- mount_move(old, "", "/tmp");
- mount_move(old, "", "/sys");
- mount_move(old, "", "/overlay");
-
- return 0;
-}
-
-static int fopivot(char *rw_root, char *ro_root)
-{
- char overlay[64], lowerdir[64];
-
- DEBUG(2, "%s %s\n", rw_root, ro_root);
-
- if (check_fs_exists("overlay")) {
- ERROR("BUG: no suitable fs found\n");
- return -1;
- }
-
- snprintf(overlay, sizeof(overlay), "overlayfs:%s", rw_root);
- snprintf(lowerdir, sizeof(lowerdir), "lowerdir=/,upperdir=%s", rw_root);
-
- if (mount(overlay, "/mnt", "overlayfs", MS_NOATIME, lowerdir)) {
- ERROR("mount failed: %s\n", strerror(errno));
- return -1;
- }
-
- return pivot("/mnt", ro_root);
-}
-
-static int ramoverlay(void)
-{
- DEBUG(2, "\n");
-
- mkdir("/tmp/root", 0755);
- mount("tmpfs", "/tmp/root", "tmpfs", MS_NOATIME, "mode=0755");
-
- return fopivot("/tmp/root", "/rom");
-}
-
-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;
- }
-
- if (mount(mtd, "/rom/overlay", "jffs2", MS_NOATIME, NULL)) {
- ERROR("failed - mount -t jffs2 %s /rom/overlay: %s\n", mtd, strerror(errno));
- return -1;
- }
-
- if (mount("none", "/", NULL, MS_NOATIME | MS_REMOUNT, 0)) {
- ERROR("failed - mount -o remount,ro none: %s\n", strerror(errno));
- return -1;
- }
-
- system("cp -a /tmp/root/* /rom/overlay");
-
- if (pivot("/rom", "/mnt")) {
- ERROR("failed - pivot /rom /mnt: %s\n", strerror(errno));
- return -1;
- }
-
- if (mount_move("/mnt", "/tmp/root", "")) {
- ERROR("failed - mount -o move /mnt /tmp/root %s\n", strerror(errno));
- return -1;
- }
-
- return fopivot("/overlay", "/rom");
-}
-
-static int handle_whiteout(const char *dir)
-{
- struct stat s;
- char link[256];
- ssize_t sz;
- struct dirent **namelist;
- int n;
-
- n = scandir(dir, &namelist, NULL, NULL);
-
- if (n < 1)
- return -1;
-
- while (n--) {
- char file[256];
-
- snprintf(file, sizeof(file), "%s%s", dir, namelist[n]->d_name);
- if (!lstat(file, &s) && S_ISLNK(s.st_mode)) {
- sz = readlink(file, link, sizeof(link) - 1);
- if (sz > 0) {
- char *orig;
-
- link[sz] = '\0';
- orig = strstr(&file[1], "/");
- if (orig && !strcmp(link, "(overlay-whiteout)")) {
- DEBUG(1, "unlinking %s\n", orig);
- unlink(orig);
- }
- }
- }
- free(namelist[n]);
- }
- free(namelist);
-
- return 0;
-}
-
-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 ask_user(int argc, char **argv)
-{
- if ((argc < 2) || strcmp(argv[1], "-y")) {
- LOG("This will erase all settings and remove any installed packages. Are you sure? [N/y]\n");
- if (getchar() != 'y')
- return -1;
- }
- return 0;
-
-}
-
-static int handle_rmdir(const char *dir)
-{
- struct stat s;
- struct dirent **namelist;
- int n;
-
- n = scandir(dir, &namelist, NULL, NULL);
-
- if (n < 1)
- return -1;
-
- while (n--) {
- char file[256];
-
- snprintf(file, sizeof(file), "%s%s", dir, namelist[n]->d_name);
- if (!lstat(file, &s) && !S_ISDIR(s.st_mode)) {
- DEBUG(1, "unlinking %s\n", file);
- unlink(file);
- }
- free(namelist[n]);
- }
- free(namelist);
-
- DEBUG(1, "rmdir %s\n", dir);
- rmdir(dir);
-
- return 0;
-}
-
-static int main_jffs2reset(int argc, char **argv)
-{
- char mtd[32];
- char *mp;
-
- if (ask_user(argc, argv))
- return -1;
-
- if (check_fs_exists("overlay")) {
- ERROR("overlayfs not found\n");
- return -1;
- }
-
- if (find_mtd_block("rootfs_data", mtd, sizeof(mtd))) {
- ERROR("no rootfs_data was found\n");
- return -1;
- }
-
- mp = find_mount_point(mtd, "jffs2");
- if (mp) {
- LOG("%s is mounted as %s, only erasing files\n", mtd, mp);
- foreachdir(mp, handle_rmdir);
- mount(mp, "/", NULL, MS_REMOUNT, 0);
- } else {
- LOG("%s is not mounted, erasing it\n", mtd);
- find_mtd_char("rootfs_data", mtd, sizeof(mtd));
- mtd_erase(mtd);
- }
-
- return 0;
-}
-
-static int main_jffs2mark(int argc, char **argv)
-{
- FILE *fp;
- __u32 deadc0de = __cpu_to_be32(0xdeadc0de);
- char mtd[32];
- size_t sz;
-
- if (ask_user(argc, argv))
- return -1;
-
- if (find_mtd_block("rootfs_data", mtd, sizeof(mtd))) {
- ERROR("no rootfs_data was found\n");
- return -1;
- }
-
- fp = fopen(mtd, "w");
- LOG("%s - marking with deadc0de\n", mtd);
- if (!fp) {
- ERROR("opening %s failed\n", mtd);
- return -1;
- }
-
- sz = fwrite(&deadc0de, sizeof(deadc0de), 1, fp);
- fclose(fp);
-
- if (sz != 1) {
- ERROR("writing %s failed: %s\n", mtd, strerror(errno));
- return -1;
- }
-
- 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))
- {
- sprintf(block_path, "/sbin/block");
-
- if (stat(block_path, &s))
- return -1;
- }
-
- sprintf(kmod_loader, "/sbin/kmodloader %s/etc/modules-boot.d/ %s", prefix, prefix);
- system(kmod_loader);
-
- LOG("starting block executable %s\n", block_path);
-
- 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;
- }
- } else {
- ERROR("block executable did not set up an overlay\n");
- }
- } else {
- ERROR("block executable failed with code %d\n", WEXITSTATUS(status));
- }
- }
- return -1;
-}
-
-int main(int argc, char **argv)
-{
- char *mp;
- char mtd[32];
-
- argv0 = basename(*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_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:
- return ramoverlay();
-
- case FS_JFFS2:
- 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;
- }
-
- 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");
- return ramoverlay();
- }
- }
- }
-
- return 0;
-}