From patchwork Mon Jun 15 17:45:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: selvamuthukumar v X-Patchwork-Id: 242447 List-Id: U-Boot discussion From: v.selvamuthukumar at gmail.com (Selva Muthukumar) Date: Mon, 15 Jun 2020 23:15:09 +0530 Subject: [PATCH] [RFC] tools: fitmount: fuse mount fit images Message-ID: <20200615174509.12557-1-selva.muthukumar@vvdntech.com> 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 --- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define FUSE_USE_VERSION 26 +#include +#include +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; +}