X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fubox.git;a=blobdiff_plain;f=block.c;h=b5bc4941cafe5b363801f363085f6853edabf73b;hp=fd8d21efd24f862acf2e4068f640b65822628a08;hb=3637b9f8e7097d38a17d5b6ffa9a4d6eb1249eb3;hpb=1b19fc217e33e9b2fc2fab6f9552da740d03a98a diff --git a/block.c b/block.c index fd8d21e..b5bc494 100644 --- a/block.c +++ b/block.c @@ -12,6 +12,7 @@ * GNU General Public License for more details. */ +#define _GNU_SOURCE #include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include #include @@ -47,6 +49,9 @@ struct mount { char *options; char *uuid; char *label; + char *device; + int extroot; + int overlay; int disabled_fsck; unsigned int prio; }; @@ -54,19 +59,47 @@ struct mount { static struct vlist_tree mounts; static struct blob_buf b; static LIST_HEAD(devices); +static int anon_mount, anon_swap, auto_mount, auto_swap, check_fs; +static unsigned int delay_root; + +enum { + CFG_ANON_MOUNT, + CFG_ANON_SWAP, + CFG_AUTO_MOUNT, + CFG_AUTO_SWAP, + CFG_DELAY_ROOT, + CFG_CHECK_FS, + __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 }, + [CFG_AUTO_SWAP] = { .name = "auto_swap", .type = BLOBMSG_TYPE_INT32 }, + [CFG_AUTO_MOUNT] = { .name = "auto_mount", .type = BLOBMSG_TYPE_INT32 }, + [CFG_DELAY_ROOT] = { .name = "delay_root", .type = BLOBMSG_TYPE_INT32 }, + [CFG_CHECK_FS] = { .name = "check_fs", .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 +113,7 @@ static const struct uci_blob_param_list mount_attr_list = { enum { SWAP_ENABLE, SWAP_UUID, + SWAP_DEVICE, SWAP_PRIO, __SWAP_MAX }; @@ -87,6 +121,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 }, }; @@ -103,6 +138,14 @@ static char *blobmsg_get_strdup(struct blob_attr *attr) return strdup(blobmsg_get_string(attr)); } +static char *blobmsg_get_basename(struct blob_attr *attr) +{ + if (!attr) + return NULL; + + return strdup(basename(blobmsg_get_string(attr))); +} + static int mount_add(struct uci_section *s) { struct blob_attr *tb[__MOUNT_MAX] = { 0 }; @@ -112,10 +155,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 +167,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_basename(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 +193,83 @@ 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_basename(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; + + if ((tb[CFG_AUTO_MOUNT]) && blobmsg_get_u32(tb[CFG_AUTO_MOUNT])) + auto_mount = 1; + if ((tb[CFG_AUTO_SWAP]) && blobmsg_get_u32(tb[CFG_AUTO_SWAP])) + auto_swap = 1; - vlist_for_each_element(&mounts, m, node) - if ((m->type == TYPE_SWAP) && m->uuid && !strcmp(m->uuid, uuid)) + if (tb[CFG_DELAY_ROOT]) + delay_root = blobmsg_get_u32(tb[CFG_DELAY_ROOT]); + + if ((tb[CFG_CHECK_FS]) && blobmsg_get_u32(tb[CFG_CHECK_FS])) + check_fs = 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) + 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->label && label && !strcmp(m->label, label)) return m; - if ((m->type == TYPE_MOUNT) && m->label && label && !strcmp(m->label, label)) + if (m->target && target && !strcmp(m->target, target)) return m; - if ((m->type == TYPE_MOUNT) && target && !strcmp(m->target, target)) + if (m->device && device && !strcmp(m->device, device)) return m; } @@ -219,6 +307,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); @@ -238,7 +328,7 @@ static int _cache_load(const char *path) struct blkid_struct_probe *pr = malloc(sizeof(struct blkid_struct_probe)); memset(pr, 0, sizeof(struct blkid_struct_probe)); probe_block(gl.gl_pathv[j], pr); - if (pr->err) + if (pr->err || !pr->id) free(pr); else list_add_tail(&pr->list, &devices); @@ -253,7 +343,12 @@ static void cache_load(int mtd) { if (mtd) _cache_load("/dev/mtdblock*"); + _cache_load("/dev/mmcblk*"); _cache_load("/dev/sd*"); + _cache_load("/dev/sdc*"); + _cache_load("/dev/hd*"); + _cache_load("/dev/md*"); + _cache_load("/dev/mapper/*"); } static int print_block_info(struct blkid_struct_probe *pr) @@ -278,16 +373,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", pr->dev); printf("\toption\tenabled\t'0'\n\n"); return 0; @@ -355,12 +450,144 @@ static void mkdir_p(char *dir) } } -static int main_hotplug(int argc, char **argv) +static void check_filesystem(struct blkid_struct_probe *pr) +{ + pid_t pid; + struct stat statbuf; + char *e2fsck = "/usr/sbin/e2fsck"; + + if (strncmp(pr->id->name, "ext", 3)) { + fprintf(stderr, "check_filesystem: %s is not supported\n", pr->id->name); + return; + } + + if (stat(e2fsck, &statbuf) < 0) { + fprintf(stderr, "check_filesystem: %s not found\n", e2fsck); + return; + } + + pid = fork(); + if (!pid) { + execl(e2fsck, e2fsck, "-p", pr->dev, NULL); + exit(-1); + } else if (pid > 0) { + int status; + + waitpid(pid, &status, 0); + if (WEXITSTATUS(status)) + fprintf(stderr, "check_filesystem: %s returned %d\n", e2fsck, WEXITSTATUS(status)); + } +} + +static int mount_device(struct blkid_struct_probe *pr, int hotplug) { struct mount *m; - char path[256]; + char *device; + + if (!pr) + return -1; + + device = basename(pr->dev); + + if (!strcmp(pr->id->name, "swap")) { + if (hotplug && !auto_swap) + return -1; + m = find_swap(pr->uuid, device); + if (m || anon_swap) + swapon(pr->dev, (m) ? (m->prio) : (0)); + + return 0; + } + + if (hotplug && !auto_mount) + return -1; + + if (find_mount_point(pr->dev)) { + fprintf(stderr, "%s is already mounted\n", pr->dev); + return -1; + } + + m = find_block(pr->uuid, pr->label, device, NULL); + if (m && m->extroot) + return -1; + + if (m) { + char *target = m->target; + char _target[32]; + int err = 0; + + if (!target) { + snprintf(_target, sizeof(_target), "/mnt/%s", device); + target = _target; + } + mkdir_p(target); + + if (check_fs) + check_filesystem(pr); + + err = mount(pr->dev, target, 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, 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); + + if (check_fs) + check_filesystem(pr); + + err = mount(pr->dev, target, pr->id->name, 0, ""); + if (err) + fprintf(stderr, "mounting %s (%s) as %s failed (%d) - %s\n", + pr->dev, pr->id->name, target, err, strerror(err)); + return err; + } + + return 0; +} + +static int umount_device(struct blkid_struct_probe *pr) +{ + struct mount *m; + char *device = basename(pr->dev); + char *mp; + int err; + + if (!pr) + return -1; + + if (!strcmp(pr->id->name, "swap")) + return -1; + + mp = find_mount_point(pr->dev); + if (!mp) + return -1; + + m = find_block(pr->uuid, pr->label, device, NULL); + if (m && m->extroot) + return -1; + + err = umount2(mp, MNT_DETACH); + if (err) + fprintf(stderr, "unmounting %s (%s) failed (%d) - %s\n", + pr->dev, mp, err, strerror(err)); + else + fprintf(stderr, "unmounted %s (%s)\n", + pr->dev, mp); + + return err; +} + +static int main_hotplug(int argc, char **argv) +{ + char path[32]; char *action, *device, *mount_point; - struct blkid_struct_probe *pr; action = getenv("ACTION"); device = getenv("DEVNAME"); @@ -376,7 +603,7 @@ static int main_hotplug(int argc, char **argv) err = umount2(mount_point, MNT_DETACH); if (err) - fprintf(stderr, "unmount of %s failed (%d) - %s\n", + fprintf(stderr, "umount of %s failed (%d) - %s\n", mount_point, err, strerror(err)); return 0; @@ -390,32 +617,7 @@ static int main_hotplug(int argc, char **argv) return -1; cache_load(0); - pr = find_block_info(NULL, NULL, path); - if (!pr && pr->uuid) { - 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; - - 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)); - } - } - - return 0; + return mount_device(find_block_info(NULL, NULL, path), 1); } static int find_block_mtd(char *name, char *part, int plen) @@ -493,28 +695,52 @@ 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 && delay_root){ + fprintf(stderr, "extroot: is not ready yet, retrying in %ui seconds\n", delay_root); + sleep(delay_root); + mkblkdev(); + cache_load(0); + 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); + + if (check_fs) + check_filesystem(pr); + 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); @@ -529,15 +755,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(); @@ -545,11 +770,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]) { @@ -559,19 +784,45 @@ 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 mount_extroot(NULL); +} - return err; +static int main_mount(int argc, char **argv) +{ + struct blkid_struct_probe *pr; + + if (config_load(NULL)) + return -1; + + cache_load(1); + list_for_each_entry(pr, &devices, list) + mount_device(pr, 0); + + return 0; +} + +static int main_umount(int argc, char **argv) +{ + struct blkid_struct_probe *pr; + + if (config_load(NULL)) + return -1; + + cache_load(0); + list_for_each_entry(pr, &devices, list) + umount_device(pr); + + return 0; } static int main_detect(int argc, char **argv) @@ -579,6 +830,13 @@ static int main_detect(int argc, char **argv) struct blkid_struct_probe *pr; cache_load(0); + printf("config 'global'\n"); + printf("\toption\tanon_swap\t'0'\n"); + printf("\toption\tanon_mount\t'0'\n"); + printf("\toption\tauto_swap\t'1'\n"); + printf("\toption\tauto_mount\t'1'\n"); + printf("\toption\tdelay_root\t'0'\n"); + printf("\toption\tcheck_fs\t'0'\n\n"); list_for_each_entry(pr, &devices, list) print_block_uci(pr); @@ -620,11 +878,25 @@ static int main_info(int argc, char **argv) static int main_swapon(int argc, char **argv) { if (argc != 2) { - fprintf(stderr, "Usage: swapoff [-a] [DEVICE]\n\nStop swapping on DEVICE\n\n\t-a Stop swapping on all swap devices\n"); + fprintf(stderr, "Usage: swapon <-s> <-a> [DEVICE]\n\n\tStart swapping on [DEVICE]\n -a\tStart swapping on all swap devices\n -s\tShow summary\n"); return -1; } - if (!strcmp(argv[1], "-a")) { + if (!strcmp(argv[1], "-s")) { + FILE *fp = fopen("/proc/swaps", "r"); + char *lineptr = NULL; + size_t s; + + if (!fp) { + fprintf(stderr, "failed to open /proc/swaps\n"); + return -1; + } + while (getline(&lineptr, &s, fp) > 0) + printf(lineptr); + if (lineptr) + free(lineptr); + fclose(fp); + } else if (!strcmp(argv[1], "-a")) { struct blkid_struct_probe *pr; cache_load(0); @@ -638,8 +910,8 @@ static int main_swapon(int argc, char **argv) struct stat s; int err; - if (stat(argv[1], &s) || !S_ISBLK(s.st_mode)) { - fprintf(stderr, "%s is not a block device\n", argv[1]); + if (stat(argv[1], &s) || (!S_ISBLK(s.st_mode) && !S_ISREG(s.st_mode))) { + fprintf(stderr, "%s is not a block device or file\n", argv[1]); return -1; } err = swapon(argv[1], 0); @@ -655,7 +927,7 @@ static int main_swapon(int argc, char **argv) static int main_swapoff(int argc, char **argv) { if (argc != 2) { - fprintf(stderr, "Usage: swapoff [-a] [DEVICE]\n\nStop swapping on DEVICE\n\n\t-a Stop swapping on all swap devices\n"); + fprintf(stderr, "Usage: swapoff [-a] [DEVICE]\n\n\tStop swapping on DEVICE\n -a\tStop swapping on all swap devices\n"); return -1; } @@ -684,8 +956,8 @@ static int main_swapoff(int argc, char **argv) struct stat s; int err; - if (stat(argv[1], &s) || !S_ISBLK(s.st_mode)) { - fprintf(stderr, "%s is not a block device\n", argv[1]); + if (stat(argv[1], &s) || (!S_ISBLK(s.st_mode) && !S_ISREG(s.st_mode))) { + fprintf(stderr, "%s is not a block device or file\n", argv[1]); return -1; } err = swapoff(argv[1]); @@ -702,6 +974,8 @@ int main(int argc, char **argv) { char *base = basename(*argv); + umask(0); + if (!strcmp(base, "swapon")) return main_swapon(argc, argv); @@ -720,9 +994,15 @@ int main(int argc, char **argv) if (!strcmp(argv[1], "extroot")) return main_extroot(argc, argv); + + if (!strcmp(argv[1], "mount")) + return main_mount(argc, argv); + + if (!strcmp(argv[1], "umount")) + return main_umount(argc, argv); } - fprintf(stderr, "Usage: block \n"); + fprintf(stderr, "Usage: block \n"); return -1; }