From: daniel Date: Mon, 12 May 2014 19:19:11 +0000 (+0200) Subject: support for ubifs overlay X-Git-Url: http://git.openwrt.org/?p=project%2Ffstools.git;a=commitdiff_plain;h=002fcb582d73f6d5c354a7f7d844fe87f07fe9d2 support for ubifs overlay Signed-off-by: Daniel Golle --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 8234b44..c1e5a09 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ ADD_LIBRARY(fstools SHARED libfstools/volume.c libfstools/mtd.c libfstools/mount.c + libfstools/ubi.c libfstools/find.c) TARGET_LINK_LIBRARIES(fstools ubox) INSTALL(TARGETS fstools LIBRARY DESTINATION lib) diff --git a/libfstools/libfstools.h b/libfstools/libfstools.h index 598196e..f9cafbd 100644 --- a/libfstools/libfstools.h +++ b/libfstools/libfstools.h @@ -22,6 +22,7 @@ enum { FS_SNAPSHOT, FS_JFFS2, FS_DEADCODE, + FS_UBIFS, }; extern char const *extroot_prefix; diff --git a/libfstools/overlay.c b/libfstools/overlay.c index 06d0bfd..e3ee7ae 100644 --- a/libfstools/overlay.c +++ b/libfstools/overlay.c @@ -187,14 +187,24 @@ jffs2_switch(int argc, char **argv) ret = -1; } break; - } + case FS_UBIFS: + ret = overlay_mount(v, "ubifs"); + if (ret) + break; + if (mount_move("/tmp", "", "/overlay") || fopivot("/overlay", "/rom")) { + fprintf(stderr, "switching to ubifs failed\n"); + ret = -1; + } + break; + } return ret; } static int overlay_mount_fs(void) { struct volume *v; + char *fstype; if (mkdir("/tmp/overlay", 0755)) { fprintf(stderr, "failed to mkdir /tmp/overlay: %s\n", strerror(errno)); @@ -207,9 +217,17 @@ static int overlay_mount_fs(void) return -1; } - if (mount(v->blk, "/tmp/overlay", "jffs2", MS_NOATIME, NULL)) { - fprintf(stderr, "failed to mount -t jffs2 %s /tmp/overlay: %s\n", - v->blk, strerror(errno)); + fstype = "jffs2"; + + switch (volume_identify(v)) { + case FS_UBIFS: + fstype = "ubifs"; + break; + } + + if (mount(v->blk, "/tmp/overlay", fstype, MS_NOATIME, NULL)) { + fprintf(stderr, "failed to mount -t %s %s /tmp/overlay: %s\n", + fstype, v->blk, strerror(errno)); return -1; } @@ -240,7 +258,7 @@ int mount_overlay(void) return 0; } - fprintf(stderr, "switching to jffs2\n"); + fprintf(stderr, "switching to overlay\n"); if (mount_move("/tmp", "", "/overlay") || fopivot("/overlay", "/rom")) { fprintf(stderr, "switching to jffs2 failed - fallback to ramoverlay\n"); return ramoverlay(); diff --git a/libfstools/ubi.c b/libfstools/ubi.c new file mode 100644 index 0000000..69f6406 --- /dev/null +++ b/libfstools/ubi.c @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2014 Daniel Golle + * + * 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 +#include +#include +#include + +#include "libfstools.h" +#include "volume.h" + +/* could use libubi-tiny instead, but already had the code directly reading + * from sysfs */ +char *ubi_dir_name = "/sys/devices/virtual/ubi"; + +struct ubi_priv { + int ubi_num; + int ubi_volidx; +}; + +static struct driver ubi_driver; + +static unsigned int +read_uint_from_file(char *dirname, char *filename, unsigned int *i) +{ + FILE *f; + char fname[128]; + int ret = -1; + + snprintf(fname, sizeof(fname), "%s/%s", dirname, filename); + + f = fopen(fname, "r"); + if (!f) + return ret; + + if (fscanf(f, "%u", i) == 1) + ret = 0; + + fclose(f); + return ret; +} + +static char +*read_string_from_file(char *dirname, char *filename) +{ + FILE *f; + char fname[128]; + char buf[128]; + int i; + char *str; + + snprintf(fname, sizeof(fname), "%s/%s", dirname, filename); + + f = fopen(fname, "r"); + if (!f) + return NULL; + + if (fgets(buf, 128, f) == NULL) + return NULL; + + i = strlen(buf); + do + buf[i--]='\0'; + while (buf[i] == '\n'); + + str = strdup(buf); + fclose(f); + return str; +} + +static unsigned int +test_open(char *filename) +{ + FILE *f; + + f = fopen(filename, "r"); + if (!f) + return 0; + + fclose(f); + return 1; +} + +static int ubi_volume_init(struct volume *v) +{ + char voldir[40], voldev[32], *volname, *voltype; + struct ubi_priv *p; + unsigned int volsize; + + p = (struct ubi_priv*)v->priv; + + snprintf(voldir, sizeof(voldir), "%s/ubi%u/ubi%u_%u", + ubi_dir_name, p->ubi_num, p->ubi_num, p->ubi_volidx); + + snprintf(voldev, sizeof(voldev), "/dev/ubi%u_%u", + p->ubi_num, p->ubi_volidx); + + volname = read_string_from_file(voldir, "name"); + if (!volname) + return -1; + + if (read_uint_from_file(voldir, "data_bytes", &volsize)) + return -1; + + v->name = volname; + v->type = UBIVOLUME; + v->size = volsize; + v->blk = strdup(voldev); + + return 0; +} + + +static int ubi_volume_match(struct volume *v, char *name, int ubi_num, int volidx) +{ + char voldir[40], volblkdev[40], *volname; + struct ubi_priv *p; + + snprintf(voldir, sizeof(voldir), "%s/ubi%u/ubi%u_%u", + ubi_dir_name, ubi_num, ubi_num, volidx); + + snprintf(volblkdev, sizeof(volblkdev), "/dev/ubiblock%u_%u", + ubi_num, volidx); + + /* skip if ubiblock device exists */ + if (test_open(volblkdev)) + return -1; + + volname = read_string_from_file(voldir, "name"); + + if (strncmp(name, volname, strlen(volname))) + return -1; + + p = calloc(1, sizeof(struct ubi_priv)); + if (!p) + return -1; + + v->priv = p; + v->drv = &ubi_driver; + p->ubi_num = ubi_num; + p->ubi_volidx = volidx; + + return ubi_volume_init(v); +} + +static int ubi_part_match(struct volume *v, char *name, unsigned int ubi_num) +{ + unsigned int i, volumes_count; + char devdir[80]; + + snprintf(devdir, sizeof(devdir), "%s/ubi%u", + ubi_dir_name, ubi_num); + + if (read_uint_from_file(devdir, "volumes_count", &volumes_count)) + return -1; + + for (i=0;id_name[0] == '.') + continue; + + sscanf(ubi_dirent->d_name, "ubi%u", &ubi_num); + if (!ubi_part_match(v, name, ubi_num)) { + ret = 0; + break; + }; + } + closedir(ubi_dir); + return ret; +} + +static int ubi_volume_identify(struct volume *v) +{ + return FS_UBIFS; +} + +static struct driver ubi_driver = { + .name = "ubi", + .find = ubi_volume_find, + .init = ubi_volume_init, + .identify = ubi_volume_identify, +}; + +DRIVER(ubi_driver); diff --git a/libfstools/volume.h b/libfstools/volume.h index 4fa5641..9c679f7 100644 --- a/libfstools/volume.h +++ b/libfstools/volume.h @@ -29,8 +29,7 @@ typedef int (*volume_erase_t)(struct volume *v, int start, int len); typedef int (*volume_erase_all_t)(struct volume *v); struct driver { - struct list_head list; - + struct list_head list; char *name; volume_probe_t probe; volume_init_t init; diff --git a/mount_root.c b/mount_root.c index e281c0b..1df4723 100644 --- a/mount_root.c +++ b/mount_root.c @@ -46,6 +46,7 @@ start(int argc, char *argv[1]) return ramoverlay(); case FS_JFFS2: + case FS_UBIFS: mount_overlay(); break;