[PATCH] [RFC] tools: fitmount: fuse mount fit images
Selva Muthukumar
v.selvamuthukumar at gmail.com
Mon Jun 15 19:45:09 CEST 2020
Allow mounting of FIT images. If FIT images are used for firmware upgrade
from linux, mouting can save space in comparison to using dumpimage.
Signed-off-by: Selva Muthukumar <selva.muthukumar at vvdntech.com>
---
tools/Makefile | 5 +-
tools/fitmount.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 258 insertions(+), 1 deletion(-)
create mode 100644 tools/fitmount.c
diff --git a/tools/Makefile b/tools/Makefile
index 081383d7a7..c2c6e952ed 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -53,7 +53,7 @@ HOSTCFLAGS_xway-swap-bytes.o := -pedantic
hostprogs-y += mkenvimage
mkenvimage-objs := mkenvimage.o os_support.o lib/crc32.o
-hostprogs-y += dumpimage mkimage
+hostprogs-y += dumpimage mkimage fitmount
hostprogs-$(CONFIG_FIT_SIGNATURE) += fit_info fit_check_sign
hostprogs-$(CONFIG_CMD_BOOTEFI_SELFTEST) += file2include
@@ -124,6 +124,8 @@ dumpimage-mkimage-objs := aisimage.o \
dumpimage-objs := $(dumpimage-mkimage-objs) dumpimage.o
mkimage-objs := $(dumpimage-mkimage-objs) mkimage.o
fit_info-objs := $(dumpimage-mkimage-objs) fit_info.o
+fitmount-objs := $(dumpimage-mkimage-objs) fitmount.o
+HOSTCFLAGS_fitmount.o += $(shell pkg-config fuse --cflags)
fit_check_sign-objs := $(dumpimage-mkimage-objs) fit_check_sign.o
file2include-objs := file2include.o
@@ -167,6 +169,7 @@ HOSTCFLAGS_fit_image.o += -DMKIMAGE_DTC=\"$(CONFIG_MKIMAGE_DTC_PATH)\"
HOSTLOADLIBES_dumpimage := $(HOSTLOADLIBES_mkimage)
HOSTLOADLIBES_fit_info := $(HOSTLOADLIBES_mkimage)
HOSTLOADLIBES_fit_check_sign := $(HOSTLOADLIBES_mkimage)
+HOSTLOADLIBES_fitmount := $(HOSTLOADLIBES_mkimage) $(shell pkg-config fuse --libs 2> /dev/null || echo "-lfuse")
hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl
hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl
diff --git a/tools/fitmount.c b/tools/fitmount.c
new file mode 100644
index 0000000000..0c52d275c6
--- /dev/null
+++ b/tools/fitmount.c
@@ -0,0 +1,254 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <libfdt.h>
+#include <errno.h>
+#include <image.h>
+#define FUSE_USE_VERSION 26
+#include <fuse/fuse.h>
+#include <fuse/fuse_opt.h>
+struct imginfo {
+ const char *name;
+ const void *data;
+ size_t len;
+};
+static int n_images = 0;
+static struct imginfo *g_imginfo = NULL;
+
+static char *imagefile = NULL;
+static char *mtpt = NULL;
+
+static struct fuse_operations fit_oper;
+enum
+{
+ KEY_HELP,
+};
+static struct fuse_opt fit_opts[] = {
+ FUSE_OPT_KEY("-h", KEY_HELP),
+ FUSE_OPT_KEY("--help", KEY_HELP),
+ FUSE_OPT_END
+};
+
+static void usage(const char *prog)
+{
+ fprintf(stderr, "usage: %s fitimage mountpoint\n", prog);
+}
+
+static struct imginfo* get_img_info(const char *path)
+{
+ int i;
+
+ for(i = 0; i < n_images; i++) {
+ if(strcmp(path, g_imginfo[i].name) == 0)
+ return &g_imginfo[i];
+ }
+ return NULL;
+}
+
+static int fit_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs)
+{
+ (void) data;
+
+ switch( key ) {
+ case FUSE_OPT_KEY_OPT:
+ return 1;
+
+ case FUSE_OPT_KEY_NONOPT:
+ if( !imagefile) {
+ imagefile = strdup(arg);
+ return 0;
+ } else if( !mtpt ) {
+ mtpt = strdup(arg);
+ }
+ return 1;
+
+ case KEY_HELP:
+ usage(outargs->argv[0]);
+ fuse_opt_add_arg(outargs, "-h");
+ fuse_main( outargs->argc, outargs->argv, &fit_oper, NULL);
+ exit(1);
+
+ default:
+ fprintf(stderr, "internal error\n");
+ abort();
+ }
+}
+
+static int fit_getattr(const char *path, struct stat *stbuf)
+{
+ int res = 0;
+ struct imginfo *in;
+
+ memset(stbuf, 0, sizeof(struct stat));
+ if (strcmp(path, "/") == 0) {
+ stbuf->st_mode = S_IFDIR | 0755;
+ stbuf->st_nlink = 2;
+ } else if ((in = get_img_info(path + 1))) {
+ stbuf->st_mode = S_IFREG | 0444;
+ stbuf->st_nlink = 1;
+ stbuf->st_size = in->len;
+ } else
+ res = -ENOENT;
+
+ return res;
+}
+
+static int fit_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+ off_t offset, struct fuse_file_info *fi)
+{
+ (void) offset;
+ int i;
+
+ if (strcmp(path, "/") != 0)
+ return -ENOENT;
+
+ filler(buf, ".", NULL, 0);
+ filler(buf, "..", NULL, 0);
+ for(i = 0; i < n_images; i++)
+ filler(buf, g_imginfo[i].name, NULL, 0);
+
+ return 0;
+}
+
+static int fit_open(const char *path, struct fuse_file_info *fi)
+{
+ struct imginfo *in;
+
+ if ((in = get_img_info(path+1)) == NULL)
+ return -ENOENT;
+
+ if ((fi->flags & 3) != O_RDONLY)
+ return -EACCES;
+
+ return 0;
+}
+
+static int fit_read(const char *path, char *buf, size_t size, off_t offset,
+ struct fuse_file_info *fi)
+{
+ struct imginfo *in;
+
+ if ((in = get_img_info(path+1)) == NULL)
+ return -ENOENT;
+
+ if (offset < in->len) {
+ if (offset + size > in->len)
+ size = in->len - offset;
+ memcpy(buf, in->data + offset, size);
+ } else
+ size = 0;
+
+ return size;
+}
+
+static struct fuse_operations fit_oper = {
+ .getattr = fit_getattr,
+ .readdir = fit_readdir,
+ .open = fit_open,
+ .read = fit_read,
+};
+
+int main(int argc, char *argv[])
+{
+ int images_noffset;
+ int noffset;
+ int ndepth;
+ int count = 0;
+ int ifd = -1;
+ char *ptr;
+ void *fit;
+ struct stat sbuf;
+ struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+
+ if ( fuse_opt_parse(&args, NULL, fit_opts, fit_opt_proc) == -1)
+ return -1;
+
+ if (imagefile == NULL) {
+ fprintf(stderr, "fitimage missing\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ if (mtpt == NULL) {
+ fprintf(stderr, "mountpoint missing\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ /* check if mtpt is ok and writeable */
+ if( stat( mtpt, &sbuf ) != 0 ) {
+ perror( "Error stat'ing mountpoint" );
+ exit( EXIT_FAILURE );
+ }
+ if( ! S_ISDIR( sbuf.st_mode ) ) {
+ fprintf( stderr, "Problem with mountpoint: %s\n",
+ strerror( ENOTDIR ) );
+ exit( EXIT_FAILURE );
+ }
+
+ ifd = open(imagefile, O_RDONLY);
+ if (ifd < 0) {
+ fprintf(stderr, "%s: Can't open \"%s\": %s\n", argv[0],
+ imagefile, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (fstat(ifd, &sbuf) < 0) {
+ fprintf(stderr, "%s: Can't stat \"%s\": %s\n", argv[0],
+ imagefile, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
+ if (ptr == MAP_FAILED) {
+ fprintf(stderr, "%s: Can't read \"%s\": %s\n", argv[0],
+ imagefile, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (fdt_check_header(ptr)) {
+ fprintf(stderr, "%s: FDT header check fails on \"%s\"\n", argv[0], imagefile);
+ exit(EXIT_FAILURE);
+ }
+
+ fit = ptr;
+
+ if (!fit_check_format(fit)) {
+ fprintf(stderr, "%s: Bad FIT image format \"%s\"\n", argv[0], imagefile);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Find images parent node offset */
+ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+ if (images_noffset < 0) {
+ fprintf(stderr, "%s: Can't find images parent node '%s' (%s)\n",
+ argv[0], FIT_IMAGES_PATH, fdt_strerror(images_noffset));
+ exit(EXIT_FAILURE);
+ }
+
+ /* Avoid any overrun */
+ count = fit_get_subimage_count(fit, images_noffset);
+
+ /* Process its subnodes, extract the desired component from image */
+ for (ndepth = 0, count = 0,
+ noffset = fdt_next_node(fit, images_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node(fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ g_imginfo = realloc(g_imginfo, (count+1) * sizeof(*g_imginfo));
+
+ g_imginfo[count].name = fit_get_name(fit, noffset, NULL);
+ fit_image_get_data(fit, noffset, &g_imginfo[count].data, &g_imginfo[count].len);
+
+ count++;
+ }
+ }
+ n_images = count;
+
+ fuse_main(args.argc, args.argv, &fit_oper, NULL);
+ free(g_imginfo);
+ return 0;
+}
--
2.11.0
More information about the U-Boot
mailing list