for all features, make sure CONFIG_MTD_UBI=y CONFIG_MTD_UBI_GLUEBI=y CONFIG_UBIFS_FS=y are set on the target.
ubi helpers for fs-state, drafted as stand-alone user-land tool.
This depends on the bluebi-sysfs kernel patch to detect gluebi<->ubi
mapping, but works without that feature on systems without the patch
or without any gluebi support.
filesystem and volume information detection can now be carried out
by libblkid-tiny's ubifs support and easily be associated with the
matching ubi volumes.
root@OpenWrt:/# ubi
read-write UBI partition
mtd device: '/dev/mtd1'
ubi device: '/dev/ubi0'
=====
read-write volume
ubi device: '/dev/ubi0_0'
gluebi emumlated mtd device: '/dev/mtd2'
volume name: 'rollback'
parent ubi device name: '/dev/ubi0'
parent mtd device: '/dev/mtd1'
=====
read-write volume
ubi device: '/dev/ubi0_1'
gluebi emumlated mtd device: '/dev/mtd3'
volume name: 'factory'
parent ubi device name: '/dev/ubi0'
parent mtd device: '/dev/mtd1'
=====
read-write volume
ubi device: '/dev/ubi0_2'
gluebi emumlated mtd device: '/dev/mtd4'
volume name: 'rootfs'
parent ubi device name: '/dev/ubi0'
parent mtd device: '/dev/mtd1'
=====
read-write volume
ubi device: '/dev/ubi0_3'
gluebi emumlated mtd device: '/dev/mtd5'
volume name: 'rootfs_data'
parent ubi device name: '/dev/ubi0'
parent mtd device: '/dev/mtd1'
=====
root@OpenWrt:/# ubi /dev/ubi0_2
/dev/mtd1
/dev/ubi0
/dev/ubi0_2
/dev/mtd4
root@OpenWrt:/# ubi ubi0:rootfs
/dev/mtd1
/dev/ubi0
/dev/ubi0_2
/dev/mtd4
root@OpenWrt:/# ubi /dev/mtd1
/dev/ubi0
root@OpenWrt:/# ubi /dev/mtd3
/dev/ubi0_1
root@OpenWrt:/# ubi /dev/mtdblock5
/dev/ubi0_3
---
package/utils/ubiprobe/Makefile | 32 +++
package/utils/ubiprobe/src/Makefile | 8 +
package/utils/ubiprobe/src/ubi.c | 486 ++++++++++++++++++++++++++++++++++++
3 files changed, 526 insertions(+)
create mode 100644 package/utils/ubiprobe/Makefile
create mode 100644 package/utils/ubiprobe/src/Makefile
create mode 100644 package/utils/ubiprobe/src/ubi.c
diff --git a/package/utils/ubiprobe/Makefile b/package/utils/ubiprobe/Makefile
new file mode 100644
index 0000000..622f631
--- /dev/null
+++ b/package/utils/ubiprobe/Makefile
@@ -0,0 +1,32 @@
+# Copyright (C) 2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ubiprobe
+PKG_RELEASE:=1
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/ubiprobe
+ SECTION:=utils
+ CATEGORY:=Utilities
+ TITLE:=ubi probe tool
+ DEPENDS:=+libubox
+endef
+
+define Build/Prepare
+ mkdir -p $(PKG_BUILD_DIR)
+ $(CP) ./src/* $(PKG_BUILD_DIR)/
+endef
+
+define Package/ubiprobe/install
+ $(INSTALL_DIR) $(1)/usr/bin/
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/ubi $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,ubiprobe))
diff --git a/package/utils/ubiprobe/src/Makefile
b/package/utils/ubiprobe/src/Makefile
new file mode 100644
index 0000000..3c04b31
--- /dev/null
+++ b/package/utils/ubiprobe/src/Makefile
@@ -0,0 +1,8 @@
+ubi: ubi.o
+ $(CC) $(LDFLAGS) ubi.o -o ubi
+
+ubi.o: ubi.c
+ $(CC) $(CFLAGS) -c ubi.c
+
+clean:
+ rm *.o ubi
diff --git a/package/utils/ubiprobe/src/ubi.c b/package/utils/ubiprobe/src/ubi.c
new file mode 100644
index 0000000..bbf49c9
--- /dev/null
+++ b/package/utils/ubiprobe/src/ubi.c
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2014 OpenWrt.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 <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+
+#include <libubox/list.h>
+
+/* FS_UBI and FS_UBIFS should be be added to the existing list */
+enum {
+ FS_NONE,
+ FS_UBI,
+ FS_UBIFS,
+};
+
+char *ubi_dir_name = "/sys/devices/virtual/ubi";
+char *mtd_dir_name = "/sys/devices/virtual/mtd";
+
+typedef struct volume volume_t;
+
+struct volume {
+ struct list_head list;
+ char *volname;
+ char *devname;
+ volume_t *parent;
+ int ubi_num;
+ int ubi_volnum;
+ int fs;
+ int readonly;
+ int mtdnum;
+ int gluebimtdnum;
+};
+
+static struct list_head volume_list = LIST_HEAD_INIT(volume_list);
+
+unsigned int
+read_uint_from_file(char *dirname, char *filename, 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, "%d", i) == 1)
+ ret = 0;
+
+ fclose(f);
+ return ret;
+}
+
+char
+*read_string_from_file(char *dirname, char *filename)
+{
+ FILE *f;
+ char fname[128];
+ char buf[128];
+ int ret = -1, 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 = strndup(buf, sizeof(buf));
+ fclose(f);
+ return str;
+}
+
+volume_t
+*ubi_probe_vol(int ubi_num, int volnum)
+{
+ int readonly = 0;
+ char voldir[40], voldev[32], *volname, *voltype;
+ int gluebinum;
+ volume_t *vol;
+
+ snprintf(voldir, sizeof(voldir), "%s/ubi%u/ubi%u_%u",
+ ubi_dir_name, ubi_num, ubi_num, volnum);
+
+ snprintf(voldev, sizeof(voldev), "/dev/ubi%u_%u",
+ ubi_num, volnum);
+
+ vol = malloc(sizeof(volume_t));
+ if (!vol)
+ return NULL;
+
+ vol->devname = strdup(voldev);
+ vol->mtdnum = -1;
+ vol->volname = read_string_from_file(voldir, "name");
+ vol->ubi_num = ubi_num;
+ vol->ubi_volnum = volnum;
+ /* gluebi fake-mtd partition should rather set this as parent */
+ vol->gluebimtdnum = -1;
+
+ voltype = read_string_from_file(voldir, "type");
+ if (voltype != NULL)
+ readonly = (strncmp(voltype, "dynamic", 7) != 0);
+ else
+ readonly = 0;
+
+ vol->readonly = readonly;
+
+ return vol;
+}
+
+volume_t
+*ubi_probe_part(unsigned int ubi_num)
+{
+ unsigned int i, volumes_count, mtd_num;
+ char devdir[80], mtddev[32], ubidev[32];
+ volume_t *mtdvol, *newvol;
+
+ snprintf(devdir, sizeof(devdir), "%s/ubi%u",
+ ubi_dir_name, ubi_num);
+
+ if (read_uint_from_file(devdir, "volumes_count", &volumes_count))
+ return NULL;
+
+ if (read_uint_from_file(devdir, "mtd_num", &mtd_num))
+ return NULL;
+
+ snprintf(mtddev, sizeof(mtddev), "/dev/mtd%u", mtd_num);
+ snprintf(ubidev, sizeof(ubidev), "/dev/ubi%u", ubi_num);
+
+ mtdvol = malloc(sizeof(volume_t));
+ mtdvol->devname = strdup(ubidev);
+ mtdvol->volname = NULL;
+ mtdvol->fs = FS_UBI;
+ mtdvol->parent = NULL; /* should be corresponding mtd volume */
+ mtdvol->readonly = 0; /* should be inherited from mtd volume */
+ mtdvol->ubi_num = ubi_num;
+ mtdvol->ubi_volnum = -1;
+ mtdvol->mtdnum = mtd_num;
+ /* see above */
+ mtdvol->gluebimtdnum = -1;
+
+ list_add_tail(&mtdvol->list, &volume_list);
+
+ /* probe volumes */
+ for (i=0;i<volumes_count;i++) {
+ newvol = ubi_probe_vol(ubi_num, i);
+ if (!newvol) break;
+ newvol->parent = mtdvol;
+ list_add_tail(&newvol->list, &volume_list);
+ }
+
+ return newvol;
+}
+
+volume_t
+*volume_lookup(unsigned int ubi_num, unsigned int vol_id)
+{
+ volume_t *vol;
+
+ list_for_each_entry(vol, &volume_list, list) {
+ if (vol->ubi_num == ubi_num && vol->ubi_volnum == vol_id)
+ return vol;
+ }
+ return NULL;
+}
+
+int
+mtd_probe_gluebi(unsigned int mtd_num)
+{
+ char mtddevdir[80];
+ unsigned int ubi_num, vol_id;
+ volume_t *vol;
+
+ snprintf(mtddevdir, sizeof(mtddevdir), "%s/mtd%u", mtd_dir_name,
mtd_num);
+
+ if (read_uint_from_file(mtddevdir, "gluebi_ubi_num", &ubi_num))
+ return -1;
+
+ if (read_uint_from_file(mtddevdir, "gluebi_vol_id", &vol_id))
+ return -1;
+
+ vol = volume_lookup(ubi_num, vol_id);
+ if (!vol)
+ return -1;
+
+ vol->gluebimtdnum = mtd_num;
+
+ return 0;
+}
+
+void
+ubi_probe()
+{
+ DIR *ubi_dir, *mtd_dir;
+ struct dirent *ubi_dirent, *mtd_dirent;
+ unsigned int ubi_num, mtd_num;
+ volume_t *newvol, *prevvol = NULL;
+ int numdevs = 0;
+ size_t len;
+
+ ubi_dir = opendir(ubi_dir_name);
+ /* check for os ubi support */
+ if (!ubi_dir)
+ return;
+
+ /* 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);
+ ubi_probe_part(ubi_num);
+ numdevs++;
+ }
+ closedir(ubi_dir);
+
+ /* no need to probe for gluebi if there is no ubi */
+ if (numdevs <= 0)
+ return;
+
+ mtd_dir = opendir(mtd_dir_name);
+ /* check for os mtd support (ubi but no mtd?!) */
+ if (!mtd_dir)
+ return;
+
+ /* probe gluebi mtd devices */
+ while ((mtd_dirent = readdir(mtd_dir)) != NULL) {
+ len = strlen(mtd_dirent->d_name);
+ /* skip /dev/mtd/.* and /dev/mtd*ro entries */
+ if (mtd_dirent->d_name[0] == '.' ||
+ mtd_dirent->d_name[len-1] == 'o')
+ continue;
+
+ sscanf(mtd_dirent->d_name, "mtd%u", &mtd_num);
+ mtd_probe_gluebi(mtd_num);
+ }
+
+ closedir(mtd_dir);
+}
+
+volume_t
+*ubi_lookup(char *arg)
+{
+ unsigned int ubi_num, ubi_volnum;
+ char *tmp, *volname, *volnum_s;
+ volume_t *vol;
+
+ /* both /dev/ubi0 and /dev/ubi0_1 syntax */
+ if (strncmp("/dev/", arg, 5) == 0) {
+ list_for_each_entry(vol, &volume_list, list)
+ if (vol->devname &&
+ (strcmp(vol->devname, arg) == 0))
+ return vol;
+ }
+
+ /* ubi0:rootfs on / type ubifs (rw,noatime) */
+ if (strncmp("ubi", arg, 3) == 0) {
+ volname = strchr(arg, ':');
+ volnum_s = strchr(arg, '_');
+ sscanf(arg, "ubi%u", &ubi_num);
+ if (volname && volname[0] != '\0') {
+ volname++;
+ list_for_each_entry(vol, &volume_list, list)
+ if (ubi_num == vol->ubi_num && vol->volname &&
+ (strcmp(vol->volname, volname) == 0))
+ return vol;
+ } else if (volnum_s && volnum_s[0] != '\0') {
+ volnum_s++;
+ sscanf(volnum_s, "%u", &ubi_volnum);
+ list_for_each_entry(vol, &volume_list, list)
+ if (ubi_num == vol->ubi_num &&
+ vol->ubi_volnum == ubi_volnum)
+ return vol;
+ } else {
+ list_for_each_entry(vol, &volume_list, list)
+ if (ubi_num == vol->ubi_num &&
+ vol->fs == FS_UBI)
+ return vol;
+ }
+ }
+
+ /* volume name only, e.g. rootfs_data */
+ list_for_each_entry(vol, &volume_list, list)
+ if (vol->volname && (strcmp(vol->volname, arg) == 0))
+ return vol;
+
+ return NULL;
+}
+
+volume_t
+*mtd_lookup(char *arg)
+{
+ volume_t *vol;
+ char blockdev_s[40], mtddev_s[40];
+
+ list_for_each_entry(vol, &volume_list, list) {
+ if (vol->mtdnum >= 0 && vol->fs == FS_UBI) {
+ snprintf(blockdev_s, sizeof(blockdev_s), "/dev/mtdblock%u",
vol->mtdnum);
+ snprintf(mtddev_s, sizeof(mtddev_s), "/dev/mtd%u",
vol->mtdnum);
+ if(strncmp(blockdev_s, arg, sizeof(blockdev_s)) == 0 ||
+ strncmp(mtddev_s, arg, sizeof(mtddev_s)) == 0)
+ return vol;
+ }
+ }
+ return NULL;
+}
+
+volume_t
+*gluebi_lookup(char *arg)
+{
+ volume_t *vol;
+ char blockdev_s[40], mtddev_s[40];
+
+ list_for_each_entry(vol, &volume_list, list) {
+ if (vol->gluebimtdnum >= 0) {
+ snprintf(blockdev_s, sizeof(blockdev_s), "/dev/mtdblock%u",
vol->gluebimtdnum);
+ snprintf(mtddev_s, sizeof(mtddev_s), "/dev/mtd%u",
vol->gluebimtdnum);
+ if(strncmp(blockdev_s, arg, sizeof(blockdev_s)) == 0 ||
+ strncmp(mtddev_s, arg, sizeof(mtddev_s)) == 0)
+ return vol;
+ }
+ }
+ return NULL;
+}
+
+void
+gluebi_find_vol(char *arg)
+{
+ volume_t *vol = gluebi_lookup(arg);
+ if (!vol)
+ return;
+
+ if (vol->devname)
+ printf("%s\n", vol->devname);
+}
+
+void
+ubi_find_gluebi(char *arg)
+{
+ volume_t *vol = ubi_lookup(arg);
+ if (!vol)
+ return;
+
+ if (vol->gluebimtdnum >= 0)
+ printf("/dev/mtd%u\n", vol->gluebimtdnum);
+}
+
+void
+ubi_find_mtddev(char *arg)
+{
+ volume_t *vol = ubi_lookup(arg);
+ if (!vol)
+ return;
+
+ if (vol->mtdnum >= 0)
+ printf("/dev/mtd%u\n", vol->mtdnum);
+ else if (vol->parent && vol->parent->mtdnum >= 0)
+ printf("/dev/mtd%u\n", vol->parent->mtdnum);
+ return;
+}
+
+void
+ubi_find_voldev(char *arg)
+{
+ volume_t *vol = ubi_lookup(arg);
+ if (!vol)
+ return;
+
+ if (vol->devname && vol->fs != FS_UBI)
+ printf("%s\n", vol->devname);
+}
+
+void
+ubi_find_ubidev(char *arg)
+{
+ volume_t *vol = ubi_lookup(arg);
+ if (!vol)
+ return;
+
+ if (vol->devname && vol->fs == FS_UBI)
+ printf("%s\n", vol->devname);
+ else if (vol->parent && vol->parent->devname &&
+ vol->parent->fs == FS_UBI )
+ printf("%s\n", vol->parent->devname);
+}
+
+
+void mtd_find_ubidev(char *arg)
+{
+ volume_t *vol = mtd_lookup(arg);
+ if (!vol)
+ return;
+
+ if (vol->devname)
+ printf("%s\n", vol->devname);
+}
+
+void
+ubi_print_volume(volume_t *vol)
+{
+ printf("read-%s", vol->readonly?"only ":"write ");
+
+ switch (vol->fs) {
+ case FS_UBI:
+ printf("UBI partition\n");
+ break;
+ ;;
+ case FS_UBIFS:
+ printf("UBIFS\n");
+ break;
+ ;;
+ default:
+ printf("volume\n");
+ }
+
+ if (vol->mtdnum >= 0)
+ printf(" mtd device: '/dev/mtd%u'\n", vol->mtdnum);
+
+ if (vol->devname)
+ printf(" ubi device: '%s'\n", vol->devname);
+
+ if (vol->gluebimtdnum >= 0)
+ printf(" gluebi emumlated mtd device: '/dev/mtd%u'\n",
vol->gluebimtdnum);
+
+ if (vol->volname)
+ printf(" volume name: '%s'\n", vol->volname);
+
+ if (vol->parent) {
+ if (vol->parent->devname)
+ printf(" parent ubi device name: '%s'\n",
vol->parent->devname);
+ if (vol->parent->mtdnum >= 0)
+ printf(" parent mtd device: '/dev/mtd%u'\n",
vol->parent->mtdnum);
+ }
+}
+
+void
+ubi_print_list()
+{
+ volume_t *vol;
+ list_for_each_entry(vol, &volume_list, list) {
+ ubi_print_volume(vol);
+ printf("=====\n");
+ }
+}
+
+int
+main(int args, char *argv[])
+{
+ ubi_probe();
+ if ( args < 2 ) {
+ ubi_print_list();
+ } else if ( args == 2 ) {
+ ubi_find_mtddev(argv[1]);
+ ubi_find_ubidev(argv[1]);
+ mtd_find_ubidev(argv[1]);
+ ubi_find_voldev(argv[1]);
+ gluebi_find_vol(argv[1]);
+ ubi_find_gluebi(argv[1]);
+ } else {
+ return 1;
+ }
+ return 0;
+}
--
1.9.0
pgpig9RGyL2yc.pgp
Description: PGP signature
_______________________________________________ openwrt-devel mailing list [email protected] https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
