Skip to content
Snippets Groups Projects
fdtextract.c 5.02 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jonas Höglund's avatar
    Jonas Höglund committed
    /*
     * dumpimage -- Tool to extract sub images from FIT image.
     *
     * Copyright (C) 2021 IOPSYS Software Solutions AB. All rights reserved.
     *
     * Author: jonas.hoglund@iopsys.eu
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 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.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
     * 02110-1301 USA
     */
    
    #include <stdio.h>
    #include <stdint.h>
    #include <stdlib.h>
    
    #include <stdarg.h>
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    #include <string.h>
    #include <stdbool.h>
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    #include <sys/types.h>
    
    #include <sys/stat.h>
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    #include <fcntl.h>
    #include <unistd.h>
    #include <errno.h>
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    
    #include <libfdt.h>
    #include <fdt.h>
    
    
    #include "util.h"
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    #define FDT_MAGIC_SIZE  4
    #define MAX_VERSION 17
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    #define MAX_PATH_LEN 100
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    #define SHA_256_LEN 32
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    
    
    /* Usage related data. */
    
    static const char usage_synopsis[] = "fdtextract [options] <file>";
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    static const char usage_short_opts[] = "le:o:s:" USAGE_COMMON_SHORT_OPTS;
    
    static struct option const usage_long_opts[] = {
        {"list",            no_argument, NULL, 'l'},
    
    Jonas Höglund's avatar
    Jonas Höglund committed
        {"extract",         a_argument, NULL, 'e'},
    	{"out",             a_argument, NULL, 'o'},
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    	{"hash",            a_argument, NULL, 's'},
    
        USAGE_COMMON_LONG_OPTS
    };
    static const char * const usage_opts_help[] = {
        "List images embedded in FIT",
        "Extract image from FIT",
    
    Jonas Höglund's avatar
    Jonas Höglund committed
        "Output image name",
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    	"Hash of image",
    
        USAGE_COMMON_OPTS_HELP
    };
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    static int list_images(char *buf)
    {
    	int ndepth = 0, count = 0, noffset;
    	const char *name;
    
    
    	/* Find images root node. */
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    	noffset = fdt_path_offset(buf, "/images");
    
    	if (noffset < 0) {
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    		return -1;
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    
    
    	/* Iterate over all images. */
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    	noffset = fdt_next_node(buf, noffset, &ndepth);
    	while (ndepth > 0) {
    		if (ndepth == 1) {
    			name = fdt_get_name(buf, noffset, NULL);
    			printf("[%d]: %s\n", count, name);
    			count++;
    		}
    		noffset = fdt_next_node(buf, noffset, &ndepth);
    	}
    
    static int extract_image(char *buf, char *name, char *out)
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    	char path[MAX_PATH_LEN];
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    	int noffset, fd, count;
    
    	unsigned int data_size, data_offset;
    	const fdt32_t *val;
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    
    	if (!out) {
    		printf("Error: please specify output file name.\n");
    		return -1;
    	}
    
    	snprintf(path, MAX_PATH_LEN, "/images/%s", name);
    	noffset = fdt_path_offset(buf, path);
    	if (noffset < 0) {
    		printf("Error: could not find image: %s.\n", name);
    		return -1;
    	}
    
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    	printf("Extracting %s to %s.\n", name, out);
    
    	/* Get offset of image. Try both relative and absolute offset. */
    	val = fdt_getprop(buf, noffset, "data-offset", NULL);
    	if(val) {
    		/* Relative offset */
    		data_offset = fdt32_to_cpu(*val);
    		data_offset += ((fdt_totalsize(buf) + 3) & ~3);
    	} else {
    		/* Absolute offset */
    		val = fdt_getprop(buf, noffset, "data-position", NULL);
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    		if (!val) {
    			printf("Error: could get offset of image: %s.\n", name);
    			return -1;
    		}
    		data_offset = fdt32_to_cpu(*val);
    
    	}
    
    	/* Size */
    	val = fdt_getprop(buf, noffset, "data-size", NULL);
    	if (!val) {
    		printf("Error: could get size of image: %s.\n", name);
    		return -1;
    	}
    
    	data_size = fdt32_to_cpu(*val);
    
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    	fd = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0666);
    	if (fd < 0) {
    		printf("Error opening output file %s.\n", out);
    		return errno;
    	}
    	count = write(fd, buf + data_offset, data_size);
    	if (count < data_size) {
    		printf("Error writing output file %s.\n", out);
    		return errno;
    	}
    
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    	return 0;
    }
    
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    static int get_hash(char *buf, char *name)
    {
    	char path[MAX_PATH_LEN];
    	int noffset, i;
    	uint8_t *val;
    
    	snprintf(path, MAX_PATH_LEN, "/images/%s/hash-1", name);
    	noffset = fdt_path_offset(buf, path);
    	if (noffset < 0) {
    		printf("Error: could not find image hash: %s.\n", name);
    		return -1;
    	}
    
    	val = (uint8_t *)fdt_getprop(buf, noffset, "value", NULL);
    	for (i=0; i<SHA_256_LEN; i++)
    		printf("%x", val[i]);
    	printf("\n");
    }
    
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    int main(int argc, char *argv[])
    {
    
    	const char *file;
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    	char *buf, *name = NULL, *out = NULL;
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    	bool list = false, extract = false, hash = false;
    
    	size_t len;
    
    
        while ((opt = util_getopt_long()) != EOF) {
            switch (opt) {
            case_USAGE_COMMON_FLAGS
    
            case 'l':
                list = true;
                break;
            case 'e':
                extract = true;
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    			name = optarg;
                break;
            case 'o':
    			out = optarg;
    
    Jonas Höglund's avatar
    Jonas Höglund committed
            case 's':
    			hash = true;
    			name = optarg;
                break;
    
            }
        }
        if (optind != argc - 1)
            usage("missing input filename");
        file = argv[optind];
    
        buf = utilfdt_read(file, &len);
        if (!buf) {
            die("could not read: %s\n", file);
    	}
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    
    
    	if (fdt_check_header(buf)) {
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    		die("Bad header in %s\n", file);
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    
    
    	if (list)
    		list_images(buf);
    
    	if (extract)
    
    		extract_image(buf, name, out);
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    	if (hash)
    		get_hash(buf, name);
    
    
    Jonas Höglund's avatar
    Jonas Höglund committed
    }