From d4208f9f9d4e9f268ba1888c1fe879ee73eb7e47 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Mon, 20 Sep 2010 12:16:13 -0700 Subject: remove the notion of "root path"; support mixed flash types (do not merge) Remove the wacky notion of "roots" and "root paths" (those things that look like "FOO:some/path" instead of just "/foo/some/path"). Let each device specify its own table of available partitions and how to mount them (needed for devices that use both MTD/yaffs2 and EMMC/ext4 partitions). Change-Id: I18b0a572a71c5e087e0b7ae11b1774388339bfd1 --- roots.c | 379 +++++++++++++++++++++++++--------------------------------------- 1 file changed, 146 insertions(+), 233 deletions(-) (limited to 'roots.c') diff --git a/roots.c b/roots.c index a510145e5..fb495fede 100644 --- a/roots.c +++ b/roots.c @@ -20,300 +20,213 @@ #include #include #include +#include #include "mtdutils/mtdutils.h" #include "mtdutils/mounts.h" -#include "minzip/Zip.h" #include "roots.h" #include "common.h" +#include "make_ext4fs.h" -typedef struct { - const char *name; - const char *device; - const char *device2; // If the first one doesn't work (may be NULL) - const char *partition_name; - const char *mount_point; - const char *filesystem; -} RootInfo; +static int num_volumes = 0; +static Volume* device_volumes = NULL; -/* Canonical pointers. -xxx may just want to use enums - */ -static const char g_mtd_device[] = "@\0g_mtd_device"; -static const char g_raw[] = "@\0g_raw"; -static const char g_package_file[] = "@\0g_package_file"; -static const char g_ramdisk[] = "@\0g_ramdisk"; - -static RootInfo g_roots[] = { - { "CACHE:", g_mtd_device, NULL, "cache", "/cache", "yaffs2" }, - { "DATA:", g_mtd_device, NULL, "userdata", "/data", "yaffs2" }, - { "MISC:", g_mtd_device, NULL, "misc", NULL, g_raw }, - { "SDCARD:", "/dev/block/mmcblk0p1", "/dev/block/mmcblk0", NULL, "/sdcard", "vfat" }, - { "TMP:", NULL, NULL, NULL, "/tmp", g_ramdisk }, -}; -#define NUM_ROOTS (sizeof(g_roots) / sizeof(g_roots[0])) - -// TODO: for SDCARD:, try /dev/block/mmcblk0 if mmcblk0p1 fails - -static const RootInfo * -get_root_info_for_path(const char *root_path) -{ - const char *c; +void load_volume_table() { + int alloc = 2; + device_volumes = malloc(alloc * sizeof(Volume)); - /* Find the first colon. - */ - c = root_path; - while (*c != '\0' && *c != ':') { - c++; + FILE* fstab = fopen("/etc/recovery.fstab", "r"); + if (fstab == NULL) { + LOGE("failed to open /etc/recovery.fstab (%s)\n", strerror(errno)); + return; } - if (*c == '\0') { - return NULL; - } - size_t len = c - root_path + 1; - size_t i; - for (i = 0; i < NUM_ROOTS; i++) { - RootInfo *info = &g_roots[i]; - if (strncmp(info->name, root_path, len) == 0) { - return info; - } - } - return NULL; -} -/* Takes a string like "SYSTEM:lib" and turns it into a string - * like "/system/lib". The translated path is put in out_buf, - * and out_buf is returned if the translation succeeded. - */ -const char * -translate_root_path(const char *root_path, char *out_buf, size_t out_buf_len) -{ - if (out_buf_len < 1) { - return NULL; - } + char buffer[1024]; + int i; + while (fgets(buffer, sizeof(buffer)-1, fstab)) { + for (i = 0; buffer[i] && isspace(buffer[i]); ++i); + if (buffer[i] == '\0' || buffer[i] == '#') continue; - const RootInfo *info = get_root_info_for_path(root_path); - if (info == NULL || info->mount_point == NULL) { - return NULL; - } + char* original = strdup(buffer); - /* Find the relative part of the non-root part of the path. - */ - root_path += strlen(info->name); // strip off the "root:" - while (*root_path != '\0' && *root_path == '/') { - root_path++; - } + char* mount_point = strtok(buffer+i, " \t\n"); + char* fs_type = strtok(NULL, " \t\n"); + char* device = strtok(NULL, " \t\n"); + // lines may optionally have a second device, to use if + // mounting the first one fails. + char* device2 = strtok(NULL, " \t\n"); - size_t mp_len = strlen(info->mount_point); - size_t rp_len = strlen(root_path); - if (mp_len + 1 + rp_len + 1 > out_buf_len) { - return NULL; + if (mount_point && fs_type && device) { + while (num_volumes >= alloc) { + alloc *= 2; + device_volumes = realloc(device_volumes, alloc*sizeof(Volume)); + } + device_volumes[num_volumes].mount_point = strdup(mount_point); + device_volumes[num_volumes].fs_type = strdup(fs_type); + device_volumes[num_volumes].device = strdup(device); + device_volumes[num_volumes].device2 = + device2 ? strdup(device2) : NULL; + ++num_volumes; + } else { + LOGE("skipping malformed recovery.fstab line: %s\n", original); + } + free(original); } - /* Glue the mount point to the relative part of the path. - */ - memcpy(out_buf, info->mount_point, mp_len); - if (out_buf[mp_len - 1] != '/') out_buf[mp_len++] = '/'; + fclose(fstab); - memcpy(out_buf + mp_len, root_path, rp_len); - out_buf[mp_len + rp_len] = '\0'; - - return out_buf; -} - -static int -internal_root_mounted(const RootInfo *info) -{ - if (info->mount_point == NULL) { - return -1; - } - if (info->filesystem == g_ramdisk) { - return 0; + printf("recovery filesystem table\n"); + printf("=========================\n"); + for (i = 0; i < num_volumes; ++i) { + Volume* v = &device_volumes[i]; + printf(" %d %s %s %s %s\n", i, v->mount_point, v->fs_type, + v->device, v->device2); } + printf("\n"); +} - /* See if this root is already mounted. - */ - int ret = scan_mounted_volumes(); - if (ret < 0) { - return ret; - } - const MountedVolume *volume; - volume = find_mounted_volume_by_mount_point(info->mount_point); - if (volume != NULL) { - /* It's already mounted. - */ - return 0; +Volume* volume_for_path(const char* path) { + int i; + for (i = 0; i < num_volumes; ++i) { + Volume* v = device_volumes+i; + int len = strlen(v->mount_point); + if (strncmp(path, v->mount_point, len) == 0 && + (path[len] == '\0' || path[len] == '/')) { + return v; + } } - return -1; + return NULL; } -int -is_root_path_mounted(const char *root_path) -{ - const RootInfo *info = get_root_info_for_path(root_path); - if (info == NULL) { +int ensure_path_mounted(const char* path) { + Volume* v = volume_for_path(path); + if (v == NULL) { + LOGE("unknown volume for path [%s]\n", path); return -1; } - return internal_root_mounted(info) >= 0; -} -int -ensure_root_path_mounted(const char *root_path) -{ - const RootInfo *info = get_root_info_for_path(root_path); - if (info == NULL) { + int result; + result = scan_mounted_volumes(); + if (result < 0) { + LOGE("failed to scan mounted volumes\n"); return -1; } - int ret = internal_root_mounted(info); - if (ret >= 0) { - /* It's already mounted. - */ + const MountedVolume* mv = + find_mounted_volume_by_mount_point(v->mount_point); + if (mv) { + // volume is already mounted return 0; } - /* It's not mounted. - */ - if (info->device == g_mtd_device) { - if (info->partition_name == NULL) { - return -1; - } -//TODO: make the mtd stuff scan once when it needs to + mkdir(v->mount_point, 0755); // in case it doesn't already exist + + if (strcmp(v->fs_type, "yaffs2") == 0) { + // mount an MTD partition as a YAFFS2 filesystem. mtd_scan_partitions(); - const MtdPartition *partition; - partition = mtd_find_partition_by_name(info->partition_name); + const MtdPartition* partition; + partition = mtd_find_partition_by_name(v->device); if (partition == NULL) { + LOGE("failed to find \"%s\" partition to mount at \"%s\"\n", + v->device, v->mount_point); return -1; } - return mtd_mount_partition(partition, info->mount_point, - info->filesystem, 0); - } + return mtd_mount_partition(partition, v->mount_point, v->fs_type, 0); + } else if (strcmp(v->fs_type, "ext4") == 0 || + strcmp(v->fs_type, "vfat") == 0) { + result = mount(v->device, v->mount_point, v->fs_type, + MS_NOATIME | MS_NODEV | MS_NODIRATIME, ""); + if (result == 0) return 0; + + if (v->device2) { + LOGW("failed to mount %s (%s); trying %s\n", + v->device, strerror(errno), v->device2); + result = mount(v->device2, v->mount_point, v->fs_type, + MS_NOATIME | MS_NODEV | MS_NODIRATIME, ""); + if (result == 0) return 0; + } - if (info->device == NULL || info->mount_point == NULL || - info->filesystem == NULL || - info->filesystem == g_raw || - info->filesystem == g_package_file) { + LOGE("failed to mount %s (%s)\n", v->mount_point, strerror(errno)); return -1; } - mkdir(info->mount_point, 0755); // in case it doesn't already exist - if (mount(info->device, info->mount_point, info->filesystem, - MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) { - if (info->device2 == NULL) { - LOGE("Can't mount %s\n(%s)\n", info->device, strerror(errno)); - return -1; - } else if (mount(info->device2, info->mount_point, info->filesystem, - MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) { - LOGE("Can't mount %s (or %s)\n(%s)\n", - info->device, info->device2, strerror(errno)); - return -1; - } - } - return 0; + LOGE("unknown fs_type \"%s\" for %s\n", v->fs_type, v->mount_point); + return -1; } -int -ensure_root_path_unmounted(const char *root_path) -{ - const RootInfo *info = get_root_info_for_path(root_path); - if (info == NULL) { +int ensure_path_unmounted(const char* path) { + Volume* v = volume_for_path(path); + if (v == NULL) { + LOGE("unknown volume for path [%s]\n", path); return -1; } - if (info->mount_point == NULL) { - /* This root can't be mounted, so by definition it isn't. - */ - return 0; - } -//xxx if TMP: (or similar) just return error - /* See if this root is already mounted. - */ - int ret = scan_mounted_volumes(); - if (ret < 0) { - return ret; + int result; + result = scan_mounted_volumes(); + if (result < 0) { + LOGE("failed to scan mounted volumes\n"); + return -1; } - const MountedVolume *volume; - volume = find_mounted_volume_by_mount_point(info->mount_point); - if (volume == NULL) { - /* It's not mounted. - */ + + const MountedVolume* mv = + find_mounted_volume_by_mount_point(v->mount_point); + if (mv == NULL) { + // volume is already unmounted return 0; } - return unmount_mounted_volume(volume); + return unmount_mounted_volume(mv); } -const MtdPartition * -get_root_mtd_partition(const char *root_path) -{ - const RootInfo *info = get_root_info_for_path(root_path); - if (info == NULL || info->device != g_mtd_device || - info->partition_name == NULL) - { - return NULL; - } - mtd_scan_partitions(); - return mtd_find_partition_by_name(info->partition_name); -} - -int -format_root_device(const char *root) -{ - /* Be a little safer here; require that "root" is just - * a device with no relative path after it. - */ - const char *c = root; - while (*c != '\0' && *c != ':') { - c++; +int format_volume(const char* volume) { + Volume* v = volume_for_path(volume); + if (v == NULL) { + LOGE("unknown volume \"%s\"\n", volume); + return -1; } - if (c[0] != ':' || c[1] != '\0') { - LOGW("format_root_device: bad root name \"%s\"\n", root); + if (strcmp(v->mount_point, volume) != 0) { + LOGE("can't give path \"%s\" to format_volume\n", volume); return -1; } - const RootInfo *info = get_root_info_for_path(root); - if (info == NULL || info->device == NULL) { - LOGW("format_root_device: can't resolve \"%s\"\n", root); + if (ensure_path_unmounted(volume) != 0) { + LOGE("format_volume failed to unmount \"%s\"\n", v->mount_point); return -1; } - if (info->mount_point != NULL) { - /* Don't try to format a mounted device. - */ - int ret = ensure_root_path_unmounted(root); - if (ret < 0) { - LOGW("format_root_device: can't unmount \"%s\"\n", root); - return ret; - } - } - /* Format the device. - */ - if (info->device == g_mtd_device) { + if (strcmp(v->fs_type, "yaffs2") == 0 || strcmp(v->fs_type, "mtd") == 0) { mtd_scan_partitions(); - const MtdPartition *partition; - partition = mtd_find_partition_by_name(info->partition_name); + const MtdPartition* partition = mtd_find_partition_by_name(v->device); if (partition == NULL) { - LOGW("format_root_device: can't find mtd partition \"%s\"\n", - info->partition_name); + LOGE("format_volume: no MTD partition \"%s\"\n", v->device); return -1; } - if (info->filesystem == g_raw || !strcmp(info->filesystem, "yaffs2")) { - MtdWriteContext *write = mtd_write_partition(partition); - if (write == NULL) { - LOGW("format_root_device: can't open \"%s\"\n", root); - return -1; - } else if (mtd_erase_blocks(write, -1) == (off_t) -1) { - LOGW("format_root_device: can't erase \"%s\"\n", root); - mtd_write_close(write); - return -1; - } else if (mtd_write_close(write)) { - LOGW("format_root_device: can't close \"%s\"\n", root); - return -1; - } else { - return 0; - } + + MtdWriteContext *write = mtd_write_partition(partition); + if (write == NULL) { + LOGW("format_volume: can't open MTD \"%s\"\n", v->device); + return -1; + } else if (mtd_erase_blocks(write, -1) == (off_t) -1) { + LOGW("format_volume: can't erase MTD \"%s\"\n", v->device); + mtd_write_close(write); + return -1; + } else if (mtd_write_close(write)) { + LOGW("format_volume: can't close MTD \"%s\"\n", v->device); + return -1; } + return 0; } -//TODO: handle other device types (sdcard, etc.) - LOGW("format_root_device: can't handle non-mtd device \"%s\"\n", root); + + if (strcmp(v->fs_type, "ext4") == 0) { + reset_ext4fs_info(); + int result = make_ext4fs(v->device, NULL, NULL, 0, 0, 0); + if (result != 0) { + LOGE("format_volume: make_extf4fs failed on %s\n", v->device); + return -1; + } + return 0; + } + + LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type); return -1; } -- cgit v1.2.3