diff options
Diffstat (limited to 'ubi-utils/src/ubinize.c')
-rw-r--r-- | ubi-utils/src/ubinize.c | 549 |
1 files changed, 0 insertions, 549 deletions
diff --git a/ubi-utils/src/ubinize.c b/ubi-utils/src/ubinize.c deleted file mode 100644 index 47dc571..0000000 --- a/ubi-utils/src/ubinize.c +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Copyright (C) 2008 Nokia Corporation - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Generate UBI images. - * - * Authors: Artem Bityutskiy - * Oliver Lohmann - */ - -#include <stdlib.h> -#include <getopt.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <sys/stat.h> - -#include <mtd/ubi-header.h> -#include <libubigen.h> -#include <libiniparser.h> -#include "common.h" - -#define PROGRAM_VERSION "1.5" -#define PROGRAM_NAME "ubinize" - -static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -" - a tool to generate UBI images. An UBI image may contain one or more UBI " -"volumes which have to be defined in the input configuration ini-file. The " -"ini file defines all the UBI volumes - their characteristics and the and the " -"contents, but it does not define the characteristics of the flash the UBI " -"image is generated for. Instead, the flash characteristics are defined via " -"the command-line options. Note, if not sure about some of the command-line " -"parameters, do not specify them and let the utility to use default values."; - -static const char *optionsstr = -"-o, --output=<file name> output file name (default is stdout)\n" -"-p, --peb-size=<bytes> size of the physical eraseblock of the flash\n" -" this UBI image is created for in bytes,\n" -" kilobytes (KiB), or megabytes (MiB)\n" -" (mandatory parameter)\n" -"-m, --min-io-size=<bytes> minimum input/output unit size of the flash\n" -" in bytes\n" -"-s, --sub-page-size=<bytes> minimum input/output unit used for UBI\n" -" headers, e.g. sub-page size in case of NAND\n" -" flash (equivalent to the minimum input/output\n" -" unit size by default)\n" -"-O, --vid-hdr-offset=<num> offset if the VID header from start of the\n" -" physical eraseblock (default is the second\n" -" minimum I/O unit or sub-page, if it was\n" -" specified)\n" -"-e, --erase-counter=<num> the erase counter value to put to EC headers\n" -" (default is 0)\n" -"-x, --ubi-ver=<num> UBI version number to put to EC headers\n" -" (default is 1)\n" -"-v --verbose be verbose\n" -"-h, --help print help message\n" -"-V, --version print program version"; - -static const char *usage = -"Usage: " PROGRAM_NAME " [-o filename] [-h] [-V] [--output=<filename>] [--help]\n" -"\t\t[--version] ini-file\n" -"Example: " PROGRAM_NAME "-o fs.raw cfg.ini"; - -static const char *ini_doc = "INI-file format.\n" -"The input configuration ini-file describes all the volumes which have to\n" -"be included to the output UBI image. Each volume is described in its own\n" -"section which may be named arbitrarily. The section consists on\n" -"\"key=value\" pairs, for example:\n\n" -"[jffs2-volume]\n" -"mode=ubi\n" -"image=../jffs2.img\n" -"vol_id=1\n" -"vol_size=30MiB\n" -"vol_type=dynamic\n" -"vol_name=jffs2_volume\n" -"vol_flags=autoresize\n" -"vol_alignment=1\n\n" -"This example configuration file tells the utility to create an UBI image\n" -"with one volume with ID 1, volume size 30MiB, the volume is dynamic, has\n" -"name \"jffs2_volume\", \"autoresize\" volume flag, and alignment 1. The\n" -"\"image=../jffs2.img\" line tells the utility to take the contents of the\n" -"volume from the \"../jffs2.img\" file. The size of the image file has to be\n" -"less or equivalent to the volume size (30MiB). The \"mode=ubi\" line is\n" -"mandatory and just tells that the section describes an UBI volume - other\n" -"section modes may be added in the future.\n" -"Notes:\n" -" * size in vol_size might be specified kilobytes (KiB), megabytes (MiB),\n" -" gigabytes (GiB) or bytes (no modifier);\n" -" * if \"vol_size\" key is absent, the volume size is assumed to be\n" -" equivalent to the size of the image file (defined by \"image\" key);\n" -" * if the \"image\" is absent, the volume is assumed to be empty;\n" -" * volume alignment must not be greater than the logical eraseblock size;\n" -" * one ini file may contain arbitrary number of sections, the utility will\n" -" put all the volumes which are described by these section to the output\n" -" UBI image file."; - -struct option long_options[] = { - { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, - { .name = "peb-size", .has_arg = 1, .flag = NULL, .val = 'p' }, - { .name = "min-io-size", .has_arg = 1, .flag = NULL, .val = 'm' }, - { .name = "sub-page-size", .has_arg = 1, .flag = NULL, .val = 's' }, - { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' }, - { .name = "erase-counter", .has_arg = 1, .flag = NULL, .val = 'e' }, - { .name = "ubi-ver", .has_arg = 1, .flag = NULL, .val = 'x' }, - { .name = "verbose", .has_arg = 1, .flag = NULL, .val = 'v' }, - { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, - { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, - { NULL, 0, NULL, 0} -}; - -struct args { - const char *f_in; - const char *f_out; - FILE *fp_out; - int peb_size; - int min_io_size; - int subpage_size; - int vid_hdr_offs; - int ec; - int ubi_ver; - int verbose; - dictionary *dict; -}; - -static struct args args = { - .f_out = NULL, - .peb_size = -1, - .min_io_size = -1, - .subpage_size = -1, - .vid_hdr_offs = 0, - .ec = 0, - .ubi_ver = 1, - .verbose = 0, -}; - -static int parse_opt(int argc, char * const argv[]) -{ - while (1) { - int key; - char *endp; - - key = getopt_long(argc, argv, "o:p:m:s:O:e:x:vhV", long_options, NULL); - if (key == -1) - break; - - switch (key) { - case 'o': - args.fp_out = fopen(optarg, "wb"); - if (!args.fp_out) - return errmsg("cannot open file \"%s\"", optarg); - args.f_out = optarg; - break; - - case 'p': - args.peb_size = ubiutils_get_bytes(optarg); - if (args.peb_size <= 0) - return errmsg("bad physical eraseblock size: \"%s\"", optarg); - break; - - case 'm': - args.min_io_size = ubiutils_get_bytes(optarg); - if (args.min_io_size <= 0) - return errmsg("bad min. I/O unit size: \"%s\"", optarg); - break; - - case 's': - args.subpage_size = ubiutils_get_bytes(optarg); - if (args.subpage_size <= 0) - return errmsg("bad sub-page size: \"%s\"", optarg); - break; - - case 'O': - args.vid_hdr_offs = strtoul(optarg, &endp, 0); - if (endp == optarg || args.vid_hdr_offs < 0) - return errmsg("bad VID header offset: \"%s\"", optarg); - break; - - case 'e': - args.ec = strtoul(optarg, &endp, 0); - if (endp == optarg || args.ec < 0) - return errmsg("bad erase counter value: \"%s\"", optarg); - break; - - case 'x': - args.ubi_ver = strtoul(optarg, &endp, 0); - if (endp == optarg || args.ubi_ver < 0) - return errmsg("bad UBI version: \"%s\"", optarg); - break; - - case 'v': - args.verbose = 1; - break; - - case 'h': - ubiutils_print_text(stderr, doc, 80); - fprintf(stderr, "\n%s\n\n", ini_doc); - fprintf(stderr, "%s\n", usage); - fprintf(stderr, "%s\n", optionsstr); - exit(EXIT_SUCCESS); - - case 'V': - fprintf(stderr, "%s\n", PROGRAM_VERSION); - exit(EXIT_SUCCESS); - - default: - fprintf(stderr, "Use -h for help\n"); - return -1; - } - } - - if (optind == argc) - return errmsg("input PFI file was not specified (use -h for help)"); - - if (optind != argc - 1) - return errmsg("more then one input PFI file was specified (use -h for help)"); - - args.f_in = argv[optind]; - - if (args.peb_size < 0) - return errmsg("physical eraseblock size was not specified (use -h for help)"); - - if (args.min_io_size < 0) - return errmsg("min. I/O unit size was not specified (use -h for help)"); - - if (args.subpage_size < 0) - args.subpage_size = args.min_io_size; - - if (!args.f_out) { - args.f_out = "stdout"; - args.fp_out = stdout; - } - - return 0; -} - -int read_section(const char *sname, struct ubigen_vol_info *vi, - const char **img) -{ - char buf[256]; - const char *p; - - *img = NULL; - - if (strlen(sname) > 128) - return errmsg("too long section name \"%s\"", sname); - - /* Make sure mode is UBI, otherwise ignore this section */ - sprintf(buf, "%s:mode", sname); - p = iniparser_getstring(args.dict, buf, NULL); - if (!p) { - errmsg("\"mode\" key not found in section \"%s\"", sname); - errmsg("the \"mode\" key is mandatory and has to be " - "\"mode=ubi\" if the section describes an UBI volume"); - return -1; - } - - /* If mode is not UBI, skip this section */ - if (strcmp(p, "ubi")) { - verbose(args.verbose, "skip non-ubi section \"%s\"", sname); - return 1; - } - - verbose(args.verbose, "mode=ubi, keep parsing"); - - /* Fetch the name of the volume image file */ - sprintf(buf, "%s:image", sname); - p = iniparser_getstring(args.dict, buf, NULL); - if (p) - *img = p; - - /* Fetch volume id */ - sprintf(buf, "%s:vol_id", sname); - vi->id = iniparser_getint(args.dict, buf, -1); - if (vi->id == -1) - return errmsg("\"vol_id\" key not found in section \"%s\"", sname); - - if (vi->id < 0) - return errmsg("negative volume ID %d", vi->id); - - if (vi->id >= UBI_MAX_VOLUMES) - return errmsg("too high volume ID %d, max. is %d", vi->id, UBI_MAX_VOLUMES); - - verbose(args.verbose, "volume ID: %d", vi->id); - - /* Fetch volume size */ - sprintf(buf, "%s:vol_size", sname); - p = iniparser_getstring(args.dict, buf, NULL); - if (p) { - vi->bytes = ubiutils_get_bytes(p); - if (vi->bytes <= 0) - return errmsg("bad \"vol_size\" key: \"%s\"", p); - - verbose(args.verbose, "volume size: %lld bytes", vi->bytes); - } else { - struct stat st; - - if (!*img) - return errmsg("neither image file (\"image=\") nor volume size (\"vol_size=\") specified"); - - if (stat(*img, &st)) - return sys_errmsg("cannot stat \"%s\"", *img); - - vi->bytes = st.st_size; - - if (vi->bytes == 0) - return errmsg("file \"%s\" referred from section \"%s\" is empty", *img, sname); - - printf(PROGRAM_NAME ": volume size was not specified in" - "section \"%s\", assume ", sname); - ubiutils_print_bytes(vi->bytes, 1); - printf("\n"); - } - - /* Fetch volume type */ - sprintf(buf, "%s:vol_type", sname); - p = iniparser_getstring(args.dict, buf, NULL); - if (!p) { - normsg(": volume type was not specified in " - "section \"%s\", assume \"dynamic\"\n", sname); - vi->type = UBI_VID_DYNAMIC; - } else { - if (!strcmp(p, "static")) - vi->type = UBI_VID_STATIC; - else if (!strcmp(p, "dynamic")) - vi->type = UBI_VID_DYNAMIC; - else - return errmsg("invalid volume type \"%s\"", p); - } - - verbose(args.verbose, "volume type: %s", - vi->type == UBI_VID_DYNAMIC ? "dynamic" : "static"); - - /* Fetch volume name */ - sprintf(buf, "%s:vol_name", sname); - p = iniparser_getstring(args.dict, buf, NULL); - if (!p) - return errmsg("\"vol_name\" key not found in section \"%s\"", sname); - - vi->name = p; - vi->name_len = strlen(p); - if (vi->name_len > UBI_VOL_NAME_MAX) - return errmsg("too long volume name in section \"%s\", max. is %d characters", - vi->name, UBI_VOL_NAME_MAX); - - verbose(args.verbose, "volume name: %s", p); - - /* Fetch volume alignment */ - sprintf(buf, "%s:vol_alignment", sname); - vi->alignment = iniparser_getint(args.dict, buf, -1); - if (vi->alignment == -1) { - normsg("volume alignment was not specified in section " - "\"%s\", assume 1", sname); - vi->alignment = 1; - } else if (vi->id < 0) - return errmsg("negative volume alignement %d", vi->alignment); - - verbose(args.verbose, "volume alignment: %d", vi->alignment); - - /* Fetch volume flags */ - sprintf(buf, "%s:vol_flags", sname); - p = iniparser_getstring(args.dict, buf, NULL); - if (p) { - if (!strcmp(p, "autoresize")) { - verbose(args.verbose, "autoresize flags found"); - vi->flags |= UBI_VTBL_AUTORESIZE_FLG; - } else { - return errmsg("unknown flags \"%s\" in section \"%s\"", p, sname); - } - } - - return 0; -} - -static void init_vol_info(const struct ubigen_info *ui, - struct ubigen_vol_info *vi) -{ - vi->data_pad = ui->leb_size % vi->alignment; - vi->usable_leb_size = ui->leb_size - vi->data_pad; - vi->used_ebs = (vi->bytes + vi->usable_leb_size - 1) / vi->usable_leb_size; - vi->compat = 0; -} - -int main(int argc, char * const argv[]) -{ - int err = -1, sects, i, volumes; - struct ubigen_info ui; - struct ubi_vtbl_record *vtbl; - - err = parse_opt(argc, argv); - if (err) - return -1; - - ubigen_info_init(&ui, args.peb_size, args.min_io_size, - args.subpage_size, args.vid_hdr_offs, - args.ubi_ver, args.ec); - - verbose(args.verbose, "LEB size: %d", ui.leb_size); - verbose(args.verbose, "PEB size: %d", ui.peb_size); - verbose(args.verbose, "min_io_size: %d", ui.min_io_size); - verbose(args.verbose, "VID offset: %d", ui.vid_hdr_offs); - - vtbl = ubigen_create_empty_vtbl(&ui); - if (!vtbl) - goto out; - - args.dict = iniparser_load(args.f_in); - if (!args.dict) { - errmsg("cannot load the input ini file \"%s\"", args.f_in); - goto out_vtbl; - } - - verbose(args.verbose, "loaded the ini-file \"%s\"", args.f_in); - - /* Each section describes one volume */ - sects = iniparser_getnsec(args.dict); - if (sects == -1) { - errmsg("ini-file parsing error (iniparser_getnsec)"); - goto out_dict; - } - - verbose(args.verbose, "count of sections: %d", sects); - if (sects == 0) { - errmsg("no sections found the ini-file \"%s\"", args.f_in); - goto out_dict; - } - - /* - * Skip 2 PEBs at the beginning of the file for the volume table which - * will be written later. - */ - if (fseek(args.fp_out, ui.peb_size * 2, SEEK_SET) == -1) { - errmsg("cannot seek file \"%s\"", args.f_out); - goto out_dict; - } - - for (i = 0; i < sects; i++) { - const char *sname = iniparser_getsecname(args.dict, i); - struct ubigen_vol_info vi; - const char *img = NULL; - struct stat st; - FILE *f; - - if (!sname) { - errmsg("ini-file parsing error (iniparser_getsecname)"); - goto out_dict; - } - - if (args.verbose) - printf("\n"); - verbose(args.verbose, "parsing section \"%s\"", sname); - - err = read_section(sname, &vi, &img); - if (err == -1) - goto out_dict; - if (!err) - volumes += 1; - init_vol_info(&ui, &vi); - - verbose(args.verbose, "adding volume %d", vi.id); - - err = ubigen_add_volume(&ui, &vi, vtbl); - if (err) { - errmsg("cannot add volume for section \"%s\"", sname); - goto out_dict; - } - - if (!img) - continue; - - if (stat(img, &st)) { - sys_errmsg("cannot stat \"%s\"", img); - goto out_dict; - } - - /* - * Make sure the image size is not larger then the volume size. - */ - if (st.st_size > vi.bytes) { - errmsg("error in section \"%s\": size of the image file \"%s\" " - "is %lld, which is larger then the volume size %lld", - sname, img, (long long)st.st_size, vi.bytes); - goto out_dict; - } - - f = fopen(img, "r"); - if (!f) { - sys_errmsg("cannot open \"%s\"", img); - goto out_dict; - } - - verbose(args.verbose, "writing volume %d", vi.id); - verbose(args.verbose, "image file: %s", img); - - err = ubigen_write_volume(&ui, &vi, st.st_size, f, args.fp_out); - fclose(f); - if (err) { - errmsg("cannot write volume for section \"%s\"", sname); - goto out_dict; - } - - if (args.verbose) - printf("\n"); - } - - verbose(args.verbose, "writing layout volume"); - - if (fseek(args.fp_out, 0, SEEK_SET) == -1) { - errmsg("cannot seek file \"%s\"", args.f_out); - goto out_dict; - } - - err = ubigen_write_layout_vol(&ui, vtbl, args.fp_out); - if (err) { - errmsg("cannot write layout volume"); - goto out_dict; - } - - verbose(args.verbose, "done"); - - iniparser_freedict(args.dict); - free(vtbl); - fclose(args.fp_out); - return 0; - -out_dict: - iniparser_freedict(args.dict); -out_vtbl: - free(vtbl); -out: - fclose(args.fp_out); - remove(args.f_out); - return err; -} |