From 3eddeb76f22273f540504de78cb147fe6d60c9f2 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 24 Jun 2013 18:35:56 +0200 Subject: [PATCH 1/1] add pivot support, anon swap, device name support, hotplug Signed-off-by: John Crispin --- block.c | 207 +++++++++++++++++++++++++++++++++++++++++++---------------- mount_root.c | 72 +++++++++++++++++---- 2 files changed, 211 insertions(+), 68 deletions(-) diff --git a/block.c b/block.c index d456dd5..57f7129 100644 --- a/block.c +++ b/block.c @@ -47,6 +47,9 @@ struct mount { char *options; char *uuid; char *label; + char *device; + int extroot; + int overlay; int disabled_fsck; unsigned int prio; }; @@ -54,19 +57,38 @@ struct mount { static struct vlist_tree mounts; static struct blob_buf b; static LIST_HEAD(devices); +static int anon_mount, anon_swap; + +enum { + CFG_ANON_MOUNT, + CFG_ANON_SWAP, + __CFG_MAX +}; + +static const struct blobmsg_policy config_policy[__CFG_MAX] = { + [CFG_ANON_SWAP] = { .name = "anon_swap", .type = BLOBMSG_TYPE_INT32 }, + [CFG_ANON_MOUNT] = { .name = "anon_mount", .type = BLOBMSG_TYPE_INT32 }, +}; enum { MOUNT_UUID, MOUNT_LABEL, MOUNT_ENABLE, MOUNT_TARGET, + MOUNT_DEVICE, MOUNT_OPTIONS, __MOUNT_MAX }; +static const struct uci_blob_param_list config_attr_list = { + .n_params = __CFG_MAX, + .params = config_policy, +}; + static const struct blobmsg_policy mount_policy[__MOUNT_MAX] = { [MOUNT_UUID] = { .name = "uuid", .type = BLOBMSG_TYPE_STRING }, [MOUNT_LABEL] = { .name = "label", .type = BLOBMSG_TYPE_STRING }, + [MOUNT_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING }, [MOUNT_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING }, [MOUNT_OPTIONS] = { .name = "options", .type = BLOBMSG_TYPE_STRING }, [MOUNT_ENABLE] = { .name = "enabled", .type = BLOBMSG_TYPE_INT32 }, @@ -80,6 +102,7 @@ static const struct uci_blob_param_list mount_attr_list = { enum { SWAP_ENABLE, SWAP_UUID, + SWAP_DEVICE, SWAP_PRIO, __SWAP_MAX }; @@ -87,6 +110,7 @@ enum { static const struct blobmsg_policy swap_policy[__SWAP_MAX] = { [SWAP_ENABLE] = { .name = "enabled", .type = BLOBMSG_TYPE_INT32 }, [SWAP_UUID] = { .name = "uuid", .type = BLOBMSG_TYPE_STRING }, + [SWAP_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING }, [SWAP_PRIO] = { .name = "priority", .type = BLOBMSG_TYPE_INT32 }, }; @@ -112,10 +136,10 @@ static int mount_add(struct uci_section *s) uci_to_blob(&b, s, &mount_attr_list); blobmsg_parse(mount_policy, __MOUNT_MAX, tb, blob_data(b.head), blob_len(b.head)); - if (!tb[MOUNT_LABEL] && !tb[MOUNT_UUID]) + if (!tb[MOUNT_LABEL] && !tb[MOUNT_UUID] && !tb[MOUNT_DEVICE]) return -1; - if (!tb[MOUNT_TARGET]) + if (tb[MOUNT_ENABLE] && !blobmsg_get_u32(tb[MOUNT_ENABLE])) return -1; m = malloc(sizeof(struct mount)); @@ -124,9 +148,19 @@ static int mount_add(struct uci_section *s) m->label = blobmsg_get_strdup(tb[MOUNT_LABEL]); m->target = blobmsg_get_strdup(tb[MOUNT_TARGET]); m->options = blobmsg_get_strdup(tb[MOUNT_OPTIONS]); - - if ((!tb[MOUNT_ENABLE]) || blobmsg_get_u32(tb[MOUNT_ENABLE])) - vlist_add(&mounts, &m->node, m->target); + m->device = blobmsg_get_strdup(tb[MOUNT_DEVICE]); + m->overlay = m->extroot = 0; + if (m->target && !strcmp(m->target, "/")) + m->extroot = 1; + if (m->target && !strcmp(m->target, "/overlay")) + m->extroot = m->overlay = 1; + + if (m->uuid) + vlist_add(&mounts, &m->node, m->uuid); + else if (m->label) + vlist_add(&mounts, &m->node, m->label); + else if (m->device) + vlist_add(&mounts, &m->node, m->device); return 0; } @@ -140,48 +174,72 @@ static int swap_add(struct uci_section *s) uci_to_blob(&b, s, &swap_attr_list); blobmsg_parse(swap_policy, __SWAP_MAX, tb, blob_data(b.head), blob_len(b.head)); - if (!tb[SWAP_UUID]) + if (!tb[SWAP_UUID] && !tb[SWAP_DEVICE]) return -1; m = malloc(sizeof(struct mount)); memset(m, 0, sizeof(struct mount)); m->type = TYPE_SWAP; m->uuid = blobmsg_get_strdup(tb[SWAP_UUID]); + m->device = blobmsg_get_strdup(tb[SWAP_DEVICE]); if (tb[SWAP_PRIO]) m->prio = blobmsg_get_u32(tb[SWAP_PRIO]); if (m->prio) m->prio = ((m->prio << SWAP_FLAG_PRIO_SHIFT) & SWAP_FLAG_PRIO_MASK) | SWAP_FLAG_PREFER; if ((!tb[SWAP_ENABLE]) || blobmsg_get_u32(tb[SWAP_ENABLE])) - vlist_add(&mounts, &m->node, m->uuid); + vlist_add(&mounts, &m->node, (m->uuid) ? (m->uuid) : (m->device)); return 0; } -static struct mount* find_swap(const char *uuid) +static int global_add(struct uci_section *s) { - struct mount *m; + struct blob_attr *tb[__CFG_MAX] = { 0 }; - if (!uuid) - return NULL; + blob_buf_init(&b, 0); + uci_to_blob(&b, s, &config_attr_list); + blobmsg_parse(config_policy, __CFG_MAX, tb, blob_data(b.head), blob_len(b.head)); + + if ((tb[CFG_ANON_MOUNT]) && blobmsg_get_u32(tb[CFG_ANON_MOUNT])) + anon_mount = 1; + if ((tb[CFG_ANON_SWAP]) && blobmsg_get_u32(tb[CFG_ANON_SWAP])) + anon_swap = 1; + + return 0; +} + +static struct mount* find_swap(const char *uuid, const char *device) +{ + struct mount *m; - vlist_for_each_element(&mounts, m, node) - if ((m->type == TYPE_SWAP) && m->uuid && !strcmp(m->uuid, uuid)) + vlist_for_each_element(&mounts, m, node) { + if (m->type != TYPE_SWAP) + continue; + if (uuid && m->uuid && !strcmp(m->uuid, uuid)) + return m; + if (device && m->device && !strcmp(m->device, device)) return m; + } return NULL; } -static struct mount* find_block(const char *uuid, const char *label, const char *target) +static struct mount* find_block(const char *uuid, const char *label, const char *device, + const char *target) { struct mount *m; vlist_for_each_element(&mounts, m, node) { - if ((m->type == TYPE_MOUNT) && m->uuid && uuid && !strcmp(m->uuid, uuid)) + if (m->type != TYPE_MOUNT) + continue; + if (m->uuid && uuid && !strcmp(m->uuid, uuid)) return m; - if ((m->type == TYPE_MOUNT) && m->label && label && !strcmp(m->label, label)) + if (m->label && label && !strcmp(m->label, label)) return m; - if ((m->type == TYPE_MOUNT) && target && !strcmp(m->target, target)) + if (m->target && target && !strcmp(m->target, target)) + return m; + if (m->device && device && !strcmp(m->device, device)) return m; } @@ -219,6 +277,8 @@ static int config_load(char *cfg) mount_add(s); if (!strcmp(s->type, "swap")) swap_add(s); + if (!strcmp(s->type, "global")) + global_add(s); } vlist_flush(&mounts); @@ -253,8 +313,8 @@ static void cache_load(int mtd) { if (mtd) _cache_load("/dev/mtdblock*"); - _cache_load("/dev/sd*"); _cache_load("/dev/mmcblk*"); + _cache_load("/dev/sd*"); } static int print_block_info(struct blkid_struct_probe *pr) @@ -279,16 +339,16 @@ static int print_block_info(struct blkid_struct_probe *pr) static int print_block_uci(struct blkid_struct_probe *pr) { - if (!pr->uuid[0]) - return 0; - if (!strcmp(pr->id->name, "swap")) { printf("config 'swap'\n"); } else { printf("config 'mount'\n"); printf("\toption\ttarget\t'/mnt/%s'\n", basename(pr->dev)); } - printf("\toption\tuuid\t'%s'\n", pr->uuid); + if (pr->uuid[0]) + printf("\toption\tuuid\t'%s'\n", pr->uuid); + else + printf("\toption\tdevice\t'%s'\n", basename(pr->dev)); printf("\toption\tenabled\t'0'\n\n"); return 0; @@ -392,28 +452,51 @@ static int main_hotplug(int argc, char **argv) cache_load(0); pr = find_block_info(NULL, NULL, path); - if (!pr && pr->uuid) { + if (!pr) { fprintf(stderr, "failed to read blockinfo for %s\n", path); return -1; } - m = find_swap(pr->uuid); - if (m) { - if (!strcmp(action, "add")) - swapon(path, m->prio); - else - swapoff(path); - } else { - m = find_block(pr->uuid, pr->label, NULL); - if (m && strcmp(m->target, "/")) { - int err = 0; + if (!strcmp(pr->id->name, "swap")) { + m = find_swap(pr->uuid, device); + if (m || anon_swap) { + if (!strcmp(action, "add")) + swapon(path, (m) ? (m->prio) : (0)); + else + swapoff(path); + } + return 0; + } - mkdir_p(m->target); - err = mount(path, m->target, pr->id->name, 0, (m->options) ? (m->options) : ("")); - if (err) - fprintf(stderr, "mounting %s (%s) as %s failed (%d) - %s\n", - path, pr->id->name, m->target, err, strerror(err)); + m = find_block(pr->uuid, pr->label, device, NULL); + if (m && !m->extroot) { + char *target = m->target; + char _target[] = "/mnt/mmcblk123"; + int err = 0; + + if (!target) { + snprintf(_target, sizeof(_target), "/mnt/%s", device); + target = _target; } + mkdir_p(target); + err = mount(path, target, pr->id->name, 0, (m->options) ? (m->options) : ("")); + if (err) + fprintf(stderr, "mounting %s (%s) as %s failed (%d) - %s\n", + path, pr->id->name, target, err, strerror(err)); + return err; + } + + if (anon_mount) { + char target[] = "/mnt/mmcblk123"; + int err = 0; + + snprintf(target, sizeof(target), "/mnt/%s", device); + mkdir_p(target); + err = mount(path, target, pr->id->name, 0, ""); + if (err) + fprintf(stderr, "mounting %s (%s) as %s failed (%d) - %s\n", + path, pr->id->name, target, err, strerror(err)); + return err; } return 0; @@ -494,28 +577,41 @@ static int check_extroot(char *path) return -1; } -static int mount_extroot(char *path, char *cfg) +static int mount_extroot(char *cfg) { - struct blkid_struct_probe *pr; + char overlay[] = "/tmp/overlay"; + char mnt[] = "/tmp/mnt"; + char *path = mnt; + struct blkid_struct_probe *pr; struct mount *m; int err = -1; if (config_load(cfg)) - return 2; + return -2; - m = find_block(NULL, NULL, "/"); + m = find_block(NULL, NULL, NULL, "/"); if (!m) - return 1; + m = find_block(NULL, NULL, NULL, "/overlay"); + + if (!m || !m->extroot) + return -1; pr = find_block_info(m->uuid, m->label, NULL); if (pr) { + if (strncmp(pr->id->name, "ext", 3)) { + fprintf(stderr, "extroot: %s is not supported, try ext4\n", pr->id->name); + return -1; + } + if (m->overlay) + path = overlay; mkdir_p(path); + err = mount(pr->dev, path, pr->id->name, 0, (m->options) ? (m->options) : ("")); if (err) { fprintf(stderr, "mounting %s (%s) as %s failed (%d) - %s\n", pr->dev, pr->id->name, path, err, strerror(err)); - } else { + } else if (m->overlay) { err = check_extroot(path); if (err) umount(path); @@ -530,15 +626,14 @@ static int main_extroot(int argc, char **argv) struct blkid_struct_probe *pr; char fs[32] = { 0 }; char fs_data[32] = { 0 }; - int err = 1; - char extroot[] = "/tmp/overlay"; + int err = -1; if (!getenv("PREINIT")) return -1; if (argc != 2) { fprintf(stderr, "Usage: block extroot mountpoint\n"); - return 1; + return -1; } mkblkdev(); @@ -546,11 +641,11 @@ static int main_extroot(int argc, char **argv) find_block_mtd("rootfs", fs, sizeof(fs)); if (!fs[0]) - return 2; + return -2; pr = find_block_info(NULL, NULL, fs); - if (!pr || strcmp(pr->id->name, "squashfs")) - return 3; + if (!pr) + return -3; find_block_mtd("rootfs_data", fs_data, sizeof(fs_data)); if (fs_data[0]) { @@ -560,19 +655,17 @@ static int main_extroot(int argc, char **argv) mkdir_p(cfg); if (!mount(fs_data, cfg, "jffs2", MS_NOATIME, NULL)) { - err = mount_extroot(extroot, cfg); + err = mount_extroot(cfg); umount2(cfg, MNT_DETACH); } - if (err) - rmdir(extroot); + if (err < 0) + rmdir("/tmp/overlay"); rmdir(cfg); return err; } } - err = mount_extroot(extroot, NULL); - - return err; + return mount_extroot(NULL); } static int main_detect(int argc, char **argv) @@ -703,6 +796,8 @@ int main(int argc, char **argv) { char *base = basename(*argv); + umask(0); + if (!strcmp(base, "swapon")) return main_swapon(argc, argv); diff --git a/mount_root.c b/mount_root.c index 96d1007..ad1de36 100644 --- a/mount_root.c +++ b/mount_root.c @@ -97,6 +97,37 @@ static int find_overlay_mount(char *overlay) 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"); @@ -219,7 +250,6 @@ 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; @@ -311,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); @@ -353,12 +383,10 @@ static int pivot(char *new, char *old) mount_move(old, "", "/tmp"); mount_move(old, "", "/sys"); mount_move(old, "", "/overlay"); - mount_move(old, "", "/extroot"); return 0; } - static int fopivot(char *rw_root, char *ro_root) { char overlay[64], lowerdir[64]; @@ -534,14 +562,34 @@ static int extroot(void) waitpid(pid, &status, 0); if (!WEXITSTATUS(status)) { - 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; + 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; + } } } } -- 2.11.0