[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