Message ID | 20200615174509.12557-1-selva.muthukumar@vvdntech.com |
---|---|
State | New |
Headers | show |
Series | [RFC] tools: fitmount: fuse mount fit images | expand |
On Mon, Jun 15, 2020 at 11:15 PM Selva Muthukumar <v.selvamuthukumar at gmail.com> wrote: > > Allow mounting of FIT images. If FIT images are used for firmware upgrade > from linux, mouting can save space in comparison to using dumpimage. > Any comments on this? Is there any other way to get FIT image contents, without extracting it? Thanks, Selva
On Tue, Jun 23, 2020 at 06:01:38PM +0530, selvamuthukumar v wrote: > On Mon, Jun 15, 2020 at 11:15 PM Selva Muthukumar > <v.selvamuthukumar at gmail.com> wrote: > > > > Allow mounting of FIT images. If FIT images are used for firmware upgrade > > from linux, mouting can save space in comparison to using dumpimage. > > > > Any comments on this? Is there any other way to get FIT image > contents, without extracting it? Sorry for the delay. For your program, there's a few things such as missing license header and being able to opt-in as otherwise we add a new build dependency for everyone. For getting FIT image contents, the existing dumpimage tool handles this. What is missing and would be greatly appreciated is updating some documentation to include what's described in: commit 39931f966adaeadd66dc7a905f7dddb93f66bac3 Author: Guilherme Maciel Ferreira <guilherme.maciel.ferreira at gmail.com> Date: Thu Jan 15 02:54:42 2015 -0200 dumpimage: fit: extract FIT images to be much more visible. What's documented there works today but I had to double check how myself as it's not as visible as it should be. Thanks!
On Tue, Jun 23, 2020 at 11:47 PM Tom Rini <trini at konsulko.com> wrote: > > On Tue, Jun 23, 2020 at 06:01:38PM +0530, selvamuthukumar v wrote: > > On Mon, Jun 15, 2020 at 11:15 PM Selva Muthukumar > > <v.selvamuthukumar at gmail.com> wrote: > > > > > > Allow mounting of FIT images. If FIT images are used for firmware upgrade > > > from linux, mouting can save space in comparison to using dumpimage. > > > > > > > Any comments on this? Is there any other way to get FIT image > > contents, without extracting it? > > Sorry for the delay. For your program, there's a few things such as > missing license header and being able to opt-in as otherwise we add a > new build dependency for everyone. > > For getting FIT image contents, the existing dumpimage tool handles > this. > dumpimage extracts image contents into new files. Current firmware upgrade process in our product is: 1. FIT image has kernel and rootfs. Get new FIT image in tmpfs. 2. dumpimage to extract the FIT image in tmpfs. 3. Write kernel and rootfs in partitions. many times step2 fails because there is not enough space in tmpfs. FIT image and individual components need to be present in tmpfs. When we mount the FIT image, it does not take extra space tmpfs. Thanks. Selva
On 24/06/2020 04.50, selvamuthukumar v wrote: > On Tue, Jun 23, 2020 at 11:47 PM Tom Rini <trini at konsulko.com> wrote: >> >> For getting FIT image contents, the existing dumpimage tool handles >> this. >> > dumpimage extracts image contents into new files. Current firmware > upgrade process in our product is: > > 1. FIT image has kernel and rootfs. Get new FIT image in tmpfs. > 2. dumpimage to extract the FIT image in tmpfs. > 3. Write kernel and rootfs in partitions. > > many times step2 fails because there is not enough space in tmpfs. FIT > image and individual components need to be present in tmpfs. When we > mount the FIT image, it does not take extra space tmpfs. But, why do you use a FIT to bundle the kernel and rootfs? Wouldn't a squashfs image be a better container format? Depending on your rootfs image type, that might even cost even less in tmpfs (and transfer to target) than a FIT. I don't have anything against your patch, except as Tom pointed out it really needs to be opt-in so not everybody needs to have libfuse present to build the host tools. Just curious why you've chosen FIT as the container format. Rasmus
On Wed, Jun 24, 2020 at 5:25 PM Rasmus Villemoes <rasmus.villemoes at prevas.dk> wrote: > > On 24/06/2020 04.50, selvamuthukumar v wrote: > > On Tue, Jun 23, 2020 at 11:47 PM Tom Rini <trini at konsulko.com> wrote: > >> > > >> For getting FIT image contents, the existing dumpimage tool handles > >> this. > >> > > dumpimage extracts image contents into new files. Current firmware > > upgrade process in our product is: > > > > 1. FIT image has kernel and rootfs. Get new FIT image in tmpfs. > > 2. dumpimage to extract the FIT image in tmpfs. > > 3. Write kernel and rootfs in partitions. > > > > many times step2 fails because there is not enough space in tmpfs. FIT > > image and individual components need to be present in tmpfs. When we > > mount the FIT image, it does not take extra space tmpfs. > > But, why do you use a FIT to bundle the kernel and rootfs? Wouldn't a > squashfs image be a better container format? Depending on your rootfs > image type, that might even cost even less in tmpfs (and transfer to > target) than a FIT. > Platform is based on OpenWRT which already has the FIT image support. Other than kernel and rootfs FIT image has some more contents, like script to upgrade the image from u-boot > I don't have anything against your patch, except as Tom pointed out it > really needs to be opt-in so not everybody needs to have libfuse present > to build the host tools. Just curious why you've chosen FIT as the > container format. > I can make this tool as a configurable option.
On Wed, Jun 24, 2020 at 08:20:38AM +0530, selvamuthukumar v wrote: > On Tue, Jun 23, 2020 at 11:47 PM Tom Rini <trini at konsulko.com> wrote: > > > > On Tue, Jun 23, 2020 at 06:01:38PM +0530, selvamuthukumar v wrote: > > > On Mon, Jun 15, 2020 at 11:15 PM Selva Muthukumar > > > <v.selvamuthukumar at gmail.com> wrote: > > > > > > > > Allow mounting of FIT images. If FIT images are used for firmware upgrade > > > > from linux, mouting can save space in comparison to using dumpimage. > > > > > > > > > > Any comments on this? Is there any other way to get FIT image > > > contents, without extracting it? > > > > Sorry for the delay. For your program, there's a few things such as > > missing license header and being able to opt-in as otherwise we add a > > new build dependency for everyone. > > > > For getting FIT image contents, the existing dumpimage tool handles > > this. > > > dumpimage extracts image contents into new files. Current firmware > upgrade process in our product is: > > 1. FIT image has kernel and rootfs. Get new FIT image in tmpfs. > 2. dumpimage to extract the FIT image in tmpfs. > 3. Write kernel and rootfs in partitions. > > many times step2 fails because there is not enough space in tmpfs. FIT > image and individual components need to be present in tmpfs. When we > mount the FIT image, it does not take extra space tmpfs. Ah, so that's your use-case. But in this case, couldn't you use a named pipe instead to stream from the image after step one? Or add a -q option to dumpimage (so it doesn't print anything) and use -o /dev/stdout and pipe that directly to whatever is writing to flash?
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; +}
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