support for ubifs overlay
authordaniel <daniel@makrotopia.org>
Mon, 12 May 2014 19:19:11 +0000 (21:19 +0200)
committerdaniel <daniel@makrotopia.org>
Tue, 13 May 2014 04:37:16 +0000 (06:37 +0200)
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
CMakeLists.txt
libfstools/libfstools.h
libfstools/overlay.c
libfstools/ubi.c [new file with mode: 0644]
libfstools/volume.h
mount_root.c

index 8234b44a753b947e84f1c4e1f1e0cc79909c6017..c1e5a09c633a4d2bfee9a97dffd6163e4b3ba5dd 100644 (file)
@@ -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)
index 598196ed5f3a66524bffb8fb3d8c8e15ddacf7ce..f9cafbde126143d63920a7fbf73417fc62560f53 100644 (file)
@@ -22,6 +22,7 @@ enum {
        FS_SNAPSHOT,
        FS_JFFS2,
        FS_DEADCODE,
+       FS_UBIFS,
 };
 
 extern char const *extroot_prefix;
index 06d0bfd3e29490f09e62a7be70f487d18606ba70..e3ee7aea2f653f37fbc2001b1742b7e8dbac0f7c 100644 (file)
@@ -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 (file)
index 0000000..69f6406
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2014 Daniel Golle <daniel@makrotopia.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 <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+
+#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;i<volumes_count;i++) {
+               if (!ubi_volume_match(v, name, ubi_num, i)) {
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+
+static int ubi_volume_find(struct volume *v, char *name)
+{
+       DIR *ubi_dir;
+       struct dirent *ubi_dirent;
+       unsigned int ubi_num;
+       int ret = -1;
+
+       ubi_dir = opendir(ubi_dir_name);
+       /* check for os ubi support */
+       if (!ubi_dir)
+               return ret;
+
+       /* probe ubi devices and volumes */
+       while ((ubi_dirent = readdir(ubi_dir)) != NULL) {
+               if (ubi_dirent->d_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);
index 4fa5641c3b82e8b0b2b4ab207a40bc8685860847..9c679f7fb126665886d59e9399d0930ddca30768 100644 (file)
@@ -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;
index e281c0b9ee978810612dfef2ba8a3718f13f98cc..1df472357db4b033dc75e7e31e1b0d4426f35cd9 100644 (file)
@@ -46,6 +46,7 @@ start(int argc, char *argv[1])
                return ramoverlay();
 
        case FS_JFFS2:
+       case FS_UBIFS:
                mount_overlay();
                break;