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 openwrt-devel@lists.openwrt.org https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel