summaryrefslogtreecommitdiff
path: root/ubi-utils/src
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2009-03-17 10:14:54 +0200
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2009-03-17 10:16:38 +0200
commit606f38a2221648ca5c5fa292c9f71d2ddd59fa66 (patch)
tree26d11905fda474261433c580c6fb58f4f4a85e59 /ubi-utils/src
parenta2d010f8fca904fffa3c6e5a5d148cc96a37a08a (diff)
ubi-utils: re-arrange directory layout
Move new-utils to ubi-utils and old ones to ubi-utils/old-utils. Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'ubi-utils/src')
-rw-r--r--ubi-utils/src/bin2nand.c344
-rw-r--r--ubi-utils/src/bootenv.c1032
-rw-r--r--ubi-utils/src/bootenv.h434
-rw-r--r--ubi-utils/src/common.c194
-rw-r--r--ubi-utils/src/common.h85
-rw-r--r--ubi-utils/src/config.h28
-rw-r--r--ubi-utils/src/crc32.c156
-rw-r--r--ubi-utils/src/crc32.h47
-rw-r--r--ubi-utils/src/dictionary.c405
-rw-r--r--ubi-utils/src/dictionary.h174
-rw-r--r--ubi-utils/src/eb_chain.c281
-rw-r--r--ubi-utils/src/error.c240
-rw-r--r--ubi-utils/src/error.h84
-rw-r--r--ubi-utils/src/example_ubi.h28
-rw-r--r--ubi-utils/src/hashmap.c412
-rw-r--r--ubi-utils/src/hashmap.h49
-rw-r--r--ubi-utils/src/libiniparser.c646
-rw-r--r--ubi-utils/src/libmtd.c314
-rw-r--r--ubi-utils/src/libpfiflash.c1325
-rw-r--r--ubi-utils/src/libscan.c225
-rw-r--r--ubi-utils/src/libubi.c1377
-rw-r--r--ubi-utils/src/libubi_int.h88
-rw-r--r--ubi-utils/src/libubigen.c665
-rw-r--r--ubi-utils/src/libubimirror.c237
-rw-r--r--ubi-utils/src/list.c149
-rw-r--r--ubi-utils/src/list.h56
-rw-r--r--ubi-utils/src/mkbootenv.c168
-rw-r--r--ubi-utils/src/nand2bin.c493
-rw-r--r--ubi-utils/src/nandcorr.c95
-rw-r--r--ubi-utils/src/nandecc.c159
-rw-r--r--ubi-utils/src/nandecc.h29
-rw-r--r--ubi-utils/src/pddcustomize.c516
-rw-r--r--ubi-utils/src/peb.c116
-rw-r--r--ubi-utils/src/peb.h41
-rw-r--r--ubi-utils/src/pfi.c458
-rw-r--r--ubi-utils/src/pfi.h244
-rw-r--r--ubi-utils/src/pfi2bin.c682
-rw-r--r--ubi-utils/src/pfiflash.c264
-rw-r--r--ubi-utils/src/pfiflash.h76
-rw-r--r--ubi-utils/src/pfiflash_error.h75
-rw-r--r--ubi-utils/src/reader.c482
-rw-r--r--ubi-utils/src/reader.h87
-rw-r--r--ubi-utils/src/ubiattach.c205
-rw-r--r--ubi-utils/src/ubicrc32.c124
-rw-r--r--ubi-utils/src/ubidetach.c181
-rw-r--r--ubi-utils/src/ubiformat.c780
-rw-r--r--ubi-utils/src/ubigen.c359
-rw-r--r--ubi-utils/src/ubigen.h149
-rw-r--r--ubi-utils/src/ubimirror.c213
-rw-r--r--ubi-utils/src/ubimirror.h66
-rw-r--r--ubi-utils/src/ubimkvol.c313
-rw-r--r--ubi-utils/src/ubinfo.c410
-rw-r--r--ubi-utils/src/ubinize.c612
-rw-r--r--ubi-utils/src/ubirename.c141
-rw-r--r--ubi-utils/src/ubirmvol.c230
-rw-r--r--ubi-utils/src/ubiupdatevol.c355
-rw-r--r--ubi-utils/src/unubi.c1024
-rw-r--r--ubi-utils/src/unubi_analyze.c463
-rw-r--r--ubi-utils/src/unubi_analyze.h87
59 files changed, 6627 insertions, 12145 deletions
diff --git a/ubi-utils/src/bin2nand.c b/ubi-utils/src/bin2nand.c
deleted file mode 100644
index c7c7ccc..0000000
--- a/ubi-utils/src/bin2nand.c
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2007
- *
- * 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.
- *
- * Author: Oliver Lohmann
- */
-
-/*
- * Create a flashable NAND image from a binary image
- *
- * History:
- * 1.0 Initial release (tglx)
- * 1.1 Understands hex and dec input parameters (tglx)
- * 1.2 Generates separated OOB data, if needed. (oloh)
- * 1.3 Padds data/oob to a given size. (oloh)
- * 1.4 Removed argp because we want to use uClibc.
- * 1.5 Minor cleanup
- * 1.6 written variable not initialized (-j did not work) (haver)
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-#include "error.h"
-#include "config.h"
-#include "nandecc.h"
-
-#define PROGRAM_VERSION "1.6"
-
-#define CHECK_ENDP(option, endp) do { \
- if (*endp) { \
- fprintf(stderr, \
- "Parse error option \'%s\'. " \
- "No correct numeric value.\n" \
- , option); \
- exit(EXIT_FAILURE); \
- } \
-} while(0)
-
-typedef enum action_t {
- ACT_NORMAL = 0x00000001,
-} action_t;
-
-#define PAGESIZE 2048
-#define PADDING 0 /* 0 means, do not adjust anything */
-#define BUFSIZE 4096
-
-static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
- "bin2nand - a tool for adding OOB information to a "
- "binary input file.\n";
-
-static const char *optionsstr =
-" -c, --copyright Print copyright informatoin.\n"
-" -j, --padding=<num> Padding in Byte/Mi/ki. Default = no padding\n"
-" -p, --pagesize=<num> Pagesize in Byte/Mi/ki. Default = 2048\n"
-" -o, --output=<fname> Output filename. Interleaved Data/OOB if\n"
-" output-oob not specified.\n"
-" -q, --output-oob=<fname> Write OOB data in separate file.\n"
-" -?, --help Give this help list\n"
-" --usage Give a short usage message\n"
-" -V, --version Print program version\n";
-
-static const char *usage =
-"Usage: bin2nand [-c?V] [-j <num>] [-p <num>] [-o <fname>] [-q <fname>]\n"
-" [--copyright] [--padding=<num>] [--pagesize=<num>]\n"
-" [--output=<fname>] [--output-oob=<fname>] [--help] [--usage]\n"
-" [--version]\n";
-
-struct option long_options[] = {
- { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' },
- { .name = "padding", .has_arg = 1, .flag = NULL, .val = 'j' },
- { .name = "pagesize", .has_arg = 1, .flag = NULL, .val = 'p' },
- { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
- { .name = "output-oob", .has_arg = 1, .flag = NULL, .val = 'q' },
- { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
- { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
- { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
- { NULL, 0, NULL, 0}
-};
-
-static const char copyright [] __attribute__((unused)) =
- "Copyright IBM Corp. 2006";
-
-typedef struct myargs {
- action_t action;
-
- size_t pagesize;
- size_t padding;
-
- FILE* fp_in;
- char *file_out_data; /* Either: Data and OOB interleaved
- or plain data */
- char *file_out_oob; /* OOB Data only. */
-
- /* special stuff needed to get additional arguments */
- char *arg1;
- char **options; /* [STRING...] */
-} myargs;
-
-
-static int ustrtoull(const char *cp, char **endp, unsigned int base)
-{
- unsigned long long res = strtoull(cp, endp, base);
-
- switch (**endp) {
- case 'G':
- res *= 1024;
- case 'M':
- res *= 1024;
- case 'k':
- case 'K':
- res *= 1024;
- /* "Ki", "ki", "Mi" or "Gi" are to be used. */
- if ((*endp)[1] == 'i')
- (*endp) += 2;
- }
- return res;
-}
-
-static int
-parse_opt(int argc, char **argv, myargs *args)
-{
- char* endp;
-
- while (1) {
- int key;
-
- key = getopt_long(argc, argv, "cj:p:o:q:?V", long_options, NULL);
- if (key == -1)
- break;
-
- switch (key) {
- case 'p': /* pagesize */
- args->pagesize = (size_t)
- ustrtoull(optarg, &endp, 0);
- CHECK_ENDP("p", endp);
- break;
- case 'j': /* padding */
- args->padding = (size_t)
- ustrtoull(optarg, &endp, 0);
- CHECK_ENDP("j", endp);
- break;
- case 'o': /* output */
- args->file_out_data = optarg;
- break;
- case 'q': /* output oob */
- args->file_out_oob = optarg;
- break;
- case '?': /* help */
- printf("%s", doc);
- printf("%s", optionsstr);
- exit(0);
- break;
- case 'V':
- printf("%s\n", PROGRAM_VERSION);
- exit(0);
- break;
- case 'c':
- printf("%s\n", copyright);
- exit(0);
- default:
- printf("%s", usage);
- exit(-1);
- }
- }
-
- if (optind < argc) {
- args->fp_in = fopen(argv[optind++], "rb");
- if ((args->fp_in) == NULL) {
- err_quit("Cannot open file %s for input\n",
- argv[optind++]);
- }
- }
-
- return 0;
-}
-
-static int
-process_page(uint8_t* buf, size_t pagesize,
- FILE *fp_data, FILE* fp_oob, size_t* written)
-{
- int eccpoi, oobsize;
- size_t i;
- uint8_t oobbuf[64];
-
- memset(oobbuf, 0xff, sizeof(oobbuf));
-
- switch(pagesize) {
- case 2048: oobsize = 64; eccpoi = 64 / 2; break;
- case 512: oobsize = 16; eccpoi = 16 / 2; break;
- default:
- err_msg("Unsupported page size: %d\n", pagesize);
- return -EINVAL;
- }
-
- for (i = 0; i < pagesize; i += 256, eccpoi += 3) {
- oobbuf[eccpoi++] = 0x0;
- /* Calculate ECC */
- nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]);
- }
-
- /* write data */
- *written += fwrite(buf, 1, pagesize, fp_data);
-
- /* either separate oob or interleave with data */
- if (fp_oob) {
- i = fwrite(oobbuf, 1, oobsize, fp_oob);
- if (ferror(fp_oob)) {
- err_msg("IO error\n");
- return -EIO;
- }
- }
- else {
- i = fwrite(oobbuf, 1, oobsize, fp_data);
- if (ferror(fp_data)) {
- err_msg("IO error\n");
- return -EIO;
- }
- }
-
- return 0;
-}
-
-int main (int argc, char** argv)
-{
- int rc = -1;
- int res = 0;
- size_t written = 0, read;
- myargs args = {
- .action = ACT_NORMAL,
- .pagesize = PAGESIZE,
- .padding = PADDING,
- .fp_in = NULL,
- .file_out_data = NULL,
- .file_out_oob = NULL,
- };
-
- FILE* fp_out_data = stdout;
- FILE* fp_out_oob = NULL;
-
- parse_opt(argc, argv, &args);
-
- uint8_t* buf = calloc(1, BUFSIZE);
- if (!buf) {
- err_quit("Cannot allocate page buffer.\n");
- }
-
- if (!args.fp_in) {
- err_msg("No input image specified!\n");
- goto err;
- }
-
- if (args.file_out_data) {
- fp_out_data = fopen(args.file_out_data, "wb");
- if (fp_out_data == NULL) {
- err_sys("Cannot open file %s for output\n",
- args.file_out_data);
- goto err;
- }
- }
-
- if (args.file_out_oob) {
- fp_out_oob = fopen(args.file_out_oob, "wb");
- if (fp_out_oob == NULL) {
- err_sys("Cannot open file %s for output\n",
- args.file_out_oob);
- goto err;
- }
- }
-
-
- while(1) {
- read = fread(buf, 1, args.pagesize, args.fp_in);
- if (feof(args.fp_in) && read == 0)
- break;
-
- if (read < args.pagesize) {
- err_msg("Image not page aligned\n");
- goto err;
- }
-
- if (ferror(args.fp_in)) {
- err_msg("Read error\n");
- goto err;
- }
-
- res = process_page(buf, args.pagesize, fp_out_data,
- fp_out_oob, &written);
- if (res != 0)
- goto err;
- }
-
- while (written < args.padding) {
- memset(buf, 0xff, args.pagesize);
- res = process_page(buf, args.pagesize, fp_out_data,
- fp_out_oob, &written);
- if (res != 0)
- goto err;
- }
-
- rc = 0;
-err:
- free(buf);
-
- if (args.fp_in)
- fclose(args.fp_in);
-
- if (fp_out_oob)
- fclose(fp_out_oob);
-
- if (fp_out_data && fp_out_data != stdout)
- fclose(fp_out_data);
-
- if (rc != 0) {
- err_msg("Error during conversion. rc: %d\n", rc);
- if (args.file_out_data)
- remove(args.file_out_data);
- if (args.file_out_oob)
- remove(args.file_out_oob);
- }
- return rc;
-}
diff --git a/ubi-utils/src/bootenv.c b/ubi-utils/src/bootenv.c
deleted file mode 100644
index 78198fe..0000000
--- a/ubi-utils/src/bootenv.c
+++ /dev/null
@@ -1,1032 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2008
- *
- * 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.
- *
- * Author: Oliver Lohmann
- */
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <netinet/in.h>
-#include <sys/stat.h>
-#include <bootenv.h>
-
-#include "hashmap.h"
-#include "error.h"
-
-#include <mtd/ubi-media.h>
-#include "crc32.h"
-
-#define ubi_unused __attribute__((unused))
-
-#define BOOTENV_MAXLINE 512 /* max line size of a bootenv.txt file */
-
-/* Structures */
-struct bootenv {
- hashmap_t map; ///< Pointer to hashmap which holds data structure.
-};
-
-struct bootenv_list {
- hashmap_t head; ///< Pointer to list which holds the data structure.
-};
-
-/**
- * @brief Remove the '\n' from a given line.
- * @param line Input/Output line.
- * @param size Size of the line.
- * @param fp File Pointer.
- * @return 0
- * @return or error
- */
-static int
-remove_lf(char *line, size_t size, FILE* fp)
-{
- size_t i;
-
- for (i = 0; i < size; i++) {
- if (line[i] == '\n') {
- line[i] = '\0';
- return 0;
- }
- }
-
- if (!feof(fp)) {
- return BOOTENV_EINVAL;
- }
-
- return 0;
-}
-
-/**
- * @brief Determine if a line contains only WS.
- * @param line The line to process.
- * @param size Size of input line.
- * @return 1 Yes, only WS.
- * @return 0 No, contains data.
- */
-static int
-is_ws(const char *line, size_t size)
-{
- size_t i = 0;
-
- while (i < size) {
- switch (line[i]) {
- case '\n':
- return 1;
- case '#':
- return 1;
- case ' ':
- i++;
- continue;
- case '\t':
- i++;
- continue;
- default: /* any other char -> no cmnt */
- return 0;
- }
- }
-
- return 0;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-/**
- * @brief Build a list from a comma seperated value string.
- * @param list Pointer to hashmap structure which shall store
- * the list.
- * @param value Comma seperated value string.
- * @return 0
- * @return or error.
- */
-static int
-build_list_definition(hashmap_t list, const char *value)
-{
- int rc = 0;
- char *str = NULL;
- char *ptr = NULL;
- size_t len, i, j;
-
- /* str: val1,val2 , val4,...,valN */
- len = strlen(value);
- str = (char*) malloc((len+1) * sizeof(char));
-
- /* 1. reformat string: remove spaces */
- for (i = 0, j = 0; i < len; i++) {
- if (value[i] == ' ')
- continue;
-
- str[j] = value[i];
- j++;
- }
- str[j] = '\0';
-
- /* str: val1,val2,val4,...,valN\0*/
- /* 2. replace ',' seperator with '\0' */
- len = strlen(str);
- for (i = 0; i < len; i++) {
- if (str[i] == ',') {
- str[i] = '\0';
- }
- }
-
- /* str: val1\0val2\0val4\0...\0valN\0*/
- /* 3. insert definitions into a hash map, using it like a list */
- i = j = 0;
- ptr = str;
- while (((i = strlen(ptr)) > 0) && (j < len)) {
- rc = hashmap_add(list, ptr, "");
- if (rc != 0) {
- free(str);
- return rc;
- }
- j += i+1;
- if (j < len)
- ptr += i+1;
- }
-
- free(str);
- return rc;
-}
-
-/**
- * @brief Extract a key value pair and add it to a hashmap
- * @param str Input string which contains a key value pair.
- * @param env The updated handle which contains the new pair.
- * @return 0
- * @return or error
- * @note The input string format is: "key=value"
- */
-static int
-extract_pair(const char *str, bootenv_t env)
-{
- int rc = 0;
- char *key = NULL;
- char *val = NULL;
-
- key = strdup(str);
- if (key == NULL)
- return -ENOMEM;
-
- val = strstr(key, "=");
- if (val == NULL) {
- rc = BOOTENV_EBADENTRY;
- goto err;
- }
-
- *val = '\0'; /* split strings */
- val++;
-
- rc = bootenv_set(env, key, val);
-
- err:
- free(key);
- return rc;
-}
-
-int
-bootenv_destroy(bootenv_t* env)
-{
- int rc = 0;
-
- if (env == NULL || *env == NULL)
- return -EINVAL;
-
- bootenv_t tmp = *env;
-
- rc = hashmap_free(tmp->map);
- if (rc != 0)
- return rc;
-
- free(tmp);
- return rc;
-}
-
-int
-bootenv_create(bootenv_t* env)
-{
- bootenv_t res;
- res = (bootenv_t) calloc(1, sizeof(struct bootenv));
-
- if (res == NULL)
- return -ENOMEM;
-
- res->map = hashmap_new();
-
- if (res->map == NULL) {
- free(res);
- return -ENOMEM;
- }
-
- *env = res;
-
- return 0;
-}
-
-
-/**
- * @brief Read a formatted buffer and scan it for valid bootenv
- * key/value pairs. Add those pairs into a hashmap.
- * @param env Hashmap which shall be used to hold the data.
- * @param buf Formatted buffer.
- * @param size Size of the buffer.
- * @return 0
- * @return or error
- */
-static int
-rd_buffer(bootenv_t env, const char *buf, size_t size)
-{
- const char *curr = buf; /* ptr to current key/value pair */
- uint32_t i, j; /* current length, chars processed */
-
- if (buf[size - 1] != '\0') /* must end in '\0' */
- return BOOTENV_EFMT;
-
- for (j = 0; j < size; j += i, curr += i) {
- /* strlen returns the size of the string upto
- but not including the null terminator;
- adding 1 to account for '\0' */
- i = strlen(curr) + 1;
-
- if (i == 1)
- return 0; /* no string found */
-
- if (extract_pair(curr, env) != 0)
- return BOOTENV_EINVAL;
- }
-
- return 0;
-}
-
-
-int
-bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t* ret_crc)
-{
- int rc;
- char *buf = NULL;
- size_t i = 0;
- uint32_t crc32_table[256];
-
- if ((fp == NULL) || (env == NULL))
- return -EINVAL;
-
- /* allocate temp buffer */
- buf = (char*) calloc(1, size * sizeof(char));
- if (buf == NULL)
- return -ENOMEM;
-
- /* FIXME Andreas, please review this I removed size-1 and
- * replaced it by just size, I saw the kernel image starting
- * with a 0x0060.... and not with the 0x60.... what it should
- * be. Is this a tools problem or is it a problem here where
- * fp is moved not to the right place due to the former size-1
- * here.
- */
- while((i < size) && (!feof(fp))) {
- int c = fgetc(fp);
- if (c == EOF) {
- /* FIXME isn't this dangerous, to update
- the boot envs with incomplete data? */
- buf[i++] = '\0';
- break; /* we have enough */
- }
- if (ferror(fp)) {
- rc = -EIO;
- goto err;
- }
-
- buf[i++] = (char)c;
- }
-
- /* calculate crc to return */
- if (ret_crc != NULL) {
- init_crc32_table(crc32_table);
- *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size);
- }
-
- /* transfer to hashmap */
- rc = rd_buffer(env, buf, size);
-
-err:
- free(buf);
- return rc;
-}
-
-
-/**
- * If we have a single file containing the boot-parameter size should
- * be specified either as the size of the file or as BOOTENV_MAXSIZE.
- * If the bootparameter are in the middle of a file we need the exact
- * length of the data.
- */
-int
-bootenv_read(FILE* fp, bootenv_t env, size_t size)
-{
- return bootenv_read_crc(fp, env, size, NULL);
-}
-
-
-int
-bootenv_read_txt(FILE* fp, bootenv_t env)
-{
- int rc = 0;
- char *buf = NULL;
- char *line = NULL;
- char *lstart = NULL;
- char *curr = NULL;
- size_t len;
- size_t size;
-
- if ((fp == NULL) || (env == NULL))
- return -EINVAL;
-
- size = BOOTENV_MAXSIZE;
-
- /* allocate temp buffers */
- buf = (char*) calloc(1, size * sizeof(char));
- lstart = line = (char*) calloc(1, size * sizeof(char));
- if ((buf == NULL) || (line == NULL)) {
- rc = -ENOMEM;
- goto err;
- }
-
- curr = buf;
- while ((line = fgets(line, size, fp)) != NULL) {
- if (is_ws(line, size)) {
- continue;
- }
- rc = remove_lf(line, BOOTENV_MAXSIZE, fp);
- if (rc != 0) {
- goto err;
- }
-
- /* copy new line to binary buffer */
- len = strlen(line);
- if (len > size) {
- rc = -EFBIG;
- goto err;
- }
- size -= len; /* track remaining space */
-
- memcpy(curr, line, len);
- curr += len + 1; /* for \0 seperator */
- }
-
- rc = rd_buffer(env, buf, BOOTENV_MAXSIZE);
-err:
- if (buf != NULL)
- free(buf);
- if (lstart != NULL)
- free(lstart);
- return rc;
-}
-
-static int
-fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max ubi_unused,
- size_t *written)
-{
- int rc = 0;
- size_t keys_size, i;
- size_t wr = 0;
- const char **keys = NULL;
- const char *val = NULL;
-
- rc = bootenv_get_key_vector(env, &keys_size, 1, &keys);
- if (rc != 0)
- goto err;
-
- for (i = 0; i < keys_size; i++) {
- if (wr > BOOTENV_MAXSIZE) {
- rc = -ENOSPC;
- goto err;
- }
-
- rc = bootenv_get(env, keys[i], &val);
- if (rc != 0)
- goto err;
-
- wr += snprintf(buf + wr, BOOTENV_MAXSIZE - wr,
- "%s=%s", keys[i], val);
- wr++; /* for \0 */
- }
-
- *written = wr;
-
-err:
- if (keys != NULL)
- free(keys);
-
- return rc;
-}
-
-int
-bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc)
-{
- int rc = 0;
- size_t size = 0;
- char *buf = NULL;
- uint32_t crc32_table[256];
-
- if ((fp == NULL) || (env == NULL))
- return -EINVAL;
-
- buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char));
- if (buf == NULL)
- return -ENOMEM;
-
-
- rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, &size);
- if (rc != 0)
- goto err;
-
- /* calculate crc to return */
- if (ret_crc != NULL) {
- init_crc32_table(crc32_table);
- *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size);
- }
-
- if (fwrite(buf, size, 1, fp) != 1) {
- rc = -EIO;
- goto err;
- }
-
-err:
- if (buf != NULL)
- free(buf);
- return rc;
-}
-
-int
-bootenv_write(FILE* fp, bootenv_t env)
-{
- return bootenv_write_crc(fp, env, NULL);
-}
-
-int
-bootenv_compare(bootenv_t first, bootenv_t second)
-{
- int rc;
- size_t written_first, written_second;
- char *buf_first, *buf_second;
-
- if (first == NULL || second == NULL)
- return -EINVAL;
-
- buf_first = malloc(BOOTENV_MAXSIZE);
- if (!buf_first)
- return -ENOMEM;
- buf_second = malloc(BOOTENV_MAXSIZE);
- if (!buf_second) {
- rc = -ENOMEM;
- goto err;
- }
-
- rc = fill_output_buffer(first, buf_first, BOOTENV_MAXSIZE,
- &written_first);
- if (rc < 0)
- goto err;
- rc = fill_output_buffer(second, buf_second, BOOTENV_MAXSIZE,
- &written_second);
- if (rc < 0)
- goto err;
-
- if (written_first != written_second) {
- rc = 1;
- goto err;
- }
-
- rc = memcmp(buf_first, buf_second, written_first);
- if (rc != 0) {
- rc = 2;
- goto err;
- }
-
-err:
- if (buf_first)
- free(buf_first);
- if (buf_second)
- free(buf_second);
-
- return rc;
-}
-
-int
-bootenv_size(bootenv_t env, size_t *size)
-{
- int rc = 0;
- char *buf = NULL;
-
- if (env == NULL)
- return -EINVAL;
-
- buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char));
- if (buf == NULL)
- return -ENOMEM;
-
- rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, size);
- if (rc != 0)
- goto err;
-
-err:
- if (buf != NULL)
- free(buf);
- return rc;
-}
-
-int
-bootenv_write_txt(FILE* fp, bootenv_t env)
-{
- int rc = 0;
- size_t size, wr, i;
- const char **keys = NULL;
- const char *key = NULL;
- const char *val = NULL;
-
- if ((fp == NULL) || (env == NULL))
- return -EINVAL;
-
- rc = bootenv_get_key_vector(env, &size, 1, &keys);
- if (rc != 0)
- goto err;
-
- for (i = 0; i < size; i++) {
- key = keys[i];
- rc = bootenv_get(env, key, &val);
- if (rc != 0)
- goto err;
-
- wr = fprintf(fp, "%s=%s\n", key, val);
- if (wr != strlen(key) + strlen(val) + 2) {
- rc = -EIO;
- goto err;
- }
- }
-
-err:
- if (keys != NULL)
- free(keys);
- return rc;
-}
-
-int
-bootenv_valid(bootenv_t env ubi_unused)
-{
- /* @FIXME No sanity check implemented. */
- return 0;
-}
-
-int
-bootenv_copy_bootenv(bootenv_t in, bootenv_t *out)
-{
- int rc = 0;
- const char *tmp = NULL;
- const char **keys = NULL;
- size_t vec_size, i;
-
- if ((in == NULL) || (out == NULL))
- return -EINVAL;
-
- /* purge output var for sure... */
- rc = bootenv_destroy(out);
- if (rc != 0)
- return rc;
-
- /* create the new map */
- rc = bootenv_create(out);
- if (rc != 0)
- goto err;
-
- /* get the key list from the input map */
- rc = bootenv_get_key_vector(in, &vec_size, 0, &keys);
- if (rc != 0)
- goto err;
-
- if (vec_size != hashmap_size(in->map)) {
- rc = BOOTENV_ECOPY;
- goto err;
- }
-
- /* make a deep copy of the hashmap */
- for (i = 0; i < vec_size; i++) {
- rc = bootenv_get(in, keys[i], &tmp);
- if (rc != 0)
- goto err;
-
- rc = bootenv_set(*out, keys[i], tmp);
- if (rc != 0)
- goto err;
- }
-
-err:
- if (keys != NULL)
- free(keys);
-
- return rc;
-}
-
-/* ------------------------------------------------------------------------- */
-
-
-int
-bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res,
- int *warnings, char *err_buf ubi_unused,
- size_t err_buf_size ubi_unused)
-{
- bootenv_list_t l_old = NULL;
- bootenv_list_t l_new = NULL;
- const char *pdd_old = NULL;
- const char *pdd_new = NULL;
- const char *tmp = NULL;
- const char **vec_old = NULL;
- const char **vec_new = NULL;
- const char **pdd_up_vec = NULL;
- size_t vec_old_size, vec_new_size, pdd_up_vec_size, i;
- int rc = 0;
-
- if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL))
- return -EINVAL;
-
- /* get the pdd strings, e.g.:
- * pdd_old=a,b,c
- * pdd_new=a,c,d,e */
- rc = bootenv_get(env_old, "pdd", &pdd_old);
- if (rc != 0)
- goto err;
- rc = bootenv_get(env_new, "pdd", &pdd_new);
- if (rc != 0)
- goto err;
-
- /* put it into a list and then convert it to an vector */
- rc = bootenv_list_create(&l_old);
- if (rc != 0)
- goto err;
- rc = bootenv_list_create(&l_new);
- if (rc != 0)
- goto err;
-
- rc = bootenv_list_import(l_old, pdd_old);
- if (rc != 0)
- goto err;
-
- rc = bootenv_list_import(l_new, pdd_new);
- if (rc != 0)
- goto err;
-
- rc = bootenv_list_to_vector(l_old, &vec_old_size, &vec_old);
- if (rc != 0)
- goto err;
-
- rc = bootenv_list_to_vector(l_new, &vec_new_size, &vec_new);
- if (rc != 0)
- goto err;
-
- rc = bootenv_copy_bootenv(env_new, env_res);
- if (rc != 0)
- goto err;
-
- /* calculate the update vector between the old and new pdd */
- pdd_up_vec = hashmap_get_update_key_vector(vec_old, vec_old_size,
- vec_new, vec_new_size, &pdd_up_vec_size);
-
- if (pdd_up_vec == NULL) {
- rc = -ENOMEM;
- goto err;
- }
-
- if (pdd_up_vec_size != 0) {
- /* need to warn the user about the unset of
- * some pdd/bootenv values */
- *warnings = BOOTENV_WPDD_STRING_DIFFERS;
-
- /* remove all entries in the new bootenv load */
- for (i = 0; i < pdd_up_vec_size; i++) {
- bootenv_unset(*env_res, pdd_up_vec[i]);
- }
- }
-
- /* generate the keep array and copy old pdd values to new bootenv */
- for (i = 0; i < vec_old_size; i++) {
- rc = bootenv_get(env_old, vec_old[i], &tmp);
- if (rc != 0) {
- rc = BOOTENV_EPDDINVAL;
- goto err;
- }
- rc = bootenv_set(*env_res, vec_old[i], tmp);
- if (rc != 0) {
- goto err;
- }
- }
- /* put the old pdd string into the result map */
- rc = bootenv_set(*env_res, "pdd", pdd_old);
- if (rc != 0) {
- goto err;
- }
-
-
-err:
- if (vec_old != NULL)
- free(vec_old);
- if (vec_new != NULL)
- free(vec_new);
- if (pdd_up_vec != NULL)
- free(pdd_up_vec);
-
- bootenv_list_destroy(&l_old);
- bootenv_list_destroy(&l_new);
- return rc;
-}
-
-
-int
-bootenv_pdd_overwrite(bootenv_t env_old, bootenv_t env_new,
- bootenv_t *env_res, int *warnings ubi_unused,
- char *err_buf ubi_unused, size_t err_buf_size ubi_unused)
-{
- if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL))
- return -EINVAL;
-
- return bootenv_copy_bootenv(env_new, env_res);
-}
-
-int
-bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res,
- int *warnings ubi_unused, char *err_buf, size_t err_buf_size)
-{
- if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL))
- return -EINVAL;
-
- snprintf(err_buf, err_buf_size, "The PDD merge operation is not "
- "implemented. Contact: <oliloh@de.ibm.com>");
-
- return BOOTENV_ENOTIMPL;
-}
-
-/* ------------------------------------------------------------------------- */
-
-int
-bootenv_get(bootenv_t env, const char *key, const char **value)
-{
- if (env == NULL)
- return -EINVAL;
-
- *value = hashmap_lookup(env->map, key);
- if (*value == NULL)
- return BOOTENV_ENOTFOUND;
-
- return 0;
-}
-
-int
-bootenv_get_num(bootenv_t env, const char *key, uint32_t *value)
-{
- char *endptr = NULL;
- const char *str;
-
- if (env == NULL)
- return 0;
-
- str = hashmap_lookup(env->map, key);
- if (!str)
- return -EINVAL;
-
- *value = strtoul(str, &endptr, 0);
-
- if (*endptr == '\0') {
- return 0;
- }
-
- return -EINVAL;
-}
-
-int
-bootenv_set(bootenv_t env, const char *key, const char *value)
-{
- if (env == NULL)
- return -EINVAL;
-
- return hashmap_add(env->map, key, value);
-}
-
-int
-bootenv_unset(bootenv_t env, const char *key)
-{
- if (env == NULL)
- return -EINVAL;
-
- return hashmap_remove(env->map, key);
-}
-
-int
-bootenv_get_key_vector(bootenv_t env, size_t* size, int sort,
- const char ***vector)
-{
- if ((env == NULL) || (size == NULL))
- return -EINVAL;
-
- *vector = hashmap_get_key_vector(env->map, size, sort);
-
- if (*vector == NULL)
- return -EINVAL;
-
- return 0;
-}
-
-int
-bootenv_dump(bootenv_t env)
-{
- if (env == NULL)
- return -EINVAL;
-
- return hashmap_dump(env->map);
-}
-
-int
-bootenv_list_create(bootenv_list_t *list)
-{
- bootenv_list_t res;
- res = (bootenv_list_t) calloc(1, sizeof(struct bootenv_list));
-
- if (res == NULL)
- return -ENOMEM;
-
- res->head = hashmap_new();
-
- if (res->head == NULL) {
- free(res);
- return -ENOMEM;
- }
-
- *list = res;
- return 0;
-}
-
-int
-bootenv_list_destroy(bootenv_list_t *list)
-{
- int rc = 0;
-
- if (list == NULL)
- return -EINVAL;
-
- bootenv_list_t tmp = *list;
- if (tmp == 0)
- return 0;
-
- rc = hashmap_free(tmp->head);
- if (rc != 0)
- return rc;
-
- free(tmp);
- *list = NULL;
- return 0;
-}
-
-int
-bootenv_list_import(bootenv_list_t list, const char *str)
-{
- if (list == NULL)
- return -EINVAL;
-
- return build_list_definition(list->head, str);
-}
-
-int
-bootenv_list_export(bootenv_list_t list, char **string)
-{
- size_t size, i, j, bufsize, tmp, rc = 0;
- const char **items;
-
- if (list == NULL)
- return -EINVAL;
-
- bufsize = BOOTENV_MAXLINE;
- char *res = (char*) malloc(bufsize * sizeof(char));
- if (res == NULL)
- return -ENOMEM;
-
- rc = bootenv_list_to_vector(list, &size, &items);
- if (rc != 0) {
- goto err;
- }
-
- j = 0;
- for (i = 0; i < size; i++) {
- tmp = strlen(items[i]);
- if (j >= bufsize) {
- bufsize += BOOTENV_MAXLINE;
- res = (char*) realloc(res, bufsize * sizeof(char));
- if (res == NULL) {
- rc = -ENOMEM;
- goto err;
- }
- }
- memcpy(res + j, items[i], tmp);
- j += tmp;
- if (i < (size - 1)) {
- res[j] = ',';
- j++;
- }
- }
- j++;
- res[j] = '\0';
- free(items);
- *string = res;
- return 0;
-err:
- free(items);
- return rc;
-}
-
-int
-bootenv_list_add(bootenv_list_t list, const char *item)
-{
- if ((list == NULL) || (item == NULL))
- return -EINVAL;
-
- return hashmap_add(list->head, item, "");
-}
-
-int
-bootenv_list_remove(bootenv_list_t list, const char *item)
-{
- if ((list == NULL) || (item == NULL))
- return -EINVAL;
-
- return hashmap_remove(list->head, item);
-}
-
-int
-bootenv_list_is_in(bootenv_list_t list, const char *item)
-{
- if ((list == NULL) || (item == NULL))
- return -EINVAL;
-
- return hashmap_lookup(list->head, item) != NULL ? 1 : 0;
-}
-
-int
-bootenv_list_to_vector(bootenv_list_t list, size_t *size, const char ***vector)
-{
- if ((list == NULL) || (size == NULL))
- return -EINVAL;
-
- *vector = hashmap_get_key_vector(list->head, size, 1);
- if (*vector == NULL)
- return -ENOMEM;
-
- return 0;
-}
-
-int
-bootenv_list_to_num_vector(bootenv_list_t list, size_t *size,
- uint32_t **vector)
-{
- int rc = 0;
- size_t i;
- uint32_t* res = NULL;
- char *endptr = NULL;
- const char **a = NULL;
-
- rc = bootenv_list_to_vector(list, size, &a);
- if (rc != 0)
- goto err;
-
- res = (uint32_t*) malloc (*size * sizeof(uint32_t));
- if (!res)
- goto err;
-
- for (i = 0; i < *size; i++) {
- res[i] = strtoul(a[i], &endptr, 0);
- if (*endptr != '\0')
- goto err;
- }
-
- if (a)
- free(a);
- *vector = res;
- return 0;
-
-err:
- if (a)
- free(a);
- if (res)
- free(res);
- return rc;
-}
diff --git a/ubi-utils/src/bootenv.h b/ubi-utils/src/bootenv.h
deleted file mode 100644
index 8fecdbf..0000000
--- a/ubi-utils/src/bootenv.h
+++ /dev/null
@@ -1,434 +0,0 @@
-#ifndef __BOOTENV_H__
-#define __BOOTENV_H__
-/*
- * 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.
- */
-
-#include <stdio.h> /* FILE */
-#include <stdint.h>
-#include <pfiflash.h>
-
-/* DOXYGEN DOCUMENTATION */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @file bootenv.h
- * @author oliloh@de.ibm.com
- * @version 1.3
- *
- * 1.3 Some renaming
- */
-
-/**
- * @mainpage Usage
- *
- * @section intro Introduction
- * This library provides all functionality to handle with the so-called
- * platform description data (PDD) and the bootparameters defined in
- * U-Boot. It is able to apply the defined PDD operations in PDD update
- * scenarios. For more information about the PDD and bootparameter
- * environment "bootenv" confer the PDD documentation.
- *
- * @section ret Return codes
- * This library defines some return codes which will be delivered classified
- * as warnings or errors. See the "Defines" section for details and numeric
- * values.
- *
- * @section benv Bootenv format description
- * There are two different input formats:
- * - text files
- * - binary files
- *
- * @subsection txt Text Files
- * Text files have to be specified like:
- * @verbatim key1=value1,value2,value7\n key2=value55,value1\n key4=value1\n@endverbatim
- *
- * @subsection bin Binary files
- * Binary files have to be specified like:
- * @verbatim<CRC32-bit>key1=value1,value2,value7\0key2=value55,value1\0... @endverbatim
- * You can confer the U-Boot documentation for more details.
- *
- * @section benvlists Bootenv lists format description.
- * Values referenced in the preceeding subsection can be
- * defined like lists:
- * @verbatim value1,value2,value3 @endverbatim
- * There are some situation where a conversion of a comma
- * seperated list can be useful, e.g. to get a list
- * of defined PDD entries.
- */
-
-#define BOOTENV_MAXSIZE (1024 * 100) /* max 100kiB space for bootenv */
-
-/**
- * @def BOOTENV_ECRC
- * @brief Given binary file is to large.
- * @def BOOTENV_EFMT
- * @brief Given bootenv section has an invalid format
- * @def BOOTENV_EBADENTRY
- * @brief Bad entry in the bootenv section.
- * @def BOOTENV_EINVAL
- * @brief Invalid bootenv defintion.
- * @def BOOTENV_ENOPDD
- * @brief Given bootenv sectoin has no PDD defintion string (pdd=...).
- * @def BOOTENV_EPDDINVAL
- * @brief Given bootenv section has an invalid PDD defintion.
- * @def BOOTENV_ENOTIMPL
- * @brief Functionality not implemented.
- * @def BOOTENV_ECOPY
- * @brief Bootenv memory copy error
- * @def BOOTENV_ENOTFOUND
- * @brief Given key has has no value.
- * @def BOOTENV_EMAX
- * @brief Highest error value.
- */
-#define BOOTENV_ETOOBIG 1
-#define BOOTENV_EFMT 2
-#define BOOTENV_EBADENTRY 3
-#define BOOTENV_EINVAL 4
-#define BOOTENV_ENOPDD 5
-#define BOOTENV_EPDDINVAL 6
-#define BOOTENV_ENOTIMPL 7
-#define BOOTENV_ECOPY 8
-#define BOOTENV_ENOTFOUND 9
-#define BOOTENV_EMAX 10
-
-/**
- * @def BOOTENV_W
- * @brief A warning which is handled internally as an error
- * but can be recovered by manual effort.
- * @def BOOTENV_WPDD_STRING_DIFFERS
- * @brief The PDD strings of old and new PDD differ and
- * can cause update problems, because new PDD values
- * are removed from the bootenv section completely.
- */
-#define BOOTENV_W 20
-#define BOOTENV_WPDD_STRING_DIFFERS 21
-#define BOOTENV_WMAX 22 /* highest warning value */
-
-
-typedef struct bootenv *bootenv_t;
- /**< A bootenv library handle. */
-
-typedef struct bootenv_list *bootenv_list_t;
- /**< A handle for a value list. */
-
-typedef int(*pdd_func_t)(bootenv_t, bootenv_t, bootenv_t*,
- int*, char*, size_t);
-
-
-/**
- * @brief Get a new handle.
- * @return 0
- * @return or error
- * */
-int bootenv_create(bootenv_t *env);
-
-/**
- * @brief Cleanup structure.
- * @param env Bootenv structure which shall be destroyed.
- * @return 0
- * @return or error
- */
-int bootenv_destroy(bootenv_t *env);
-
-/**
- * @brief Copy a bootenv handle.
- * @param in The input bootenv.
- * @param out The copied output bootenv. Discards old data.
- * @return 0
- * @return or error
- */
-int bootenv_copy_bootenv(bootenv_t in, bootenv_t *out);
-
-/**
- * @brief Looks for a value inside the bootenv data.
- * @param env Handle to a bootenv structure.
- * @param key The key.
- * @return NULL key not found
- * @return !NULL ptr to value
- */
-int bootenv_get(bootenv_t env, const char *key, const char **value);
-
-
-/**
- * @brief Looks for a value inside the bootenv data and converts it to num.
- * @param env Handle to a bootenv structure.
- * @param key The key.
- * @param value A pointer to the resulting numerical value
- * @return NULL key not found
- * @return !NULL ptr to value
- */
-int bootenv_get_num(bootenv_t env, const char *key, uint32_t *value);
-
-/**
- * @brief Set a bootenv value by key.
- * @param env Handle to a bootenv structure.
- * @param key Key.
- * @param value Value to set.
- * @return 0
- * @return or error
- */
-int bootenv_set(bootenv_t env, const char *key, const char *value);
-
-/**
- * @brief Remove the given key (and its value) from a bootenv structure.
- * @param env Handle to a bootenv structure.
- * @param key Key.
- * @return 0
- * @return or error
- */
-int bootenv_unset(bootenv_t env, const char *key);
-
-
-/**
- * @brief Get a vector of all keys which are currently set
- * within a bootenv handle.
- * @param env Handle to a bootenv structure.
- * @param size The size of the allocated array structure.
- * @param sort Flag, if set the vector is sorted ascending.
- * @return NULL on error.
- * @return !NULL a pointer to the first element the allocated vector.
- * @warning Free the allocate memory yourself!
- */
-int bootenv_get_key_vector(bootenv_t env, size_t *size, int sort,
- const char ***vector);
-
-/**
- * @brief Calculate the size in bytes which are necessary to write the
- * current bootenv section in a *binary file.
- * @param env bootenv handle.
- * @param size The size in bytes of the bootenv handle.
- * @return 0
- * @return or ERROR.
- */
-int bootenv_size(bootenv_t env, size_t *size);
-
-/**
- * @brief Read a binary bootenv file.
- * @param fp File pointer to input stream.
- * @param env bootenv handle.
- * @param size maximum data size.
- * @return 0
- * @return or ERROR.
- */
-int bootenv_read(FILE* fp, bootenv_t env, size_t size);
-
-/**
- * @param ret_crc return value of crc of read data
- */
-int bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t *ret_crc);
-
-/**
- * @brief Read bootenv data from an text/ascii file.
- * @param fp File pointer to ascii PDD file.
- * @param env bootenv handle
- * @return 0
- * @return or ERROR.
- */
-int bootenv_read_txt(FILE* fp, bootenv_t env);
-
-/**
- * @brief Write a bootenv structure to the given location (binary).
- * @param fp Filepointer to binary file.
- * @param env Bootenv structure which shall be written.
- * @return 0
- * @return or error
- */
-int bootenv_write(FILE* fp, bootenv_t env);
-
-/**
- * @param ret_crc return value of crc of read data
- */
-int bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc);
-
-/**
- * @brief Write a bootenv structure to the given location (text).
- * @param fp Filepointer to text file.
- * @param env Bootenv structure which shall be written.
- * @return 0
- * @return or error
- */
-int bootenv_write_txt(FILE* fp, bootenv_t env);
-
-/**
- * @brief Compare bootenvs using memcmp().
- * @param first First bootenv.
- * @param second Second bootenv.
- * @return 0 if bootenvs are equal
- * @return < 0 if error
- * @return > 0 if unequal
- */
-int bootenv_compare(bootenv_t first, bootenv_t second);
-
-/**
- * @brief Prototype for a PDD handling funtion
- */
-
-/**
- * @brief The PDD keep operation.
- * @param env_old The old bootenv structure.
- * @param env_new The new bootenv structure.
- * @param env_res The result of PDD keep.
- * @param warnings A flag which marks any warnings.
- * @return 0
- * @return or error
- * @note For a complete documentation about the algorithm confer the
- * PDD documentation.
- */
-int bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new,
- bootenv_t *env_res, int *warnings,
- char *err_buf, size_t err_buf_size);
-
-
-/**
- * @brief The PDD merge operation.
- * @param env_old The old bootenv structure.
- * @param env_new The new bootenv structure.
- * @param env_res The result of merge-pdd.
- * @param warnings A flag which marks any warnings.
- * @return 0
- * @return or error
- * @note For a complete documentation about the algorithm confer the
- * PDD documentation.
- */
-int bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new,
- bootenv_t *env_res, int *warnings,
- char *err_buf, size_t err_buf_size);
-
-/**
- * @brief The PDD overwrite operation.
- * @param env_old The old bootenv structure.
- * @param env_new The new bootenv structure.
- * @param env_res The result of overwrite-pdd.
- * @param warnings A flag which marks any warnings.
- * @return 0
- * @return or error
- * @note For a complete documentation about the algorithm confer the
- * PDD documentation.
- */
-int bootenv_pdd_overwrite(bootenv_t env_new,
- bootenv_t env_old, bootenv_t *env_res, int *warnings,
- char *err_buf, size_t err_buf_size);
-
-/**
- * @brief Dump a bootenv structure to stdout. (Debug)
- * @param env Handle to a bootenv structure.
- * @return 0
- * @return or error
- */
-int bootenv_dump(bootenv_t env);
-
-/**
- * @brief Validate a bootenv structure.
- * @param env Handle to a bootenv structure.
- * @return 0
- * @return or error
- */
-int bootenv_valid(bootenv_t env);
-
-/**
- * @brief Create a new bootenv list structure.
- * @return NULL on error
- * @return or a new list handle.
- * @note This structure is used to store values in a list.
- * A useful addition when handling PDD strings.
- */
-int bootenv_list_create(bootenv_list_t *list);
-
-/**
- * @brief Destroy a bootenv list structure
- * @param list Handle to a bootenv list structure.
- * @return 0
- * @return or error
- */
-int bootenv_list_destroy(bootenv_list_t *list);
-
-/**
- * @brief Import a list from a comma seperated string
- * @param list Handle to a bootenv list structure.
- * @param str Comma seperated string list.
- * @return 0
- * @return or error
- */
-int bootenv_list_import(bootenv_list_t list, const char *str);
-
-/**
- * @brief Export a list to a string of comma seperated values.
- * @param list Handle to a bootenv list structure.
- * @return NULL one error
- * @return or pointer to a newly allocated string.
- * @warning Free the allocated memory by yourself!
- */
-int bootenv_list_export(bootenv_list_t list, char **string);
-
-/**
- * @brief Add an item to the list.
- * @param list A handle of a list structure.
- * @param item An item.
- * @return 0
- * @return or error
- */
-int bootenv_list_add(bootenv_list_t list, const char *item);
-
-/**
- * @brief Remove an item from the list.
- * @param list A handle of a list structure.
- * @param item An item.
- * @return 0
- * @return or error
- */
-int bootenv_list_remove(bootenv_list_t list, const char *item);
-
-/**
- * @brief Check if a given item is in a given list.
- * @param list A handle of a list structure.
- * @param item An item.
- * @return 1 Item is in list.
- * @return 0 Item is not in list.
- */
-int bootenv_list_is_in(bootenv_list_t list, const char *item);
-
-
-/**
- * @brief Convert a list into a vector of all values inside the list.
- * @param list Handle to a bootenv structure.
- * @param size The size of the allocated vector structure.
- * @return 0
- * @return or error
- * @warning Free the allocate memory yourself!
- */
-int bootenv_list_to_vector(bootenv_list_t list, size_t *size,
- const char ***vector);
-
-/**
- * @brief Convert a list into a vector of all values inside the list.
- * @param list Handle to a bootenv structure.
- * @param size The size of the allocated vector structure.
- * @return 0
- * @return or error
- * @warning Free the allocate memory yourself!
- */
-int bootenv_list_to_num_vector(bootenv_list_t list, size_t *size,
- uint32_t **vector);
-
-#ifdef __cplusplus
-}
-#endif
-#endif /*__BOOTENV_H__ */
diff --git a/ubi-utils/src/common.c b/ubi-utils/src/common.c
new file mode 100644
index 0000000..bcb775c
--- /dev/null
+++ b/ubi-utils/src/common.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2007, 2008 Nokia Corporation
+ *
+ * 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.
+ */
+
+/*
+ * This file contains various common stuff used by UBI utilities.
+ *
+ * Authors: Artem Bityutskiy
+ * Adrian Hunter
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/**
+ * get_multiplier - convert size specifier to an integer multiplier.
+ * @str: the size specifier string
+ *
+ * This function parses the @str size specifier, which may be one of
+ * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive
+ * size multiplier in case of success and %-1 in case of failure.
+ */
+static int get_multiplier(const char *str)
+{
+ if (!str)
+ return 1;
+
+ /* Remove spaces before the specifier */
+ while (*str == ' ' || *str == '\t')
+ str += 1;
+
+ if (!strcmp(str, "KiB"))
+ return 1024;
+ if (!strcmp(str, "MiB"))
+ return 1024 * 1024;
+ if (!strcmp(str, "GiB"))
+ return 1024 * 1024 * 1024;
+
+ /* Handle deprecated stuff */
+ if (!strcmp(str, "KB") || !strcmp(str, "Kib") || !strcmp(str, "kib") ||
+ !strcmp(str, "kiB")) {
+ fprintf(stderr, "Warning: use \"KiB\" instead of \"%s\" to "
+ "specify Kilobytes - support will be removed\n", str);
+ return 1024;
+ }
+ if (!strcmp(str, "MB") || !strcmp(str, "Mib") || !strcmp(str, "mb")) {
+ fprintf(stderr, "Warning: use \"MiB\" instead of \"%s\", "
+ "this support will be removed\n", str);
+ return 1024*1024;
+ }
+ if (!strcmp(str, "GB") || !strcmp(str, "Gib") || !strcmp(str, "gb")) {
+ fprintf(stderr, "Warning: use \"GiB\" instead of \"%s\", "
+ "this support will be removed\n", str);
+ return 1024*1024*1024;
+ }
+
+ return -1;
+}
+
+/**
+ * ubiutils_get_bytes - convert a string containing amount of bytes into an
+ * integer
+ * @str: string to convert
+ *
+ * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB'
+ * size specifiers. Returns positive amount of bytes in case of success and %-1
+ * in case of failure.
+ */
+long long ubiutils_get_bytes(const char *str)
+{
+ char *endp;
+ long long bytes = strtoull(str, &endp, 0);
+
+ if (endp == str || bytes < 0) {
+ fprintf(stderr, "incorrect amount of bytes: \"%s\"\n", str);
+ return -1;
+ }
+
+ if (*endp != '\0') {
+ int mult = get_multiplier(endp);
+
+ if (mult == -1) {
+ fprintf(stderr, "bad size specifier: \"%s\" - "
+ "should be 'KiB', 'MiB' or 'GiB'\n", endp);
+ return -1;
+ }
+ bytes *= mult;
+ }
+
+ return bytes;
+}
+
+/**
+ * ubiutils_print_bytes - print bytes.
+ * @bytes: variable to print
+ * @bracket: whether brackets have to be put or not
+ *
+ * This is a helper function which prints amount of bytes in a human-readable
+ * form, i.e., it prints the exact amount of bytes following by the approximate
+ * amount of Kilobytes, Megabytes, or Gigabytes, depending on how big @bytes
+ * is.
+ */
+void ubiutils_print_bytes(long long bytes, int bracket)
+{
+ const char *p;
+
+ if (bracket)
+ p = " (";
+ else
+ p = ", ";
+
+ printf("%lld bytes", bytes);
+
+ if (bytes > 1024 * 1024 * 1024)
+ printf("%s%.1f GiB", p, (double)bytes / (1024 * 1024 * 1024));
+ else if (bytes > 1024 * 1024)
+ printf("%s%.1f MiB", p, (double)bytes / (1024 * 1024));
+ else if (bytes > 1024 && bytes != 0)
+ printf("%s%.1f KiB", p, (double)bytes / 1024);
+ else
+ return;
+
+ if (bracket)
+ printf(")");
+}
+
+/**
+ * ubiutils_print_text - print text and fold it.
+ * @stream: file stream to print to
+ * @text: text to print
+ * @width: maximum allowed text width
+ *
+ * Print text and fold it so that each line would not have more then @width
+ * characters.
+ */
+void ubiutils_print_text(FILE *stream, const char *text, int width)
+{
+ int pos, bpos = 0;
+ const char *p;
+ char line[1024];
+
+ if (width > 1023) {
+ fprintf(stream, "%s\n", text);
+ return;
+ }
+ p = text;
+ pos = 0;
+ while (p[pos]) {
+ while (!isspace(p[pos])) {
+ line[pos] = p[pos];
+ if (!p[pos])
+ break;
+ ++pos;
+ if (pos == width) {
+ line[pos] = '\0';
+ fprintf(stream, "%s\n", line);
+ p += pos;
+ pos = 0;
+ }
+ }
+ while (pos < width) {
+ line[pos] = p[pos];
+ if (!p[pos]) {
+ bpos = pos;
+ break;
+ }
+ if (isspace(p[pos]))
+ bpos = pos;
+ ++pos;
+ }
+ line[bpos] = '\0';
+ fprintf(stream, "%s\n", line);
+ p += bpos;
+ pos = 0;
+ while (p[pos] && isspace(p[pos]))
+ ++p;
+ }
+}
diff --git a/ubi-utils/src/common.h b/ubi-utils/src/common.h
new file mode 100644
index 0000000..56fa020
--- /dev/null
+++ b/ubi-utils/src/common.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) Artem Bityutskiy, 2007, 2008
+ *
+ * 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.
+ */
+
+#ifndef __UBI_UTILS_COMMON_H__
+#define __UBI_UTILS_COMMON_H__
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MIN(a ,b) ((a) < (b) ? (a) : (b))
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+/* Verbose messages */
+#define verbose(verbose, fmt, ...) do { \
+ if (verbose) \
+ printf(PROGRAM_NAME ": " fmt "\n", ##__VA_ARGS__); \
+} while(0)
+
+/* Normal messages */
+#define normsg(fmt, ...) do { \
+ printf(PROGRAM_NAME ": " fmt "\n", ##__VA_ARGS__); \
+} while(0)
+#define normsg_cont(fmt, ...) do { \
+ printf(PROGRAM_NAME ": " fmt, ##__VA_ARGS__); \
+} while(0)
+#define normsg_cont(fmt, ...) do { \
+ printf(PROGRAM_NAME ": " fmt, ##__VA_ARGS__); \
+} while(0)
+
+/* Error messages */
+#define errmsg(fmt, ...) ({ \
+ fprintf(stderr, PROGRAM_NAME ": error!: " fmt "\n", ##__VA_ARGS__); \
+ -1; \
+})
+
+/* System error messages */
+#define sys_errmsg(fmt, ...) ({ \
+ int _err = errno; \
+ size_t _i; \
+ fprintf(stderr, PROGRAM_NAME ": error!: " fmt "\n", ##__VA_ARGS__); \
+ for (_i = 0; _i < sizeof(PROGRAM_NAME) + 1; _i++) \
+ fprintf(stderr, " "); \
+ fprintf(stderr, "error %d (%s)\n", _err, strerror(_err)); \
+ -1; \
+})
+
+/* Warnings */
+#define warnmsg(fmt, ...) do { \
+ fprintf(stderr, PROGRAM_NAME ": warning!: " fmt "\n", ##__VA_ARGS__); \
+} while(0)
+
+static inline int is_power_of_2(unsigned long long n)
+{
+ return (n != 0 && ((n & (n - 1)) == 0));
+}
+
+long long ubiutils_get_bytes(const char *str);
+void ubiutils_print_bytes(long long bytes, int bracket);
+void ubiutils_print_text(FILE *stream, const char *txt, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__UBI_UTILS_COMMON_H__ */
diff --git a/ubi-utils/src/config.h b/ubi-utils/src/config.h
deleted file mode 100644
index 55e60f3..0000000
--- a/ubi-utils/src/config.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef __CONFIG_H__
-#define __CONFIG_H__
-/*
- * 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.
- *
- * Author: Frank Haverkamp
- */
-
-#define PACKAGE_BUGREPORT \
- "haver@vnet.ibm.com, dedekind@linutronix.de, or tglx@linutronix.de"
-
-#define ubi_unused __attribute__((unused))
-
-#endif
diff --git a/ubi-utils/src/crc32.c b/ubi-utils/src/crc32.c
index 666e217..6b1e50c 100644
--- a/ubi-utils/src/crc32.c
+++ b/ubi-utils/src/crc32.c
@@ -1,83 +1,95 @@
/*
- * Copyright (c) International Business Machines Corp., 2006
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
*
- * 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.
+ * First, the polynomial itself and its table of feedback terms. The
+ * polynomial is
+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
*
- * 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.
+ * Note that we take it "backwards" and put the highest-order term in
+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
+ * the MSB being 1
*
- * 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.
+ * Note that the usual hardware shift register implementation, which
+ * is what we're using (we're merely optimizing it by doing eight-bit
+ * chunks at a time) shifts bits into the lowest-order term. In our
+ * implementation, that means shifting towards the right. Why do we
+ * do it this way? Because the calculated CRC must be transmitted in
+ * order from highest-order term to lowest-order term. UARTs transmit
+ * characters in order from LSB to MSB. By storing the CRC this way
+ * we hand it to the UART in the order low-byte to high-byte; the UART
+ * sends each low-bit to hight-bit; and the result is transmission bit
+ * by bit from highest- to lowest-order term without requiring any bit
+ * shuffling on our part. Reception works similarly
*
- * Author: Thomas Gleixner
- */
-
-/*
- * CRC32 functions
+ * The feedback terms table consists of 256, 32-bit entries. Notes
*
- * Can be compiled as seperate object, but is included into the ipl source
- * so gcc can inline the functions. We optimize for size so the omission of
- * the function frame is helpful.
+ * The table can be generated at runtime if desired; code to do so
+ * is shown later. It might not be obvious, but the feedback
+ * terms simply represent the results of eight shift/xor opera
+ * tions for all combinations of data and CRC register values
*
+ * The values must be right-shifted by eight bits by the "updcrc
+ * logic; the shift must be unsigned (bring in zeroes). On some
+ * hardware you could probably optimize the shift in assembler by
+ * using byte-swap instructions
+ * polynomial $edb88320
*/
#include <stdint.h>
-#include <crc32.h>
-
-/* CRC polynomial */
-#define CRC_POLY 0xEDB88320
-
-/**
- * init_crc32_table - Initialize crc table
- *
- * @table: pointer to the CRC table which must be initialized
- *
- * Create CRC32 table for given polynomial. The table is created with
- * the lowest order term in the highest order bit. So the x^32 term
- * has to implied in the crc calculation function.
- */
-void init_crc32_table(uint32_t *table)
-{
- uint32_t crc;
- int i, j;
-
- for (i = 0; i < 256; i++) {
- crc = i;
- for (j = 8; j > 0; j--) {
- if (crc & 1)
- crc = (crc >> 1) ^ CRC_POLY;
- else
- crc >>= 1;
- }
- table[i] = crc;
- }
-}
-
-/**
- * clc_crc32 - Calculate CRC32 over a buffer
- *
- * @table: pointer to the CRC table
- * @crc: initial crc value
- * @buf: pointer to the buffer
- * @len: number of bytes to calc
- *
- * Returns the updated crc value.
- *
- * The algorithm resembles a hardware shift register, but calculates 8
- * bit at once.
- */
-uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf,
- int len)
-{
- const unsigned char *p = buf;
- while(--len >= 0)
- crc = table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
- return crc;
-}
+const uint32_t crc32_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
diff --git a/ubi-utils/src/crc32.h b/ubi-utils/src/crc32.h
index 31362b0..ee3145b 100644
--- a/ubi-utils/src/crc32.h
+++ b/ubi-utils/src/crc32.h
@@ -1,36 +1,19 @@
-#ifndef __CRC32_H__
-#define __CRC32_H__
-/*
- * 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.
- */
+#ifndef CRC32_H
+#define CRC32_H
-/*
- * Author: Thomas Gleixner
- *
- * CRC32 functions
- *
- * Can be compiled as seperate object, but is included into the ipl source
- * so gcc can inline the functions. We optimize for size so the omission of
- * the function frame is helpful.
- *
- */
#include <stdint.h>
-void init_crc32_table(uint32_t *table);
-uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, int len);
+extern const uint32_t crc32_table[256];
-#endif /* __CRC32_H__ */
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+ static inline uint32_t
+crc32(uint32_t val, const void *ss, int len)
+{
+ const unsigned char *s = ss;
+ while (--len >= 0)
+ val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
+ return val;
+}
+
+#endif
diff --git a/ubi-utils/src/dictionary.c b/ubi-utils/src/dictionary.c
new file mode 100644
index 0000000..b7c9ebf
--- /dev/null
+++ b/ubi-utils/src/dictionary.c
@@ -0,0 +1,405 @@
+/*-------------------------------------------------------------------------*/
+/**
+ @file dictionary.c
+ @author N. Devillard
+ @date Sep 2007
+ @version $Revision: 1.27 $
+ @brief Implements a dictionary for string variables.
+
+ This module implements a simple dictionary object, i.e. a list
+ of string/string associations. This object is useful to store e.g.
+ informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ $Id: dictionary.c,v 1.27 2007-11-23 21:39:18 ndevilla Exp $
+ $Revision: 1.27 $
+*/
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+#include "dictionary.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/** Maximum value size for integers and doubles. */
+#define MAXVALSZ 1024
+
+/** Minimal allocated number of entries in a dictionary */
+#define DICTMINSZ 128
+
+/** Invalid key token */
+#define DICT_INVALID_KEY ((char*)-1)
+
+/*---------------------------------------------------------------------------
+ Private functions
+ ---------------------------------------------------------------------------*/
+
+/* Doubles the allocated size associated to a pointer */
+/* 'size' is the current allocated size. */
+static void * mem_double(void * ptr, int size)
+{
+ void * newptr ;
+
+ newptr = calloc(2*size, 1);
+ if (newptr==NULL) {
+ return NULL ;
+ }
+ memcpy(newptr, ptr, size);
+ free(ptr);
+ return newptr ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Duplicate a string
+ @param s String to duplicate
+ @return Pointer to a newly allocated string, to be freed with free()
+
+ This is a replacement for strdup(). This implementation is provided
+ for systems that do not have it.
+ */
+/*--------------------------------------------------------------------------*/
+static char * xstrdup(char * s)
+{
+ char * t ;
+ if (!s)
+ return NULL ;
+ t = malloc(strlen(s)+1) ;
+ if (t) {
+ strcpy(t,s);
+ }
+ return t ;
+}
+
+/*---------------------------------------------------------------------------
+ Function codes
+ ---------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Compute the hash key for a string.
+ @param key Character string to use for key.
+ @return 1 unsigned int on at least 32 bits.
+
+ This hash function has been taken from an Article in Dr Dobbs Journal.
+ This is normally a collision-free function, distributing keys evenly.
+ The key is stored anyway in the struct so that collision can be avoided
+ by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+unsigned dictionary_hash(char * key)
+{
+ int len ;
+ unsigned hash ;
+ int i ;
+
+ len = strlen(key);
+ for (hash=0, i=0 ; i<len ; i++) {
+ hash += (unsigned)key[i] ;
+ hash += (hash<<10);
+ hash ^= (hash>>6) ;
+ }
+ hash += (hash <<3);
+ hash ^= (hash >>11);
+ hash += (hash <<15);
+ return hash ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Create a new dictionary object.
+ @param size Optional initial size of the dictionary.
+ @return 1 newly allocated dictionary objet.
+
+ This function allocates a new dictionary object of given size and returns
+ it. If you do not know in advance (roughly) the number of entries in the
+ dictionary, give size=0.
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * dictionary_new(int size)
+{
+ dictionary * d ;
+
+ /* If no size was specified, allocate space for DICTMINSZ */
+ if (size<DICTMINSZ) size=DICTMINSZ ;
+
+ if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) {
+ return NULL;
+ }
+ d->size = size ;
+ d->val = (char **)calloc(size, sizeof(char*));
+ d->key = (char **)calloc(size, sizeof(char*));
+ d->hash = (unsigned int *)calloc(size, sizeof(unsigned));
+ return d ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a dictionary object
+ @param d dictionary object to deallocate.
+ @return void
+
+ Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_del(dictionary * d)
+{
+ int i ;
+
+ if (d==NULL) return ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]!=NULL)
+ free(d->key[i]);
+ if (d->val[i]!=NULL)
+ free(d->val[i]);
+ }
+ free(d->val);
+ free(d->key);
+ free(d->hash);
+ free(d);
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value to return if key not found.
+ @return 1 pointer to internally allocated character string.
+
+ This function locates a key in a dictionary and returns a pointer to its
+ value, or the passed 'def' pointer if no such key can be found in
+ dictionary. The returned character pointer points to data internal to the
+ dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * dictionary_get(dictionary * d, char * key, char * def)
+{
+ unsigned hash ;
+ int i ;
+
+ hash = dictionary_hash(key);
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ /* Compare hash */
+ if (hash==d->hash[i]) {
+ /* Compare string, to avoid hash collisions */
+ if (!strcmp(key, d->key[i])) {
+ return d->val[i] ;
+ }
+ }
+ }
+ return def ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set a value in a dictionary.
+ @param d dictionary object to modify.
+ @param key Key to modify or add.
+ @param val Value to add.
+ @return int 0 if Ok, anything else otherwise
+
+ If the given key is found in the dictionary, the associated value is
+ replaced by the provided one. If the key cannot be found in the
+ dictionary, it is added to it.
+
+ It is Ok to provide a NULL value for val, but NULL values for the dictionary
+ or the key are considered as errors: the function will return immediately
+ in such a case.
+
+ Notice that if you dictionary_set a variable to NULL, a call to
+ dictionary_get will return a NULL value: the variable will be found, and
+ its value (NULL) is returned. In other words, setting the variable
+ content to NULL is equivalent to deleting the variable from the
+ dictionary. It is not possible (in this implementation) to have a key in
+ the dictionary without value.
+
+ This function returns non-zero in case of failure.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_set(dictionary * d, char * key, char * val)
+{
+ int i ;
+ unsigned hash ;
+
+ if (d==NULL || key==NULL) return -1 ;
+
+ /* Compute hash for this key */
+ hash = dictionary_hash(key) ;
+ /* Find if value is already in dictionary */
+ if (d->n>0) {
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (hash==d->hash[i]) { /* Same hash value */
+ if (!strcmp(key, d->key[i])) { /* Same key */
+ /* Found a value: modify and return */
+ if (d->val[i]!=NULL)
+ free(d->val[i]);
+ d->val[i] = val ? xstrdup(val) : NULL ;
+ /* Value has been modified: return */
+ return 0 ;
+ }
+ }
+ }
+ }
+ /* Add a new value */
+ /* See if dictionary needs to grow */
+ if (d->n==d->size) {
+
+ /* Reached maximum size: reallocate dictionary */
+ d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ;
+ d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ;
+ d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ;
+ if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) {
+ /* Cannot grow dictionary */
+ return -1 ;
+ }
+ /* Double size */
+ d->size *= 2 ;
+ }
+
+ /* Insert key in the first empty slot */
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL) {
+ /* Add key here */
+ break ;
+ }
+ }
+ /* Copy key */
+ d->key[i] = xstrdup(key);
+ d->val[i] = val ? xstrdup(val) : NULL ;
+ d->hash[i] = hash;
+ d->n ++ ;
+ return 0 ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a key in a dictionary
+ @param d dictionary object to modify.
+ @param key Key to remove.
+ @return void
+
+ This function deletes a key in a dictionary. Nothing is done if the
+ key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, char * key)
+{
+ unsigned hash ;
+ int i ;
+
+ if (key == NULL) {
+ return;
+ }
+
+ hash = dictionary_hash(key);
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ /* Compare hash */
+ if (hash==d->hash[i]) {
+ /* Compare string, to avoid hash collisions */
+ if (!strcmp(key, d->key[i])) {
+ /* Found key */
+ break ;
+ }
+ }
+ }
+ if (i>=d->size)
+ /* Key not found */
+ return ;
+
+ free(d->key[i]);
+ d->key[i] = NULL ;
+ if (d->val[i]!=NULL) {
+ free(d->val[i]);
+ d->val[i] = NULL ;
+ }
+ d->hash[i] = 0 ;
+ d->n -- ;
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump
+ @param f Opened file pointer.
+ @return void
+
+ Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+ as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+ output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_dump(dictionary * d, FILE * out)
+{
+ int i ;
+
+ if (d==NULL || out==NULL) return ;
+ if (d->n<1) {
+ fprintf(out, "empty dictionary\n");
+ return ;
+ }
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]) {
+ fprintf(out, "%20s\t[%s]\n",
+ d->key[i],
+ d->val[i] ? d->val[i] : "UNDEF");
+ }
+ }
+ return ;
+}
+
+
+/* Test code */
+#ifdef TESTDIC
+#define NVALS 20000
+int main(int argc, char *argv[])
+{
+ dictionary * d ;
+ char * val ;
+ int i ;
+ char cval[90] ;
+
+ /* Allocate dictionary */
+ printf("allocating...\n");
+ d = dictionary_new(0);
+
+ /* Set values in dictionary */
+ printf("setting %d values...\n", NVALS);
+ for (i=0 ; i<NVALS ; i++) {
+ sprintf(cval, "%04d", i);
+ dictionary_set(d, cval, "salut");
+ }
+ printf("getting %d values...\n", NVALS);
+ for (i=0 ; i<NVALS ; i++) {
+ sprintf(cval, "%04d", i);
+ val = dictionary_get(d, cval, DICT_INVALID_KEY);
+ if (val==DICT_INVALID_KEY) {
+ printf("cannot get value for key [%s]\n", cval);
+ }
+ }
+ printf("unsetting %d values...\n", NVALS);
+ for (i=0 ; i<NVALS ; i++) {
+ sprintf(cval, "%04d", i);
+ dictionary_unset(d, cval);
+ }
+ if (d->n != 0) {
+ printf("error deleting values\n");
+ }
+ printf("deallocating...\n");
+ dictionary_del(d);
+ return 0 ;
+}
+#endif
+/* vim: set ts=4 et sw=4 tw=75 */
diff --git a/ubi-utils/src/dictionary.h b/ubi-utils/src/dictionary.h
new file mode 100644
index 0000000..c7d1790
--- /dev/null
+++ b/ubi-utils/src/dictionary.h
@@ -0,0 +1,174 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file dictionary.h
+ @author N. Devillard
+ @date Sep 2007
+ @version $Revision: 1.12 $
+ @brief Implements a dictionary for string variables.
+
+ This module implements a simple dictionary object, i.e. a list
+ of string/string associations. This object is useful to store e.g.
+ informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ $Id: dictionary.h,v 1.12 2007-11-23 21:37:00 ndevilla Exp $
+ $Author: ndevilla $
+ $Date: 2007-11-23 21:37:00 $
+ $Revision: 1.12 $
+*/
+
+#ifndef _DICTIONARY_H_
+#define _DICTIONARY_H_
+
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*---------------------------------------------------------------------------
+ New types
+ ---------------------------------------------------------------------------*/
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dictionary object
+
+ This object contains a list of string/string associations. Each
+ association is identified by a unique string key. Looking up values
+ in the dictionary is speeded up by the use of a (hopefully collision-free)
+ hash function.
+ */
+/*-------------------------------------------------------------------------*/
+typedef struct _dictionary_ {
+ int n ; /** Number of entries in dictionary */
+ int size ; /** Storage size */
+ char ** val ; /** List of string values */
+ char ** key ; /** List of string keys */
+ unsigned * hash ; /** List of hash values for keys */
+} dictionary ;
+
+
+/*---------------------------------------------------------------------------
+ Function prototypes
+ ---------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Compute the hash key for a string.
+ @param key Character string to use for key.
+ @return 1 unsigned int on at least 32 bits.
+
+ This hash function has been taken from an Article in Dr Dobbs Journal.
+ This is normally a collision-free function, distributing keys evenly.
+ The key is stored anyway in the struct so that collision can be avoided
+ by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+unsigned dictionary_hash(char * key);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Create a new dictionary object.
+ @param size Optional initial size of the dictionary.
+ @return 1 newly allocated dictionary objet.
+
+ This function allocates a new dictionary object of given size and returns
+ it. If you do not know in advance (roughly) the number of entries in the
+ dictionary, give size=0.
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * dictionary_new(int size);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a dictionary object
+ @param d dictionary object to deallocate.
+ @return void
+
+ Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_del(dictionary * vd);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value to return if key not found.
+ @return 1 pointer to internally allocated character string.
+
+ This function locates a key in a dictionary and returns a pointer to its
+ value, or the passed 'def' pointer if no such key can be found in
+ dictionary. The returned character pointer points to data internal to the
+ dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * dictionary_get(dictionary * d, char * key, char * def);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set a value in a dictionary.
+ @param d dictionary object to modify.
+ @param key Key to modify or add.
+ @param val Value to add.
+ @return int 0 if Ok, anything else otherwise
+
+ If the given key is found in the dictionary, the associated value is
+ replaced by the provided one. If the key cannot be found in the
+ dictionary, it is added to it.
+
+ It is Ok to provide a NULL value for val, but NULL values for the dictionary
+ or the key are considered as errors: the function will return immediately
+ in such a case.
+
+ Notice that if you dictionary_set a variable to NULL, a call to
+ dictionary_get will return a NULL value: the variable will be found, and
+ its value (NULL) is returned. In other words, setting the variable
+ content to NULL is equivalent to deleting the variable from the
+ dictionary. It is not possible (in this implementation) to have a key in
+ the dictionary without value.
+
+ This function returns non-zero in case of failure.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_set(dictionary * vd, char * key, char * val);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a key in a dictionary
+ @param d dictionary object to modify.
+ @param key Key to remove.
+ @return void
+
+ This function deletes a key in a dictionary. Nothing is done if the
+ key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, char * key);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump
+ @param f Opened file pointer.
+ @return void
+
+ Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+ as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+ output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_dump(dictionary * d, FILE * out);
+
+#endif
diff --git a/ubi-utils/src/eb_chain.c b/ubi-utils/src/eb_chain.c
deleted file mode 100644
index da5c2e3..0000000
--- a/ubi-utils/src/eb_chain.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2006, 2007
- *
- * 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.
- */
-
-/*
- * Author: Drake Dowsett, dowsett@de.ibm.com
- * Contact: Andreas Arnez, arnez@de.ibm.com
- */
-
-/* see eb_chain.h */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <mtd_swab.h>
-#include "unubi_analyze.h"
-#include "crc32.h"
-
-#define COPY(dst, src) \
- do { \
- dst = malloc(sizeof(*dst)); \
- if (dst == NULL) \
- return -ENOMEM; \
- memcpy(dst, src, sizeof(*dst)); \
- } while (0)
-
-
-/**
- * inserts an eb_info into the chain starting at head, then searching
- * linearly for the correct position;
- * new should contain valid vid and ec headers and the data_crc should
- * already have been checked before insertion, otherwise the chain
- * could be have un an undesired manner;
- * returns -ENOMEM if alloc fails, otherwise SHOULD always return 0,
- * if not, the code reached the last line and returned -EAGAIN,
- * meaning there is a bug or a case not being handled here;
- **/
-int
-eb_chain_insert(struct eb_info **head, struct eb_info *new)
-{
- uint32_t vol, num, ver;
- uint32_t new_vol, new_num, new_ver;
- struct eb_info *prev, *cur, *hist, *ins;
- struct eb_info **prev_ptr;
-
- if ((head == NULL) || (new == NULL))
- return 0;
-
- if (*head == NULL) {
- COPY(*head, new);
- (*head)->next = NULL;
- return 0;
- }
-
- new_vol = be32_to_cpu(new->vid.vol_id);
- new_num = be32_to_cpu(new->vid.lnum);
- new_ver = be32_to_cpu(new->vid.leb_ver);
-
- /** TRAVERSE HORIZONTALY **/
-
- cur = *head;
- prev = NULL;
-
- /* traverse until vol_id/lnum align */
- vol = be32_to_cpu(cur->vid.vol_id);
- num = be32_to_cpu(cur->vid.lnum);
- while ((new_vol > vol) || ((new_vol == vol) && (new_num > num))) {
- /* insert new at end of chain */
- if (cur->next == NULL) {
- COPY(ins, new);
- ins->next = NULL;
- cur->next = ins;
- return 0;
- }
-
- prev = cur;
- cur = cur->next;
- vol = be32_to_cpu(cur->vid.vol_id);
- num = be32_to_cpu(cur->vid.lnum);
- }
-
- if (prev == NULL)
- prev_ptr = head;
- else
- prev_ptr = &(prev->next);
-
- /* insert new into the middle of chain */
- if ((new_vol != vol) || (new_num != num)) {
- COPY(ins, new);
- ins->next = cur;
- *prev_ptr = ins;
- return 0;
- }
-
- /** TRAVERSE VERTICALY **/
-
- hist = cur;
- prev = NULL;
-
- /* traverse until versions align */
- ver = be32_to_cpu(cur->vid.leb_ver);
- while (new_ver < ver) {
- /* insert new at bottom of history */
- if (hist->older == NULL) {
- COPY(ins, new);
- ins->next = NULL;
- ins->older = NULL;
- hist->older = ins;
- return 0;
- }
-
- prev = hist;
- hist = hist->older;
- ver = be32_to_cpu(hist->vid.leb_ver);
- }
-
- if (prev == NULL) {
- /* replace active version */
- COPY(ins, new);
- ins->next = hist->next;
- *prev_ptr = ins;
-
- /* place cur in vertical histroy */
- ins->older = hist;
- hist->next = NULL;
- return 0;
- }
-
- /* insert between versions, beneath active version */
- COPY(ins, new);
- ins->next = NULL;
- ins->older = prev->older;
- prev->older = ins;
- return 0;
-}
-
-
-/**
- * sets the pointer at pos to the position of the first entry in the chain
- * with of vol_id and, if given, with the same lnum as *lnum;
- * if there is no entry in the chain, then *pos is NULL on return;
- * always returns 0;
- **/
-int
-eb_chain_position(struct eb_info **head, uint32_t vol_id, uint32_t *lnum,
- struct eb_info **pos)
-{
- uint32_t vol, num;
- struct eb_info *cur;
-
- if ((head == NULL) || (*head == NULL) || (pos == NULL))
- return 0;
-
- *pos = NULL;
-
- cur = *head;
- while (cur != NULL) {
- vol = be32_to_cpu(cur->vid.vol_id);
- num = be32_to_cpu(cur->vid.lnum);
-
- if ((vol_id == vol) && ((lnum == NULL) || (*lnum == num))) {
- *pos = cur;
- return 0;
- }
-
- cur = cur->next;
- }
-
- return 0;
-}
-
-
-/**
- * prints to stream, the vol_id, lnum and leb_ver for each entry in the
- * chain, starting at head;
- * this is intended for debuging purposes;
- * always returns 0;
- *
- * FIXME I do not like the double list traversion ...
- **/
-int
-eb_chain_print(FILE* stream, struct eb_info *head)
-{
- struct eb_info *cur;
-
- if (stream == NULL)
- stream = stdout;
-
- if (head == NULL) {
- fprintf(stream, "EMPTY\n");
- return 0;
- }
- /* 012345678012345678012345678012301230123 0123 01234567 0123457 01234567*/
- fprintf(stream, "VOL_ID LNUM LEB_VER EC VID DAT PBLK PADDR DSIZE EC\n");
- cur = head;
- while (cur != NULL) {
- struct eb_info *hist;
-
- fprintf(stream, "%08x %-8u %08x %-4s%-4s",
- be32_to_cpu(cur->vid.vol_id),
- be32_to_cpu(cur->vid.lnum),
- be32_to_cpu(cur->vid.leb_ver),
- cur->ec_crc_ok ? "ok":"bad",
- cur->vid_crc_ok ? "ok":"bad");
- if (cur->vid.vol_type == UBI_VID_STATIC)
- fprintf(stream, "%-4s", cur->data_crc_ok ? "ok":"bad");
- else fprintf(stream, "%-4s", cur->data_crc_ok ? "ok":"ign");
- fprintf(stream, " %-4d %08x %-8u %-8llu\n", cur->phys_block,
- cur->phys_addr, be32_to_cpu(cur->vid.data_size),
- (unsigned long long)be64_to_cpu(cur->ec.ec));
-
- hist = cur->older;
- while (hist != NULL) {
- fprintf(stream, "%08x %-8u %08x %-4s%-4s",
- be32_to_cpu(hist->vid.vol_id),
- be32_to_cpu(hist->vid.lnum),
- be32_to_cpu(hist->vid.leb_ver),
- hist->ec_crc_ok ? "ok":"bad",
- hist->vid_crc_ok ? "ok":"bad");
- if (hist->vid.vol_type == UBI_VID_STATIC)
- fprintf(stream, "%-4s", hist->data_crc_ok ? "ok":"bad");
- else fprintf(stream, "%-4s", hist->data_crc_ok ? "ok":"ign");
- fprintf(stream, " %-4d %08x %-8u %-8llu (*)\n",
- hist->phys_block, hist->phys_addr,
- be32_to_cpu(hist->vid.data_size),
- (unsigned long long)be64_to_cpu(hist->ec.ec));
-
- hist = hist->older;
- }
- cur = cur->next;
- }
-
- return 0;
-}
-
-
-/**
- * frees the memory of the entire chain, starting at head;
- * head will be NULL on return;
- * always returns 0;
- **/
-int
-eb_chain_destroy(struct eb_info **head)
-{
- if (head == NULL)
- return 0;
-
- while (*head != NULL) {
- struct eb_info *cur;
- struct eb_info *hist;
-
- cur = *head;
- *head = (*head)->next;
-
- hist = cur->older;
- while (hist != NULL) {
- struct eb_info *temp;
-
- temp = hist;
- hist = hist->older;
- free(temp);
- }
- free(cur);
- }
- return 0;
-}
-
diff --git a/ubi-utils/src/error.c b/ubi-utils/src/error.c
deleted file mode 100644
index 4aaedad..0000000
--- a/ubi-utils/src/error.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * 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.
- */
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <syslog.h>
-#include <stdlib.h>
-#include <sys/errno.h>
-#include <string.h>
-#include "error.h"
-
-#define MAXLINE 4096
-#define MAXWIDTH 80
-
-static FILE *logfp = NULL;
-
-static void err_doit(int, int, const char *, va_list);
-
-int
-read_procfile(FILE *fp_out, const char *procfile)
-{
- FILE *fp;
-
- if (!fp_out)
- return -ENXIO;
-
- fp = fopen(procfile, "r");
- if (!fp)
- return -ENOENT;
-
- while(!feof(fp)) {
- int c = fgetc(fp);
-
- if (c == EOF)
- return 0;
-
- if (putc(c, fp_out) == EOF)
- return -EIO;
-
- if (ferror(fp))
- return -EIO;
- }
- return fclose(fp);
-}
-
-void
-error_initlog(const char *logfile)
-{
- if (!logfile)
- return;
-
- logfp = fopen(logfile, "a+");
- read_procfile(logfp, "/proc/cpuinfo");
-}
-
-void
-info_msg(const char *fmt, ...)
-{
- FILE* fpout;
- char buf[MAXLINE + 1];
- va_list ap;
- int n;
-
- fpout = stdout;
-
- va_start(ap, fmt);
- vsnprintf(buf, MAXLINE, fmt, ap);
- n = strlen(buf);
- strcat(buf, "\n");
-
- fputs(buf, fpout);
- fflush(fpout);
- if (fpout != stdout)
- fclose(fpout);
-
- va_end(ap);
- return;
-}
-
-void
-__err_ret(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- err_doit(1, LOG_INFO, fmt, ap);
- va_end(ap);
- return;
-}
-
-void
-__err_sys(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- err_doit(1, LOG_ERR, fmt, ap);
- va_end(ap);
- exit(EXIT_FAILURE);
-}
-
-
-void
-__err_msg(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- err_doit(0, LOG_INFO, fmt, ap);
- va_end(ap);
-
- return;
-}
-
-void
-__err_quit(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- err_doit(0, LOG_ERR, fmt, ap);
- va_end(ap);
- exit(EXIT_FAILURE);
-}
-
-void
-__err_dump(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- err_doit(1, LOG_ERR, fmt, ap);
- va_end(ap);
- abort(); /* dump core and terminate */
- exit(EXIT_FAILURE); /* shouldn't get here */
-}
-
-/**
- * If a logfile is used we must not print on stderr and stdout
- * anymore. Since pfilfash might be used in a server context, it is
- * even dangerous to write to those descriptors.
- */
-static void
-err_doit(int errnoflag, int level __attribute__((unused)),
- const char *fmt, va_list ap)
-{
- FILE* fpout;
- int errno_save, n;
- char buf[MAXLINE + 1];
- fpout = stderr;
-
- errno_save = errno; /* value caller might want printed */
-
- vsnprintf(buf, MAXLINE, fmt, ap); /* safe */
-
- n = strlen(buf);
-
- if (errnoflag)
- snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
- strcat(buf, "\n");
-
- if (logfp) {
- fputs(buf, logfp);
- fflush(logfp);
- return; /* exit when logging completes */
- }
-
- if (fpout == stderr) {
- /* perform line wrap when outputting to stderr */
- int word_len, post_len, chars;
- char *buf_ptr;
- const char *frmt = "%*s%n %n";
-
- chars = 0;
- buf_ptr = buf;
- while (sscanf(buf_ptr, frmt, &word_len, &post_len) != EOF) {
- int i;
- char word[word_len + 1];
- char post[post_len + 1];
-
- strncpy(word, buf_ptr, word_len);
- word[word_len] = '\0';
- buf_ptr += word_len;
- post_len -= word_len;
-
- if (chars + word_len > MAXWIDTH) {
- fputc('\n', fpout);
- chars = 0;
- }
- fputs(word, fpout);
- chars += word_len;
-
- if (post_len > 0) {
- strncpy(post, buf_ptr, post_len);
- post[post_len] = '\0';
- buf_ptr += post_len;
- }
- for (i = 0; i < post_len; i++) {
- int inc = 1, chars_new;
-
- if (post[i] == '\t')
- inc = 8;
- if (post[i] == '\n') {
- inc = 0;
- chars_new = 0;
- } else
- chars_new = chars + inc;
-
- if (chars_new > MAXWIDTH) {
- fputc('\n', fpout);
- chars_new = inc;
- }
- fputc(post[i], fpout);
- chars = chars_new;
- }
- }
- }
- else
- fputs(buf, fpout);
- fflush(fpout);
- if (fpout != stderr)
- fclose(fpout);
-
- return;
-}
diff --git a/ubi-utils/src/error.h b/ubi-utils/src/error.h
deleted file mode 100644
index 05d8078..0000000
--- a/ubi-utils/src/error.h
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef __ERROR_H__
-#define __ERROR_H__
-/*
- * 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.
- */
-
-#include <stdio.h>
-
-void error_initlog(const char *logfile);
-int read_procfile(FILE *fp_out, const char *procfile);
-
-void __err_ret(const char *fmt, ...);
-void __err_sys(const char *fmt, ...);
-void __err_msg(const char *fmt, ...);
-void __err_quit(const char *fmt, ...);
-void __err_dump(const char *fmt, ...);
-
-void info_msg(const char *fmt, ...);
-
-#ifdef DEBUG
-#define __loc_msg(str) do { \
- __err_msg("[%s. FILE: %s FUNC: %s LINE: %d]\n", \
- str, __FILE__, __FUNCTION__, __LINE__); \
-} while (0)
-#else
-#define __loc_msg(str)
-#endif
-
-
-#define err_dump(fmt, ...) do { \
- __loc_msg("ErrDump"); \
- __err_dump(fmt, ##__VA_ARGS__); \
-} while (0)
-
-#define err_quit(fmt, ...) do { \
- __loc_msg("ErrQuit"); \
- __err_quit(fmt, ##__VA_ARGS__); \
-} while (0)
-
-
-#define err_ret(fmt, ...) do { \
- __loc_msg("ErrRet"); \
- __err_ret(fmt, ##__VA_ARGS__); \
-} while (0)
-
-#define err_sys(fmt, ...) do { \
- __loc_msg("ErrSys"); \
- __err_sys(fmt, ##__VA_ARGS__); \
-} while (0)
-
-#define err_msg(fmt, ...) do { \
- __loc_msg("ErrMsg"); \
- __err_msg(fmt, ##__VA_ARGS__); \
-} while (0)
-
-#define log_msg(fmt, ...) do { \
- /* __loc_msg("LogMsg"); */ \
- __err_msg(fmt, ##__VA_ARGS__); \
-} while (0)
-
-#ifdef DEBUG
-#define dbg_msg(fmt, ...) do { \
- __loc_msg("DbgMsg"); \
- __err_msg(fmt, ##__VA_ARGS__); \
-} while (0)
-#else
-#define dbg_msg(fmt, ...) do {} while (0)
-#endif
-
-#endif /* __ERROR_H__ */
diff --git a/ubi-utils/src/example_ubi.h b/ubi-utils/src/example_ubi.h
deleted file mode 100644
index 23c7b54..0000000
--- a/ubi-utils/src/example_ubi.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef __EXAMPLE_UBI_H__
-#define __EXAMPLE_UBI_H__
-/*
- * 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.
- */
-
-/**
- * Defaults for our cards.
- */
-#define EXAMPLE_UBI_DEVICE 0
-#define EXAMPLE_BOOTENV_VOL_ID_1 4
-#define EXAMPLE_BOOTENV_VOL_ID_2 5
-
-#endif /* __EXAMPLE_UBI_H__ */
diff --git a/ubi-utils/src/hashmap.c b/ubi-utils/src/hashmap.c
deleted file mode 100644
index 3511d56..0000000
--- a/ubi-utils/src/hashmap.c
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * 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.
- *
- * Author: Oliver Lohmann
- */
-
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "error.h"
-#include "hashmap.h"
-#define DEFAULT_BUCKETS 4096
-
-#if 0
-#define INFO_MSG(fmt...) do { \
- info_msg(fmt); \
-} while (0)
-#else
-#define INFO_MSG(fmt...)
-#endif
-
-struct hashentry {
- char* key; /* key '0' term. str */
- char* value; /* payload '0' term. str */
-
- hashentry_t next;
-};
-
-struct hashmap {
- size_t entries; /* current #entries */
- size_t maxsize; /* no. of hash buckets */
- hashentry_t* data; /* array of buckets */
-};
-
-static int
-is_empty(hashentry_t l)
-{
- return l == NULL ? 1 : 0;
-}
-
-hashmap_t
-hashmap_new(void)
-{
- hashmap_t res;
- res = (hashmap_t) calloc(1, sizeof(struct hashmap));
-
- if (res == NULL)
- return NULL;
-
- res->maxsize = DEFAULT_BUCKETS;
- res->entries = 0;
-
- res->data = (hashentry_t*)
- calloc(1, res->maxsize * sizeof(struct hashentry));
-
- if (res->data == NULL)
- return NULL;
-
- return res;
-}
-
-static hashentry_t
-new_entry(const char* key, const char* value)
-{
- hashentry_t res;
-
- res = (hashentry_t) calloc(1, sizeof(struct hashentry));
-
- if (res == NULL)
- return NULL;
-
- /* allocate key and value and copy them */
- res->key = strdup(key);
- if (res->key == NULL) {
- free(res);
- return NULL;
- }
-
- res->value = strdup(value);
- if (res->value == NULL) {
- free(res->key);
- free(res);
- return NULL;
- }
-
- res->next = NULL;
-
- return res;
-}
-
-static hashentry_t
-free_entry(hashentry_t e)
-{
- if (!is_empty(e)) {
- if(e->key != NULL) {
- free(e->key);
- }
- if(e->value != NULL)
- free(e->value);
- free(e);
- }
-
- return NULL;
-}
-
-static hashentry_t
-remove_entry(hashentry_t l, const char* key, size_t* entries)
-{
- hashentry_t lnext;
- if (is_empty(l))
- return NULL;
-
- if(strcmp(l->key,key) == 0) {
- lnext = l->next;
- l = free_entry(l);
- (*entries)--;
- return lnext;
- }
-
- l->next = remove_entry(l->next, key, entries);
-
- return l;
-}
-
-static hashentry_t
-insert_entry(hashentry_t l, hashentry_t e, size_t* entries)
-{
- if (is_empty(l)) {
- (*entries)++;
- return e;
- }
-
- /* check for update */
- if (strcmp(l->key, e->key) == 0) {
- e->next = l->next;
- l = free_entry(l);
- return e;
- }
-
- l->next = insert_entry(l->next, e, entries);
- return l;
-}
-
-static hashentry_t
-remove_all(hashentry_t l, size_t* entries)
-{
- hashentry_t lnext;
- if (is_empty(l))
- return NULL;
-
- lnext = l->next;
- free_entry(l);
- (*entries)--;
-
- return remove_all(lnext, entries);
-}
-
-static const char*
-value_lookup(hashentry_t l, const char* key)
-{
- if (is_empty(l))
- return NULL;
-
- if (strcmp(l->key, key) == 0)
- return l->value;
-
- return value_lookup(l->next, key);
-}
-
-static void
-print_all(hashentry_t l)
-{
- if (is_empty(l)) {
- printf("\n");
- return;
- }
-
- printf("%s=%s", l->key, l->value);
- if (!is_empty(l->next)) {
- printf(",");
- }
-
- print_all(l->next);
-}
-
-static void
-keys_to_array(hashentry_t l, const char** a, size_t* i)
-{
- if (is_empty(l))
- return;
-
- a[*i] = l->key;
- (*i)++;
-
- keys_to_array(l->next, a, i);
-}
-
-uint32_t
-hash_str(const char* str, uint32_t mapsize)
-{
- uint32_t hash = 0;
- uint32_t x = 0;
- uint32_t i = 0;
- size_t len = strlen(str);
-
- for(i = 0; i < len; str++, i++) {
- hash = (hash << 4) + (*str);
- if((x = hash & 0xF0000000L) != 0) {
- hash ^= (x >> 24);
- hash &= ~x;
- }
- }
-
- return (hash & 0x7FFFFFFF) % mapsize;
-}
-
-
-int
-hashmap_is_empty(hashmap_t map)
-{
- if (map == NULL)
- return -EINVAL;
-
- return map->entries > 0 ? 1 : 0;
-}
-
-const char*
-hashmap_lookup(hashmap_t map, const char* key)
-{
- uint32_t i;
-
- if ((map == NULL) || (key == NULL))
- return NULL;
-
- i = hash_str(key, map->maxsize);
-
- return value_lookup(map->data[i], key);
-}
-
-int
-hashmap_add(hashmap_t map, const char* key, const char* value)
-{
- uint32_t i;
- hashentry_t entry;
-
- if ((map == NULL) || (key == NULL) || (value == NULL))
- return -EINVAL;
-
- i = hash_str(key, map->maxsize);
- entry = new_entry(key, value);
- if (entry == NULL)
- return -ENOMEM;
-
- map->data[i] = insert_entry(map->data[i],
- entry, &map->entries);
-
- INFO_MSG("HASH_ADD: chain[%d] key:%s val:%s",i, key, value);
- return 0;
-}
-
-int
-hashmap_remove(hashmap_t map, const char* key)
-{
- uint32_t i;
-
- if ((map == NULL) || (key == NULL))
- return -EINVAL;
-
- i = hash_str(key, map->maxsize);
- map->data[i] = remove_entry(map->data[i], key, &map->entries);
-
- return 0;
-}
-
-size_t
-hashmap_size(hashmap_t map)
-{
- if (map != NULL)
- return map->entries;
- else
- return 0;
-}
-
-int
-hashmap_free(hashmap_t map)
-{
- size_t i;
-
- if (map == NULL)
- return -EINVAL;
-
- /* "children" first */
- for(i = 0; i < map->maxsize; i++) {
- map->data[i] = remove_all(map->data[i], &map->entries);
- }
- free(map->data);
- free(map);
-
- return 0;
-}
-
-int
-hashmap_dump(hashmap_t map)
-{
- size_t i;
- if (map == NULL)
- return -EINVAL;
-
- for(i = 0; i < map->maxsize; i++) {
- if (map->data[i] != NULL) {
- printf("[%zd]: ", i);
- print_all(map->data[i]);
- }
- }
-
- return 0;
-}
-
-static const char**
-sort_key_vector(const char** a, size_t size)
-{
- /* uses bubblesort */
- size_t i, j;
- const char* tmp;
-
- if (size <= 0)
- return a;
-
- for (i = size - 1; i > 0; i--) {
- for (j = 0; j < i; j++) {
- if (strcmp(a[j], a[j+1]) > 0) {
- tmp = a[j];
- a[j] = a[j+1];
- a[j+1] = tmp;
- }
- }
- }
- return a;
-}
-
-const char**
-hashmap_get_key_vector(hashmap_t map, size_t* size, int sort)
-{
- const char** res;
- size_t i, j;
- *size = map->entries;
-
- res = (const char**) malloc(*size * sizeof(char*));
- if (res == NULL)
- return NULL;
-
- j = 0;
- for(i=0; i < map->maxsize; i++) {
- keys_to_array(map->data[i], res, &j);
- }
-
- if (sort)
- res = sort_key_vector(res, *size);
-
- return res;
-}
-
-int
-hashmap_key_is_in_vector(const char** vec, size_t size, const char* key)
-{
- size_t i;
- for (i = 0; i < size; i++) {
- if (strcmp(vec[i], key) == 0) /* found */
- return 1;
- }
-
- return 0;
-}
-
-const char**
-hashmap_get_update_key_vector(const char** vec1, size_t vec1_size,
- const char** vec2, size_t vec2_size, size_t* res_size)
-{
- const char** res;
- size_t i, j;
-
- *res_size = vec2_size;
-
- res = (const char**) malloc(*res_size * sizeof(char*));
- if (res == NULL)
- return NULL;
-
- /* get all keys from vec2 which are not set in vec1 */
- j = 0;
- for (i = 0; i < vec2_size; i++) {
- if (!hashmap_key_is_in_vector(vec1, vec1_size, vec2[i]))
- res[j++] = vec2[i];
- }
-
- *res_size = j;
- return res;
-}
diff --git a/ubi-utils/src/hashmap.h b/ubi-utils/src/hashmap.h
deleted file mode 100644
index 1b13e95..0000000
--- a/ubi-utils/src/hashmap.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef __HASHMAP_H__
-#define __HASHMAP_H__
-/*
- * 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.
- *
- * Author: Oliver Lohmann
- */
-
-#include <stdlib.h>
-#include <stdint.h>
-
-typedef struct hashentry *hashentry_t;
-typedef struct hashmap *hashmap_t;
-
-hashmap_t hashmap_new(void);
-int hashmap_free(hashmap_t map);
-
-int hashmap_add(hashmap_t map, const char* key, const char* value);
-int hashmap_update(hashmap_t map, const char* key, const char* value);
-int hashmap_remove(hashmap_t map, const char* key);
-const char* hashmap_lookup(hashmap_t map, const char* key);
-
-const char** hashmap_get_key_vector(hashmap_t map, size_t* size, int sort);
-int hashmap_key_is_in_vector(const char** vec, size_t size, const char* key);
-const char** hashmap_get_update_key_vector(const char** vec1, size_t vec1_size,
- const char** vec2, size_t vec2_size, size_t* res_size);
-
-int hashmap_dump(hashmap_t map);
-
-int hashmap_is_empty(hashmap_t map);
-size_t hashmap_size(hashmap_t map);
-
-uint32_t hash_str(const char* str, uint32_t mapsize);
-
-#endif /* __HASHMAP_H__ */
diff --git a/ubi-utils/src/libiniparser.c b/ubi-utils/src/libiniparser.c
new file mode 100644
index 0000000..3bea51e
--- /dev/null
+++ b/ubi-utils/src/libiniparser.c
@@ -0,0 +1,646 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file iniparser.c
+ @author N. Devillard
+ @date Sep 2007
+ @version 3.0
+ @brief Parser for ini files.
+*/
+/*--------------------------------------------------------------------------*/
+/*
+ $Id: iniparser.c,v 2.18 2008-01-03 18:35:39 ndevilla Exp $
+ $Revision: 2.18 $
+ $Date: 2008-01-03 18:35:39 $
+*/
+/*---------------------------- Includes ------------------------------------*/
+#include <ctype.h>
+#include <libiniparser.h>
+
+/*---------------------------- Defines -------------------------------------*/
+#define ASCIILINESZ (1024)
+#define INI_INVALID_KEY ((char*)-1)
+
+/*---------------------------------------------------------------------------
+ Private to this module
+ ---------------------------------------------------------------------------*/
+/**
+ * This enum stores the status for each parsed line (internal use only).
+ */
+typedef enum _line_status_ {
+ LINE_UNPROCESSED,
+ LINE_ERROR,
+ LINE_EMPTY,
+ LINE_COMMENT,
+ LINE_SECTION,
+ LINE_VALUE
+} line_status ;
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Convert a string to lowercase.
+ @param s String to convert.
+ @return ptr to statically allocated string.
+
+ This function returns a pointer to a statically allocated string
+ containing a lowercased version of the input string. Do not free
+ or modify the returned string! Since the returned string is statically
+ allocated, it will be modified at each function call (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+static char * strlwc(const char * s)
+{
+ static char l[ASCIILINESZ+1];
+ int i ;
+
+ if (s==NULL) return NULL ;
+ memset(l, 0, ASCIILINESZ+1);
+ i=0 ;
+ while (s[i] && i<ASCIILINESZ) {
+ l[i] = (char)tolower((int)s[i]);
+ i++ ;
+ }
+ l[ASCIILINESZ]=(char)0;
+ return l ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Remove blanks at the beginning and the end of a string.
+ @param s String to parse.
+ @return ptr to statically allocated string.
+
+ This function returns a pointer to a statically allocated string,
+ which is identical to the input string, except that all blank
+ characters at the end and the beg. of the string have been removed.
+ Do not free or modify the returned string! Since the returned string
+ is statically allocated, it will be modified at each function call
+ (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+static char * strstrip(char * s)
+{
+ static char l[ASCIILINESZ+1];
+ char * last ;
+
+ if (s==NULL) return NULL ;
+
+ while (isspace((int)*s) && *s) s++;
+ memset(l, 0, ASCIILINESZ+1);
+ strcpy(l, s);
+ last = l + strlen(l);
+ while (last > l) {
+ if (!isspace((int)*(last-1)))
+ break ;
+ last -- ;
+ }
+ *last = (char)0;
+ return (char*)l ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get number of sections in a dictionary
+ @param d Dictionary to examine
+ @return int Number of sections found in dictionary
+
+ This function returns the number of sections found in a dictionary.
+ The test to recognize sections is done on the string stored in the
+ dictionary: a section name is given as "section" whereas a key is
+ stored as "section:key", thus the test looks for entries that do not
+ contain a colon.
+
+ This clearly fails in the case a section name contains a colon, but
+ this should simply be avoided.
+
+ This function returns -1 in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getnsec(dictionary * d)
+{
+ int i ;
+ int nsec ;
+
+ if (d==NULL) return -1 ;
+ nsec=0 ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (strchr(d->key[i], ':')==NULL) {
+ nsec ++ ;
+ }
+ }
+ return nsec ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get name for section n in a dictionary.
+ @param d Dictionary to examine
+ @param n Section number (from 0 to nsec-1).
+ @return Pointer to char string
+
+ This function locates the n-th section in a dictionary and returns
+ its name as a pointer to a string statically allocated inside the
+ dictionary. Do not free or modify the returned string!
+
+ This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getsecname(dictionary * d, int n)
+{
+ int i ;
+ int foundsec ;
+
+ if (d==NULL || n<0) return NULL ;
+ foundsec=0 ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (strchr(d->key[i], ':')==NULL) {
+ foundsec++ ;
+ if (foundsec>n)
+ break ;
+ }
+ }
+ if (foundsec<=n) {
+ return NULL ;
+ }
+ return d->key[i] ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump.
+ @param f Opened file pointer to dump to.
+ @return void
+
+ This function prints out the contents of a dictionary, one element by
+ line, onto the provided file pointer. It is OK to specify @c stderr
+ or @c stdout as output files. This function is meant for debugging
+ purposes mostly.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump(dictionary * d, FILE * f)
+{
+ int i ;
+
+ if (d==NULL || f==NULL) return ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (d->val[i]!=NULL) {
+ fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
+ } else {
+ fprintf(f, "[%s]=UNDEF\n", d->key[i]);
+ }
+ }
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Save a dictionary to a loadable ini file
+ @param d Dictionary to dump
+ @param f Opened file pointer to dump to
+ @return void
+
+ This function dumps a given dictionary into a loadable ini file.
+ It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump_ini(dictionary * d, FILE * f)
+{
+ int i, j ;
+ char keym[ASCIILINESZ+1];
+ int nsec ;
+ char * secname ;
+ int seclen ;
+
+ if (d==NULL || f==NULL) return ;
+
+ nsec = iniparser_getnsec(d);
+ if (nsec<1) {
+ /* No section in file: dump all keys as they are */
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
+ }
+ return ;
+ }
+ for (i=0 ; i<nsec ; i++) {
+ secname = iniparser_getsecname(d, i) ;
+ seclen = (int)strlen(secname);
+ fprintf(f, "\n[%s]\n", secname);
+ sprintf(keym, "%s:", secname);
+ for (j=0 ; j<d->size ; j++) {
+ if (d->key[j]==NULL)
+ continue ;
+ if (!strncmp(d->key[j], keym, seclen+1)) {
+ fprintf(f,
+ "%-30s = %s\n",
+ d->key[j]+seclen+1,
+ d->val[j] ? d->val[j] : "");
+ }
+ }
+ }
+ fprintf(f, "\n");
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param def Default value to return if key not found.
+ @return pointer to statically allocated character string
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the pointer passed as 'def' is returned.
+ The returned char pointer is pointing to a string allocated in
+ the dictionary, do not free or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getstring(dictionary * d, const char * key, char * def)
+{
+ char * lc_key ;
+ char * sval ;
+
+ if (d==NULL || key==NULL)
+ return def ;
+
+ lc_key = strlwc(key);
+ sval = dictionary_get(d, lc_key, def);
+ return sval ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to an int
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return integer
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+
+ Supported values for integers include the usual C notation
+ so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
+ are supported. Examples:
+
+ "42" -> 42
+ "042" -> 34 (octal -> decimal)
+ "0x42" -> 66 (hexa -> decimal)
+
+ Warning: the conversion may overflow in various ways. Conversion is
+ totally outsourced to strtol(), see the associated man page for overflow
+ handling.
+
+ Credits: Thanks to A. Becker for suggesting strtol()
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getint(dictionary * d, const char * key, int notfound)
+{
+ char * str ;
+
+ str = iniparser_getstring(d, key, INI_INVALID_KEY);
+ if (str==INI_INVALID_KEY) return notfound ;
+ return (int)strtol(str, NULL, 0);
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a double
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return double
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+ */
+/*--------------------------------------------------------------------------*/
+double iniparser_getdouble(dictionary * d, char * key, double notfound)
+{
+ char * str ;
+
+ str = iniparser_getstring(d, key, INI_INVALID_KEY);
+ if (str==INI_INVALID_KEY) return notfound ;
+ return atof(str);
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a boolean
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return integer
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+
+ A true boolean is found if one of the following is matched:
+
+ - A string starting with 'y'
+ - A string starting with 'Y'
+ - A string starting with 't'
+ - A string starting with 'T'
+ - A string starting with '1'
+
+ A false boolean is found if one of the following is matched:
+
+ - A string starting with 'n'
+ - A string starting with 'N'
+ - A string starting with 'f'
+ - A string starting with 'F'
+ - A string starting with '0'
+
+ The notfound value returned if no boolean is identified, does not
+ necessarily have to be 0 or 1.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getboolean(dictionary * d, const char * key, int notfound)
+{
+ char * c ;
+ int ret ;
+
+ c = iniparser_getstring(d, key, INI_INVALID_KEY);
+ if (c==INI_INVALID_KEY) return notfound ;
+ if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
+ ret = 1 ;
+ } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
+ ret = 0 ;
+ } else {
+ ret = notfound ;
+ }
+ return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Finds out if a given entry exists in a dictionary
+ @param ini Dictionary to search
+ @param entry Name of the entry to look for
+ @return integer 1 if entry exists, 0 otherwise
+
+ Finds out if a given entry exists in the dictionary. Since sections
+ are stored as keys with NULL associated values, this is the only way
+ of querying for the presence of sections in a dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_find_entry(
+ dictionary * ini,
+ char * entry
+)
+{
+ int found=0 ;
+ if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
+ found = 1 ;
+ }
+ return found ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set an entry in a dictionary.
+ @param ini Dictionary to modify.
+ @param entry Entry to modify (entry name)
+ @param val New value to associate to the entry.
+ @return int 0 if Ok, -1 otherwise.
+
+ If the given entry can be found in the dictionary, it is modified to
+ contain the provided value. If it cannot be found, -1 is returned.
+ It is Ok to set val to NULL.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_set(dictionary * ini, char * entry, char * val)
+{
+ return dictionary_set(ini, strlwc(entry), val) ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete an entry in a dictionary
+ @param ini Dictionary to modify
+ @param entry Entry to delete (entry name)
+ @return void
+
+ If the given entry can be found, it is deleted from the dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_unset(dictionary * ini, char * entry)
+{
+ dictionary_unset(ini, strlwc(entry));
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Load a single line from an INI file
+ @param input_line Input line, may be concatenated multi-line input
+ @param section Output space to store section
+ @param key Output space to store key
+ @param value Output space to store value
+ @return line_status value
+ */
+/*--------------------------------------------------------------------------*/
+static line_status iniparser_line(
+ char * input_line,
+ char * section,
+ char * key,
+ char * value)
+{
+ line_status sta ;
+ char line[ASCIILINESZ+1];
+ int len ;
+
+ strcpy(line, strstrip(input_line));
+ len = (int)strlen(line);
+
+ sta = LINE_UNPROCESSED ;
+ if (len<1) {
+ /* Empty line */
+ sta = LINE_EMPTY ;
+ } else if (line[0]=='#') {
+ /* Comment line */
+ sta = LINE_COMMENT ;
+ } else if (line[0]=='[' && line[len-1]==']') {
+ /* Section name */
+ sscanf(line, "[%[^]]", section);
+ strcpy(section, strstrip(section));
+ strcpy(section, strlwc(section));
+ sta = LINE_SECTION ;
+ } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
+ || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
+ || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
+ /* Usual key=value, with or without comments */
+ strcpy(key, strstrip(key));
+ strcpy(key, strlwc(key));
+ strcpy(value, strstrip(value));
+ /*
+ * sscanf cannot handle '' or "" as empty values
+ * this is done here
+ */
+ if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
+ value[0]=0 ;
+ }
+ sta = LINE_VALUE ;
+ } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
+ || sscanf(line, "%[^=] %[=]", key, value) == 2) {
+ /*
+ * Special cases:
+ * key=
+ * key=;
+ * key=#
+ */
+ strcpy(key, strstrip(key));
+ strcpy(key, strlwc(key));
+ value[0]=0 ;
+ sta = LINE_VALUE ;
+ } else {
+ /* Generate syntax error */
+ sta = LINE_ERROR ;
+ }
+ return sta ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Parse an ini file and return an allocated dictionary object
+ @param ininame Name of the ini file to read.
+ @return Pointer to newly allocated dictionary
+
+ This is the parser for ini files. This function is called, providing
+ the name of the file to be read. It returns a dictionary object that
+ should not be accessed directly, but through accessor functions
+ instead.
+
+ The returned dictionary must be freed using iniparser_freedict().
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * iniparser_load(const char * ininame)
+{
+ FILE * in ;
+
+ char line [ASCIILINESZ+1] ;
+ char section [ASCIILINESZ+1] ;
+ char key [ASCIILINESZ+1] ;
+ char tmp [ASCIILINESZ+1] ;
+ char val [ASCIILINESZ+1] ;
+
+ int last=0 ;
+ int len ;
+ int lineno=0 ;
+ int errs=0;
+
+ dictionary * dict ;
+
+ if ((in=fopen(ininame, "r"))==NULL) {
+ fprintf(stderr, "iniparser: cannot open %s\n", ininame);
+ return NULL ;
+ }
+
+ dict = dictionary_new(0) ;
+ if (!dict) {
+ fclose(in);
+ return NULL ;
+ }
+
+ memset(line, 0, ASCIILINESZ);
+ memset(section, 0, ASCIILINESZ);
+ memset(key, 0, ASCIILINESZ);
+ memset(val, 0, ASCIILINESZ);
+ last=0 ;
+
+ while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
+ lineno++ ;
+ len = (int)strlen(line)-1;
+ /* Safety check against buffer overflows */
+ if (line[len]!='\n') {
+ fprintf(stderr,
+ "iniparser: input line too long in %s (%d)\n",
+ ininame,
+ lineno);
+ dictionary_del(dict);
+ fclose(in);
+ return NULL ;
+ }
+ /* Get rid of \n and spaces at end of line */
+ while ((len>=0) &&
+ ((line[len]=='\n') || (isspace(line[len])))) {
+ line[len]=0 ;
+ len-- ;
+ }
+ /* Detect multi-line */
+ if (line[len]=='\\') {
+ /* Multi-line value */
+ last=len ;
+ continue ;
+ } else {
+ last=0 ;
+ }
+ switch (iniparser_line(line, section, key, val)) {
+ case LINE_EMPTY:
+ case LINE_COMMENT:
+ break ;
+
+ case LINE_SECTION:
+ errs = dictionary_set(dict, section, NULL);
+ break ;
+
+ case LINE_VALUE:
+ sprintf(tmp, "%s:%s", section, key);
+ errs = dictionary_set(dict, tmp, val) ;
+ break ;
+
+ case LINE_ERROR:
+ fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
+ ininame,
+ lineno);
+ fprintf(stderr, "-> %s\n", line);
+ errs++ ;
+ break;
+
+ default:
+ break ;
+ }
+ memset(line, 0, ASCIILINESZ);
+ last=0;
+ if (errs<0) {
+ fprintf(stderr, "iniparser: memory allocation failure\n");
+ break ;
+ }
+ }
+ if (errs) {
+ dictionary_del(dict);
+ dict = NULL ;
+ }
+ fclose(in);
+ return dict ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Free all memory associated to an ini dictionary
+ @param d Dictionary to free
+ @return void
+
+ Free all memory associated to an ini dictionary.
+ It is mandatory to call this function before the dictionary object
+ gets out of the current context.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_freedict(dictionary * d)
+{
+ dictionary_del(d);
+}
+
+/* vim: set ts=4 et sw=4 tw=75 */
diff --git a/ubi-utils/src/libmtd.c b/ubi-utils/src/libmtd.c
new file mode 100644
index 0000000..b60ddbd
--- /dev/null
+++ b/ubi-utils/src/libmtd.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * 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.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * MTD library.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <mtd/mtd-user.h>
+#include <libmtd.h>
+#include "common.h"
+
+#define PROGRAM_NAME "libmtd"
+#define MTD_DEV_MAJOR 90
+
+/**
+ * mtd_get_info - get information about an MTD device.
+ * @node: name of the MTD device node
+ * @mtd: the MTD device information is returned here
+ *
+ * This function gets information about MTD device defined by the @node device
+ * node file and saves this information in the @mtd object. Returns %0 in case
+ * of success and %-1 in case of failure.
+ */
+int mtd_get_info(const char *node, struct mtd_info *mtd)
+{
+ struct stat st;
+ struct mtd_info_user ui;
+ int ret;
+ loff_t offs = 0;
+
+ if (stat(node, &st))
+ return sys_errmsg("cannot open \"%s\"", node);
+
+ if (!S_ISCHR(st.st_mode)) {
+ errno = EINVAL;
+ return errmsg("\"%s\" is not a character device", node);
+ }
+
+ mtd->major = major(st.st_rdev);
+ mtd->minor = minor(st.st_rdev);
+
+ if (mtd->major != MTD_DEV_MAJOR) {
+ errno = EINVAL;
+ return errmsg("\"%s\" has major number %d, MTD devices have "
+ "major %d", node, mtd->major, MTD_DEV_MAJOR);
+ }
+
+ mtd->num = mtd->minor / 2;
+ mtd->rdonly = mtd->minor & 1;
+
+ mtd->fd = open(node, O_RDWR);
+ if (mtd->fd == -1)
+ return sys_errmsg("cannot open \"%s\"", node);
+
+ if (ioctl(mtd->fd, MEMGETINFO, &ui)) {
+ sys_errmsg("MEMGETINFO ioctl request failed");
+ goto out_close;
+ }
+
+ ret = ioctl(mtd->fd, MEMGETBADBLOCK, &offs);
+ if (ret == -1) {
+ if (errno != EOPNOTSUPP) {
+ sys_errmsg("MEMGETBADBLOCK ioctl failed");
+ goto out_close;
+ }
+ errno = 0;
+ mtd->allows_bb = 0;
+ } else
+ mtd->allows_bb = 1;
+
+ mtd->type = ui.type;
+ mtd->size = ui.size;
+ mtd->eb_size = ui.erasesize;
+ mtd->min_io_size = ui.writesize;
+
+ if (mtd->min_io_size <= 0) {
+ errmsg("mtd%d (%s) has insane min. I/O unit size %d",
+ mtd->num, node, mtd->min_io_size);
+ goto out_close;
+ }
+ if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) {
+ errmsg("mtd%d (%s) has insane eraseblock size %d",
+ mtd->num, node, mtd->eb_size);
+ goto out_close;
+ }
+ if (mtd->size <= 0 || mtd->size < mtd->eb_size) {
+ errmsg("mtd%d (%s) has insane size %lld",
+ mtd->num, node, mtd->size);
+ goto out_close;
+ }
+ mtd->eb_cnt = mtd->size / mtd->eb_size;
+
+ switch(mtd->type) {
+ case MTD_ABSENT:
+ errmsg("mtd%d (%s) is removable and is not present",
+ mtd->num, node);
+ goto out_close;
+ case MTD_RAM:
+ mtd->type_str = "RAM-based";
+ break;
+ case MTD_ROM:
+ mtd->type_str = "ROM";
+ break;
+ case MTD_NORFLASH:
+ mtd->type_str = "NOR";
+ break;
+ case MTD_NANDFLASH:
+ mtd->type_str = "NAND";
+ break;
+ case MTD_DATAFLASH:
+ mtd->type_str = "DataFlash";
+ break;
+ case MTD_UBIVOLUME:
+ mtd->type_str = "UBI-emulated MTD";
+ break;
+ default:
+ mtd->type_str = "Unknown flash type";
+ break;
+ }
+
+ if (!(ui.flags & MTD_WRITEABLE))
+ mtd->rdonly = 1;
+
+ return 0;
+
+out_close:
+ close(mtd->fd);
+ return -1;
+}
+
+/**
+ * mtd_erase - erase an eraseblock.
+ * @mtd: MTD device description object
+ * @eb: eraseblock to erase
+ *
+ * This function erases the eraseblock and returns %0 in case of success and
+ * %-1 in case of failure.
+ */
+int mtd_erase(const struct mtd_info *mtd, int eb)
+{
+ struct erase_info_user ei;
+
+ ei.start = eb * mtd->eb_size;;
+ ei.length = mtd->eb_size;
+ return ioctl(mtd->fd, MEMERASE, &ei);
+}
+
+/**
+ * mtd_is_bad - check if eraseblock is bad.
+ * @mtd: MTD device description object
+ * @eb: eraseblock to check
+ *
+ * This function checks if eraseblock @eb is bad. Returns %0 if not, %1 if yes,
+ * and %-1 in case of failure.
+ */
+int mtd_is_bad(const struct mtd_info *mtd, int eb)
+{
+ int ret;
+ loff_t seek;
+
+ if (eb < 0 || eb >= mtd->eb_cnt) {
+ errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks",
+ eb, mtd->num, mtd->eb_cnt);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!mtd->allows_bb)
+ return 0;
+
+ seek = (loff_t)eb * mtd->eb_size;
+ ret = ioctl(mtd->fd, MEMGETBADBLOCK, &seek);
+ if (ret == -1) {
+ sys_errmsg("MEMGETBADBLOCK ioctl failed for "
+ "eraseblock %d (mtd%d)", eb, mtd->num);
+ return -1;
+ }
+
+ return ret;
+}
+
+/**
+ * mtd_read - read data from an MTD device.
+ * @mtd: MTD device description object
+ * @eb: eraseblock to read from
+ * @offs: offset withing the eraseblock to read from
+ * @buf: buffer to read data to
+ * @len: how many bytes to read
+ *
+ * This function reads @len bytes of data from eraseblock @eb and offset @offs
+ * of the MTD device defined by @mtd and stores the read data at buffer @buf.
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+int mtd_read(const struct mtd_info *mtd, int eb, int offs, void *buf, int len)
+{
+ int ret, rd = 0;
+ off_t seek;
+
+ if (eb < 0 || eb >= mtd->eb_cnt) {
+ errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks",
+ eb, mtd->num, mtd->eb_cnt);
+ errno = EINVAL;
+ return -1;
+ }
+ if (offs < 0 || offs + len > mtd->eb_size) {
+ errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d",
+ offs, len, mtd->num, mtd->eb_size);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Seek to the beginning of the eraseblock */
+ seek = (off_t)eb * mtd->eb_size + offs;
+ if (lseek(mtd->fd, seek, SEEK_SET) != seek) {
+ sys_errmsg("cannot seek mtd%d to offset %llu",
+ mtd->num, (unsigned long long)seek);
+ return -1;
+ }
+
+ while (rd < len) {
+ ret = read(mtd->fd, buf, len);
+ if (ret < 0) {
+ sys_errmsg("cannot read %d bytes from mtd%d (eraseblock %d, offset %d)",
+ len, mtd->num, eb, offs);
+ return -1;
+ }
+ rd += ret;
+ }
+
+ return 0;
+}
+
+/**
+ * mtd_write - write data to an MTD device.
+ * @mtd: MTD device description object
+ * @eb: eraseblock to write to
+ * @offs: offset withing the eraseblock to write to
+ * @buf: buffer to write
+ * @len: how many bytes to write
+ *
+ * This function writes @len bytes of data to eraseblock @eb and offset @offs
+ * of the MTD device defined by @mtd. Returns %0 in case of success and %-1 in
+ * case of failure.
+ */
+int mtd_write(const struct mtd_info *mtd, int eb, int offs, void *buf, int len)
+{
+ int ret;
+ off_t seek;
+
+ if (eb < 0 || eb >= mtd->eb_cnt) {
+ errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks",
+ eb, mtd->num, mtd->eb_cnt);
+ errno = EINVAL;
+ return -1;
+ }
+ if (offs < 0 || offs + len > mtd->eb_size) {
+ errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d",
+ offs, len, mtd->num, mtd->eb_size);
+ errno = EINVAL;
+ return -1;
+ }
+#if 0
+ if (offs % mtd->subpage_size) {
+ errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
+ offs, mtd->num, mtd->subpage_size);
+ errno = EINVAL;
+ return -1;
+ }
+ if (len % mtd->subpage_size) {
+ errmsg("write length %d is not aligned to mtd%d min. I/O size %d",
+ len, mtd->num, mtd->subpage_size);
+ errno = EINVAL;
+ return -1;
+ }
+#endif
+
+ /* Seek to the beginning of the eraseblock */
+ seek = (off_t)eb * mtd->eb_size + offs;
+ if (lseek(mtd->fd, seek, SEEK_SET) != seek) {
+ sys_errmsg("cannot seek mtd%d to offset %llu",
+ mtd->num, (unsigned long long)seek);
+ return -1;
+ }
+
+ ret = write(mtd->fd, buf, len);
+ if (ret != len) {
+ sys_errmsg("cannot write %d bytes to mtd%d (eraseblock %d, offset %d)",
+ len, mtd->num, eb, offs);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/ubi-utils/src/libpfiflash.c b/ubi-utils/src/libpfiflash.c
deleted file mode 100644
index b0d454a..0000000
--- a/ubi-utils/src/libpfiflash.c
+++ /dev/null
@@ -1,1325 +0,0 @@
-/*
- * Copyright International Business Machines Corp., 2006, 2007
- *
- * 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.
- */
-
-/*
- * Authors: Oliver Lohmann <oliloh@de.ibm.com>
- * Drake Dowsett <dowsett@de.ibm.com>
- * Contact: Andreas Arnez <anrez@de.ibm.com>
- */
-
-/* TODO Compare data before writing it. This implies that the volume
- * parameters are compared first: size, alignment, name, type, ...,
- * this is the same, compare the data. Volume deletion is deffered
- * until the difference has been found out.
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#define __USE_GNU
-#include <string.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <sys/ioctl.h>
-
-#include <libubi.h>
-#include <pfiflash.h>
-
-#include <mtd/ubi-user.h> /* FIXME Is this ok here? */
-#include <mtd/mtd-user.h>
-
-#include "pfiflash_error.h"
-#include "ubimirror.h"
-#include "error.h"
-#include "reader.h"
-#include "example_ubi.h"
-#include "bootenv.h"
-
-/* ubi-header.h and crc32.h needed for CRC checking */
-#include <mtd/ubi-media.h> /* FIXME Is this ok here? */
-#include "crc32.h"
-
-#define ubi_unused __attribute__((unused))
-
-#define COMPARE_BUFFER_SIZE 2048
-
-#define DEFAULT_DEV_PATTERN "/dev/ubi%d"
-#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d"
-
-static const char copyright [] ubi_unused =
- "Copyright International Business Machines Corp., 2006, 2007";
-
-/* simply clear buffer, then write into front of it */
-#define EBUF(fmt...) \
- snprintf(err_buf, err_buf_size, fmt);
-
-/* make a history of buffer and then prepend something in front */
-#define EBUF_PREPEND(fmt) \
- do { \
- int EBUF_HISTORY_LENGTH = strlen(err_buf); \
- char EBUF_HISTORY[EBUF_HISTORY_LENGTH + 1]; \
- strncpy(EBUF_HISTORY, err_buf, EBUF_HISTORY_LENGTH + 1);\
- EBUF(fmt ": %s", EBUF_HISTORY); \
- } while (0)
-
-/* An array of PDD function pointers indexed by the algorithm. */
-static pdd_func_t pdd_funcs[PDD_HANDLING_NUM] =
- {
- &bootenv_pdd_keep,
- &bootenv_pdd_merge,
- &bootenv_pdd_overwrite
- };
-
-typedef enum ubi_update_process_t {
- UBI_REMOVE = 0,
- UBI_WRITE,
- UBI_COMPARE,
-} ubi_update_process_t;
-
-
-/**
- * skip_raw_volumes - reads data from pfi to advance fp past raw block
- * @pfi: fp to pfi data
- * @pfi_raws: header information
- *
- * Error handling):
- * when early EOF in pfi data
- * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err
- * when file I/O error
- * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err
- **/
-static int
-skip_raw_volumes(FILE* pfi, list_t pfi_raws,
- char* err_buf, size_t err_buf_size)
-{
- int rc;
- void *i;
- list_t ptr;
-
- if (is_empty(pfi_raws))
- return 0;
-
- rc = 0;
- foreach(i, ptr, pfi_raws) {
- size_t j;
- pfi_raw_t raw;
-
- raw = (pfi_raw_t)i;
- for(j = 0; j < raw->data_size; j++) {
- int c;
-
- c = fgetc(pfi);
- if (c == EOF)
- rc = -PFIFLASH_ERR_EOF;
- else if (ferror(pfi))
- rc = -PFIFLASH_ERR_FIO;
-
- if (rc != 0)
- goto err;
- }
- }
-
- err:
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- return rc;
-}
-
-
-/**
- * my_ubi_mkvol - wraps the ubi_mkvol functions and impl. bootenv update hook
- * @devno: UBI device number.
- * @s: Current seqnum.
- * @u: Information about the UBI volume from the PFI.
- *
- * Error handling:
- * when UBI system couldn't be opened
- * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
- * when UBI system couldn't create a volume
- * - returns -PFIFLASH_ERR_UBI_MKVOL, err_buf matches text to err
- **/
-static int
-my_ubi_mkvol(int devno, int s, pfi_ubi_t u,
- char *err_buf, size_t err_buf_size)
-{
- int rc, type;
- char path[PATH_MAX];
- libubi_t ulib;
- struct ubi_mkvol_request req;
-
- rc = 0;
- ulib = NULL;
-
- log_msg("[ ubimkvol id=%d, size=%d, data_size=%d, type=%d, "
- "alig=%d, nlen=%d, name=%s",
- u->ids[s], u->size, u->data_size, u->type, u->alignment,
- strnlen(u->names[s], PFI_UBI_VOL_NAME_LEN), u->names[s]);
-
- ulib = libubi_open();
- if (ulib == NULL) {
- rc = -PFIFLASH_ERR_UBI_OPEN;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
-
- switch (u->type) {
- case pfi_ubi_static:
- type = UBI_STATIC_VOLUME; break;
- case pfi_ubi_dynamic:
- default:
- type = UBI_DYNAMIC_VOLUME;
- }
-
- snprintf(path, PATH_MAX, DEFAULT_DEV_PATTERN, devno);
-
- req.vol_id = u->ids[s];
- req.alignment = u->alignment;
- req.bytes = u->size;
- req.vol_type = type;
- req.name = u->names[s];
-
- rc = ubi_mkvol(ulib, path, &req);
- if (rc != 0) {
- rc = -PFIFLASH_ERR_UBI_MKVOL;
- EBUF(PFIFLASH_ERRSTR[-rc], u->ids[s]);
- goto err;
- }
-
- err:
- if (ulib != NULL)
- libubi_close(ulib);
-
- return rc;
-}
-
-
-/**
- * my_ubi_rmvol - a wrapper around the UBI library function ubi_rmvol
- * @devno UBI device number
- * @id UBI volume id to remove
- *
- * If the volume does not exist, the function will return success.
- *
- * Error handling:
- * when UBI system couldn't be opened
- * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
- * when UBI system couldn't update (truncate) a volume
- * - returns -PFIFLASH_ERR_UBI_VOL_UPDATE, err_buf matches text to err
- * when UBI system couldn't remove a volume
- * - returns -PFIFLASH_ERR_UBI_RMVOL, err_buf matches text to err
- **/
-static int
-my_ubi_rmvol(int devno, uint32_t id,
- char *err_buf, size_t err_buf_size)
-{
- int rc, fd;
- char path[PATH_MAX];
- libubi_t ulib;
-
- rc = 0;
- ulib = NULL;
-
- log_msg("[ ubirmvol id=%d", id);
-
- ulib = libubi_open();
- if (ulib == NULL) {
- rc = -PFIFLASH_ERR_UBI_OPEN;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
-
- snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id);
-
- /* truncate whether it exist or not */
- fd = open(path, O_RDWR);
- if (fd < 0) {
- libubi_close(ulib);
- return 0; /* not existent, return 0 */
- }
-
- rc = ubi_update_start(ulib, fd, 0);
- close(fd);
- if (rc < 0) {
- rc = -PFIFLASH_ERR_UBI_VOL_UPDATE;
- EBUF(PFIFLASH_ERRSTR[-rc], id);
- goto err; /* if EBUSY than empty device, continue */
- }
-
- snprintf(path, PATH_MAX, DEFAULT_DEV_PATTERN, devno);
-
- rc = ubi_rmvol(ulib, path, id);
- if (rc != 0) {
-#ifdef DEBUG
- int rc_old = rc;
- dbg_msg("Remove UBI volume %d returned with error: %d "
- "errno=%d", id, rc_old, errno);
-#endif
-
- rc = -PFIFLASH_ERR_UBI_RMVOL;
- EBUF(PFIFLASH_ERRSTR[-rc], id);
-
- /* TODO Define a ubi_rmvol return value which says
- * sth like EUBI_NOSUCHDEV. In this case, a failed
- * operation is acceptable. Everything else has to be
- * classified as real error. But talk to Andreas Arnez
- * before defining something odd...
- */
- /* if ((errno == EINVAL) || (errno == ENODEV))
- return 0; */ /* currently it is EINVAL or ENODEV */
-
- goto err;
- }
-
- err:
- if (ulib != NULL)
- libubi_close(ulib);
-
- return rc;
-}
-
-
-/**
- * read_bootenv_volume - reads the current bootenv data from id into be_old
- * @devno UBI device number
- * @id UBI volume id to remove
- * @bootenv_old to hold old boot_env data
- *
- * Error handling:
- * when UBI system couldn't be opened
- * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
- * when UBI system couldn't open a volume to read
- * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err
- * when couldn't read bootenv data
- * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err
- **/
-static int
-read_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old,
- char *err_buf, size_t err_buf_size)
-{
- int rc;
- FILE* fp_in;
- char path[PATH_MAX];
- libubi_t ulib;
-
- rc = 0;
- fp_in = NULL;
- ulib = NULL;
-
- ulib = libubi_open();
- if (ulib == NULL) {
- rc = -PFIFLASH_ERR_UBI_OPEN;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
-
- snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id);
-
- fp_in = fopen(path, "r");
- if (!fp_in) {
- rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
- EBUF(PFIFLASH_ERRSTR[-rc], id);
- goto err;
- }
-
- log_msg("[ reading old bootenvs ...");
-
- /* Save old bootenvs for reference */
- rc = bootenv_read(fp_in, bootenv_old, BOOTENV_MAXSIZE);
- if (rc != 0) {
- rc = -PFIFLASH_ERR_BOOTENV_READ;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
-
- err:
- if (fp_in)
- fclose(fp_in);
- if (ulib)
- libubi_close(ulib);
-
- return rc;
-}
-
-
-/**
- * write_bootenv_volume - writes data from PFI file int to bootenv UBI volume
- * @devno UBI device number
- * @id UBI volume id
- * @bootend_old old PDD data from machine
- * @pdd_f function to handle PDD with
- * @fp_in new pdd data contained in PFI
- * @fp_in_size data size of new pdd data in PFI
- * @pfi_crc crc value from PFI header
- *
- * Error handling:
- * when UBI system couldn't be opened
- * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
- * when bootenv can't be created
- * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err
- * when bootenv can't be read
- * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err
- * when PDD handling function returns and error
- * - passes rc and err_buf data
- * when CRC check fails
- * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err
- * when bootenv can't be resized
- * - returns -PFIFLASH_ERR_BOOTENV_SIZE, err_buf matches text to err
- * when UBI system couldn't open a volume
- * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err
- * when couldn't write bootenv data
- * - returns -PFIFLASH_ERR_BOOTENV_WRITE, err_buf matches text to err
- **/
-static int
-write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old,
- pdd_func_t pdd_f, FILE* fp_in, size_t fp_in_size,
- uint32_t pfi_crc,
- char *err_buf, size_t err_buf_size)
-{
- int rc, warnings, fd_out;
- uint32_t crc;
- char path[PATH_MAX];
- size_t update_size;
- FILE *fp_out;
- bootenv_t bootenv_new, bootenv_res;
- libubi_t ulib;
-
- rc = 0;
- warnings = 0;
- crc = 0;
- update_size = 0;
- fp_out = NULL;
- bootenv_new = NULL;
- bootenv_res = NULL;
- ulib = NULL;
-
- log_msg("[ ubiupdatevol bootenv id=%d, fp_in=%p", id, fp_in);
-
- /* Workflow:
- * 1. Apply PDD operation and get the size of the returning
- * bootenv_res section. Without the correct size it wouldn't
- * be possible to call UBI update vol.
- * 2. Call UBI update vol
- * 3. Get FILE* to vol dev
- * 4. Write to FILE*
- */
-
- ulib = libubi_open();
- if (ulib == NULL) {
- rc = -PFIFLASH_ERR_UBI_OPEN;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
-
- rc = bootenv_create(&bootenv_new);
- if (rc != 0) {
- rc = -PFIFLASH_ERR_BOOTENV_CREATE;
- EBUF(PFIFLASH_ERRSTR[-rc], " 'new'");
- goto err;
- }
-
- rc = bootenv_create(&bootenv_res);
- if (rc != 0) {
- rc = -PFIFLASH_ERR_BOOTENV_CREATE;
- EBUF(PFIFLASH_ERRSTR[-rc], " 'res'");
- goto err;
- }
-
- rc = bootenv_read_crc(fp_in, bootenv_new, fp_in_size, &crc);
- if (rc != 0) {
- rc = -PFIFLASH_ERR_BOOTENV_READ;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- } else if (crc != pfi_crc) {
- rc = -PFIFLASH_ERR_CRC_CHECK;
- EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc);
- goto err;
- }
-
- rc = pdd_f(bootenv_old, bootenv_new, &bootenv_res, &warnings,
- err_buf, err_buf_size);
- if (rc != 0) {
- EBUF_PREPEND("handling PDD");
- goto err;
- }
- else if (warnings)
- /* TODO do something with warnings */
- dbg_msg("A warning in the PDD operation occured: %d",
- warnings);
-
- rc = bootenv_size(bootenv_res, &update_size);
- if (rc != 0) {
- rc = -PFIFLASH_ERR_BOOTENV_SIZE;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
-
- snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id);
-
- fd_out = open(path, O_RDWR);
- if (fd_out < 0) {
- rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
- EBUF(PFIFLASH_ERRSTR[-rc], id);
- goto err;
- }
- fp_out = fdopen(fd_out, "r+");
- if (!fp_out) {
- rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
- EBUF(PFIFLASH_ERRSTR[-rc], id);
- goto err;
- }
- rc = ubi_update_start(ulib, fd_out, update_size);
- if (rc < 0) {
- rc = -PFIFLASH_ERR_UBI_VOL_UPDATE;
- EBUF(PFIFLASH_ERRSTR[-rc], id);
- goto err;
- }
-
- rc = bootenv_write(fp_out, bootenv_res);
- if (rc != 0) {
- rc = -PFIFLASH_ERR_BOOTENV_WRITE;
- EBUF(PFIFLASH_ERRSTR[-rc], devno, id);
- goto err;
- }
-
- err:
- if (ulib != NULL)
- libubi_close(ulib);
- if (bootenv_new != NULL)
- bootenv_destroy(&bootenv_new);
- if (bootenv_res != NULL)
- bootenv_destroy(&bootenv_res);
- if (fp_out)
- fclose(fp_out);
-
- return rc;
-}
-
-
-/**
- * write_normal_volume - writes data from PFI file int to regular UBI volume
- * @devno UBI device number
- * @id UBI volume id
- * @update_size size of data stream
- * @fp_in PFI data file pointer
- * @pfi_crc CRC data from PFI header
- *
- * Error handling:
- * when UBI system couldn't be opened
- * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
- * when UBI system couldn't open a volume
- * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err
- * when unexpected EOF is encountered
- * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err
- * when file I/O error
- * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err
- * when CRC check fails
- * - retruns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err
- **/
-static int
-write_normal_volume(int devno, uint32_t id, size_t update_size, FILE* fp_in,
- uint32_t pfi_crc,
- char *err_buf, size_t err_buf_size)
-{
- int rc, fd_out;
- uint32_t crc, crc32_table[256];
- char path[PATH_MAX];
- size_t bytes_left;
- FILE* fp_out;
- libubi_t ulib;
-
- rc = 0;
- crc = UBI_CRC32_INIT;
- bytes_left = update_size;
- fp_out = NULL;
- ulib = NULL;
-
- log_msg("[ ubiupdatevol id=%d, update_size=%d fp_in=%p",
- id, update_size, fp_in);
-
- ulib = libubi_open();
- if (ulib == NULL) {
- rc = -PFIFLASH_ERR_UBI_OPEN;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
-
- snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id);
-
- fd_out = open(path, O_RDWR);
- if (fd_out < 0) {
- rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
- EBUF(PFIFLASH_ERRSTR[-rc], id);
- goto err;
- }
- fp_out = fdopen(fd_out, "r+");
- if (!fp_out) {
- rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
- EBUF(PFIFLASH_ERRSTR[-rc], id);
- goto err;
- }
- rc = ubi_update_start(ulib, fd_out, update_size);
- if (rc < 0) {
- rc = -PFIFLASH_ERR_UBI_VOL_UPDATE;
- EBUF(PFIFLASH_ERRSTR[-rc], id);
- goto err;
- }
-
- init_crc32_table(crc32_table);
- while (bytes_left) {
- char buf[1024];
- size_t to_rw = sizeof buf > bytes_left ?
- bytes_left : sizeof buf;
- if (fread(buf, 1, to_rw, fp_in) != to_rw) {
- rc = -PFIFLASH_ERR_EOF;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
- crc = clc_crc32(crc32_table, crc, buf, to_rw);
- if (fwrite(buf, 1, to_rw, fp_out) != to_rw) {
- rc = -PFIFLASH_ERR_FIO;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
- bytes_left -= to_rw;
- }
-
- if (crc != pfi_crc) {
- rc = -PFIFLASH_ERR_CRC_CHECK;
- EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc);
- goto err;
- }
-
- err:
- if (fp_out)
- fclose(fp_out);
- if (ulib)
- libubi_close(ulib);
-
- return rc;
-}
-
-static int compare_bootenv(FILE *fp_pfi, FILE **fp_flash, uint32_t ids_size,
- uint32_t data_size, pdd_func_t pdd_f, char *err_buf,
- size_t err_buf_size)
-{
- int rc, warnings = 0;
- unsigned int i;
- bootenv_t bootenv_pfi, bootenv_res = NULL, bootenv_flash = NULL;
-
- rc = bootenv_create(&bootenv_pfi);
- if (rc != 0) {
- rc = -PFIFLASH_ERR_BOOTENV_CREATE;
- goto err;
- }
-
- rc = bootenv_create(&bootenv_res);
- if (rc != 0) {
- rc = -PFIFLASH_ERR_BOOTENV_CREATE;
- goto err;
- }
-
- rc = bootenv_read(fp_pfi, bootenv_pfi, data_size);
- if (rc != 0) {
- rc = -PFIFLASH_ERR_BOOTENV_READ;
- goto err;
- }
-
- for (i = 0; i < ids_size; i++) {
- rc = bootenv_create(&bootenv_flash);
- if (rc != 0) {
- rc = -PFIFLASH_ERR_BOOTENV_CREATE;
- goto err;
- }
-
- rc = bootenv_read(fp_flash[i], bootenv_flash, BOOTENV_MAXSIZE);
- if (rc != 0) {
- rc = -PFIFLASH_ERR_BOOTENV_READ;
- goto err;
- }
-
- rc = pdd_f(bootenv_flash, bootenv_pfi, &bootenv_res,
- &warnings, err_buf, err_buf_size);
- if (rc != 0) {
- rc = -PFIFLASH_ERR_PDD_UNKNOWN;
- goto err;
- }
-
- rc = bootenv_compare(bootenv_flash, bootenv_res);
- if (rc > 0) {
- rc = -PFIFLASH_CMP_DIFF;
- goto err;
- } else if (rc < 0) {
- rc = -PFIFLASH_ERR_COMPARE;
- goto err;
- }
-
- bootenv_destroy(&bootenv_flash);
- bootenv_flash = NULL;
- }
-
-err:
- if (bootenv_pfi)
- bootenv_destroy(&bootenv_pfi);
- if (bootenv_res)
- bootenv_destroy(&bootenv_res);
- if (bootenv_flash)
- bootenv_destroy(&bootenv_flash);
-
- return rc;
-}
-
-static int compare_data(FILE *fp_pfi, FILE **fp_flash, uint32_t ids_size,
- uint32_t bytes_left)
-{
- unsigned int i;
- size_t read_bytes, rc = 0;
- char buf_pfi[COMPARE_BUFFER_SIZE];
- char *buf_flash[ids_size];
-
- for (i = 0; i < ids_size; i++) {
- buf_flash[i] = malloc(COMPARE_BUFFER_SIZE);
- if (!buf_flash[i])
- return -PFIFLASH_ERR_COMPARE;
- }
-
- while (bytes_left) {
- if (bytes_left > COMPARE_BUFFER_SIZE)
- read_bytes = COMPARE_BUFFER_SIZE;
- else
- read_bytes = bytes_left;
-
- rc = fread(buf_pfi, 1, read_bytes, fp_pfi);
- if (rc != read_bytes) {
- rc = -PFIFLASH_ERR_COMPARE;
- goto err;
- }
-
- for (i = 0; i < ids_size; i++) {
- rc = fread(buf_flash[i], 1, read_bytes, fp_flash[i]);
- if (rc != read_bytes) {
- rc = -PFIFLASH_CMP_DIFF;
- goto err;
- }
-
- rc = memcmp(buf_pfi, buf_flash[i], read_bytes);
- if (rc != 0) {
- rc = -PFIFLASH_CMP_DIFF;
- goto err;
- }
- }
-
- bytes_left -= read_bytes;
- }
-
-err:
- for (i = 0; i < ids_size; i++)
- free(buf_flash[i]);
-
- return rc;
-}
-
-static int compare_volumes(int devno, pfi_ubi_t u, FILE *fp_pfi,
- pdd_func_t pdd_f, char *err_buf, size_t err_buf_size)
-{
- int rc, is_bootenv = 0;
- unsigned int i;
- char path[PATH_MAX];
- libubi_t ulib = NULL;
- FILE *fp_flash[u->ids_size];
-
- ulib = libubi_open();
- if (ulib == NULL) {
- rc = -PFIFLASH_ERR_UBI_OPEN;
- goto err;
- }
-
- for (i = 0; i < u->ids_size; i++) {
- if (u->ids[i] == EXAMPLE_BOOTENV_VOL_ID_1 ||
- u->ids[i] == EXAMPLE_BOOTENV_VOL_ID_2)
- is_bootenv = 1;
-
- snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, u->ids[i]);
-
- fp_flash[i] = fopen(path, "r");
- if (fp_flash[i] == NULL) {
- rc = -PFIFLASH_ERR_UBI_OPEN;
- goto err;
- }
- }
-
- if (is_bootenv)
- rc = compare_bootenv(fp_pfi, fp_flash, u->ids_size,
- u->data_size, pdd_f, err_buf, err_buf_size);
- else
- rc = compare_data(fp_pfi, fp_flash, u->ids_size, u->data_size);
-
-err:
- if (rc < 0)
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
-
- for (i = 0; i < u->ids_size; i++)
- fclose(fp_flash[i]);
- if (ulib)
- libubi_close(ulib);
-
- return rc;
-}
-
-static int
-erase_mtd_region(FILE* file_p, int start, int length)
-{
- int rc, fd;
- erase_info_t erase;
- mtd_info_t mtdinfo;
- loff_t offset = start;
- loff_t end = offset + length;
-
- fd = fileno(file_p);
- if (fd < 0)
- return -PFIFLASH_ERR_MTD_ERASE;
-
- rc = ioctl(fd, MEMGETINFO, &mtdinfo);
- if (rc)
- return -PFIFLASH_ERR_MTD_ERASE;
-
- /* check for bad blocks in case of NAND flash */
- if (mtdinfo.type == MTD_NANDFLASH) {
- while (offset < end) {
- rc = ioctl(fd, MEMGETBADBLOCK, &offset);
- if (rc > 0) {
- return -PFIFLASH_ERR_MTD_ERASE;
- }
-
- offset += mtdinfo.erasesize;
- }
- }
-
- erase.start = start;
- erase.length = length;
-
- rc = ioctl(fd, MEMERASE, &erase);
- if (rc) {
- return -PFIFLASH_ERR_MTD_ERASE;
- }
-
- return rc;
-}
-
-/**
- * process_raw_volumes - writes the raw sections of the PFI data
- * @pfi PFI data file pointer
- * @pfi_raws list of PFI raw headers
- * @rawdev device to use to write raw data
- *
- * Error handling:
- * when early EOF in PFI data
- * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err
- * when file I/O error
- * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err
- * when CRC check fails
- * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err
- * when opening MTD device fails
- * - reutrns -PFIFLASH_ERR_MTD_OPEN, err_buf matches text to err
- * when closing MTD device fails
- * - returns -PFIFLASH_ERR_MTD_CLOSE, err_buf matches text to err
- **/
-static int
-process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev,
- char* err_buf, size_t err_buf_size)
-{
- int rc;
- char *pfi_data;
- void *i;
- uint32_t crc, crc32_table[256];
- size_t j, k;
- FILE* mtd = NULL;
- list_t ptr;
-
- if (is_empty(pfi_raws))
- return 0;
-
- if (rawdev == NULL)
- return 0;
-
- rc = 0;
-
- pfi_data = NULL;
-
- log_msg("[ rawupdate dev=%s", rawdev);
-
- crc = UBI_CRC32_INIT;
- init_crc32_table(crc32_table);
-
- /* most likely only one element in list, but just in case */
- foreach(i, ptr, pfi_raws) {
- pfi_raw_t r = (pfi_raw_t)i;
-
- /* read in pfi data */
- if (pfi_data != NULL)
- free(pfi_data);
- pfi_data = malloc(r->data_size * sizeof(char));
- for (j = 0; j < r->data_size; j++) {
- int c = fgetc(pfi);
- if (c == EOF) {
- rc = -PFIFLASH_ERR_EOF;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- } else if (ferror(pfi)) {
- rc = -PFIFLASH_ERR_FIO;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
- pfi_data[j] = (char)c;
- }
- crc = clc_crc32(crc32_table, crc, pfi_data, r->data_size);
-
- /* check crc */
- if (crc != r->crc) {
- rc = -PFIFLASH_ERR_CRC_CHECK;
- EBUF(PFIFLASH_ERRSTR[-rc], r->crc, crc);
- goto err;
- }
-
- /* open device */
- mtd = fopen(rawdev, "r+");
- if (mtd == NULL) {
- rc = -PFIFLASH_ERR_MTD_OPEN;
- EBUF(PFIFLASH_ERRSTR[-rc], rawdev);
- goto err;
- }
-
- for (j = 0; j < r->starts_size; j++) {
- rc = erase_mtd_region(mtd, r->starts[j], r->data_size);
- if (rc) {
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
-
- fseek(mtd, r->starts[j], SEEK_SET);
- for (k = 0; k < r->data_size; k++) {
- int c = fputc((int)pfi_data[k], mtd);
- if (c == EOF) {
- fclose(mtd);
- rc = -PFIFLASH_ERR_EOF;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
- if ((char)c != pfi_data[k]) {
- fclose(mtd);
- rc = -1;
- goto err;
- }
- }
- }
- rc = fclose(mtd);
- mtd = NULL;
- if (rc != 0) {
- rc = -PFIFLASH_ERR_MTD_CLOSE;
- EBUF(PFIFLASH_ERRSTR[-rc], rawdev);
- goto err;
- }
- }
-
- err:
- if (mtd != NULL)
- fclose(mtd);
- if (pfi_data != NULL)
- free(pfi_data);
- return rc;
-}
-
-
-/**
- * erase_unmapped_ubi_volumes - skip volumes provided by PFI file, clear rest
- * @devno UBI device number
- * @pfi_ubis list of UBI header data
- *
- * Error handling:
- * when UBI id is out of bounds
- * - returns -PFIFLASH_ERR_UBI_VID_OOB, err_buf matches text to err
- * when UBI volume can't be removed
- * - passes rc, prepends err_buf with contextual aid
- **/
-static int
-erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis,
- char *err_buf, size_t err_buf_size)
-{
- int rc;
- uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES];
- size_t i;
- list_t ptr;
- pfi_ubi_t u;
-
- rc = 0;
-
- for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++)
- ubi_volumes[i] = 1;
-
- foreach(u, ptr, pfi_ubis) {
- /* iterate over each vol_id */
- for(i = 0; i < u->ids_size; i++) {
- if (u->ids[i] >= PFI_UBI_MAX_VOLUMES) {
- rc = -PFIFLASH_ERR_UBI_VID_OOB;
- EBUF(PFIFLASH_ERRSTR[-rc], u->ids[i]);
- goto err;
- }
- /* remove from removal list */
- ubi_volumes[u->ids[i]] = 0;
- }
- }
-
- for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) {
- if (ubi_volumes[i]) {
- rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size);
- if (rc != 0) {
- EBUF_PREPEND("remove volume failed");
- goto err;
- }
- }
- }
-
- err:
- return rc;
-}
-
-
-/**
- * process_ubi_volumes - delegate tasks regarding UBI volumes
- * @pfi PFI data file pointer
- * @seqnum sequence number
- * @pfi_ubis list of UBI header data
- * @bootenv_old storage for current system PDD
- * @pdd_f function to handle PDD
- * @ubi_update_process whether reading or writing
- *
- * Error handling:
- * when and unknown ubi_update_process is given
- * - returns -PFIFLASH_ERR_UBI_UNKNOWN, err_buf matches text to err
- * otherwise
- * - passes rc and err_buf
- **/
-static int
-process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis,
- bootenv_t bootenv_old, pdd_func_t pdd_f,
- ubi_update_process_t ubi_update_process,
- char *err_buf, size_t err_buf_size)
-{
- int rc;
- pfi_ubi_t u;
- list_t ptr;
-
- rc = 0;
-
- foreach(u, ptr, pfi_ubis) {
- int s = seqnum;
-
- if (s > ((int)u->ids_size - 1))
- s = 0; /* per default use the first */
- u->curr_seqnum = s;
-
- switch (ubi_update_process) {
- case UBI_REMOVE:
- /* TODO are all these "EXAMPLE" vars okay? */
- if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) ||
- (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) {
- rc = read_bootenv_volume(EXAMPLE_UBI_DEVICE,
- u->ids[s], bootenv_old,
- err_buf, err_buf_size);
- /* it's okay if there is no bootenv
- * we're going to write one */
- if ((rc == -PFIFLASH_ERR_UBI_VOL_FOPEN) ||
- (rc == -PFIFLASH_ERR_BOOTENV_READ))
- rc = 0;
- if (rc != 0)
- goto err;
- }
-
- rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE, u->ids[s],
- err_buf, err_buf_size);
- if (rc != 0)
- goto err;
-
- break;
- case UBI_WRITE:
- rc = my_ubi_mkvol(EXAMPLE_UBI_DEVICE, s, u,
- err_buf, err_buf_size);
- if (rc != 0) {
- EBUF_PREPEND("creating volume");
- goto err;
- }
-
- if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) ||
- (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) {
- rc = write_bootenv_volume(EXAMPLE_UBI_DEVICE,
- u->ids[s],
- bootenv_old, pdd_f,
- pfi,
- u->data_size,
- u->crc,
- err_buf,
- err_buf_size);
- if (rc != 0)
- EBUF_PREPEND("bootenv volume");
- } else {
- rc = write_normal_volume(EXAMPLE_UBI_DEVICE,
- u->ids[s],
- u->data_size, pfi,
- u->crc,
- err_buf,
- err_buf_size);
- if (rc != 0)
- EBUF_PREPEND("normal volume");
- }
- if (rc != 0)
- goto err;
-
- break;
- case UBI_COMPARE:
- rc = compare_volumes(EXAMPLE_UBI_DEVICE, u, pfi, pdd_f,
- err_buf, err_buf_size);
- if (rc != 0) {
- EBUF_PREPEND("compare volume");
- goto err;
- }
-
- break;
- default:
- rc = -PFIFLASH_ERR_UBI_UNKNOWN;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
- }
-
- err:
- return rc;
-}
-
-
-/**
- * mirror_ubi_volumes - mirror redundant pairs of volumes
- * @devno UBI device number
- * @pfi_ubis list of PFI header data
- *
- * Error handling:
- * when UBI system couldn't be opened
- * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
- **/
-static int
-mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis,
- char *err_buf, size_t err_buf_size)
-{
- int rc;
- uint32_t j;
- list_t ptr;
- pfi_ubi_t i;
- libubi_t ulib;
-
- rc = 0;
- ulib = NULL;
-
- log_msg("[ mirror ...");
-
- ulib = libubi_open();
- if (ulib == NULL) {
- rc = -PFIFLASH_ERR_UBI_OPEN;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
-
- /**
- * Execute all mirror operations on redundant groups.
- * Create a volume within a redundant group if it does
- * not exist already (this is a precondition of
- * ubimirror).
- */
- foreach(i, ptr, pfi_ubis) {
- for (j = 0; j < i->ids_size; j++) {
- /* skip self-match */
- if (i->ids[j] == i->ids[i->curr_seqnum])
- continue;
-
- rc = my_ubi_rmvol(devno, i->ids[j],
- err_buf, err_buf_size);
- if (rc != 0)
- goto err;
-
- rc = my_ubi_mkvol(devno, j, i,
- err_buf, err_buf_size);
- if (rc != 0)
- goto err;
- }
- }
-
- foreach(i, ptr, pfi_ubis) {
- rc = ubimirror(devno, i->curr_seqnum, i->ids, i->ids_size,
- err_buf, err_buf_size);
- if (rc != 0)
- goto err;
- }
-
-
- err:
- if (ulib != NULL)
- libubi_close(ulib);
-
- return rc;
-}
-
-
-/**
- * pfiflash_with_options - exposed func to flash memory with a PFI file
- * @pfi PFI data file pointer
- * @complete flag to erase unmapped volumes
- * @seqnum sequence number
- * @compare flag to compare
- * @pdd_handling method to handle pdd (keep, merge, overwrite...)
- *
- * Error handling:
- * when bootenv can't be created
- * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err
- * when PFI headers can't be read, or
- * when fail to skip raw sections, or
- * when error occurs while processing raw volumes, or
- * when fail to erase unmapped UBI vols, or
- * when error occurs while processing UBI volumes, or
- * when error occurs while mirroring UBI volumes
- * - passes rc, prepends err_buf with contextual aid
- **/
-int
-pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare,
- pdd_handling_t pdd_handling, const char* rawdev,
- char *err_buf, size_t err_buf_size)
-{
- int rc;
- bootenv_t bootenv;
- pdd_func_t pdd_f;
-
- if (pfi == NULL)
- return -EINVAL;
-
- rc = 0;
- pdd_f = NULL;
-
- /* If the user didnt specify a seqnum we start per default
- * with the index 0 */
- int curr_seqnum = seqnum < 0 ? 0 : seqnum;
-
- list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */
- list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */
-
- rc = bootenv_create(&bootenv);
- if (rc != 0) {
- rc = -PFIFLASH_ERR_BOOTENV_CREATE;
- EBUF(PFIFLASH_ERRSTR[-rc], "");
- goto err;
- }
-
- rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi, err_buf, err_buf_size);
- if (rc != 0) {
- EBUF_PREPEND("reading PFI header");
- goto err;
- }
-
- if (rawdev == NULL || compare)
- rc = skip_raw_volumes(pfi, pfi_raws, err_buf, err_buf_size);
- else
- rc = process_raw_volumes(pfi, pfi_raws, rawdev, err_buf,
- err_buf_size);
- if (rc != 0) {
- EBUF_PREPEND("handling raw section");
- goto err;
- }
-
- if (complete && !compare) {
- rc = erase_unmapped_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis,
- err_buf, err_buf_size);
- if (rc != 0) {
- EBUF_PREPEND("deleting unmapped UBI volumes");
- goto err;
- }
- }
-
- if (((int)pdd_handling >= 0) &&
- (pdd_handling < PDD_HANDLING_NUM))
- pdd_f = pdd_funcs[pdd_handling];
- else {
- rc = -PFIFLASH_ERR_PDD_UNKNOWN;
- EBUF("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- }
-
- if (!compare) {
- rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv,
- pdd_f, UBI_REMOVE, err_buf, err_buf_size);
- if (rc != 0) {
- EBUF_PREPEND("removing UBI volumes");
- goto err;
- }
-
- rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv,
- pdd_f, UBI_WRITE, err_buf, err_buf_size);
- if (rc != 0) {
- EBUF_PREPEND("writing UBI volumes");
- goto err;
- }
-
- if (seqnum < 0) { /* mirror redundant pairs */
- rc = mirror_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis,
- err_buf, err_buf_size);
- if (rc != 0) {
- EBUF_PREPEND("mirroring UBI volumes");
- goto err;
- }
- }
- } else {
- /* only compare volumes, don't alter the content */
- rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv,
- pdd_f, UBI_COMPARE, err_buf, err_buf_size);
-
- if (rc == -PFIFLASH_CMP_DIFF)
- /* update is necessary, return positive value */
- rc = 1;
-
- if (rc < 0) {
- EBUF_PREPEND("comparing UBI volumes");
- goto err;
- }
- }
-
- err:
- pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws);
- pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, pfi_ubis);
- bootenv_destroy(&bootenv);
- return rc;
-}
-
-
-/**
- * pfiflash - passes to pfiflash_with_options
- * @pfi PFI data file pointer
- * @complete flag to erase unmapped volumes
- * @seqnum sequence number
- * @pdd_handling method to handle pdd (keep, merge, overwrite...)
- **/
-int
-pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling,
- char *err_buf, size_t err_buf_size)
-{
- return pfiflash_with_options(pfi, complete, seqnum, 0, pdd_handling,
- NULL, err_buf, err_buf_size);
-}
diff --git a/ubi-utils/src/libscan.c b/ubi-utils/src/libscan.c
new file mode 100644
index 0000000..dc1f083
--- /dev/null
+++ b/ubi-utils/src/libscan.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * 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.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * UBI scanning library.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <mtd_swab.h>
+#include <mtd/ubi-media.h>
+#include <mtd/mtd-user.h>
+#include <libmtd.h>
+#include <libscan.h>
+#include "common.h"
+#include "crc32.h"
+
+#define PROGRAM_NAME "libscan"
+
+static int all_ff(const void *buf, int len)
+{
+ int i;
+ const uint8_t *p = buf;
+
+ for (i = 0; i < len; i++)
+ if (p[i] != 0xFF)
+ return 0;
+ return 1;
+}
+
+int ubi_scan(struct mtd_info *mtd, struct ubi_scan_info **info, int verbose)
+{
+ int eb, v = (verbose == 2), pr = (verbose == 1);
+ struct ubi_scan_info *si;
+ unsigned long long sum = 0;
+
+ si = calloc(1, sizeof(struct ubi_scan_info));
+ if (!si)
+ return sys_errmsg("cannot allocate %zd bytes of memory",
+ sizeof(struct ubi_scan_info));
+
+ si->ec = calloc(mtd->eb_cnt, sizeof(uint32_t));
+ if (!si->ec) {
+ sys_errmsg("cannot allocate %zd bytes of memory",
+ sizeof(struct ubi_scan_info));
+ goto out_si;
+ }
+
+ si->vid_hdr_offs = si->data_offs = -1;
+
+ verbose(v, "start scanning eraseblocks 0-%d", mtd->eb_cnt);
+ for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ int ret;
+ uint32_t crc;
+ struct ubi_ec_hdr hdr;
+ unsigned long long ec;
+
+ if (v) {
+ normsg_cont("scanning eraseblock %d", eb);
+ fflush(stdout);
+ }
+ if (pr) {
+ printf("\r" PROGRAM_NAME ": scanning eraseblock %d -- %2lld %% complete ",
+ eb, (long long)(eb + 1) * 100 / mtd->eb_cnt);
+ fflush(stdout);
+ }
+
+ ret = mtd_is_bad(mtd, eb);
+ if (ret == -1)
+ goto out_ec;
+ if (ret) {
+ si->bad_cnt += 1;
+ si->ec[eb] = EB_BAD;
+ if (v)
+ printf(": bad\n");
+ continue;
+ }
+
+ ret = mtd_read(mtd, eb, 0, &hdr, sizeof(struct ubi_ec_hdr));;
+ if (ret < 0)
+ goto out_ec;
+
+ /* Check the EC header */
+ if (be32_to_cpu(hdr.magic) != UBI_EC_HDR_MAGIC) {
+ if (all_ff(&hdr, sizeof(struct ubi_ec_hdr))) {
+ si->empty_cnt += 1;
+ si->ec[eb] = EB_EMPTY;
+ if (v)
+ printf(": empty\n");
+ } else {
+ si->alien_cnt += 1;
+ si->ec[eb] = EB_ALIEN;
+ if (v)
+ printf(": alien\n");
+ }
+ continue;
+ }
+
+ crc = crc32(UBI_CRC32_INIT, &hdr, UBI_EC_HDR_SIZE_CRC);
+ if (be32_to_cpu(hdr.hdr_crc) != crc) {
+ si->corrupted_cnt += 1;
+ si->ec[eb] = EB_CORRUPTED;
+ if (v)
+ printf(": bad CRC %#08x, should be %#08x\n",
+ crc, be32_to_cpu(hdr.hdr_crc));
+ continue;
+ }
+
+ ec = be64_to_cpu(hdr.ec);
+ if (ec > EC_MAX) {
+ if (pr)
+ printf("\n");
+ errmsg("erase counter in EB %d is %llu, while this "
+ "program expects them to be less than %u",
+ eb, ec, EC_MAX);
+ goto out_ec;
+ }
+
+ if (si->vid_hdr_offs == -1) {
+ si->vid_hdr_offs = be32_to_cpu(hdr.vid_hdr_offset);
+ si->data_offs = be32_to_cpu(hdr.data_offset);
+ if (si->data_offs % mtd->min_io_size) {
+ if (pr)
+ printf("\n");
+ if (v)
+ printf(": corrupted because of the below\n");
+ warnmsg("bad data offset %d at eraseblock %d (n"
+ "of multiple of min. I/O unit size %d)",
+ si->data_offs, eb, mtd->min_io_size);
+ warnmsg("treat eraseblock %d as corrupted", eb);
+ si->corrupted_cnt += 1;
+ si->ec[eb] = EB_CORRUPTED;
+ continue;
+
+ }
+ } else {
+ if ((int)be32_to_cpu(hdr.vid_hdr_offset) != si->vid_hdr_offs) {
+ if (pr)
+ printf("\n");
+ if (v)
+ printf(": corrupted because of the below\n");
+ warnmsg("inconsistent VID header offset: was "
+ "%d, but is %d in eraseblock %d",
+ si->vid_hdr_offs,
+ be32_to_cpu(hdr.vid_hdr_offset), eb);
+ warnmsg("treat eraseblock %d as corrupted", eb);
+ si->corrupted_cnt += 1;
+ si->ec[eb] = EB_CORRUPTED;
+ continue;
+ }
+ if ((int)be32_to_cpu(hdr.data_offset) != si->data_offs) {
+ if (pr)
+ printf("\n");
+ if (v)
+ printf(": corrupted because of the below\n");
+ warnmsg("inconsistent data offset: was %d, but"
+ " is %d in eraseblock %d",
+ si->data_offs,
+ be32_to_cpu(hdr.data_offset), eb);
+ warnmsg("treat eraseblock %d as corrupted", eb);
+ si->corrupted_cnt += 1;
+ si->ec[eb] = EB_CORRUPTED;
+ continue;
+ }
+ }
+
+ si->ok_cnt += 1;
+ si->ec[eb] = ec;
+ if (v)
+ printf(": OK, erase counter %u\n", si->ec[eb]);
+ }
+
+ if (si->ok_cnt != 0) {
+ /* Calculate mean erase counter */
+ for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ if (si->ec[eb] > EC_MAX)
+ continue;
+ sum += si->ec[eb];
+ }
+ si->mean_ec = sum / si->ok_cnt;
+ }
+
+ si->good_cnt = mtd->eb_cnt - si->bad_cnt;
+ verbose(v, "finished, mean EC %lld, %d OK, %d corrupted, %d empty, %d "
+ "alien, bad %d", si->mean_ec, si->ok_cnt, si->corrupted_cnt,
+ si->empty_cnt, si->alien_cnt, si->bad_cnt);
+
+ *info = si;
+ if (pr)
+ printf("\n");
+ return 0;
+
+out_ec:
+ free(si->ec);
+out_si:
+ free(si);
+ *info = NULL;
+ return -1;
+}
+
+void ubi_scan_free(struct ubi_scan_info *si)
+{
+ free(si->ec);
+ free(si);
+}
diff --git a/ubi-utils/src/libubi.c b/ubi-utils/src/libubi.c
index a536b47..1aa66d8 100644
--- a/ubi-utils/src/libubi.c
+++ b/ubi-utils/src/libubi.c
@@ -15,7 +15,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Author: Artem B. Bityutskiy
+ * Author: Artem Bityutskiy
*
* UBI (Unsorted Block Images) library.
*/
@@ -27,14 +27,487 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
-#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <limits.h>
#include "libubi.h"
#include "libubi_int.h"
+#include "common.h"
-libubi_t libubi_open(void)
+#define PROGRAM_NAME "libubi"
+
+/**
+ * mkpath - compose full path from 2 given components.
+ * @path: the first component
+ * @name: the second component
+ *
+ * This function returns the resulting path in case of success and %NULL in
+ * case of failure.
+ */
+static char *mkpath(const char *path, const char *name)
+{
+ char *n;
+ int len1 = strlen(path);
+ int len2 = strlen(name);
+
+ n = malloc(len1 + len2 + 2);
+ if (!n) {
+ sys_errmsg("cannot allocate %d bytes", len1 + len2 + 2);
+ return NULL;
+ }
+
+ memcpy(n, path, len1);
+ if (n[len1 - 1] != '/')
+ n[len1++] = '/';
+
+ memcpy(n + len1, name, len2 + 1);
+ return n;
+}
+
+/**
+ * read_positive_ll - read a positive 'long long' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function reads file @file and interprets its contents as a positive
+ * 'long long' integer. If this is not true, it fails with %EINVAL error code.
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+static int read_positive_ll(const char *file, long long *value)
+{
+ int fd, rd;
+ char buf[50];
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rd = read(fd, buf, 50);
+ if (rd == -1) {
+ sys_errmsg("cannot read \"%s\"", file);
+ goto out_error;
+ }
+ if (rd == 50) {
+ errmsg("contents of \"%s\" is too long", file);
+ errno = EINVAL;
+ goto out_error;
+ }
+
+ if (sscanf(buf, "%lld\n", value) != 1) {
+ /* This must be a UBI bug */
+ errmsg("cannot read integer from \"%s\"\n", file);
+ errno = EINVAL;
+ goto out_error;
+ }
+
+ if (*value < 0) {
+ errmsg("negative value %lld in \"%s\"", *value, file);
+ errno = EINVAL;
+ goto out_error;
+ }
+
+ if (close(fd))
+ return sys_errmsg("close failed on \"%s\"", file);
+
+ return 0;
+
+out_error:
+ close(fd);
+ return -1;
+}
+
+/**
+ * read_positive_int - read a positive 'int' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function is the same as 'read_positive_ll()', but it reads an 'int'
+ * value, not 'long long'.
+ */
+static int read_positive_int(const char *file, int *value)
+{
+ long long res;
+
+ if (read_positive_ll(file, &res))
+ return -1;
+
+ /* Make sure the value is not too big */
+ if (res > INT_MAX) {
+ errmsg("value %lld read from file \"%s\" is out of range",
+ res, file);
+ errno = EINVAL;
+ return -1;
+ }
+
+ *value = res;
+ return 0;
+}
+
+/**
+ * read_data - read data from a file.
+ * @file: the file to read from
+ * @buf: the buffer to read to
+ * @buf_len: buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure. Note, if the file contains more then @buf_len bytes of
+ * date, this function fails with %EINVAL error code.
+ */
+static int read_data(const char *file, void *buf, int buf_len)
+{
+ int fd, rd, tmp, tmp1;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rd = read(fd, buf, buf_len);
+ if (rd == -1) {
+ sys_errmsg("cannot read \"%s\"", file);
+ goto out_error;
+ }
+
+ /* Make sure all data is read */
+ tmp1 = read(fd, &tmp, 1);
+ if (tmp1 == 1) {
+ sys_errmsg("cannot read \"%s\"", file);
+ goto out_error;
+ }
+ if (tmp1) {
+ errmsg("file \"%s\" contains too much data (> %d bytes)",
+ file, buf_len);
+ errno = EINVAL;
+ goto out_error;
+ }
+
+ if (close(fd)) {
+ sys_errmsg("close failed on \"%s\"", file);
+ return -1;
+ }
+
+ return rd;
+
+out_error:
+ close(fd);
+ return -1;
+}
+
+/**
+ * read_major - read major and minor numbers from a file.
+ * @file: name of the file to read from
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns % in case of succes, and %-1 in case of failure.
+ */
+static int read_major(const char *file, int *major, int *minor)
+{
+ int ret;
+ char buf[50];
+
+ ret = read_data(file, buf, 50);
+ if (ret < 0)
+ return ret;
+
+ ret = sscanf(buf, "%d:%d\n", major, minor);
+ if (ret != 2) {
+ errno = EINVAL;
+ return errmsg("\"%s\" does not have major:minor format", file);
+ }
+
+ if (*major < 0 || *minor < 0) {
+ errno = EINVAL;
+ return errmsg("bad major:minor %d:%d in \"%s\"",
+ *major, *minor, file);
+ }
+
+ return 0;
+}
+
+/**
+ * dev_read_int - read a positive 'int' value from an UBI device sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_int(const char *patt, int dev_num, int *value)
+{
+ char file[strlen(patt) + 50];
+
+ sprintf(file, patt, dev_num);
+ return read_positive_int(file, value);
+}
+
+/**
+ * vol_read_int - read a positive 'int' value from an UBI volume sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value)
+{
+ char file[strlen(patt) + 100];
+
+ sprintf(file, patt, dev_num, vol_id);
+ return read_positive_int(file, value);
+}
+
+/**
+ * dev_read_ll - read a positive 'long long' value from an UBI device sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_ll(const char *patt, int dev_num, long long *value)
+{
+ char file[strlen(patt) + 50];
+
+ sprintf(file, patt, dev_num);
+ return read_positive_ll(file, value);
+}
+
+/**
+ * vol_read_ll - read a positive 'long long' value from an UBI volume sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int vol_read_ll(const char *patt, int dev_num, int vol_id,
+ long long *value)
+{
+ char file[strlen(patt) + 100];
+
+ sprintf(file, patt, dev_num, vol_id);
+ return read_positive_ll(file, value);
+}
+
+/**
+ * vol_read_data - read data from an UBI volume's sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @buf: buffer to read to
+ * @buf_len: buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure.
+ */
+static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
+ int buf_len)
+{
+ char file[strlen(patt) + 100];
+
+ sprintf(file, patt, dev_num, vol_id);
+ return read_data(file, buf, buf_len);
+}
+
+/**
+ * dev_get_major - get major and minor numbers of an UBI device.
+ * @lib: libubi descriptor
+ * @dev_num: UBI device number
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns zero in case of succes and %-1 in case of failure.
+ */
+static int dev_get_major(struct libubi *lib, int dev_num, int *major, int *minor)
+{
+ char file[strlen(lib->dev_dev) + 50];
+
+ sprintf(file, lib->dev_dev, dev_num);
+ return read_major(file, major, minor);
+}
+
+/**
+ * vol_get_major - get major and minor numbers of an UBI volume.
+ * @lib: libubi descriptor
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns zero in case of succes and %-1 in case of failure.
+ */
+static int vol_get_major(struct libubi *lib, int dev_num, int vol_id,
+ int *major, int *minor)
+{
+ char file[strlen(lib->vol_dev) + 100];
+
+ sprintf(file, lib->vol_dev, dev_num, vol_id);
+ return read_major(file, major, minor);
+}
+
+/**
+ * vol_node2nums - find UBI device number and volume ID by volume device node
+ * file.
+ * @lib: UBI library descriptor
+ * @node: UBI character device node name
+ * @dev_num: UBI device number is returned here
+ * @vol_id: volume ID is returned hers
+ *
+ * This function returns zero in case of succes and %-1 in case of failure.
+ */
+static int vol_node2nums(struct libubi *lib, const char *node, int *dev_num,
+ int *vol_id)
+{
+ struct stat st;
+ struct ubi_info info;
+ int i, fd, major, minor;
+ char file[strlen(lib->ubi_vol) + 100];
+
+ if (stat(node, &st))
+ return sys_errmsg("cannot get information about \"%s\"",
+ node);
+
+ if (!S_ISCHR(st.st_mode)) {
+ errno = EINVAL;
+ return errmsg("\"%s\" is not a character device", node);
+ }
+
+ major = major(st.st_rdev);
+ minor = minor(st.st_rdev);
+
+ if (minor == 0) {
+ errno = EINVAL;
+ return errmsg("\"%s\" is not a volume character device", node);
+ }
+
+ if (ubi_get_info((libubi_t *)lib, &info))
+ return -1;
+
+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+ int major1, minor1, ret;
+
+ ret = dev_get_major(lib, i, &major1, &minor1);
+ if (ret) {
+ if (errno == ENOENT)
+ continue;
+ return -1;
+ }
+
+ if (major1 == major)
+ break;
+ }
+
+ if (i > info.highest_dev_num) {
+ errno = ENODEV;
+ return -1;
+ }
+
+ /* Make sure this UBI volume exists */
+ sprintf(file, lib->ubi_vol, i, minor - 1);
+ fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ errno = ENODEV;
+ return -1;
+ }
+
+ *dev_num = i;
+ *vol_id = minor - 1;
+ errno = 0;
+ return 0;
+}
+
+/**
+ * dev_node2num - find UBI device number by its character device node.
+ * @lib: UBI library descriptor
+ * @node: UBI character device node name
+ *
+ * This function returns positive UBI device number in case of success and %-1
+ * in case of failure.
+ */
+static int dev_node2num(struct libubi *lib, const char *node, int *dev_num)
+{
+ struct stat st;
+ struct ubi_info info;
+ int i, major, minor;
+
+ if (stat(node, &st))
+ return sys_errmsg("cannot get information about \"%s\"",
+ node);
+
+ if (!S_ISCHR(st.st_mode)) {
+ errno = EINVAL;
+ return errmsg("\"%s\" is not a character device", node);
+ }
+
+ major = major(st.st_rdev);
+ minor = minor(st.st_rdev);
+
+ if (minor != 0) {
+ errno = EINVAL;
+ return errmsg("\"%s\" is not an UBI character device", node);
+ }
+
+ if (ubi_get_info((libubi_t *)lib, &info))
+ return -1;
+
+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+ int major1, minor1, ret;
+
+ ret = dev_get_major(lib, i, &major1, &minor1);
+ if (ret) {
+ if (errno == ENOENT)
+ continue;
+ return -1;
+ }
+
+ if (major1 == major) {
+ if (minor1 != 0) {
+ errmsg("UBI character device minor number is "
+ "%d, but must be 0", minor1);
+ errno = EINVAL;
+ return -1;
+ }
+ errno = 0;
+ *dev_num = i;
+ return 0;
+ }
+ }
+
+ errno = ENODEV;
+ return -1;
+}
+
+int mtd_num2ubi_dev(libubi_t desc, int mtd_num, int *dev_num)
+{
+ struct ubi_info info;
+ int i, ret, mtd_num1;
+ struct libubi *lib = desc;
+
+ if (ubi_get_info(desc, &info))
+ return -1;
+
+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+ ret = dev_read_int(lib->dev_mtd_num, i, &mtd_num1);
+ if (ret) {
+ if (errno == ENOENT)
+ continue;
+ return -1;
+ }
+
+ if (mtd_num1 == mtd_num) {
+ errno = 0;
+ *dev_num = i;
+ return 0;
+ }
+ }
+
+ errno = 0;
+ return -1;
+}
+
+libubi_t libubi_open(int required)
{
int fd, version;
struct libubi *lib;
@@ -46,132 +519,130 @@ libubi_t libubi_open(void)
/* TODO: this must be discovered instead */
lib->sysfs = strdup("/sys");
if (!lib->sysfs)
- goto error;
+ goto out_error;
+
+ lib->sysfs_ctrl = mkpath(lib->sysfs, SYSFS_CTRL);
+ if (!lib->sysfs_ctrl)
+ goto out_error;
+
+ lib->ctrl_dev = mkpath(lib->sysfs_ctrl, CTRL_DEV);
+ if (!lib->ctrl_dev)
+ goto out_error;
lib->sysfs_ubi = mkpath(lib->sysfs, SYSFS_UBI);
if (!lib->sysfs_ubi)
- goto error;
+ goto out_error;
/* Make sure UBI is present */
fd = open(lib->sysfs_ubi, O_RDONLY);
- if (fd == -1)
- goto error;
- close(fd);
+ if (fd == -1) {
+ if (required)
+ errmsg("cannot open \"%s\", UBI does not seem to "
+ "exist in system", lib->sysfs_ubi);
+ goto out_error;
+ }
+
+ if (close(fd)) {
+ sys_errmsg("close failed on \"%s\"", lib->sysfs_ubi);
+ goto out_error;
+ }
lib->ubi_dev = mkpath(lib->sysfs_ubi, UBI_DEV_NAME_PATT);
if (!lib->ubi_dev)
- goto error;
+ goto out_error;
lib->ubi_version = mkpath(lib->sysfs_ubi, UBI_VER);
if (!lib->ubi_version)
- goto error;
+ goto out_error;
lib->dev_dev = mkpath(lib->ubi_dev, DEV_DEV);
if (!lib->dev_dev)
- goto error;
+ goto out_error;
lib->dev_avail_ebs = mkpath(lib->ubi_dev, DEV_AVAIL_EBS);
if (!lib->dev_avail_ebs)
- goto error;
+ goto out_error;
lib->dev_total_ebs = mkpath(lib->ubi_dev, DEV_TOTAL_EBS);
if (!lib->dev_total_ebs)
- goto error;
+ goto out_error;
lib->dev_bad_count = mkpath(lib->ubi_dev, DEV_BAD_COUNT);
if (!lib->dev_bad_count)
- goto error;
+ goto out_error;
lib->dev_eb_size = mkpath(lib->ubi_dev, DEV_EB_SIZE);
if (!lib->dev_eb_size)
- goto error;
+ goto out_error;
lib->dev_max_ec = mkpath(lib->ubi_dev, DEV_MAX_EC);
if (!lib->dev_max_ec)
- goto error;
+ goto out_error;
lib->dev_bad_rsvd = mkpath(lib->ubi_dev, DEV_MAX_RSVD);
if (!lib->dev_bad_rsvd)
- goto error;
+ goto out_error;
lib->dev_max_vols = mkpath(lib->ubi_dev, DEV_MAX_VOLS);
if (!lib->dev_max_vols)
- goto error;
+ goto out_error;
lib->dev_min_io_size = mkpath(lib->ubi_dev, DEV_MIN_IO_SIZE);
if (!lib->dev_min_io_size)
- goto error;
+ goto out_error;
+
+ lib->dev_mtd_num = mkpath(lib->ubi_dev, DEV_MTD_NUM);
+ if (!lib->dev_mtd_num)
+ goto out_error;
lib->ubi_vol = mkpath(lib->sysfs_ubi, UBI_VOL_NAME_PATT);
if (!lib->ubi_vol)
- goto error;
+ goto out_error;
lib->vol_type = mkpath(lib->ubi_vol, VOL_TYPE);
if (!lib->vol_type)
- goto error;
+ goto out_error;
lib->vol_dev = mkpath(lib->ubi_vol, VOL_DEV);
if (!lib->vol_dev)
- goto error;
+ goto out_error;
lib->vol_alignment = mkpath(lib->ubi_vol, VOL_ALIGNMENT);
if (!lib->vol_alignment)
- goto error;
+ goto out_error;
lib->vol_data_bytes = mkpath(lib->ubi_vol, VOL_DATA_BYTES);
if (!lib->vol_data_bytes)
- goto error;
+ goto out_error;
lib->vol_rsvd_ebs = mkpath(lib->ubi_vol, VOL_RSVD_EBS);
if (!lib->vol_rsvd_ebs)
- goto error;
+ goto out_error;
lib->vol_eb_size = mkpath(lib->ubi_vol, VOL_EB_SIZE);
if (!lib->vol_eb_size)
- goto error;
+ goto out_error;
lib->vol_corrupted = mkpath(lib->ubi_vol, VOL_CORRUPTED);
if (!lib->vol_corrupted)
- goto error;
+ goto out_error;
lib->vol_name = mkpath(lib->ubi_vol, VOL_NAME);
if (!lib->vol_name)
- goto error;
+ goto out_error;
- if (read_int(lib->ubi_version, &version))
- goto error;
+ if (read_positive_int(lib->ubi_version, &version))
+ goto out_error;
if (version != LIBUBI_UBI_VERSION) {
- fprintf(stderr, "LIBUBI: this library was made for UBI version "
- "%d, but UBI version %d is detected\n",
- LIBUBI_UBI_VERSION, version);
- goto error;
+ errmsg("this library was made for UBI version %d, but UBI "
+ "version %d is detected\n", LIBUBI_UBI_VERSION, version);
+ goto out_error;
}
return lib;
-error:
- free(lib->vol_corrupted);
- free(lib->vol_eb_size);
- free(lib->vol_rsvd_ebs);
- free(lib->vol_data_bytes);
- free(lib->vol_alignment);
- free(lib->vol_dev);
- free(lib->vol_type);
- free(lib->ubi_vol);
- free(lib->dev_min_io_size);
- free(lib->dev_max_vols);
- free(lib->dev_bad_rsvd);
- free(lib->dev_max_ec);
- free(lib->dev_eb_size);
- free(lib->dev_bad_count);
- free(lib->dev_total_ebs);
- free(lib->dev_avail_ebs);
- free(lib->dev_dev);
- free(lib->ubi_version);
- free(lib->ubi_dev);
- free(lib->sysfs_ubi);
- free(lib->sysfs);
- free(lib);
+out_error:
+ libubi_close((libubi_t)lib);
return NULL;
}
@@ -188,6 +659,7 @@ void libubi_close(libubi_t desc)
free(lib->vol_dev);
free(lib->vol_type);
free(lib->ubi_vol);
+ free(lib->dev_mtd_num);
free(lib->dev_min_io_size);
free(lib->dev_max_vols);
free(lib->dev_bad_rsvd);
@@ -200,10 +672,143 @@ void libubi_close(libubi_t desc)
free(lib->ubi_version);
free(lib->ubi_dev);
free(lib->sysfs_ubi);
+ free(lib->ctrl_dev);
+ free(lib->sysfs_ctrl);
free(lib->sysfs);
free(lib);
}
+int ubi_attach_mtd(libubi_t desc, const char *node,
+ struct ubi_attach_request *req)
+{
+ int fd, ret;
+ struct ubi_attach_req r;
+
+ memset(&r, sizeof(struct ubi_attach_req), '\0');
+
+ desc = desc;
+ r.ubi_num = req->dev_num;
+ r.mtd_num = req->mtd_num;
+ r.vid_hdr_offset = req->vid_hdr_offset;
+
+ fd = open(node, O_RDONLY);
+ if (fd == -1)
+ return sys_errmsg("cannot open \"%s\"", node);
+
+ ret = ioctl(fd, UBI_IOCATT, &r);
+ close(fd);
+ if (ret == -1)
+ return -1;
+
+ req->dev_num = r.ubi_num;
+
+#ifdef UDEV_SETTLE_HACK
+ if (system("udevsettle") == -1)
+ return -1;
+#endif
+
+ return ret;
+}
+
+int ubi_detach_mtd(libubi_t desc, const char *node, int mtd_num)
+{
+ int ret, ubi_dev;
+
+ ret = mtd_num2ubi_dev(desc, mtd_num, &ubi_dev);
+ if (ret == -1) {
+ errno = ENODEV;
+ return ret;
+ }
+
+ return ubi_remove_dev(desc, node, ubi_dev);
+}
+
+int ubi_remove_dev(libubi_t desc, const char *node, int ubi_dev)
+{
+ int fd, ret;
+
+ desc = desc;
+
+ fd = open(node, O_RDONLY);
+ if (fd == -1)
+ return sys_errmsg("cannot open \"%s\"", node);
+ ret = ioctl(fd, UBI_IOCDET, &ubi_dev);
+ if (ret == -1)
+ goto out_close;
+
+#ifdef UDEV_SETTLE_HACK
+ if (system("udevsettle") == -1)
+ return -1;
+#endif
+
+out_close:
+ close(fd);
+ return ret;
+}
+
+int ubi_node_type(libubi_t desc, const char *node)
+{
+ struct stat st;
+ struct ubi_info info;
+ int i, fd, major, minor;
+ struct libubi *lib = (struct libubi *)desc;
+ char file[strlen(lib->ubi_vol) + 100];
+
+ if (stat(node, &st))
+ return sys_errmsg("cannot get information about \"%s\"",
+ node);
+
+ if (!S_ISCHR(st.st_mode)) {
+ errmsg("\"%s\" is not a character device", node);
+ errno = EINVAL;
+ return -1;
+ }
+
+ major = major(st.st_rdev);
+ minor = minor(st.st_rdev);
+
+ if (ubi_get_info((libubi_t *)lib, &info))
+ return -1;
+
+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+ int major1, minor1, ret;
+
+ ret = dev_get_major(lib, i, &major1, &minor1);
+ if (ret) {
+ if (errno == ENOENT)
+ continue;
+ if (!errno)
+ goto out_not_ubi;
+ return -1;
+ }
+
+ if (major1 == major)
+ break;
+ }
+
+ if (i > info.highest_dev_num)
+ goto out_not_ubi;
+
+ if (minor == 0)
+ return 1;
+
+ /* This is supposdely an UBI volume device node */
+ sprintf(file, lib->ubi_vol, i, minor - 1);
+ fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ sys_errmsg("cannot open \"%s\"", node);
+ return -1;
+ }
+
+ return 2;
+
+out_not_ubi:
+ errmsg("\"%s\" has major:minor %d:%d, but this does not correspond to "
+ "any UBI device or volume", node, major, minor);
+ errno = 0;
+ return -1;
+}
+
int ubi_get_info(libubi_t desc, struct ubi_info *info)
{
DIR *sysfs_ubi;
@@ -212,6 +817,16 @@ int ubi_get_info(libubi_t desc, struct ubi_info *info)
memset(info, '\0', sizeof(struct ubi_info));
+ if (read_major(lib->ctrl_dev, &info->ctrl_major, &info->ctrl_minor)) {
+ /*
+ * Older UBI versions did not have control device, so we do not
+ * panic here for compatibility reasons. May be few years later
+ * we could return -1 here, but for now just set major:minor to
+ * -1.
+ */
+ info->ctrl_major = info->ctrl_minor = -1;
+ }
+
/*
* We have to scan the UBI sysfs directory to identify how many UBI
* devices are present.
@@ -221,11 +836,23 @@ int ubi_get_info(libubi_t desc, struct ubi_info *info)
return -1;
info->lowest_dev_num = INT_MAX;
- while ((dirent = readdir(sysfs_ubi))) {
- char *name = &dirent->d_name[0];
+ while (1) {
int dev_num, ret;
+ char tmp_buf[256];
+
+ errno = 0;
+ dirent = readdir(sysfs_ubi);
+ if (!dirent)
+ break;
+
+ if (strlen(dirent->d_name) > 256) {
+ errmsg("invalid entry in %s: \"%s\"",
+ lib->sysfs_ubi, dirent->d_name);
+ goto out_close;
+ }
- ret = sscanf(name, UBI_DEV_NAME_PATT, &dev_num);
+ ret = sscanf(dirent->d_name, UBI_DEV_NAME_PATT"%s",
+ &dev_num, tmp_buf);
if (ret == 1) {
info->dev_count += 1;
if (dev_num > info->highest_dev_num)
@@ -235,15 +862,23 @@ int ubi_get_info(libubi_t desc, struct ubi_info *info)
}
}
+ if (!dirent && errno) {
+ sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
+ goto out_close;
+ }
+
+ if (closedir(sysfs_ubi))
+ return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
+
if (info->lowest_dev_num == INT_MAX)
info->lowest_dev_num = 0;
- if (read_int(lib->ubi_version, &info->version))
- goto close;
+ if (read_positive_int(lib->ubi_version, &info->version))
+ return -1;
- return closedir(sysfs_ubi);
+ return 0;
-close:
+out_close:
closedir(sysfs_ubi);
return -1;
}
@@ -254,6 +889,8 @@ int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req)
struct ubi_mkvol_req r;
size_t n;
+ memset(&r, sizeof(struct ubi_mkvol_req), '\0');
+
desc = desc;
r.vol_id = req->vol_id;
r.alignment = req->alignment;
@@ -269,12 +906,20 @@ int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req)
fd = open(node, O_RDONLY);
if (fd == -1)
- return -1;
+ return sys_errmsg("cannot open \"%s\"", node);
ret = ioctl(fd, UBI_IOCMKVOL, &r);
- if (!ret)
- req->vol_id = r.vol_id;
+ if (ret == -1)
+ goto out_close;
+
+ req->vol_id = r.vol_id;
+#ifdef UDEV_SETTLE_HACK
+ if (system("udevsettle") == -1)
+ return -1;
+#endif
+
+out_close:
close(fd);
return ret;
}
@@ -286,9 +931,39 @@ int ubi_rmvol(libubi_t desc, const char *node, int vol_id)
desc = desc;
fd = open(node, O_RDONLY);
if (fd == -1)
- return -1;
+ return sys_errmsg("cannot open \"%s\"", node);
ret = ioctl(fd, UBI_IOCRMVOL, &vol_id);
+ if (ret == -1)
+ goto out_close;
+
+#ifdef UDEV_SETTLE_HACK
+ if (system("udevsettle") == -1)
+ return -1;
+#endif
+
+out_close:
+ close(fd);
+ return ret;
+}
+
+int ubi_rnvols(libubi_t desc, const char *node, struct ubi_rnvol_req *rnvol)
+{
+ int fd, ret;
+
+ fd = open(node, O_RDONLY);
+ if (fd == -1)
+ return -1;
+ ret = ioctl(fd, UBI_IOCRNVOL, rnvol);
+ if (ret == -1)
+ goto out_close;
+
+#ifdef UDEV_SETTLE_HACK
+ if (system("udevsettle") == -1)
+ return -1;
+#endif
+
+out_close:
close(fd);
return ret;
}
@@ -301,7 +976,7 @@ int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes)
desc = desc;
fd = open(node, O_RDONLY);
if (fd == -1)
- return -1;
+ return sys_errmsg("cannot open \"%s\"", node);
req.bytes = bytes;
req.vol_id = vol_id;
@@ -319,16 +994,19 @@ int ubi_update_start(libubi_t desc, int fd, long long bytes)
return 0;
}
-int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info)
+int ubi_leb_change_start(libubi_t desc, int fd, int lnum, int bytes, int dtype)
{
- int dev_num;
- struct libubi *lib = (struct libubi *)desc;
+ struct ubi_leb_change_req req;
- dev_num = find_dev_num(lib, node);
- if (dev_num == -1)
- return -1;
+ desc = desc;
+ memset(&req, 0, sizeof(struct ubi_leb_change_req));
+ req.lnum = lnum;
+ req.bytes = bytes;
+ req.dtype = dtype;
- return ubi_get_dev_info1(desc, dev_num, info);
+ if (ioctl(fd, UBI_IOCEBCH, &req))
+ return -1;
+ return 0;
}
int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
@@ -344,33 +1022,54 @@ int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
if (!sysfs_ubi)
return -1;
- info->lowest_vol_num = INT_MAX;
- while ((dirent = readdir(sysfs_ubi))) {
- char *name = &dirent->d_name[0];
+ info->lowest_vol_id = INT_MAX;
+
+ while (1) {
int vol_id, ret, devno;
+ char tmp_buf[256];
+
+ errno = 0;
+ dirent = readdir(sysfs_ubi);
+ if (!dirent)
+ break;
+
+ if (strlen(dirent->d_name) > 256) {
+ errmsg("invalid entry in %s: \"%s\"",
+ lib->sysfs_ubi, dirent->d_name);
+ goto out_close;
+ }
- ret = sscanf(name, UBI_VOL_NAME_PATT, &devno, &vol_id);
+ ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT"%s", &devno, &vol_id, tmp_buf);
if (ret == 2 && devno == dev_num) {
info->vol_count += 1;
- if (vol_id > info->highest_vol_num)
- info->highest_vol_num = vol_id;
- if (vol_id < info->lowest_vol_num)
- info->lowest_vol_num = vol_id;
+ if (vol_id > info->highest_vol_id)
+ info->highest_vol_id = vol_id;
+ if (vol_id < info->lowest_vol_id)
+ info->lowest_vol_id = vol_id;
}
}
- closedir(sysfs_ubi);
+ if (!dirent && errno) {
+ sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
+ goto out_close;
+ }
- if (info->lowest_vol_num == INT_MAX)
- info->lowest_vol_num = 0;
+ if (closedir(sysfs_ubi))
+ return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
- if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_ebs))
+ if (info->lowest_vol_id == INT_MAX)
+ info->lowest_vol_id = 0;
+
+ if (dev_get_major(lib, dev_num, &info->major, &info->minor))
+ return -1;
+
+ if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_lebs))
return -1;
- if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_ebs))
+ if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_lebs))
return -1;
if (dev_read_int(lib->dev_bad_count, dev_num, &info->bad_count))
return -1;
- if (dev_read_int(lib->dev_eb_size, dev_num, &info->eb_size))
+ if (dev_read_int(lib->dev_eb_size, dev_num, &info->leb_size))
return -1;
if (dev_read_int(lib->dev_bad_rsvd, dev_num, &info->bad_rsvd))
return -1;
@@ -381,26 +1080,25 @@ int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
if (dev_read_int(lib->dev_min_io_size, dev_num, &info->min_io_size))
return -1;
- info->avail_bytes = info->avail_ebs * info->eb_size;
- info->total_bytes = info->total_ebs * info->eb_size;
+ info->avail_bytes = info->avail_lebs * info->leb_size;
+ info->total_bytes = info->total_lebs * info->leb_size;
return 0;
+
+out_close:
+ closedir(sysfs_ubi);
+ return -1;
}
-int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info)
+int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info)
{
- int vol_id, dev_num;
+ int dev_num;
struct libubi *lib = (struct libubi *)desc;
- dev_num = find_dev_num_vol(lib, node);
- if (dev_num == -1)
- return -1;
-
- vol_id = find_vol_num(lib, dev_num, node);
- if (vol_id == -1)
+ if (dev_node2num(lib, node, &dev_num))
return -1;
- return ubi_get_vol_info1(desc, dev_num, vol_id, info);
+ return ubi_get_dev_info1(desc, dev_num, info);
}
int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
@@ -414,16 +1112,21 @@ int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
info->dev_num = dev_num;
info->vol_id = vol_id;
- ret = vol_read_data(lib->vol_type, dev_num, vol_id, &buf[0], 50);
+ if (dev_get_major(lib, dev_num, &info->dev_major, &info->dev_minor))
+ return -1;
+ if (vol_get_major(lib, dev_num, vol_id, &info->major, &info->minor))
+ return -1;
+
+ ret = vol_read_data(lib->vol_type, dev_num, vol_id, buf, 50);
if (ret < 0)
return -1;
- if (strncmp(&buf[0], "static\n", ret) == 0)
+ if (strncmp(buf, "static\n", ret) == 0)
info->type = UBI_STATIC_VOLUME;
- else if (strncmp(&buf[0], "dynamic\n", ret) == 0)
+ else if (strncmp(buf, "dynamic\n", ret) == 0)
info->type = UBI_DYNAMIC_VOLUME;
else {
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+ errmsg("bad value at \"%s\"", buf);
errno = EINVAL;
return -1;
}
@@ -436,17 +1139,17 @@ int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
&info->data_bytes);
if (ret)
return -1;
- ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_ebs);
+ ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_lebs);
if (ret)
return -1;
- ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->eb_size);
+ ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->leb_size);
if (ret)
return -1;
ret = vol_read_int(lib->vol_corrupted, dev_num, vol_id,
&info->corrupted);
if (ret)
return -1;
- info->rsvd_bytes = info->eb_size * info->rsvd_ebs;
+ info->rsvd_bytes = info->leb_size * info->rsvd_lebs;
ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name,
UBI_VOL_NAME_MAX + 2);
@@ -457,457 +1160,45 @@ int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
return 0;
}
-/**
- * read_int - read an 'int' value from a file.
- *
- * @file the file to read from
- * @value the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int read_int(const char *file, int *value)
-{
- int fd, rd;
- char buf[50];
-
- fd = open(file, O_RDONLY);
- if (fd == -1)
- return -1;
-
- rd = read(fd, &buf[0], 50);
- if (rd == -1)
- goto error;
-
- if (sscanf(&buf[0], "%d\n", value) != 1) {
- /* This must be a UBI bug */
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- goto error;
- }
-
- close(fd);
- return 0;
-
-error:
- close(fd);
- return -1;
-}
-
-/**
- * dev_read_int - read an 'int' value from an UBI device's sysfs file.
- *
- * @patt the file pattern to read from
- * @dev_num UBI device number
- * @value the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int dev_read_int(const char *patt, int dev_num, int *value)
-{
- int fd, rd;
- char buf[50];
- char file[strlen(patt) + 50];
-
- sprintf(&file[0], patt, dev_num);
- fd = open(&file[0], O_RDONLY);
- if (fd == -1)
- return -1;
-
- rd = read(fd, &buf[0], 50);
- if (rd == -1)
- goto error;
-
- if (sscanf(&buf[0], "%d\n", value) != 1) {
- /* This must be a UBI bug */
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- goto error;
- }
-
- close(fd);
- return 0;
-
-error:
- close(fd);
- return -1;
-}
-
-/**
- * dev_read_ll - read a 'long long' value from an UBI device's sysfs file.
- *
- * @patt the file pattern to read from
- * @dev_num UBI device number
- * @value the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int dev_read_ll(const char *patt, int dev_num, long long *value)
-{
- int fd, rd;
- char buf[50];
- char file[strlen(patt) + 50];
-
- sprintf(&file[0], patt, dev_num);
- fd = open(&file[0], O_RDONLY);
- if (fd == -1)
- return -1;
-
- rd = read(fd, &buf[0], 50);
- if (rd == -1)
- goto error;
-
- if (sscanf(&buf[0], "%lld\n", value) != 1) {
- /* This must be a UBI bug */
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- goto error;
- }
-
- close(fd);
- return 0;
-
-error:
- close(fd);
- return -1;
-}
-
-/**
- * dev_read_data - read data from an UBI device's sysfs file.
- *
- * @patt the file pattern to read from
- * @dev_num UBI device number
- * @buf buffer to read data to
- * @buf_len buffer length
- *
- * This function returns number of read bytes in case of success and %-1 in
- * case of failure.
- */
-static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len)
-{
- int fd, rd;
- char file[strlen(patt) + 50];
-
- sprintf(&file[0], patt, dev_num);
- fd = open(&file[0], O_RDONLY);
- if (fd == -1)
- return -1;
-
- rd = read(fd, buf, buf_len);
- if (rd == -1) {
- close(fd);
- return -1;
- }
-
- close(fd);
- return rd;
-}
-
-/**
- * vol_read_int - read an 'int' value from an UBI volume's sysfs file.
- *
- * @patt the file pattern to read from
- * @dev_num UBI device number
- * @vol_id volume identifier
- * @value the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value)
-{
- int fd, rd;
- char buf[50];
- char file[strlen(patt) + 100];
-
- sprintf(&file[0], patt, dev_num, vol_id);
- fd = open(&file[0], O_RDONLY);
- if (fd == -1)
- return -1;
-
- rd = read(fd, &buf[0], 50);
- if (rd == -1)
- goto error;
-
- if (sscanf(&buf[0], "%d\n", value) != 1) {
- /* This must be a UBI bug */
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- goto error;
- }
-
- close(fd);
- return 0;
-
-error:
- close(fd);
- return -1;
-}
-
-/**
- * vol_read_ll - read a 'long long' value from an UBI volume's sysfs file.
- *
- * @patt the file pattern to read from
- * @dev_num UBI device number
- * @vol_id volume identifier
- * @value the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int vol_read_ll(const char *patt, int dev_num, int vol_id,
- long long *value)
-{
- int fd, rd;
- char buf[50];
- char file[strlen(patt) + 100];
-
- sprintf(&file[0], patt, dev_num, vol_id);
- fd = open(&file[0], O_RDONLY);
- if (fd == -1)
- return -1;
-
- rd = read(fd, &buf[0], 50);
- if (rd == -1)
- goto error;
-
- if (sscanf(&buf[0], "%lld\n", value) != 1) {
- /* This must be a UBI bug */
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- goto error;
- }
-
- close(fd);
- return 0;
-
-error:
- close(fd);
- return -1;
-}
-
-/**
- * vol_read_data - read data from an UBI volume's sysfs file.
- *
- * @patt the file pattern to read from
- * @dev_num UBI device number
- * @vol_id volume identifier
- * @buf buffer to read to
- * @buf_len buffer length
- *
- * This function returns number of read bytes in case of success and %-1 in
- * case of failure.
- */
-static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
- int buf_len)
-{
- int fd, rd;
- char file[strlen(patt) + 100];
-
- sprintf(&file[0], patt, dev_num, vol_id);
- fd = open(&file[0], O_RDONLY);
- if (fd == -1)
- return -1;
-
- rd = read(fd, buf, buf_len);
- if (rd == -1) {
- close(fd);
- return -1;
- }
-
- close(fd);
- return rd;
-}
-
-/**
- * mkpath - compose full path from 2 given components.
- *
- * @path first component
- * @name second component
- *
- * This function returns the resulting path in case of success and %NULL in
- * case of failure.
- */
-static char *mkpath(const char *path, const char *name)
-{
- char *n;
- int len1 = strlen(path);
- int len2 = strlen(name);
-
- n = malloc(len1 + len2 + 2);
- if (!n)
- return NULL;
-
- memcpy(n, path, len1);
- if (n[len1 - 1] != '/')
- n[len1++] = '/';
-
- memcpy(n + len1, name, len2 + 1);
- return n;
-}
-
-/**
- * find_dev_num - find UBI device number by its character device node.
- *
- * @lib UBI library descriptor
- * @node UBI character device node name
- *
- * This function returns positive UBI device number in case of success and %-1
- * in case of failure.
- */
-static int find_dev_num(struct libubi *lib, const char *node)
-{
- struct stat st;
- struct ubi_info info;
- int i, major, minor;
-
- if (stat(node, &st))
- return -1;
-
- if (!S_ISCHR(st.st_mode)) {
- errno = EINVAL;
- return -1;
- }
-
- major = major(st.st_rdev);
- minor = minor(st.st_rdev);
-
- if (minor != 0) {
- errno = -EINVAL;
- return -1;
- }
-
- if (ubi_get_info((libubi_t *)lib, &info))
- return -1;
-
- for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
- int major1, minor1, ret;
- char buf[50];
-
- ret = dev_read_data(lib->dev_dev, i, &buf[0], 50);
- if (ret < 0)
- return -1;
-
- ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
- if (ret != 2) {
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- return -1;
- }
-
- if (minor1 == minor && major1 == major)
- return i;
- }
-
- errno = ENOENT;
- return -1;
-}
-
-/**
- * find_dev_num_vol - find UBI device number by volume character device node.
- *
- * @lib UBI library descriptor
- * @node UBI character device node name
- *
- * This function returns positive UBI device number in case of success and %-1
- * in case of failure.
- */
-static int find_dev_num_vol(struct libubi *lib, const char *node)
+int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info)
{
- struct stat st;
- struct ubi_info info;
- int i, major;
-
- if (stat(node, &st))
- return -1;
-
- if (!S_ISCHR(st.st_mode)) {
- errno = EINVAL;
- return -1;
- }
-
- major = major(st.st_rdev);
-
- if (minor(st.st_rdev) == 0) {
- errno = -EINVAL;
- return -1;
- }
+ int vol_id, dev_num;
+ struct libubi *lib = (struct libubi *)desc;
- if (ubi_get_info((libubi_t *)lib, &info))
+ if (vol_node2nums(lib, node, &dev_num, &vol_id))
return -1;
- for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
- int major1, minor1, ret;
- char buf[50];
-
- ret = dev_read_data(lib->dev_dev, i, &buf[0], 50);
- if (ret < 0)
- return -1;
-
- ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
- if (ret != 2) {
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- return -1;
- }
-
- if (major1 == major)
- return i;
- }
-
- errno = ENOENT;
- return -1;
+ return ubi_get_vol_info1(desc, dev_num, vol_id, info);
}
-/**
- * find_vol_num - find UBI volume number by its character device node.
- *
- * @lib UBI library descriptor
- * @dev_num UBI device number
- * @node UBI volume character device node name
- *
- * This function returns positive UBI volume number in case of success and %-1
- * in case of failure.
- */
-static int find_vol_num(struct libubi *lib, int dev_num, const char *node)
+int ubi_get_vol_info1_nm(libubi_t desc, int dev_num, const char *name,
+ struct ubi_vol_info *info)
{
- struct stat st;
- struct ubi_dev_info info;
- int i, major, minor;
-
- if (stat(node, &st))
- return -1;
+ int i, err;
+ unsigned int nlen = strlen(name);
+ struct ubi_dev_info dev_info;
- if (!S_ISCHR(st.st_mode)) {
+ if (nlen == 0) {
+ errmsg("bad \"name\" input parameter");
errno = EINVAL;
return -1;
}
- major = major(st.st_rdev);
- minor = minor(st.st_rdev);
-
- if (minor == 0) {
- errno = -EINVAL;
- return -1;
- }
-
- if (ubi_get_dev_info1((libubi_t *)lib, dev_num, &info))
- return -1;
-
- for (i = info.lowest_vol_num; i <= info.highest_vol_num; i++) {
- int major1, minor1, ret;
- char buf[50];
-
- ret = vol_read_data(lib->vol_dev, dev_num, i, &buf[0], 50);
- if (ret < 0)
- return -1;
+ err = ubi_get_dev_info1(desc, dev_num, &dev_info);
+ if (err)
+ return err;
- ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
- if (ret != 2) {
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
+ for (i = dev_info.lowest_vol_id;
+ i <= dev_info.highest_vol_id; i++) {
+ err = ubi_get_vol_info1(desc, dev_num, i, info);
+ if (err == -1) {
+ if (errno == ENOENT)
+ continue;
return -1;
}
- if (minor1 == minor && major1 == major)
- return i;
+ if (nlen == strlen(info->name) && !strcmp(name, info->name))
+ return 0;
}
errno = ENOENT;
diff --git a/ubi-utils/src/libubi_int.h b/ubi-utils/src/libubi_int.h
index e68b791..2e664b8 100644
--- a/ubi-utils/src/libubi_int.h
+++ b/ubi-utils/src/libubi_int.h
@@ -15,7 +15,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Author: Artem B. Bityutskiy
+ * Author: Artem Bityutskiy
*
* UBI (Unsorted Block Images) library.
*/
@@ -23,20 +23,31 @@
#ifndef __LIBUBI_INT_H__
#define __LIBUBI_INT_H__
+#include <string.h>
+#include <errno.h>
+
#ifdef __cplusplus
extern "C" {
#endif
/*
- * UBI heavily makes use of the sysfs file system to interact with users-pace.
* The below are pre-define UBI file and directory names.
+ *
+ * Note, older kernels put 'ubiX_Y' directories straight to '/sys/class/ubi/'.
+ * New kernels puts 'ubiX_Y' directories to '/sys/class/ubi/ubiX/', which is
+ * saner. And for compatibility reasons it also puts symlinks to 'ubiX_Y'
+ * directories to '/sys/class/ubi/'. For now libubi assumes old layout.
*/
#define SYSFS_UBI "class/ubi"
-#define UBI_DEV_NAME_PATT "ubi%d"
+#define SYSFS_CTRL "class/misc/ubi_ctrl/"
+
+#define CTRL_DEV "dev"
+
#define UBI_VER "version"
+#define UBI_DEV_NAME_PATT "ubi%d"
+
#define DEV_DEV "dev"
-#define UBI_VOL_NAME_PATT "ubi%d_%d"
#define DEV_AVAIL_EBS "avail_eraseblocks"
#define DEV_TOTAL_EBS "total_eraseblocks"
#define DEV_BAD_COUNT "bad_peb_count"
@@ -45,6 +56,9 @@ extern "C" {
#define DEV_MAX_RSVD "reserved_for_bad"
#define DEV_MAX_VOLS "max_vol_count"
#define DEV_MIN_IO_SIZE "min_io_size"
+#define DEV_MTD_NUM "mtd_num"
+
+#define UBI_VOL_NAME_PATT "ubi%d_%d"
#define VOL_TYPE "type"
#define VOL_DEV "dev"
#define VOL_ALIGNMENT "alignment"
@@ -56,34 +70,37 @@ extern "C" {
/**
* libubi - UBI library description data structure.
- *
- * @sysfs sysfs file system path
- * @sysfs_ubi UBI directory in sysfs
- * @ubi_dev UBI device sysfs directory pattern
- * @ubi_version UBI version file sysfs path
- * @dev_dev UBI device's major/minor numbers file pattern
- * @dev_avail_ebs count of available eraseblocks sysfs path pattern
- * @dev_total_ebs total eraseblocks count sysfs path pattern
- * @dev_bad_count count of bad eraseblocks sysfs path pattern
- * @dev_eb_size size of UBI device's eraseblocks sysfs path pattern
- * @dev_max_ec maximum erase counter sysfs path pattern
- * @dev_bad_rsvd count of physical eraseblock reserved for bad eraseblocks
- * handling
- * @dev_max_vols maximum volumes number count sysfs path pattern
- * @dev_min_io_size minimum I/O unit size sysfs path pattern
- * @ubi_vol UBI volume sysfs directory pattern
- * @vol_type volume type sysfs path pattern
- * @vol_dev volume's major/minor numbers file pattern
- * @vol_alignment volume alignment sysfs path pattern
- * @vol_data_bytes volume data size sysfs path pattern
- * @vol_rsvd_ebs volume reserved size sysfs path pattern
- * @vol_eb_size volume eraseblock size sysfs path pattern
- * @vol_corrupted volume corruption flag sysfs path pattern
- * @vol_name volume name sysfs path pattern
+ * @sysfs: sysfs file system path
+ * @sysfs_ctrl: UBI control device directory in sysfs
+ * @ctrl_dev: UBI control device major/minor numbers sysfs file
+ * @sysfs_ubi: UBI directory in sysfs
+ * @ubi_dev: UBI device sysfs directory pattern
+ * @ubi_version: UBI version file sysfs path
+ * @dev_dev: UBI device major/minor numbers file pattern
+ * @dev_avail_ebs: count of available eraseblocks sysfs path pattern
+ * @dev_total_ebs: total eraseblocks count sysfs path pattern
+ * @dev_bad_count: count of bad eraseblocks sysfs path pattern
+ * @dev_eb_size: size of UBI device's eraseblocks sysfs path pattern
+ * @dev_max_ec: maximum erase counter sysfs path pattern
+ * @dev_bad_rsvd: count of physical eraseblock reserved for bad eraseblocks
+ * handling
+ * @dev_max_vols: maximum volumes number count sysfs path pattern
+ * @dev_min_io_size: minimum I/O unit size sysfs path pattern
+ * @ubi_vol: UBI volume sysfs directory pattern
+ * @vol_type: volume type sysfs path pattern
+ * @vol_dev: volume major/minor numbers file pattern
+ * @vol_alignment: volume alignment sysfs path pattern
+ * @vol_data_bytes: volume data size sysfs path pattern
+ * @vol_rsvd_ebs: volume reserved size sysfs path pattern
+ * @vol_eb_size: volume eraseblock size sysfs path pattern
+ * @vol_corrupted: volume corruption flag sysfs path pattern
+ * @vol_name: volume name sysfs path pattern
*/
struct libubi
{
char *sysfs;
+ char *sysfs_ctrl;
+ char *ctrl_dev;
char *sysfs_ubi;
char *ubi_dev;
char *ubi_version;
@@ -96,6 +113,7 @@ struct libubi
char *dev_bad_rsvd;
char *dev_max_vols;
char *dev_min_io_size;
+ char *dev_mtd_num;
char *ubi_vol;
char *vol_type;
char *vol_dev;
@@ -108,20 +126,6 @@ struct libubi
char *vol_max_count;
};
-static int read_int(const char *file, int *value);
-static int dev_read_int(const char *patt, int dev_num, int *value);
-static int dev_read_ll(const char *patt, int dev_num, long long *value);
-static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len);
-static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value);
-static int vol_read_ll(const char *patt, int dev_num, int vol_id,
- long long *value);
-static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
- int buf_len);
-static char *mkpath(const char *path, const char *name);
-static int find_dev_num(struct libubi *lib, const char *node);
-static int find_dev_num_vol(struct libubi *lib, const char *node);
-static int find_vol_num(struct libubi *lib, int dev_num, const char *node);
-
#ifdef __cplusplus
}
#endif
diff --git a/ubi-utils/src/libubigen.c b/ubi-utils/src/libubigen.c
index 1793009..91bb274 100644
--- a/ubi-utils/src/libubigen.c
+++ b/ubi-utils/src/libubigen.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) International Business Machines Corp., 2006
+ * Copyright (C) 2008 Nokia Corporation
*
* 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
@@ -14,474 +15,316 @@
* 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.
+ */
+
+/*
+ * Generating UBI images.
*
- * Author: Oliver Lohmann
- *
- * Add UBI headers to binary data.
+ * Authors: Oliver Lohmann
+ * Artem Bityutskiy
*/
#include <stdlib.h>
#include <stdint.h>
-#include <stdio.h>
-#include <errno.h>
+#include <unistd.h>
#include <string.h>
+
#include <mtd/ubi-media.h>
#include <mtd_swab.h>
-
-#include "config.h"
-#include "ubigen.h"
+#include <libubigen.h>
#include "crc32.h"
-
-#define UBI_NAME_SIZE 256
-#define DEFAULT_VID_OFFSET ((DEFAULT_PAGESIZE) - (UBI_VID_HDR_SIZE))
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-
-static uint32_t crc32_table[256];
-
-struct ubi_info {
- struct ubi_vid_hdr* v; /* Volume ID header */
- struct ubi_ec_hdr* ec; /* Erase count header */
-
- FILE* fp_in; /* Input Stream */
- FILE* fp_out; /* Output stream */
-
- size_t eb_size; /* Physical EB size in bytes */
- size_t leb_size; /* Size of a logical EB in a physical EB */
- size_t leb_total; /* Total input size in logical EB */
- size_t alignment; /* Block alignment */
- size_t data_pad; /* Size of padding in each physical EB */
-
- size_t bytes_total; /* Total input size in bytes */
- size_t bytes_read; /* Nymber of read bytes (total) */
-
- uint32_t blks_written; /* Number of written logical EB */
-
- uint8_t* buf; /* Allocated buffer */
- uint8_t* ptr_ec_hdr; /* Pointer to EC hdr in buf */
- uint8_t* ptr_vid_hdr; /* Pointer to VID hdr in buf */
- uint8_t* ptr_data; /* Pointer to data region in buf */
-};
-
-
-static uint32_t
-byte_to_blk(uint64_t byte, uint32_t eb_size)
-{
- return (byte % eb_size) == 0
- ? (byte / eb_size)
- : (byte / eb_size) + 1;
-}
-
-static int
-validate_ubi_info(ubi_info_t u)
-{
- if ((u->v->vol_type != UBI_VID_DYNAMIC) &&
- (u->v->vol_type != UBI_VID_STATIC)) {
- return EUBIGEN_INVALID_TYPE;
- }
-
- if (be32_to_cpu(u->ec->vid_hdr_offset) < UBI_VID_HDR_SIZE) {
- return EUBIGEN_INVALID_HDR_OFFSET;
- }
-
- return 0;
-}
-
-static int
-skip_blks(ubi_info_t u, uint32_t blks)
-{
- uint32_t i;
- size_t read = 0, to_read = 0;
-
- /* Step to a maximum of leb_total - 1 to keep the
- restrictions. */
- for (i = 0; i < MIN(blks, u->leb_total-1); i++) {
- /* Read in data */
- to_read = MIN(u->leb_size,
- (u->bytes_total - u->bytes_read));
- read = fread(u->ptr_data, 1, to_read, u->fp_in);
- if (read != to_read) {
- return -EIO;
- }
- u->bytes_read += read;
- u->blks_written++;
- }
-
- return 0;
-}
-
-static void
-clear_buf(ubi_info_t u)
-{
- memset(u->buf, 0xff, u->eb_size);
-}
-
-static void
-write_ec_hdr(ubi_info_t u)
-{
- memcpy(u->ptr_ec_hdr, u->ec, UBI_EC_HDR_SIZE);
-}
-
-static int
-fill_data_buffer_from_file(ubi_info_t u, size_t* read)
-{
- size_t to_read = 0;
-
- if (u-> fp_in == NULL)
- return -EIO;
-
- to_read = MIN(u->leb_size, (u->bytes_total - u->bytes_read));
- *read = fread(u->ptr_data, 1, to_read, u->fp_in);
- if (*read != to_read) {
- return -EIO;
- }
- return 0;
-}
-
-static void
-add_static_info(ubi_info_t u, size_t data_size, ubigen_action_t action)
-{
- uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT,
- u->ptr_data, data_size);
-
- u->v->data_size = cpu_to_be32(data_size);
- u->v->data_crc = cpu_to_be32(crc);
-
- if (action & BROKEN_DATA_CRC) {
- u->v->data_crc =
- cpu_to_be32(be32_to_cpu(u->v->data_crc) + 1);
- }
- if (action & BROKEN_DATA_SIZE) {
- u->v->data_size =
- cpu_to_be32(be32_to_cpu(u->v->data_size) + 1);
- }
-}
-
-static void
-write_vid_hdr(ubi_info_t u, ubigen_action_t action)
+#include "common.h"
+
+#define PROGRAM_NAME "libubigen"
+
+/**
+ * ubigen_info_init - initialize libubigen.
+ * @ui: libubigen information
+ * @peb_size: flash physical eraseblock size
+ * @min_io_size: flash minimum input/output unit size
+ * @subpage_size: flash sub-page, if present (has to be equivalent to
+ * @min_io_size if does not exist)
+ * @vid_hdr_offs: offset of the VID header
+ * @ubi_ver: UBI version
+ */
+void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
+ int subpage_size, int vid_hdr_offs, int ubi_ver)
{
- uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT,
- u->v, UBI_VID_HDR_SIZE_CRC);
- /* Write VID header */
- u->v->hdr_crc = cpu_to_be32(crc);
- if (action & BROKEN_HDR_CRC) {
- u->v->hdr_crc = cpu_to_be32(be32_to_cpu(u->v->hdr_crc) + 1);
+ if (!vid_hdr_offs) {
+ vid_hdr_offs = UBI_EC_HDR_SIZE + subpage_size - 1;
+ vid_hdr_offs /= subpage_size;
+ vid_hdr_offs *= subpage_size;
}
- memcpy(u->ptr_vid_hdr, u->v, UBI_VID_HDR_SIZE);
-}
-static int
-write_to_output_stream(ubi_info_t u)
-{
- size_t written;
-
- written = fwrite(u->buf, 1, u->eb_size, u->fp_out);
- if (written != u->eb_size) {
- return -EIO;
- }
- return 0;
+ ui->peb_size = peb_size;
+ ui->min_io_size = min_io_size;
+ ui->vid_hdr_offs = vid_hdr_offs;
+ ui->data_offs = vid_hdr_offs + UBI_VID_HDR_SIZE + min_io_size - 1;
+ ui->data_offs /= min_io_size;
+ ui->data_offs *= min_io_size;
+ ui->leb_size = peb_size - ui->data_offs;
+ ui->ubi_ver = ubi_ver;
+
+ ui->max_volumes = ui->leb_size / UBI_VTBL_RECORD_SIZE;
+ if (ui->max_volumes > UBI_MAX_VOLUMES)
+ ui->max_volumes = UBI_MAX_VOLUMES;
+ ui->vtbl_size = ui->max_volumes * UBI_VTBL_RECORD_SIZE;
}
-int
-ubigen_write_leb(ubi_info_t u, ubigen_action_t action)
+/**
+ * ubigen_create_empty_vtbl - creates empty volume table.
+ *
+ * This function creates an empty volume table and returns a pointer to it in
+ * case of success and %NULL in case of failure. The returned object has to be
+ * freed with 'free()' call.
+ */
+struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui)
{
- int rc = 0;
- size_t read = 0;
-
- clear_buf(u);
- write_ec_hdr(u);
+ struct ubi_vtbl_record *vtbl;
+ int i;
- rc = fill_data_buffer_from_file(u, &read);
- if (rc != 0)
- return rc;
-
- if (u->v->vol_type == UBI_VID_STATIC) {
- add_static_info(u, read, action);
+ vtbl = calloc(1, ui->vtbl_size);
+ if (!vtbl) {
+ sys_errmsg("cannot allocate %d bytes of memory", ui->vtbl_size);
+ return NULL;
}
- u->v->lnum = cpu_to_be32(u->blks_written);
-
- if (action & MARK_AS_UPDATE) {
- u->v->copy_flag = (u->v->copy_flag)++;
+ for (i = 0; i < ui->max_volumes; i++) {
+ uint32_t crc = crc32(UBI_CRC32_INIT, &vtbl[i],
+ UBI_VTBL_RECORD_SIZE_CRC);
+ vtbl[i].crc = cpu_to_be32(crc);
}
- write_vid_hdr(u, action);
- rc = write_to_output_stream(u);
- if (rc != 0)
- return rc;
-
- /* Update current handle */
- u->bytes_read += read;
- u->blks_written++;
- return 0;
+ return vtbl;
}
-int
-ubigen_write_complete(ubi_info_t u)
+/**
+ * ubigen_add_volume - add a volume to the volume table.
+ * @ui: libubigen information
+ * @vi: volume information
+ * @vtbl: volume table to add to
+ *
+ * This function adds volume described by input parameters to the volume table
+ * @vtbl.
+ */
+int ubigen_add_volume(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi,
+ struct ubi_vtbl_record *vtbl)
{
- size_t i;
- int rc = 0;
-
- for (i = 0; i < u->leb_total; i++) {
- rc = ubigen_write_leb(u, NO_ERROR);
- if (rc != 0)
- return rc;
- }
-
+ struct ubi_vtbl_record *vtbl_rec = &vtbl[vi->id];
+ uint32_t tmp;
+
+ if (vi->id >= ui->max_volumes)
+ return errmsg("too high volume id %d, max. volumes is %d",
+ vi->id, ui->max_volumes);
+
+ if (vi->alignment >= ui->leb_size)
+ return errmsg("too large alignment %d, max is %d (LEB size)",
+ vi->alignment, ui->leb_size);
+
+ memset(vtbl_rec, '\0', sizeof(struct ubi_vtbl_record));
+ tmp = (vi->bytes + ui->leb_size - 1) / ui->leb_size;
+ vtbl_rec->reserved_pebs = cpu_to_be32(tmp);
+ vtbl_rec->alignment = cpu_to_be32(vi->alignment);
+ vtbl_rec->vol_type = vi->type;
+ tmp = ui->leb_size % vi->alignment;
+ vtbl_rec->data_pad = cpu_to_be32(tmp);
+ vtbl_rec->flags = vi->flags;
+
+ memcpy(vtbl_rec->name, vi->name, vi->name_len);
+ vtbl_rec->name[vi->name_len] = '\0';
+ vtbl_rec->name_len = cpu_to_be16(vi->name_len);
+
+ tmp = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
+ vtbl_rec->crc = cpu_to_be32(tmp);
return 0;
}
-int
-ubigen_write_broken_update(ubi_info_t u, uint32_t blk)
+/**
+ * ubigen_init_ec_hdr - initialize EC header.
+ * @ui: libubigen information
+ * @hdr: the EC header to initialize
+ * @ec: erase counter value
+ */
+void ubigen_init_ec_hdr(const struct ubigen_info *ui,
+ struct ubi_ec_hdr *hdr, long long ec)
{
- int rc = 0;
+ uint32_t crc;
- rc = skip_blks(u, blk);
- if (rc != 0)
- return rc;
+ memset(hdr, '\0', sizeof(struct ubi_ec_hdr));
- rc = ubigen_write_leb(u, MARK_AS_UPDATE | BROKEN_DATA_CRC);
- if (rc != 0)
- return rc;
+ hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
+ hdr->version = ui->ubi_ver;
+ hdr->ec = cpu_to_be64(ec);
+ hdr->vid_hdr_offset = cpu_to_be32(ui->vid_hdr_offs);
+ hdr->data_offset = cpu_to_be32(ui->data_offs);
- return 0;
+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
+ hdr->hdr_crc = cpu_to_be32(crc);
}
-void
-dump_info(ubi_info_t u ubi_unused)
+/**
+ * init_vid_hdr - initialize VID header.
+ * @ui: libubigen information
+ * @vi: volume information
+ * @hdr: the VID header to initialize
+ * @lnum: logical eraseblock number
+ * @data: the contents of the LEB (static volumes only)
+ * @data_size: amount of data in this LEB (static volumes only)
+ *
+ * Note, @used_ebs, @data and @data_size are ignored in case of dynamic
+ * volumes.
+ */
+static void init_vid_hdr(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi,
+ struct ubi_vid_hdr *hdr, int lnum,
+ const void *data, int data_size)
{
-#ifdef DEBUG
- int err = 0;
- if (!u) {
- fprintf(stderr, "<empty>");
- return;
- }
- if (!u->ec) {
- fprintf(stderr, "<ec-empty>");
- err = 1;
- }
- if (!u->v) {
- fprintf(stderr, "<v-empty>");
- err = 1;
- }
- if (err) return;
-
- fprintf(stderr, "ubi volume\n");
- fprintf(stderr, "version : %8d\n", u->v->version);
- fprintf(stderr, "vol_id : %8d\n", be32_to_cpu(u->v->vol_id));
- fprintf(stderr, "vol_type : %8s\n",
- u->v->vol_type == UBI_VID_STATIC ?
- "static" : "dynamic");
- fprintf(stderr, "used_ebs : %8d\n",
- be32_to_cpu(u->v->used_ebs));
- fprintf(stderr, "eb_size : 0x%08x\n", u->eb_size);
- fprintf(stderr, "leb_size : 0x%08x\n", u->leb_size);
- fprintf(stderr, "data_pad : 0x%08x\n",
- be32_to_cpu(u->v->data_pad));
- fprintf(stderr, "leb_total : %8d\n", u->leb_total);
- fprintf(stderr, "header offs : 0x%08x\n",
- be32_to_cpu(u->ec->vid_hdr_offset));
- fprintf(stderr, "bytes_total : %8d\n", u->bytes_total);
- fprintf(stderr, " + in MiB : %8.2f M\n",
- ((float)(u->bytes_total)) / 1024 / 1024);
- fprintf(stderr, "-------------------------------\n\n");
-#else
- return;
-#endif
-}
+ uint32_t crc;
-int
-ubigen_destroy(ubi_info_t *u)
-{
- if (u == NULL)
- return -EINVAL;
-
- ubi_info_t tmp = *u;
-
- if (tmp) {
- if (tmp->v)
- free(tmp->v);
- if (tmp->ec)
- free(tmp->ec);
- if (tmp->buf)
- free(tmp->buf);
- free(tmp);
+ memset(hdr, '\0', sizeof(struct ubi_vid_hdr));
+
+ hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
+ hdr->version = ui->ubi_ver;
+ hdr->vol_type = vi->type;
+ hdr->vol_id = cpu_to_be32(vi->id);
+ hdr->lnum = cpu_to_be32(lnum);
+ hdr->data_pad = cpu_to_be32(vi->data_pad);
+ hdr->compat = vi->compat;
+
+ if (vi->type == UBI_VID_STATIC) {
+ hdr->data_size = cpu_to_be32(data_size);
+ hdr->used_ebs = cpu_to_be32(vi->used_ebs);
+ crc = crc32(UBI_CRC32_INIT, data, data_size);
+ hdr->data_crc = cpu_to_be32(crc);
}
- *u = NULL;
- return 0;
-}
-void
-ubigen_init(void)
-{
- init_crc32_table(crc32_table);
+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_VID_HDR_SIZE_CRC);
+ hdr->hdr_crc = cpu_to_be32(crc);
}
-int
-ubigen_create(ubi_info_t* u, uint32_t vol_id, uint8_t vol_type,
- uint32_t eb_size, uint64_t ec, uint32_t alignment,
- uint8_t version, uint32_t vid_hdr_offset, uint8_t compat_flag,
- size_t data_size, FILE* fp_in, FILE* fp_out)
+/**
+ * ubigen_write_volume - write UBI volume.
+ * @ui: libubigen information
+ * @vi: volume information
+ * @ec: erase coutner value to put to EC headers
+ * @bytes: volume size in bytes
+ * @in: input file descriptor (has to be properly seeked)
+ * @out: output file descriptor
+ *
+ * This function reads the contents of the volume from the input file @in and
+ * writes the UBI volume to the output file @out. Returns zero on success and
+ * %-1 on failure.
+ */
+int ubigen_write_volume(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi, long long ec,
+ long long bytes, int in, int out)
{
- int rc = 0;
- ubi_info_t res = NULL;
- uint32_t crc;
- uint32_t data_offset;
+ int len = vi->usable_leb_size, rd, lnum = 0;
+ char inbuf[ui->leb_size], outbuf[ui->peb_size];
- if (alignment == 0) {
- rc = EUBIGEN_INVALID_ALIGNMENT;
- goto ubigen_create_err;
- }
- if ((fp_in == NULL) || (fp_out == NULL)) {
- rc = -EINVAL;
- goto ubigen_create_err;
- }
+ if (vi->id >= ui->max_volumes)
+ return errmsg("too high volume id %d, max. volumes is %d",
+ vi->id, ui->max_volumes);
- res = (ubi_info_t) calloc(1, sizeof(struct ubi_info));
- if (res == NULL) {
- rc = -ENOMEM;
- goto ubigen_create_err;
- }
+ if (vi->alignment >= ui->leb_size)
+ return errmsg("too large alignment %d, max is %d (LEB size)",
+ vi->alignment, ui->leb_size);
- res->v = (struct ubi_vid_hdr*) calloc(1, sizeof(struct ubi_vid_hdr));
- if (res->v == NULL) {
- rc = -ENOMEM;
- goto ubigen_create_err;
- }
+ memset(outbuf, 0xFF, ui->data_offs);
+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec);
- res->ec = (struct ubi_ec_hdr*) calloc(1, sizeof(struct ubi_ec_hdr));
- if (res->ec == NULL) {
- rc = -ENOMEM;
- goto ubigen_create_err;
- }
+ while (bytes) {
+ int l;
+ struct ubi_vid_hdr *vid_hdr;
- /* data which is needed in the general process */
- vid_hdr_offset = vid_hdr_offset ? vid_hdr_offset : DEFAULT_VID_OFFSET;
- data_offset = vid_hdr_offset + UBI_VID_HDR_SIZE;
- res->bytes_total = data_size;
- res->eb_size = eb_size ? eb_size : DEFAULT_BLOCKSIZE;
- res->data_pad = (res->eb_size - data_offset) % alignment;
- res->leb_size = res->eb_size - data_offset - res->data_pad;
- res->leb_total = byte_to_blk(data_size, res->leb_size);
- res->alignment = alignment;
-
- if ((res->eb_size < (vid_hdr_offset + UBI_VID_HDR_SIZE))) {
- rc = EUBIGEN_TOO_SMALL_EB;
- goto ubigen_create_err;
- }
- res->fp_in = fp_in;
- res->fp_out = fp_out;
-
- /* vid hdr data which doesn't change */
- res->v->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
- res->v->version = version ? version : UBI_VERSION;
- res->v->vol_type = vol_type;
- res->v->vol_id = cpu_to_be32(vol_id);
- res->v->compat = compat_flag;
- res->v->data_pad = cpu_to_be32(res->data_pad);
-
- /* static only: used_ebs */
- if (res->v->vol_type == UBI_VID_STATIC) {
- res->v->used_ebs = cpu_to_be32(byte_to_blk
- (res->bytes_total,
- res->leb_size));
- }
+ if (bytes < len)
+ len = bytes;
+ bytes -= len;
- /* ec hdr (fixed, doesn't change) */
- res->ec->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
- res->ec->version = version ? version : UBI_VERSION;
- res->ec->ec = cpu_to_be64(ec);
- res->ec->vid_hdr_offset = cpu_to_be32(vid_hdr_offset);
+ l = len;
+ do {
+ rd = read(in, inbuf + len - l, l);
+ if (rd != l)
+ return sys_errmsg("cannot read %d bytes from the input file", l);
- res->ec->data_offset = cpu_to_be32(data_offset);
+ l -= rd;
+ } while (l);
- crc = clc_crc32(crc32_table, UBI_CRC32_INIT, res->ec,
- UBI_EC_HDR_SIZE_CRC);
- res->ec->hdr_crc = cpu_to_be32(crc);
+ vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
+ init_vid_hdr(ui, vi, vid_hdr, lnum, inbuf, len);
- /* prepare a read buffer */
- res->buf = (uint8_t*) malloc (res->eb_size * sizeof(uint8_t));
- if (res->buf == NULL) {
- rc = -ENOMEM;
- goto ubigen_create_err;
- }
-
- /* point to distinct regions within the buffer */
- res->ptr_ec_hdr = res->buf;
- res->ptr_vid_hdr = res->buf + be32_to_cpu(res->ec->vid_hdr_offset);
- res->ptr_data = res->buf + be32_to_cpu(res->ec->vid_hdr_offset)
- + UBI_VID_HDR_SIZE;
+ memcpy(outbuf + ui->data_offs, inbuf, len);
+ memset(outbuf + ui->data_offs + len, 0xFF,
+ ui->peb_size - ui->data_offs - len);
- rc = validate_ubi_info(res);
- if (rc != 0) {
- fprintf(stderr, "Volume validation failed: %d\n", rc);
- goto ubigen_create_err;
- }
+ if (write(out, outbuf, ui->peb_size) != ui->peb_size)
+ return sys_errmsg("cannot write %d bytes to the output file", ui->peb_size);
- dump_info(res);
- *u = res;
- return rc;
-
- ubigen_create_err:
- if (res) {
- if (res->v)
- free(res->v);
- if (res->ec)
- free(res->ec);
- if (res->buf)
- free(res->buf);
- free(res);
+ lnum += 1;
}
- *u = NULL;
- return rc;
-}
-int
-ubigen_get_leb_size(ubi_info_t u, size_t* size)
-{
- if (u == NULL)
- return -EINVAL;
-
- *size = u->leb_size;
return 0;
}
-
-int
-ubigen_get_leb_total(ubi_info_t u, size_t* total)
-{
- if (u == NULL)
- return -EINVAL;
-
- *total = u->leb_total;
- return 0;
-}
-
-int
-ubigen_set_lvol_rec(ubi_info_t u, size_t reserved_bytes,
- const char* vol_name, struct ubi_vtbl_record *lvol_rec)
+/**
+ * ubigen_write_layout_vol - write UBI layout volume
+ * @ui: libubigen information
+ * @peb1: physical eraseblock number to write the first volume table copy
+ * @peb2: physical eraseblock number to write the second volume table copy
+ * @ec1: erase counter value for @peb1
+ * @ec2: erase counter value for @peb1
+ * @vtbl: volume table
+ * @fd: output file descriptor seeked to the proper position
+ *
+ * This function creates the UBI layout volume which contains 2 copies of the
+ * volume table. Returns zero in case of success and %-1 in case of failure.
+ */
+int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2,
+ long long ec1, long long ec2,
+ struct ubi_vtbl_record *vtbl, int fd)
{
- uint32_t crc;
-
- if ((u == NULL) || (vol_name == NULL))
- return -EINVAL;
-
- memset(lvol_rec, 0x0, UBI_VTBL_RECORD_SIZE);
-
- lvol_rec->reserved_pebs =
- cpu_to_be32(byte_to_blk(reserved_bytes, u->leb_size));
- lvol_rec->alignment = cpu_to_be32(u->alignment);
- lvol_rec->data_pad = u->v->data_pad;
- lvol_rec->vol_type = u->v->vol_type;
-
- lvol_rec->name_len =
- cpu_to_be16((uint16_t)strlen((const char*)vol_name));
-
- memcpy(lvol_rec->name, vol_name, UBI_VOL_NAME_MAX + 1);
-
- crc = clc_crc32(crc32_table, UBI_CRC32_INIT,
- lvol_rec, UBI_VTBL_RECORD_SIZE_CRC);
- lvol_rec->crc = cpu_to_be32(crc);
+ int ret;
+ struct ubigen_vol_info vi;
+ char outbuf[ui->peb_size];
+ struct ubi_vid_hdr *vid_hdr;
+ off_t seek;
+
+ vi.bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS;
+ vi.id = UBI_LAYOUT_VOLUME_ID;
+ vi.alignment = UBI_LAYOUT_VOLUME_ALIGN;
+ vi.data_pad = ui->leb_size % UBI_LAYOUT_VOLUME_ALIGN;
+ vi.usable_leb_size = ui->leb_size - vi.data_pad;
+ vi.data_pad = ui->leb_size - vi.usable_leb_size;
+ vi.type = UBI_LAYOUT_VOLUME_TYPE;
+ vi.name = UBI_LAYOUT_VOLUME_NAME;
+ vi.name_len = strlen(UBI_LAYOUT_VOLUME_NAME);
+ vi.compat = UBI_LAYOUT_VOLUME_COMPAT;
+
+ memset(outbuf, 0xFF, ui->data_offs);
+ vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
+ memcpy(outbuf + ui->data_offs, vtbl, ui->vtbl_size);
+ memset(outbuf + ui->data_offs + ui->vtbl_size, 0xFF,
+ ui->peb_size - ui->data_offs - ui->vtbl_size);
+
+ seek = peb1 * ui->peb_size;
+ if (lseek(fd, seek, SEEK_SET) != seek)
+ return sys_errmsg("cannot seek output file");
+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec1);
+ init_vid_hdr(ui, &vi, vid_hdr, 0, NULL, 0);
+ ret = write(fd, outbuf, ui->peb_size);
+ if (ret != ui->peb_size)
+ return sys_errmsg("cannot write %d bytes", ui->peb_size);
+
+ seek = peb2 * ui->peb_size;
+ if (lseek(fd, seek, SEEK_SET) != seek)
+ return sys_errmsg("cannot seek output file");
+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec2);
+ init_vid_hdr(ui, &vi, vid_hdr, 1, NULL, 0);
+ ret = write(fd, outbuf, ui->peb_size);
+ if (ret != ui->peb_size)
+ return sys_errmsg("cannot write %d bytes", ui->peb_size);
return 0;
}
diff --git a/ubi-utils/src/libubimirror.c b/ubi-utils/src/libubimirror.c
deleted file mode 100644
index d06770e..0000000
--- a/ubi-utils/src/libubimirror.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * 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.
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <memory.h>
-#include <limits.h>
-#include <fcntl.h>
-
-#include <libubi.h>
-#include "ubimirror.h"
-
-#define COMPARE_BUF_SIZE (128 * 1024)
-
-#define DEFAULT_DEV_PATTERN "/dev/ubi%d"
-#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d"
-
-#define EBUF(fmt...) do { \
- snprintf(err_buf, err_buf_size, fmt); \
-} while (0)
-
-enum {
- compare_error = -1,
- seek_error = -2,
- write_error = -3,
- read_error = -4,
- update_error = -5,
- ubi_error = -6,
- open_error = -7,
- close_error = -8,
- compare_equal = 0,
- compare_different = 1
-};
-
-/*
- * Read len number of bytes from fd.
- * Return 0 on EOF, -1 on error.
- */
-static ssize_t fill_buffer(int fd, unsigned char *buf, ssize_t len)
-{
- ssize_t got, have = 0;
-
- do {
- got = read(fd, buf + have, len - have);
- if (got == -1 && errno != EINTR)
- return -1;
- have += got;
- } while (got > 0 && have < len);
- return have;
-}
-
-/*
- * Write len number of bytes to fd.
- * Return bytes written (>= 0), -1 on error.
- */
-static ssize_t flush_buffer(int fd, unsigned char *buf, ssize_t len)
-{
- ssize_t done, have = 0;
-
- do {
- done = write(fd, buf + have, len - have);
- if (done == -1 && errno != EINTR)
- return -1;
- have += done;
- } while (done > 0 && have < len);
- return have;
-}
-
-/*
- * Compare two files. Return 0, 1, or -1, depending on whether the
- * files are equal, different, or an error occured.
- * Return compare-different when target volume can not be read. Might be
- * an interrupted volume update and then the target device returns -EIO but
- * can be updated.
- *
- * fd_a is source
- * fd_b is destination
- */
-static int compare_files(int fd_a, int fd_b)
-{
- unsigned char buf_a[COMPARE_BUF_SIZE], buf_b[COMPARE_BUF_SIZE];
- ssize_t len_a, len_b;
- int rc;
-
- for (;;) {
- len_a = fill_buffer(fd_a, buf_a, sizeof(buf_a));
- if (len_a == -1) {
- rc = compare_error;
- break;
- }
- len_b = fill_buffer(fd_b, buf_b, sizeof(buf_b));
- if (len_b == -1) {
- rc = compare_different;
- break;
- }
- if (len_a != len_b) {
- rc = compare_different;
- break;
- }
- if (len_a == 0) { /* Size on both files equal and EOF */
- rc = compare_equal;
- break;
- }
- if (memcmp(buf_a, buf_b, len_a) != 0 ) {
- rc = compare_different;
- break;
- }
- }
- /* Position both files at the beginning */
- if (lseek(fd_a, 0, SEEK_SET) == -1 ||
- lseek(fd_b, 0, SEEK_SET) == -1)
- rc = seek_error;
- return rc;
-}
-
-int vol_get_used_bytes(int vol_fd, unsigned long long *bytes)
-{
- off_t res;
-
- res = lseek(vol_fd, 0, SEEK_END);
- if (res == (off_t)-1)
- return -1;
- *bytes = (unsigned long long) res;
- res = lseek(vol_fd, 0, SEEK_SET);
- return res == (off_t)-1 ? -1 : 0;
-}
-
-static int copy_files(libubi_t ulib, int fd_in, int fd_out)
-{
- unsigned char buf_a[COMPARE_BUF_SIZE];
- ssize_t len_a, len_b;
- unsigned long long update_size, copied;
-
- if (vol_get_used_bytes(fd_in, &update_size) == -1 ||
- ubi_update_start(ulib, fd_out, update_size) == -1)
- return update_error;
- for (copied = 0; copied < update_size; copied += len_b ) {
- len_a = fill_buffer(fd_in, buf_a, sizeof(buf_a));
- if (len_a == -1)
- return read_error;
- if (len_a == 0) /* Reach EOF */
- return 0;
- len_b = flush_buffer(fd_out, buf_a, len_a);
- if (len_b != len_a)
- return write_error;
- }
- return 0;
-}
-
-int ubimirror(uint32_t devno, int seqnum, uint32_t *ids, ssize_t ids_size,
- char *err_buf, size_t err_buf_size)
-{
- int rc = 0;
- uint32_t src_id;
- char path[PATH_MAX];
- libubi_t ulib;
- int fd_in = -1, i = 0, fd_out = -1;
-
- if (ids_size == 0)
- return 0;
- else {
- if ((seqnum < 0) || (seqnum > (ids_size - 1))) {
- EBUF("volume id %d out of range", seqnum);
- return EUBIMIRROR_NO_SRC;
- }
- src_id = ids[seqnum];
- }
-
- ulib = libubi_open();
- if (ulib == NULL)
- return ubi_error;
-
- snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, src_id);
-
- fd_in = open(path, O_RDONLY);
- if (fd_in == -1) {
- EBUF("open error source volume %d", ids[i]);
- rc = open_error;
- goto err;
- }
-
- for (i = 0; i < ids_size; i++) {
- if (ids[i] == src_id) /* skip self-mirror */
- continue;
-
- snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, ids[i]);
-
- fd_out = open(path, O_RDWR);
- if (fd_out < 0){
- EBUF("open error destination volume %d", ids[i]);
- rc = open_error;
- goto err;
- }
- rc = compare_files(fd_in, fd_out);
- if (rc < 0) {
- EBUF("compare error volume %d and %d", src_id, ids[i]);
- goto err;
- } else if (rc == compare_different) {
- rc = copy_files(ulib, fd_in, fd_out);
- if (rc != 0) {
- EBUF("mirror error volume %d to %d", src_id,
- ids[i]);
- goto err;
- }
- }
- if ((rc = close(fd_out)) == -1) {
- EBUF("close error volume %d", ids[i]);
- rc = close_error;
- goto err;
- } else
- fd_out = -1;
- }
-err:
- if (fd_out != -1)
- close(fd_out);
- if (fd_in != -1)
- close(fd_in);
- if (ulib != NULL)
- libubi_close(ulib);
- return rc;
-}
diff --git a/ubi-utils/src/list.c b/ubi-utils/src/list.c
deleted file mode 100644
index 6eb716b..0000000
--- a/ubi-utils/src/list.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * 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.
- *
- * Author: Oliver Lohmann
- */
-
-#include <stdlib.h>
-#include <assert.h>
-#include <stdio.h>
-
-#include "list.h"
-
-list_t
-mk_empty(void)
-{
- return (list_t) NULL;
-}
-
-int
-is_empty(list_t l)
-{
- return l == NULL;
-}
-
-info_t
-head(list_t l)
-{
- assert(!is_empty(l));
- return l->info;
-}
-
-list_t
-tail(list_t l)
-{
- assert(!is_empty(l));
- return l->next;
-}
-
-list_t
-remove_head(list_t l)
-{
- list_t res;
- assert(!is_empty(l));
-
- res = l->next;
- free(l);
- return res;
-}
-
-list_t
-cons(info_t e, list_t l)
-{
- list_t res = malloc(sizeof(*l));
- if (!res)
- return NULL;
- res->info = e;
- res->next = l;
-
- return res;
-}
-
-list_t
-prepend_elem(info_t e, list_t l)
-{
- return cons(e,l);
-}
-
-list_t
-append_elem(info_t e, list_t l)
-{
- if (is_empty(l)) {
- return cons(e,l);
- }
- l->next = append_elem(e, l->next);
-
- return l;
-}
-
-list_t
-insert_sorted(cmp_func_t cmp, info_t e, list_t l)
-{
- if (is_empty(l))
- return cons(e, l);
-
- switch (cmp(e, l->info)) {
- case -1:
- case 0:
- return l;
- break;
- case 1:
- l->next = insert_sorted(cmp, e, l);
- break;
- default:
- break;
- }
-
- /* never reached */
- return NULL;
-}
-
-list_t
-remove_all(free_func_t free_func, list_t l)
-{
- if (is_empty(l))
- return l;
- list_t lnext = l->next;
-
- if (free_func && l->info) {
- free_func(&(l->info));
- }
- free(l);
-
- return remove_all(free_func, lnext);
-}
-
-
-info_t
-is_in(cmp_func_t cmp, info_t e, list_t l)
-{
- return
- (is_empty(l))
- ? NULL
- : (cmp(e, l->info)) == 0 ? l->info : is_in(cmp, e, l->next);
-}
-
-
-void
-apply(process_func_t process_func, list_t l)
-{
- list_t ptr;
- void *i;
- foreach(i, ptr, l) {
- process_func(i);
- }
-}
diff --git a/ubi-utils/src/list.h b/ubi-utils/src/list.h
deleted file mode 100644
index e8452a2..0000000
--- a/ubi-utils/src/list.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef __LIST_H__
-#define __LIST_H__
-/*
- * 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.
- *
- * Author: Oliver Lohmann
- */
-
-#include <stdint.h>
-
-#define foreach(elem, ptr, list) \
- for (elem = list != NULL ? (typeof(elem)) head(list) \
- : NULL, ptr = list; \
- ptr != NULL; \
- ptr = tail(ptr), \
- elem = (typeof(elem)) ptr ? head(ptr) : NULL)
-
-typedef struct node* list_t;
-typedef void* info_t;
-typedef int (*free_func_t)(info_t*);
-typedef int (*cmp_func_t)(info_t, info_t);
-typedef void (*process_func_t)(info_t);
-
-struct node {
- list_t next;
- info_t info;
-};
-
-list_t mk_empty(void);
-int is_empty(list_t l);
-info_t is_in(cmp_func_t cmp, info_t e, list_t l);
-info_t head(list_t l);
-list_t tail(list_t l);
-list_t remove_head(list_t l);
-list_t cons(info_t e, list_t l);
-list_t prepend_elem(info_t e, list_t);
-list_t append_elem(info_t e, list_t);
-list_t remove_all(free_func_t free_func, list_t l);
-list_t insert_sorted(cmp_func_t cmp_func, info_t e, list_t l);
-void apply(process_func_t process_func, list_t l);
-
-#endif /* __LIST_H__ */
diff --git a/ubi-utils/src/mkbootenv.c b/ubi-utils/src/mkbootenv.c
deleted file mode 100644
index 50fc8ac..0000000
--- a/ubi-utils/src/mkbootenv.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * 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.
- *
- * Author: Oliver Lohmann
- *
- * Create boot-parameter/pdd data from an ASCII-text input file.
- *
- * 1.2 Removed argp because we want to use uClibc.
- * 1.3 Minor cleanup
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <errno.h>
-#include <mtd/ubi-media.h>
-
-#include "config.h"
-#include "bootenv.h"
-#include "error.h"
-
-#define PROGRAM_VERSION "1.3"
-
-static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
- "mkbootenv - processes bootenv text files and convertes "
- "them into a binary format.\n";
-
-static const char copyright [] __attribute__((unused)) =
- "Copyright (c) International Business Machines Corp., 2006";
-
-static const char *optionsstr =
-" -c, --copyright Print copyright informatoin.\n"
-" -o, --output=<fname> Write the output data to <output> instead of\n"
-" stdout.\n"
-" -?, --help Give this help list\n"
-" --usage Give a short usage message\n"
-" -V, --version Print program version\n";
-
-static const char *usage =
-"Usage: mkbootenv [-c?V] [-o <output>] [--copyright] [--output=<output>]\n"
-" [--help] [--usage] [--version] [bootenv-txt-file]\n";
-
-struct option long_options[] = {
- { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' },
- { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
- { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
- { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
- { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
- { NULL, 0, NULL, 0}
-};
-
-typedef struct myargs {
- FILE* fp_in;
- FILE* fp_out;
-
- char *arg1;
- char **options; /* [STRING...] */
-} myargs;
-
-static int
-parse_opt(int argc, char **argv, myargs *args)
-{
- while (1) {
- int key;
-
- key = getopt_long(argc, argv, "co:?V", long_options, NULL);
- if (key == -1)
- break;
-
- switch (key) {
- case 'c':
- fprintf(stderr, "%s\n", copyright);
- exit(0);
- break;
- case 'o':
- args->fp_out = fopen(optarg, "wb");
- if ((args->fp_out) == NULL) {
- fprintf(stderr, "Cannot open file %s "
- "for output\n", optarg);
- exit(1);
- }
- break;
- case '?': /* help */
- printf("%s", doc);
- printf("%s", optionsstr);
- printf("\nReport bugs to %s\n",
- PACKAGE_BUGREPORT);
- exit(0);
- break;
- case 'V':
- printf("%s\n", PROGRAM_VERSION);
- exit(0);
- break;
- default:
- printf("%s", usage);
- exit(-1);
- }
- }
-
- if (optind < argc) {
- args->fp_in = fopen(argv[optind++], "rb");
- if ((args->fp_in) == NULL) {
- fprintf(stderr, "Cannot open file %s for input\n",
- argv[optind]);
- exit(1);
- }
- }
-
- return 0;
-}
-
-int
-main(int argc, char **argv) {
- int rc = 0;
- bootenv_t env;
-
- myargs args = {
- .fp_in = stdin,
- .fp_out = stdout,
- .arg1 = NULL,
- .options = NULL,
- };
-
- parse_opt(argc, argv, &args);
-
- rc = bootenv_create(&env);
- if (rc != 0) {
- err_msg("Cannot create bootenv handle.");
- goto err;
- }
- rc = bootenv_read_txt(args.fp_in, env);
- if (rc != 0) {
- err_msg("Cannot read bootenv from input file.");
- goto err;
- }
- rc = bootenv_write(args.fp_out, env);
- if (rc != 0) {
- err_msg("Cannot write bootenv to output file.");
- goto err;
- }
-
- if (args.fp_in != stdin) {
- fclose(args.fp_in);
- }
- if (args.fp_out != stdout) {
- fclose(args.fp_out);
- }
-
-err:
- bootenv_destroy(&env);
- return rc;
-}
diff --git a/ubi-utils/src/nand2bin.c b/ubi-utils/src/nand2bin.c
deleted file mode 100644
index 93ba29f..0000000
--- a/ubi-utils/src/nand2bin.c
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2006, 2007
- *
- * 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.
- *
- * Author: Frank Haverkamp
- *
- * An utility to decompose NAND images and strip OOB off. Not yet finished ...
- *
- * 1.2 Removed argp because we want to use uClibc.
- * 1.3 Minor cleanup
- * 1.4 Fixed OOB output file
- * 1.5 Added verbose output and option to set blocksize.
- * Added split block mode for more convenient analysis.
- * 1.6 Fixed ECC error detection and correction.
- */
-
-#include <config.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <getopt.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "config.h"
-#include "nandecc.h"
-
-#define PROGRAM_VERSION "1.6"
-
-#define MAXPATH 1024
-#define MIN(x,y) ((x)<(y)?(x):(y))
-
-struct args {
- const char *oob_file;
- const char *output_file;
- size_t pagesize;
- size_t blocksize;
- int split_blocks;
- size_t in_len; /* size of input file */
- int correct_ecc;
-
- /* special stuff needed to get additional arguments */
- char *arg1;
- char **options; /* [STRING...] */
-};
-
-static struct args myargs = {
- .output_file = "data.bin",
- .oob_file = "oob.bin",
- .pagesize = 2048,
- .blocksize = 128 * 1024,
- .in_len = 0,
- .split_blocks = 0,
- .correct_ecc = 0,
- .arg1 = NULL,
- .options = NULL,
-};
-
-static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
- "nand2bin - split data and OOB.\n";
-
-static const char *optionsstr =
-" -o, --output=<output> Data output file\n"
-" -O, --oob=<oob> OOB output file\n"
-" -p, --pagesize=<pagesize> NAND pagesize\n"
-" -b, --blocksize=<blocksize> NAND blocksize\n"
-" -s, --split-blocks generate binaries for each block\n"
-" -e, --correct-ecc Correct data according to ECC info\n"
-" -v, --verbose verbose output\n"
-" -?, --help Give this help list\n"
-" --usage Give a short usage message\n";
-
-static const char *usage =
-"Usage: nand2bin [-?] [-o <output>] [-O <oob>] [-p <pagesize>]\n"
-" [--output=<output>] [--oob=<oob>] [--pagesize=<pagesize>] [--help]\n"
-" [--usage] input.mif\n";
-
-static int verbose = 0;
-
-static struct option long_options[] = {
- { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
- { .name = "oob", .has_arg = 1, .flag = NULL, .val = 'O' },
- { .name = "pagesize", .has_arg = 1, .flag = NULL, .val = 'p' },
- { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'b' },
- { .name = "split-blocks", .has_arg = 0, .flag = NULL, .val = 's' },
- { .name = "correct-ecc", .has_arg = 0, .flag = NULL, .val = 'e' },
- { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' },
- { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
- { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
- { NULL, 0, NULL, 0}
-};
-
-/*
- * str_to_num - Convert string into number and cope with endings like
- * k, K, kib, KiB for kilobyte
- * m, M, mib, MiB for megabyte
- */
-static uint32_t str_to_num(char *str)
-{
- char *s = str;
- ulong num = strtoul(s, &s, 0);
-
- if (*s != '\0') {
- if (strcmp(s, "KiB") == 0)
- num *= 1024;
- else if (strcmp(s, "MiB") == 0)
- num *= 1024*1024;
- else {
- fprintf(stderr, "WARNING: Wrong number format "
- "\"%s\", check your paramters!\n", str);
- }
- }
- return num;
-}
-
-/*
- * @brief Parse the arguments passed into the test case.
- *
- * @param argc The number of arguments
- * @param argv The argument list
- * @param args Pointer to program args structure
- *
- * @return error
- *
- */
-static int parse_opt(int argc, char **argv, struct args *args)
-{
- while (1) {
- int key;
-
- key = getopt_long(argc, argv, "b:eo:O:p:sv?", long_options, NULL);
- if (key == -1)
- break;
-
- switch (key) {
- case 'p': /* --pagesize<pagesize> */
- args->pagesize = str_to_num(optarg);
- break;
-
- case 'b': /* --blocksize<blocksize> */
- args->blocksize = str_to_num(optarg);
- break;
-
- case 'v': /* --verbose */
- verbose++;
- break;
-
- case 's': /* --split-blocks */
- args->split_blocks = 1;
- break;
-
- case 'e': /* --correct-ecc */
- args->correct_ecc = 1;
- break;
-
- case 'o': /* --output=<output.bin> */
- args->output_file = optarg;
- break;
-
- case 'O': /* --oob=<oob.bin> */
- args->oob_file = optarg;
- break;
-
- case '?': /* help */
- printf("Usage: nand2bin [OPTION...] input.mif\n");
- printf("%s", doc);
- printf("%s", optionsstr);
- printf("\nReport bugs to %s\n",
- PACKAGE_BUGREPORT);
- exit(0);
- break;
-
- case 'V':
- printf("%s\n", PROGRAM_VERSION);
- exit(0);
- break;
-
- default:
- printf("%s", usage);
- exit(-1);
- }
- }
-
- if (optind < argc)
- args->arg1 = argv[optind++];
-
- return 0;
-}
-
-static int calc_oobsize(size_t pagesize)
-{
- switch (pagesize) {
- case 512: return 16;
- case 2048: return 64;
- default:
- exit(EXIT_FAILURE);
- }
- return 0;
-}
-
-static inline void hexdump(FILE *fp, const uint8_t *buf, ssize_t size)
-{
- int k;
-
- for (k = 0; k < size; k++) {
- fprintf(fp, "%02x ", buf[k]);
- if ((k & 15) == 15)
- fprintf(fp, "\n");
- }
-}
-
-static int process_page(uint8_t* buf, uint8_t *oobbuf, size_t pagesize)
-{
- int eccpoi, oobsize;
- size_t i;
-
- switch (pagesize) {
- case 2048: oobsize = 64; eccpoi = 64 / 2; break;
- case 512: oobsize = 16; eccpoi = 16 / 2; break;
- default:
- fprintf(stderr, "Unsupported page size: %zd\n", pagesize);
- return -EINVAL;
- }
- memset(oobbuf, 0xff, oobsize);
-
- for (i = 0; i < pagesize; i += 256, eccpoi += 3) {
- oobbuf[eccpoi++] = 0x0;
- /* Calculate ECC */
- nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]);
- }
- return 0;
-}
-
-static int bad_marker_offs_in_oob(int pagesize)
-{
- switch (pagesize) {
- case 2048: return 0;
- case 512: return 5;
- }
- return -EINVAL;
-}
-
-static int decompose_image(struct args *args, FILE *in_fp,
- FILE *bin_fp, FILE *oob_fp)
-{
- int read, rc, page = 0;
- size_t oobsize = calc_oobsize(args->pagesize);
- uint8_t *buf = malloc(args->pagesize);
- uint8_t *oob = malloc(oobsize);
- uint8_t *calc_oob = malloc(oobsize);
- uint8_t *calc_buf = malloc(args->pagesize);
- uint8_t *page_buf;
- int pages_per_block = args->blocksize / args->pagesize;
- int eccpoi = 0, eccpoi_start;
- unsigned int i;
- int badpos = bad_marker_offs_in_oob(args->pagesize);
-
- switch (args->pagesize) {
- case 2048: eccpoi_start = 64 / 2; break;
- case 512: eccpoi_start = 16 / 2; break;
- default: exit(EXIT_FAILURE);
- }
-
- if (!buf)
- exit(EXIT_FAILURE);
- if (!oob)
- exit(EXIT_FAILURE);
- if (!calc_oob)
- exit(EXIT_FAILURE);
- if (!calc_buf)
- exit(EXIT_FAILURE);
-
- while (!feof(in_fp)) {
- /* read page by page */
- read = fread(buf, 1, args->pagesize, in_fp);
- if (ferror(in_fp)) {
- fprintf(stderr, "I/O Error.");
- exit(EXIT_FAILURE);
- }
- if (read != (ssize_t)args->pagesize)
- break;
-
- read = fread(oob, 1, oobsize, in_fp);
- if (ferror(in_fp)) {
- fprintf(stderr, "I/O Error.");
- exit(EXIT_FAILURE);
- }
-
- page_buf = buf; /* default is unmodified data */
-
- if ((page == 0 || page == 1) && (oob[badpos] != 0xff)) {
- if (verbose)
- printf("Block %d is bad\n",
- page / pages_per_block);
- goto write_data;
- }
- if (args->correct_ecc)
- page_buf = calc_buf;
-
- process_page(buf, calc_oob, args->pagesize);
- memcpy(calc_buf, buf, args->pagesize);
-
- /*
- * Our oob format uses only the last 3 bytes out of 4.
- * The first byte is 0x00 when the ECC is generated by
- * our toolset and 0xff when generated by Linux. This
- * is to be fixed when we want nand2bin work for other
- * ECC layouts too.
- */
- for (i = 0, eccpoi = eccpoi_start; i < args->pagesize;
- i += 256, eccpoi += 4)
- oob[eccpoi] = calc_oob[eccpoi] = 0xff;
-
- if (verbose && memcmp(oob, calc_oob, oobsize) != 0) {
- printf("\nECC compare mismatch found at block %d page %d!\n",
- page / pages_per_block, page % pages_per_block);
-
- printf("Read out OOB Data:\n");
- hexdump(stdout, oob, oobsize);
-
- printf("Calculated OOB Data:\n");
- hexdump(stdout, calc_oob, oobsize);
- }
-
- /* Do correction on subpage base */
- for (i = 0, eccpoi = eccpoi_start; i < args->pagesize;
- i += 256, eccpoi += 4) {
- rc = nand_correct_data(calc_buf + i, &oob[eccpoi + 1],
- &calc_oob[eccpoi + 1]);
-
- if (rc == -1)
- fprintf(stdout, "Uncorrectable ECC error at "
- "block %d page %d/%d\n",
- page / pages_per_block,
- page % pages_per_block, i / 256);
- else if (rc > 0)
- fprintf(stdout, "Correctable ECC error at "
- "block %d page %d/%d\n",
- page / pages_per_block,
- page % pages_per_block, i / 256);
- }
-
- write_data:
- rc = fwrite(page_buf, 1, args->pagesize, bin_fp);
- if (ferror(bin_fp)) {
- fprintf(stderr, "I/O Error.");
- exit(EXIT_FAILURE);
- }
- rc = fwrite(oob, 1, oobsize, oob_fp);
- if (ferror(bin_fp)) {
- fprintf(stderr, "I/O Error.");
- exit(EXIT_FAILURE);
- }
-
- page++;
- }
- free(calc_buf);
- free(calc_oob);
- free(oob);
- free(buf);
- return 0;
-}
-
-static int split_blocks(struct args *args, FILE *in_fp)
-{
- uint8_t *buf;
- size_t oobsize = calc_oobsize(args->pagesize);
- int pages_per_block = args->blocksize / args->pagesize;
- int block_len = pages_per_block * (args->pagesize + oobsize);
- int blocks = args->in_len / block_len;
- char bname[256] = { 0, };
- int badpos = bad_marker_offs_in_oob(args->pagesize);
- int bad_blocks = 0, i, bad_block = 0;
- ssize_t rc;
- FILE *b;
-
- buf = malloc(block_len);
- if (!buf) {
- perror("Not enough memory");
- exit(EXIT_FAILURE);
- }
-
- for (i = 0; i < blocks; i++) {
- rc = fread(buf, 1, block_len, in_fp);
- if (rc != block_len) {
- fprintf(stderr, "cannot read enough data!\n");
- exit(EXIT_FAILURE);
- }
-
- /* do block analysis */
- bad_block = 0;
- if ((buf[args->pagesize + badpos] != 0xff) ||
- (buf[2 * args->pagesize + oobsize + badpos] != 0xff)) {
- bad_blocks++;
- bad_block = 1;
- }
- if ((verbose && bad_block) || (verbose > 1)) {
- printf("-- (block %d oob of page 0 and 1)\n", i);
- hexdump(stdout, buf + args->pagesize, oobsize);
- printf("--\n");
- hexdump(stdout, buf + 2 * args->pagesize +
- oobsize, oobsize);
- }
-
- /* write complete block out */
- snprintf(bname, sizeof(bname) - 1, "%s.%d", args->arg1, i);
- b = fopen(bname, "w+");
- if (!b) {
- perror("Cannot open file");
- exit(EXIT_FAILURE);
- }
- rc = fwrite(buf, 1, block_len, b);
- if (rc != block_len) {
- fprintf(stderr, "could not write all data!\n");
- exit(EXIT_FAILURE);
- }
- fclose(b);
- }
-
- free(buf);
- if (bad_blocks || verbose)
- fprintf(stderr, "%d blocks, %d bad blocks\n",
- blocks, bad_blocks);
- return 0;
-}
-
-int
-main(int argc, char *argv[])
-{
- FILE *in, *bin = NULL, *oob = NULL;
- struct stat file_info;
-
- parse_opt(argc, argv, &myargs);
-
- if (!myargs.arg1) {
- fprintf(stderr, "Please specify input file!\n");
- exit(EXIT_FAILURE);
- }
-
- if (stat(myargs.arg1, &file_info) != 0) {
- perror("Cannot fetch file size from input file.\n");
- exit(EXIT_FAILURE);
- }
- myargs.in_len = file_info.st_size;
-
- in = fopen(myargs.arg1, "r");
- if (!in) {
- perror("Cannot open file");
- exit(EXIT_FAILURE);
- }
-
- if (myargs.split_blocks) {
- split_blocks(&myargs, in);
- goto out;
- }
-
- bin = fopen(myargs.output_file, "w+");
- if (!bin) {
- perror("Cannot open file");
- exit(EXIT_FAILURE);
- }
- oob = fopen(myargs.oob_file, "w+");
- if (!oob) {
- perror("Cannot open file");
- exit(EXIT_FAILURE);
- }
- decompose_image(&myargs, in, bin, oob);
-
- out:
- if (in) fclose(in);
- if (bin) fclose(bin);
- if (oob) fclose(oob);
- exit(EXIT_SUCCESS);
-}
diff --git a/ubi-utils/src/nandcorr.c b/ubi-utils/src/nandcorr.c
deleted file mode 100644
index caa07e2..0000000
--- a/ubi-utils/src/nandcorr.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * ECC algorithm for NAND FLASH. Detects and corrects 1 bit errors in
- * a 256 bytes of data.
- *
- * Reimplement by Thomas Gleixner after staring long enough at the
- * mess in drivers/mtd/nand/nandecc.c
- *
- */
-
-#include "nandecc.h"
-
-static int countbits(uint32_t byte)
-{
- int res = 0;
-
- for (;byte; byte >>= 1)
- res += byte & 0x01;
- return res;
-}
-
-/**
- * @dat: data which should be corrected
- * @read_ecc: ecc information read from flash
- * @calc_ecc: calculated ecc information from the data
- * @return: number of corrected bytes
- * or -1 when no correction is possible
- */
-int nand_correct_data(uint8_t *dat, const uint8_t *read_ecc,
- const uint8_t *calc_ecc)
-{
- uint8_t s0, s1, s2;
-
- /*
- * Do error detection
- *
- * Be careful, the index magic is due to a pointer to a
- * uint32_t.
- */
- s0 = calc_ecc[0] ^ read_ecc[0];
- s1 = calc_ecc[1] ^ read_ecc[1];
- s2 = calc_ecc[2] ^ read_ecc[2];
-
- if ((s0 | s1 | s2) == 0)
- return 0;
-
- /* Check for a single bit error */
- if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 &&
- ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 &&
- ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) {
-
- uint32_t byteoffs, bitnum;
-
- byteoffs = (s1 << 0) & 0x80;
- byteoffs |= (s1 << 1) & 0x40;
- byteoffs |= (s1 << 2) & 0x20;
- byteoffs |= (s1 << 3) & 0x10;
-
- byteoffs |= (s0 >> 4) & 0x08;
- byteoffs |= (s0 >> 3) & 0x04;
- byteoffs |= (s0 >> 2) & 0x02;
- byteoffs |= (s0 >> 1) & 0x01;
-
- bitnum = (s2 >> 5) & 0x04;
- bitnum |= (s2 >> 4) & 0x02;
- bitnum |= (s2 >> 3) & 0x01;
-
- dat[byteoffs] ^= (1 << bitnum);
-
- return 1;
- }
-
- if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1)
- return 1;
-
- return -1;
-}
-
diff --git a/ubi-utils/src/nandecc.c b/ubi-utils/src/nandecc.c
deleted file mode 100644
index 71660ef..0000000
--- a/ubi-utils/src/nandecc.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * This file contains an ECC algorithm from Toshiba that detects and
- * corrects 1 bit errors in a 256 byte block of data.
- *
- * drivers/mtd/nand/nand_ecc.c
- *
- * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
- * Toshiba America Electronics Components, Inc.
- *
- * This file 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 or (at your option) any
- * later version.
- *
- * This file 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 file; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * As a special exception, if other files instantiate templates or use
- * macros or inline functions from these files, or you compile these
- * files and link them with other works to produce a work based on these
- * files, these files do not by themselves cause the resulting work to be
- * covered by the GNU General Public License. However the source code for
- * these files must still be made available in accordance with section (3)
- * of the GNU General Public License.
- *
- * This exception does not invalidate any other reasons why a work based on
- * this file might be covered by the GNU General Public License.
- */
-
-#include "nandecc.h"
-
-/*
- * Pre-calculated 256-way 1 byte column parity
- */
-static const uint8_t nand_ecc_precalc_table[] = {
- 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
- 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
- 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
- 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
- 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
- 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
- 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
- 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
- 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
- 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
- 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
- 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
- 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
- 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
- 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
- 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
- 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
- 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
- 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
- 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
- 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
- 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
- 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
- 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
- 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
- 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
- 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
- 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
- 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
- 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
- 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
- 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
-};
-
-/**
- * nand_trans_result - [GENERIC] create non-inverted ECC
- * @reg2: line parity reg 2
- * @reg3: line parity reg 3
- * @ecc_code: ecc
- *
- * Creates non-inverted ECC code from line parity
- */
-static void nand_trans_result(uint8_t reg2, uint8_t reg3,
- uint8_t *ecc_code)
-{
- uint8_t a, b, i, tmp1, tmp2;
-
- /* Initialize variables */
- a = b = 0x80;
- tmp1 = tmp2 = 0;
-
- /* Calculate first ECC byte */
- for (i = 0; i < 4; i++) {
- if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */
- tmp1 |= b;
- b >>= 1;
- if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */
- tmp1 |= b;
- b >>= 1;
- a >>= 1;
- }
-
- /* Calculate second ECC byte */
- b = 0x80;
- for (i = 0; i < 4; i++) {
- if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */
- tmp2 |= b;
- b >>= 1;
- if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */
- tmp2 |= b;
- b >>= 1;
- a >>= 1;
- }
-
- /* Store two of the ECC bytes */
- ecc_code[1] = tmp1;
- ecc_code[0] = tmp2;
-}
-
-/**
- * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for
- * 256 byte block
- *
- * @dat: raw data
- * @ecc_code: buffer for ECC
- */
-int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code)
-{
- uint8_t idx, reg1, reg2, reg3;
- int j;
-
- /* Initialize variables */
- reg1 = reg2 = reg3 = 0;
- ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
-
- /* Build up column parity */
- for(j = 0; j < 256; j++) {
-
- /* Get CP0 - CP5 from table */
- idx = nand_ecc_precalc_table[dat[j]];
- reg1 ^= (idx & 0x3f);
-
- /* All bit XOR = 1 ? */
- if (idx & 0x40) {
- reg3 ^= (uint8_t) j;
- reg2 ^= ~((uint8_t) j);
- }
- }
-
- /* Create non-inverted ECC code from line parity */
- nand_trans_result(reg2, reg3, ecc_code);
-
- /* Calculate final ECC code */
- ecc_code[0] = ~ecc_code[0];
- ecc_code[1] = ~ecc_code[1];
- ecc_code[2] = ((~reg1) << 2) | 0x03;
- return 0;
-}
diff --git a/ubi-utils/src/nandecc.h b/ubi-utils/src/nandecc.h
deleted file mode 100644
index bcf1982..0000000
--- a/ubi-utils/src/nandecc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef _NAND_ECC_H
-#define _NAND_ECC_H
-/*
- * 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.
- *
- * NAND ecc functions
- */
-
-#include <stdint.h>
-
-int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code);
-int nand_correct_data(uint8_t *dat, const uint8_t *read_ecc,
- const uint8_t *calc_ecc);
-
-#endif
diff --git a/ubi-utils/src/pddcustomize.c b/ubi-utils/src/pddcustomize.c
deleted file mode 100644
index 1eb9b9a..0000000
--- a/ubi-utils/src/pddcustomize.c
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2008
- *
- * 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.
- *
- * Author: Oliver Lohmann
- *
- * PDD (platform description data) contains a set of system specific
- * boot-parameters. Some of those parameters need to be handled
- * special on updates, e.g. the MAC addresses. They must also be kept
- * if the system is updated and one must be able to modify them when
- * the system has booted the first time. This tool is intended to do
- * PDD modification.
- *
- * 1.3 Removed argp because we want to use uClibc.
- * 1.4 Minor cleanups
- * 1.5 Migrated to new libubi
- * 1.6 Fixed broken volume update
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <limits.h>
-#include <errno.h>
-#include <mtd/ubi-media.h>
-
-#include "config.h"
-#include "bootenv.h"
-#include "error.h"
-#include "example_ubi.h"
-#include "libubi.h"
-#include "ubimirror.h"
-
-#define PROGRAM_VERSION "1.6"
-
-#define DEFAULT_DEV_PATTERN "/dev/ubi%d"
-#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d"
-
-typedef enum action_t {
- ACT_NORMAL = 0,
- ACT_LIST,
- ACT_ARGP_ABORT,
- ACT_ARGP_ERR,
-} action_t;
-
-#define ABORT_ARGP do { \
- args->action = ACT_ARGP_ABORT; \
-} while (0)
-
-#define ERR_ARGP do { \
- args->action = ACT_ARGP_ERR; \
-} while (0)
-
-static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
- "pddcustomize - customize bootenv and pdd values.\n";
-
-static const char *optionsstr =
-" -b, --both Mirror updated PDD to redundand copy.\n"
-" -c, --copyright Print copyright information.\n"
-" -i, --input=<input> Binary input file. For debug purposes.\n"
-" -l, --list List card bootenv/pdd values.\n"
-" -o, --output=<output> Binary output file. For debug purposes.\n"
-" -s, --side=<seqnum> The side/seqnum to update.\n"
-" -x, --host use x86 platform for debugging.\n"
-" -?, --help Give this help list\n"
-" --usage Give a short usage message\n"
-" -V, --version Print program version\n";
-
-static const char *usage =
-"Usage: pddcustomize [-bclx?V] [-i <input>] [-o <output>] [-s <seqnum>]\n"
-" [--both] [--copyright] [--input=<input>] [--list]\n"
-" [--output=<output>] [--side=<seqnum>] [--host] [--help] [--usage]\n"
-" [--version] [key=value] [...]\n";
-
-struct option long_options[] = {
- { .name = "both", .has_arg = 0, .flag = NULL, .val = 'b' },
- { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' },
- { .name = "input", .has_arg = 1, .flag = NULL, .val = 'i' },
- { .name = "list", .has_arg = 0, .flag = NULL, .val = 'l' },
- { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
- { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' },
- { .name = "host", .has_arg = 0, .flag = NULL, .val = 'x' },
- { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
- { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
- { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
- { NULL, 0, NULL, 0}
-};
-
-static const char copyright [] __attribute__((unused)) =
- "Copyright IBM Corp 2006";
-
-typedef struct myargs {
- action_t action;
- const char* file_in;
- const char* file_out;
- int both;
- int side;
- int x86; /* X86 host, use files for testing */
- bootenv_t env_in;
-
- char *arg1;
- char **options; /* [STRING...] */
-} myargs;
-
-static int
-get_update_side(const char* str)
-{
- uint32_t i = strtoul(str, NULL, 0);
-
- if ((i != 0) && (i != 1)) {
- return -1;
- }
-
- return i;
-}
-
-static int
-extract_pair(bootenv_t env, const char* str)
-{
- int rc = 0;
- char* key;
- char* val;
-
- key = strdup(str);
- if (key == NULL)
- return -ENOMEM;
-
- val = strstr(key, "=");
- if (val == NULL) {
- err_msg("Wrong argument: %s\n"
- "Expecting key=value pair.\n", str);
- rc = -1;
- goto err;
- }
-
- *val = '\0'; /* split strings */
- val++;
- rc = bootenv_set(env, key, val);
-
-err:
- free(key);
- return rc;
-}
-
-static int
-parse_opt(int argc, char **argv, myargs *args)
-{
- int rc = 0;
-
- while (1) {
- int key;
-
- key = getopt_long(argc, argv, "clbxs:i:o:?V",
- long_options, NULL);
- if (key == -1)
- break;
-
- switch (key) {
- case 'c':
- err_msg("%s\n", copyright);
- ABORT_ARGP;
- break;
- case 'l':
- args->action = ACT_LIST;
- break;
- case 'b':
- args->both = 1;
- break;
- case 'x':
- args->x86 = 1;
- break;
- case 's':
- args->side = get_update_side(optarg);
- if (args->side < 0) {
- err_msg("Unsupported seqnum: %d.\n"
- "Supported seqnums are "
- "'0' and '1'\n",
- args->side, optarg);
- ERR_ARGP;
- }
- break;
- case 'i':
- args->file_in = optarg;
- break;
- case 'o':
- args->file_out = optarg;
- break;
- case '?': /* help */
- err_msg("Usage: pddcustomize [OPTION...] "
- "[key=value] [...]");
- err_msg("%s", doc);
- err_msg("%s", optionsstr);
- err_msg("\nReport bugs to %s",
- PACKAGE_BUGREPORT);
- exit(0);
- break;
- case 'V':
- err_msg("%s", PROGRAM_VERSION);
- exit(0);
- break;
- default:
- err_msg("%s", usage);
- exit(-1);
- }
- }
-
- if (optind < argc) {
- rc = extract_pair(args->env_in, argv[optind++]);
- if (rc != 0)
- ERR_ARGP;
- }
-
- return 0;
-}
-
-static int
-list_bootenv(bootenv_t env)
-{
- int rc = 0;
- rc = bootenv_write_txt(stdout, env);
- if (rc != 0) {
- err_msg("Cannot list bootenv/pdd. rc: %d\n", rc);
- goto err;
- }
-err:
- return rc;
-}
-
-static int
-process_key_value(bootenv_t env_in, bootenv_t env)
-{
- int rc = 0;
- size_t size, i;
- const char* tmp;
- const char** key_vec = NULL;
-
- rc = bootenv_get_key_vector(env_in, &size, 0, &key_vec);
- if (rc != 0)
- goto err;
-
- for (i = 0; i < size; i++) {
- rc = bootenv_get(env_in, key_vec[i], &tmp);
- if (rc != 0) {
- err_msg("Cannot read value to input key: %s. rc: %d\n",
- key_vec[i], rc);
- goto err;
- }
- rc = bootenv_set(env, key_vec[i], tmp);
- if (rc != 0) {
- err_msg("Cannot set value key: %s. rc: %d\n",
- key_vec[i], rc);
- goto err;
- }
- }
-
-err:
- if (key_vec != NULL)
- free(key_vec);
- return rc;
-}
-
-static int
-read_bootenv(const char* file, bootenv_t env)
-{
- int rc = 0;
- FILE* fp_in = NULL;
-
- fp_in = fopen(file, "rb");
- if (fp_in == NULL) {
- err_msg("Cannot open file: %s\n", file);
- return -EIO;
- }
-
- rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE);
- if (rc != 0) {
- err_msg("Cannot read bootenv from file %s. rc: %d\n",
- file, rc);
- goto err;
- }
-
-err:
- fclose(fp_in);
- return rc;
-}
-
-/*
- * Read bootenv from ubi volume
- */
-static int
-ubi_read_bootenv(uint32_t devno, uint32_t id, bootenv_t env)
-{
- libubi_t ulib;
- int rc = 0;
- char path[PATH_MAX];
- FILE* fp_in = NULL;
-
- ulib = libubi_open();
- if (ulib == NULL) {
- err_msg("Cannot allocate ubi structure\n");
- return -1;
- }
-
- snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id);
-
- fp_in = fopen(path, "r");
- if (fp_in == NULL) {
- err_msg("Cannot open volume:%d number:%d\n", devno, id);
- goto err;
- }
-
- rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE);
- if (rc != 0) {
- err_msg("Cannot read volume:%d number:%d\n", devno, id);
- goto err;
- }
-
-err:
- if (fp_in)
- fclose(fp_in);
- libubi_close(ulib);
- return rc;
-}
-
-static int
-write_bootenv(const char* file, bootenv_t env)
-{
- int rc = 0;
- FILE* fp_out;
-
- fp_out = fopen(file, "wb");
- if (fp_out == NULL) {
- err_msg("Cannot open file: %s\n", file);
- return -EIO;
- }
-
- rc = bootenv_write(fp_out, env);
- if (rc != 0) {
- err_msg("Cannot write bootenv to file %s. rc: %d\n", file, rc);
- goto err;
- }
-
-err:
- fclose(fp_out);
- return rc;
-}
-
-/*
- * Read bootenv from ubi volume
- */
-static int
-ubi_write_bootenv(uint32_t devno, uint32_t id, bootenv_t env)
-{
- libubi_t ulib;
- int rc = 0;
- char path[PATH_MAX];
- FILE* fp_out = NULL;
- size_t nbytes;
-
- rc = bootenv_size(env, &nbytes);
- if (rc) {
- err_msg("Cannot determine size of bootenv structure\n");
- return rc;
- }
- ulib = libubi_open();
- if (ulib == NULL) {
- err_msg("Cannot allocate ubi structure\n");
- return rc;
- }
-
- snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id);
-
- fp_out = fopen(path, "r+");
- if (fp_out == NULL) {
- err_msg("Cannot fopen volume:%d number:%d\n", devno, id);
- rc = -EBADF;
- goto err;
- }
-
- rc = ubi_update_start(ulib, fileno(fp_out), nbytes);
- if (rc != 0) {
- err_msg("Cannot start update for %s\n", path);
- goto err;
- }
-
- rc = bootenv_write(fp_out, env);
- if (rc != 0) {
- err_msg("Cannot write bootenv to volume %d number:%d\n",
- devno, id);
- goto err;
- }
-err:
- if( fp_out )
- fclose(fp_out);
- libubi_close(ulib);
- return rc;
-}
-
-static int
-do_mirror(int volno)
-{
- char errbuf[1024];
- uint32_t ids[2];
- int rc;
- int src_volno_idx = 0;
-
- ids[0] = EXAMPLE_BOOTENV_VOL_ID_1;
- ids[1] = EXAMPLE_BOOTENV_VOL_ID_2;
-
- if (volno == EXAMPLE_BOOTENV_VOL_ID_2)
- src_volno_idx = 1;
-
- rc = ubimirror(EXAMPLE_UBI_DEVICE, src_volno_idx, ids, 2, errbuf,
- sizeof errbuf);
- if( rc )
- err_msg(errbuf);
- return rc;
-}
-
-int
-main(int argc, char **argv) {
- int rc = 0;
- bootenv_t env = NULL;
- uint32_t boot_volno;
- myargs args = {
- .action = ACT_NORMAL,
- .file_in = NULL,
- .file_out = NULL,
- .side = -1,
- .x86 = 0,
- .both = 0,
- .env_in = NULL,
-
- .arg1 = NULL,
- .options = NULL,
- };
-
- rc = bootenv_create(&env);
- if (rc != 0) {
- err_msg("Cannot create bootenv handle. rc: %d", rc);
- goto err;
- }
-
- rc = bootenv_create(&(args.env_in));
- if (rc != 0) {
- err_msg("Cannot create bootenv handle. rc: %d", rc);
- goto err;
- }
-
- parse_opt(argc, argv, &args);
- if (args.action == ACT_ARGP_ERR) {
- rc = -1;
- goto err;
- }
- if (args.action == ACT_ARGP_ABORT) {
- rc = 0;
- goto out;
- }
-
- if ((args.side == 0) || (args.side == -1))
- boot_volno = EXAMPLE_BOOTENV_VOL_ID_1;
- else
- boot_volno = EXAMPLE_BOOTENV_VOL_ID_2;
-
- if( args.x86 )
- rc = read_bootenv(args.file_in, env);
- else
- rc = ubi_read_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env);
- if (rc != 0) {
- goto err;
- }
-
- if (args.action == ACT_LIST) {
- rc = list_bootenv(env);
- if (rc != 0) {
- goto err;
- }
- goto out;
- }
-
- rc = process_key_value(args.env_in, env);
- if (rc != 0) {
- goto err;
- }
-
- if( args.x86 )
- rc = write_bootenv(args.file_in, env);
- else
- rc = ubi_write_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env);
- if (rc != 0)
- goto err;
-
- if( args.both ) /* No side specified, update both */
- rc = do_mirror(boot_volno);
-
- out:
- err:
- bootenv_destroy(&env);
- bootenv_destroy(&(args.env_in));
- return rc;
-}
diff --git a/ubi-utils/src/peb.c b/ubi-utils/src/peb.c
deleted file mode 100644
index 08b770f..0000000
--- a/ubi-utils/src/peb.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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.
- */
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-
-#include "peb.h"
-
-int
-peb_cmp(peb_t eb_1, peb_t eb_2)
-{
- assert(eb_1);
- assert(eb_2);
-
- return eb_1->num == eb_2->num ? 0
- : eb_1->num > eb_2->num ? 1 : -1;
-}
-
-int
-peb_new(uint32_t eb_num, uint32_t eb_size, peb_t *peb)
-{
- int rc = 0;
-
- peb_t res = (peb_t) malloc(sizeof(struct peb));
- if (!res) {
- rc = -ENOMEM;
- goto err;
- }
-
- res->num = eb_num;
- res->size = eb_size;
- res->data = (uint8_t*) malloc(res->size * sizeof(uint8_t));
- if (!res->data) {
- rc = -ENOMEM;
- goto err;
- }
- memset(res->data, 0xff, res->size);
-
- *peb = res;
- return 0;
-err:
- if (res) {
- if (res->data)
- free(res->data);
- free(res);
- }
- *peb = NULL;
- return rc;
-}
-
-int
-peb_fill(peb_t peb, uint8_t* buf, size_t buf_size)
-{
- if (!peb)
- return -EINVAL;
-
- if (buf_size > peb->size)
- return -EINVAL;
-
- memcpy(peb->data, buf, buf_size);
- return 0;
-}
-
-int
-peb_write(FILE* fp_out, peb_t peb)
-{
- size_t written = 0;
-
- if (peb == NULL)
- return -EINVAL;
-
- written = fwrite(peb->data, 1, peb->size, fp_out);
-
- if (written != peb->size)
- return -EIO;
-
- return 0;
-}
-
-int
-peb_free(peb_t* peb)
-{
- peb_t tmp = *peb;
- if (tmp) {
- if (tmp->data)
- free(tmp->data);
- free(tmp);
- }
- *peb = NULL;
-
- return 0;
-}
-
-void peb_dump(FILE* fp_out, peb_t peb)
-{
- fprintf(fp_out, "num: %08d\tsize: 0x%08x\n", peb->num, peb->size);
-}
diff --git a/ubi-utils/src/peb.h b/ubi-utils/src/peb.h
deleted file mode 100644
index 246bce8..0000000
--- a/ubi-utils/src/peb.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef __RAW_BLOCK_H__
-#define __RAW_BLOCK_H__
-/*
- * 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.
- *
- * Author: Oliver Lohmann
- */
-
-#include <stdint.h>
-#include <stdio.h>
-
-typedef struct peb *peb_t;
-struct peb {
- uint32_t num; /* Physical eraseblock number
- * in the RAW file. */
- uint32_t size; /* Data Size (equals physical
- * erase block size) */
- uint8_t* data; /* Data buffer */
-};
-
-int peb_new(uint32_t peb_num, uint32_t peb_size, peb_t* peb);
-int peb_free(peb_t* peb);
-int peb_cmp(peb_t peb_1, peb_t peb_2);
-int peb_write(FILE* fp_out, peb_t peb);
-void peb_dump(FILE* fp_out, peb_t peb);
-
-#endif /* __RAW_BLOCK_H__ */
diff --git a/ubi-utils/src/pfi.c b/ubi-utils/src/pfi.c
deleted file mode 100644
index fa835e2..0000000
--- a/ubi-utils/src/pfi.c
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * @file pfi.c
- *
- * @author Oliver Lohmann
- * Andreas Arnez
- * Joern Engel
- * Frank Haverkamp
- *
- * @brief libpfi holds all code to create and process pfi files.
- *
- * <oliloh@de.ibm.com> Wed Feb 8 11:38:22 CET 2006: Initial creation.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <syslog.h>
-#include <stdarg.h>
-#include <errno.h>
-
-#include "pfi.h"
-
-#define PFI_MAGIC "PFI!\n"
-#define PFI_DATA "DATA\n" /* The same size as PFI_MAGIC */
-#define PFI_MAGIC_LEN 5
-
-static const char copyright [] __attribute__((unused)) =
- "Copyright (c) International Business Machines Corp., 2006";
-
-enum key_id {
- /* version 1 */
- key_version, /* must be index position 0! */
- key_mode,
- key_size,
- key_crc,
- key_label,
- key_flags,
- key_ubi_ids,
- key_ubi_size,
- key_ubi_type,
- key_ubi_names,
- key_ubi_alignment,
- key_raw_starts,
- key_raw_total_size,
- num_keys,
-};
-
-struct pfi_header {
- char defined[num_keys]; /* reserve all possible keys even if
- version does not require this. */
- int mode_no; /* current mode no. -> can only increase */
- union {
- char *str;
- uint32_t num;
- } value[num_keys];
-};
-
-
-#define PFI_MANDATORY 0x0001
-#define PFI_STRING 0x0002
-#define PFI_LISTVALUE 0x0004 /* comma seperated list of nums */
-#define PFI_MANDATORY_UBI 0x0008
-#define PFI_MANDATORY_RAW 0x0010
-
-struct key_descriptor {
- enum key_id id;
- const char *name;
- uint32_t flags;
-};
-
-static const struct key_descriptor key_desc_v1[] = {
- { key_version, "version", PFI_MANDATORY },
- { key_mode, "mode", PFI_MANDATORY | PFI_STRING },
- { key_size, "size", PFI_MANDATORY },
- { key_crc, "crc", PFI_MANDATORY },
- { key_label, "label", PFI_MANDATORY | PFI_STRING },
- { key_flags, "flags", PFI_MANDATORY },
- { key_ubi_ids, "ubi_ids", PFI_MANDATORY_UBI | PFI_STRING },
- { key_ubi_size, "ubi_size", PFI_MANDATORY_UBI },
- { key_ubi_type, "ubi_type", PFI_MANDATORY_UBI | PFI_STRING },
- { key_ubi_names, "ubi_names", PFI_MANDATORY_UBI | PFI_STRING },
- { key_ubi_alignment, "ubi_alignment", PFI_MANDATORY_UBI },
- { key_raw_starts, "raw_starts", PFI_MANDATORY_RAW | PFI_STRING },
- { key_raw_total_size, "raw_total_size", PFI_MANDATORY_RAW },
-};
-
-static const struct key_descriptor *key_descriptors[] = {
- NULL,
- key_desc_v1, /* version 1 */
-};
-
-static const int key_descriptors_max[] = {
- 0, /* version 0 */
- sizeof(key_desc_v1)/sizeof(struct key_descriptor), /* version 1 */
-};
-
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-
-static const char* modes[] = {"raw", "ubi"}; /* order isn't arbitrary! */
-
-/* latest version contains all possible keys */
-static const struct key_descriptor *key_desc = key_desc_v1;
-
-#define PFI_IS_UBI(mode) \
- (((mode) != NULL) && (strcmp("ubi", (mode)) == 0))
-
-#define PFI_IS_RAW(mode) \
- (((mode) != NULL) && (strcmp("raw", (mode)) == 0))
-
-/**
- * @return <0 On Error.
- * >=0 Mode no.
- */
-static int
-get_mode_no(const char* mode)
-{
- int i;
-
- for (i = 0; i < (int)ARRAY_SIZE(modes); i++)
- if (strcmp(mode, modes[i]) == 0)
- return i;
- return -1;
-}
-
-static int
-find_key_by_name (const char *name)
-{
- int i;
-
- for (i = 0; i < num_keys; i++) {
- if (strcmp(name, key_desc[i].name) == 0)
- return i;
- }
- return -1;
-}
-
-static int
-check_valid (pfi_header head)
-{
- int i;
- int max_keys;
- uint32_t version;
- const char *mode;
- const struct key_descriptor *desc;
- uint32_t to_check = PFI_MANDATORY;
-
- /*
- * For the validity check the list of possible keys depends on
- * the version of the PFI file used.
- */
- version = head->value[key_version].num;
- if (version > PFI_HDRVERSION)
- return PFI_ENOHEADER;
-
- max_keys = key_descriptors_max[version];
- desc = key_descriptors[version];
-
- if (!desc)
- return PFI_ENOVERSION;
-
- mode = head->value[key_mode].str;
- if (PFI_IS_UBI(mode)) {
- to_check |= PFI_MANDATORY_UBI;
- }
- else if (PFI_IS_RAW(mode)) {
- to_check |= PFI_MANDATORY_RAW;
- }
- else { /* neither UBI nor RAW == ERR */
- return PFI_EINSUFF;
- }
-
- for (i = 0; i < max_keys; i++) {
- if ((desc[i].flags & to_check) && !head->defined[i]) {
- fprintf(stderr, "libpfi: %s missing\n", desc[i].name);
- return PFI_EINSUFF;
- }
- }
-
- return 0;
-}
-
-int pfi_header_init (pfi_header *head)
-{
- int i;
- pfi_header self = (pfi_header) malloc(sizeof(*self));
-
- *head = self;
- if (self == NULL)
- return PFI_ENOMEM;
-
- /* initialize maximum number of possible keys */
- for (i = 0; i < num_keys; i++) {
- memset(self, 0, sizeof(*self));
- self->defined[i] = 0;
- }
-
- return 0;
-}
-
-int pfi_header_destroy (pfi_header *head)
-{
- int i;
- pfi_header self = *head;
-
- for (i = 0; i < num_keys; i++) {
- if (self->defined[i] && (key_desc[i].flags & PFI_STRING) &&
- self->value[i].str) {
- free(self->value[i].str);
- }
- }
- free(*head);
- *head = NULL;
- return 0;
-}
-
-int pfi_header_setnumber (pfi_header head,
- const char *key, uint32_t value)
-{
- int key_id = find_key_by_name(key);
-
- if (key_id < 0)
- return PFI_EUNDEF;
-
- if (key_desc[key_id].flags & PFI_STRING)
- return PFI_EBADTYPE;
-
- head->value[key_id].num = value;
- head->defined[key_id] = 1;
- return 0;
-}
-
-int pfi_header_setvalue (pfi_header head,
- const char *key, const char *value)
-{
- int key_id = find_key_by_name(key);
-
- if (value == NULL)
- return PFI_EINSUFF;
-
- if ((key_id < 0) || (key_id >= num_keys))
- return PFI_EUNDEF;
-
- if (key_desc[key_id].flags & PFI_STRING) {
- /*
- * The value is a string. Copy to a newly allocated
- * buffer. Delete the old value, if already set.
- */
- size_t len = strlen(value) + 1;
- char *old_str = NULL;
- char *str;
-
- old_str = head->value[key_id].str;
- if (old_str != NULL)
- free(old_str);
-
- str = head->value[key_id].str = (char *) malloc(len);
- if (str == NULL)
- return PFI_ENOMEM;
-
- strcpy(str, value);
- } else {
- int len;
- int ret;
- /* FIXME: here we assume that the value is always
- given in hex and starts with '0x'. */
- ret = sscanf(value, "0x%x%n", &head->value[key_id].num, &len);
- if (ret < 1 || value[len] != '\0')
- return PFI_EBADTYPE;
- }
- head->defined[key_id] = 1;
- return 0;
-}
-
-int pfi_header_getnumber (pfi_header head,
- const char *key, uint32_t *value)
-{
- int key_id = find_key_by_name(key);
-
- if (key_id < 0)
- return PFI_EUNDEF;
-
- if (key_desc[key_id].flags & PFI_STRING)
- return PFI_EBADTYPE;
-
- if (!head->defined[key_id])
- return PFI_EUNDEF;
-
- *value = head->value[key_id].num;
- return 0;
-}
-
-int pfi_header_getstring (pfi_header head,
- const char *key, char *value, size_t size)
-{
- int key_id = find_key_by_name(key);
-
- if (key_id < 0)
- return PFI_EUNDEF;
-
- if (!(key_desc[key_id].flags & PFI_STRING))
- return PFI_EBADTYPE;
-
- if (!head->defined[key_id])
- return PFI_EUNDEF;
-
- strncpy(value, head->value[key_id].str, size-1);
- value[size-1] = '\0';
- return 0;
-}
-
-int pfi_header_write (FILE *out, pfi_header head)
-{
- int i;
- int ret;
-
- pfi_header_setnumber(head, "version", PFI_HDRVERSION);
-
- if ((ret = check_valid(head)) != 0)
- return ret;
-
- /* OK. Now write the header. */
-
- ret = fwrite(PFI_MAGIC, 1, PFI_MAGIC_LEN, out);
- if (ret < PFI_MAGIC_LEN)
- return ret;
-
-
- for (i = 0; i < num_keys; i++) {
- if (!head->defined[i])
- continue;
-
- ret = fprintf(out, "%s=", key_desc[i].name);
- if (ret < 0)
- return PFI_EFILE;
-
- if (key_desc[i].flags & PFI_STRING) {
- ret = fprintf(out, "%s", head->value[i].str);
- if (ret < 0)
- return PFI_EFILE;
- } else {
- ret = fprintf(out, "0x%8x", head->value[i].num);
- if (ret < 0)
- return PFI_EFILE;
-
- }
- ret = fprintf(out, "\n");
- if (ret < 0)
- return PFI_EFILE;
- }
- ret = fprintf(out, "\n");
- if (ret < 0)
- return PFI_EFILE;
-
- ret = fflush(out);
- if (ret != 0)
- return PFI_EFILE;
-
- return 0;
-}
-
-int pfi_header_read (FILE *in, pfi_header head)
-{
- char magic[PFI_MAGIC_LEN];
- char mode[PFI_KEYWORD_LEN];
- char buf[256];
-
- if (PFI_MAGIC_LEN != fread(magic, 1, PFI_MAGIC_LEN, in))
- return PFI_EFILE;
- if (memcmp(magic, PFI_MAGIC, PFI_MAGIC_LEN) != 0) {
- if (memcmp(magic, PFI_DATA, PFI_MAGIC_LEN) == 0) {
- return PFI_DATA_START;
- }
- return PFI_ENOHEADER;
- }
-
- while (fgets(buf, sizeof(buf), in) != NULL && buf[0] != '\n') {
- char *value;
- char *end;
- value = strchr(buf, '=');
- if (value == NULL)
- return PFI_ENOHEADER;
-
- *value = '\0';
- value++;
- end = strchr(value, '\n');
- if (end)
- *end = '\0';
-
- if (pfi_header_setvalue(head, buf, value))
- return PFI_ENOHEADER;
- }
-
- if (check_valid(head) != 0)
- return PFI_ENOHEADER;
-
- /* set current mode no. in head */
- pfi_header_getstring(head, "mode", mode, PFI_KEYWORD_LEN);
- if (head->mode_no > get_mode_no(mode)) {
- return PFI_EMODE;
- }
- head->mode_no = get_mode_no(mode);
- return 0;
-}
-
-int pfi_header_dump (FILE *out, pfi_header head __attribute__((__unused__)))
-{
- fprintf(out, "Sorry not implemented yet. Write mail to "
- "Andreas Arnez and complain!\n");
- return 0;
-}
-
-int pfi_read (FILE *in, pfi_read_func func, void *priv_data)
-{
- int rc;
- pfi_header header;
-
- rc = pfi_header_init (&header);
- if (0 != rc)
- return rc;
- if (!func)
- return PFI_EINVAL;
-
- while ((0 == rc) && !feof(in)) {
- /*
- * Read header and check consistency of the fields.
- */
- rc = pfi_header_read( in, header );
- if (0 != rc)
- break;
- if (func) {
- rc = func(in, header, priv_data);
- if (rc != 0)
- break;
- }
- }
-
- pfi_header_destroy(&header);
- return rc;
-}
diff --git a/ubi-utils/src/pfi.h b/ubi-utils/src/pfi.h
deleted file mode 100644
index 8c5cc07..0000000
--- a/ubi-utils/src/pfi.h
+++ /dev/null
@@ -1,244 +0,0 @@
-#ifndef __pfi_h
-#define __pfi_h
-/*
- * 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.
- */
-
-/**
- * @file pfi.h
- *
- * @author Oliver Lohmann <oliloh@de.ibm.com>
- * Andreas Arnez <arnez@de.ibm.com>
- * Joern Engel <engeljoe@de.ibm.com>
- * Frank Haverkamp <haverkam@de.ibm.com>
- *
- * @brief libpfi will hold all code to create and process pfi
- * images. Definitions made in this file are equaly usable for the
- * development host and the target system.
- *
- * @note This header additionally holds the official definitions for
- * the pfi headers.
- */
-
-#include <stdio.h> /* FILE */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Definitions. */
-
-#define PFI_HDRVERSION 1 /* current header version */
-
-#define PFI_ENOVERSION 1 /* unknown version */
-#define PFI_ENOHEADER 2 /* not a pfi header */
-#define PFI_EINSUFF 3 /* insufficient information */
-#define PFI_EUNDEF 4 /* key not defined */
-#define PFI_ENOMEM 5 /* out of memory */
-#define PFI_EBADTYPE 6 /* bad data type */
-#define PFI_EFILE 7 /* file I/O error: see errno */
-#define PFI_EFILEINVAL 8 /* file format not valid */
-#define PFI_EINVAL 9 /* invalid parameter */
-#define PFI_ERANGE 10 /* invalid range */
-#define PFI_EMODE 11 /* expecting other mode in this header */
-#define PFI_DATA_START 12 /* data section starts */
-#define PFI_EMAX 13 /* should be always larger as the largest
- error code */
-
-#define PFI_LABEL_LEN 64 /* This is the maximum length for a
- PFI header label */
-#define PFI_KEYWORD_LEN 32 /* This is the maximum length for an
- entry in the mode and type fields */
-
-#define PFI_UBI_MAX_VOLUMES 128
-#define PFI_UBI_VOL_NAME_LEN 127
-
-/**
- * @brief The pfi header allows to set flags which influence the flashing
- * behaviour.
- */
-#define PFI_FLAG_PROTECTED 0x00000001
-
-
-/**
- * @brief Handle to pfi header. Used in most of the functions associated
- * with pfi file handling.
- */
-typedef struct pfi_header *pfi_header;
-
-
-/**
- * @brief Initialize a pfi header object.
- *
- * @param head Pointer to handle. This function allocates memory
- * for this data structure.
- * @return 0 on success, otherwise:
- * PFI_ENOMEM : no memory available for the handle.
- */
-int pfi_header_init (pfi_header *head);
-
-
-/**
- * @brief Destroy a pfi header object.
- *
- * @param head handle. head is invalid after calling this function.
- * @return 0 always.
- */
-int pfi_header_destroy (pfi_header *head);
-
-
-/**
- * @brief Add a key/value pair to a pfi header object.
- *
- * @param head handle.
- * @param key pointer to key string. Must be 0 terminated.
- * @param value pointer to value string. Must be 0 terminated.
- * @return 0 on success, otherwise:
- * PFI_EUNDEF : key was not found.
- * PFI_ENOMEM : no memory available for the handle.
- * PFI_EBADTYPE : value is not an hex string. This happens
- * when the key stores an integer and the
- * new value is not convertable e.g. not in
- * 0xXXXXXXXX format.
- */
-int pfi_header_setvalue (pfi_header head,
- const char *key, const char *value);
-
-
-/**
- * @brief Add a key/value pair to a pfi header object. Provide the
- * value as a number.
- *
- * @param head handle.
- * @param key pointer to key string. Must be 0 terminated.
- * @param value value to set.
- * @return 0 on success, otherwise:
- * PFI_EUNDEF : key was not found.
- * PFI_EBADTYPE : value is not a string. This happens
- * when the key stores a string.
- */
-int pfi_header_setnumber (pfi_header head,
- const char *key, uint32_t value);
-
-
-/**
- * @brief For a given key, return the numerical value stored in a
- * pfi header object.
- *
- * @param head handle.
- * @param key pointer to key string. Must be 0 terminated.
- * @param value pointer to value.
- * @return 0 on success, otherwise:
- * PFI_EUNDEF : key was not found.
- * PFI_EBADTYPE : stored value is not an integer but a string.
- */
-int pfi_header_getnumber (pfi_header head,
- const char *key, uint32_t *value);
-
-
-static inline uint32_t
-pfi_getnumber(pfi_header head, const char *key)
-{
- uint32_t value;
- pfi_header_getnumber(head, key, &value);
- return value;
-}
-
-/**
- * @brief For a given key, return the string value stored in a pfi
- * header object.
- *
- * @param head handle.
- * @param key pointer to key string. Must be 0 terminated.
- * @param value pointer to value string. Memory must be allocated by the user.
- * @return 0 on success, otherwise:
- * PFI_EUNDEF : key was not found.
- * PFI_EBADTYPE : stored value is not a string but an integer.
- */
-int pfi_header_getstring (pfi_header head,
- const char *key, char *value, size_t size);
-
-
-/**
- * @brief Write a pfi header object into a given file.
- *
- * @param out output stream.
- * @param head handle.
- * @return 0 on success, error values otherwise:
- * PFI_EINSUFF : not all mandatory fields are filled.
- * PFI_ENOHEADER : wrong header version or magic number.
- * -E* : see <asm/errno.h>.
- */
-int pfi_header_write (FILE *out, pfi_header head);
-
-
-/**
- * @brief Read a pfi header object from a given file.
- *
- * @param in input stream.
- * @param head handle.
- * @return 0 on success, error values otherwise:
- * PFI_ENOVERSION: unknown header version.
- * PFI_EFILE : cannot read enough data.
- * PFI_ENOHEADER : wrong header version or magic number.
- * -E* : see <asm/errno.h>.
- *
- * If the header verification returned success the user can assume that
- * all mandatory fields for a particular version are accessible. Checking
- * the return code when calling the get-function for those keys is not
- * required in those cases. For optional fields the checking must still be
- * done.
- */
-int pfi_header_read (FILE *in, pfi_header head);
-
-
-/**
- * @brief Display a pfi header in human-readable form.
- *
- * @param out output stream.
- * @param head handle.
- * @return always 0.
- *
- * @note Prints out that it is not implemented and whom you should
- * contact if you need it urgently!.
- */
-int pfi_header_dump (FILE *out, pfi_header head);
-
-
-/*
- * @brief Iterates over a stream of pfi files. The iterator function
- * must advance the file pointer in FILE *in to the next pfi
- * header. Function exists on feof(in).
- *
- * @param in input file descriptor, must be open and valid.
- * @param func iterator function called when pfi header could be
- * read and was validated. The function must return 0 on
- * success.
- * @return See pfi_header_init and pfi_header_read.
- * PFI_EINVAL : func is not valid
- * 0 ok.
- */
-typedef int (* pfi_read_func)(FILE *in, pfi_header hdr, void *priv_data);
-
-int pfi_read (FILE *in, pfi_read_func func, void *priv_data);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __pfi_h */
diff --git a/ubi-utils/src/pfi2bin.c b/ubi-utils/src/pfi2bin.c
deleted file mode 100644
index 34ecc92..0000000
--- a/ubi-utils/src/pfi2bin.c
+++ /dev/null
@@ -1,682 +0,0 @@
-/*
- * 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.
- *
- * Author: Oliver Lohmann
- *
- * Convert a PFI file (partial flash image) into a plain binary file.
- * This tool can be used to prepare the data to be burned into flash
- * chips in a manufacturing step where the flashes are written before
- * being soldered onto the hardware. For NAND images another step is
- * required to add the right OOB data to the binary image.
- *
- * 1.3 Removed argp because we want to use uClibc.
- * 1.4 Minor cleanups
- */
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <ubigen.h>
-#include <mtd/ubi-media.h>
-#include <mtd_swab.h>
-
-#include "config.h"
-#include "list.h"
-#include "error.h"
-#include "reader.h"
-#include "peb.h"
-#include "crc32.h"
-
-#define PROGRAM_VERSION "1.4"
-
-#define MAX_FNAME 255
-#define DEFAULT_ERASE_COUNT 0 /* Hmmm.... Perhaps */
-#define ERR_BUF_SIZE 1024
-
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-
-static uint32_t crc32_table[256];
-static char err_buf[ERR_BUF_SIZE];
-
-/*
- * Data used to buffer raw blocks which have to be
- * located at a specific point inside the generated RAW file
- */
-
-typedef enum action_t {
- ACT_NOTHING = 0x00000000,
- ACT_RAW = 0x00000001,
-} action_t;
-
-static const char copyright [] __attribute__((unused)) =
- "(c) Copyright IBM Corp 2006\n";
-
-static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
- "pfi2bin - a tool to convert PFI files into binary images.\n";
-
-static const char *optionsstr =
-" Common settings:\n"
-" -c, --copyright\n"
-" -v, --verbose Print more information.\n"
-"\n"
-" Input:\n"
-" -j, --platform=pdd-file PDD information which contains the card settings.\n"
-"\n"
-" Output:\n"
-" -o, --output=filename Outputfile, default: stdout.\n"
-"\n"
-" -?, --help Give this help list\n"
-" --usage Give a short usage message\n"
-" -V, --version Print program version\n";
-
-static const char *usage =
-"Usage: pfi2bin [-cv?V] [-j pdd-file] [-o filename] [--copyright]\n"
-" [--verbose] [--platform=pdd-file] [--output=filename] [--help]\n"
-" [--usage] [--version] pfifile\n";
-
-struct option long_options[] = {
- { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' },
- { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' },
- { .name = "platform", .has_arg = 1, .flag = NULL, .val = 'j' },
- { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
- { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
- { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
- { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
- { NULL, 0, NULL, 0}
-};
-
-typedef struct io {
- FILE* fp_pdd; /* a FilePointer to the PDD data */
- FILE* fp_pfi; /* a FilePointer to the PFI input stream */
- FILE* fp_out; /* a FilePointer to the output stream */
-} *io_t;
-
-typedef struct myargs {
- /* common settings */
- action_t action;
- int verbose;
- const char *f_in_pfi;
- const char *f_in_pdd;
- const char *f_out;
-
- /* special stuff needed to get additional arguments */
- char *arg1;
- char **options; /* [STRING...] */
-} myargs;
-
-static int
-parse_opt(int argc, char **argv, myargs *args)
-{
- while (1) {
- int key;
-
- key = getopt_long(argc, argv, "cvj:o:?V", long_options, NULL);
- if (key == -1)
- break;
-
- switch (key) {
- /* common settings */
- case 'v': /* --verbose=<level> */
- args->verbose = 1;
- break;
-
- case 'c': /* --copyright */
- fprintf(stderr, "%s\n", copyright);
- exit(0);
- break;
-
- case 'j': /* --platform */
- args->f_in_pdd = optarg;
- break;
-
- case 'o': /* --output */
- args->f_out = optarg;
- break;
-
- case '?': /* help */
- printf("pfi2bin [OPTION...] pfifile\n");
- printf("%s", doc);
- printf("%s", optionsstr);
- printf("\nReport bugs to %s\n",
- PACKAGE_BUGREPORT);
- exit(0);
- break;
-
- case 'V':
- printf("%s\n", PROGRAM_VERSION);
- exit(0);
- break;
-
- default:
- printf("%s", usage);
- exit(-1);
- }
- }
-
- if (optind < argc)
- args->f_in_pfi = argv[optind++];
-
- return 0;
-}
-
-
-static size_t
-byte_to_blk(size_t byte, size_t blk_size)
-{
- return (byte % blk_size) == 0
- ? byte / blk_size
- : byte / blk_size + 1;
-}
-
-
-
-
-/**
- * @precondition IO: File stream points to first byte of RAW data.
- * @postcondition IO: File stream points to first byte of next
- * or EOF.
- */
-static int
-memorize_raw_eb(pfi_raw_t pfi_raw, pdd_data_t pdd, list_t *raw_pebs,
- io_t io)
-{
- int rc = 0;
- uint32_t i;
-
- size_t read, to_read, eb_num;
- size_t bytes_left;
- list_t pebs = *raw_pebs;
- peb_t peb = NULL;
-
- long old_file_pos = ftell(io->fp_pfi);
- for (i = 0; i < pfi_raw->starts_size; i++) {
- bytes_left = pfi_raw->data_size;
- rc = fseek(io->fp_pfi, old_file_pos, SEEK_SET);
- if (rc != 0)
- goto err;
-
- eb_num = byte_to_blk(pfi_raw->starts[i], pdd->eb_size);
- while (bytes_left) {
- to_read = MIN(bytes_left, pdd->eb_size);
- rc = peb_new(eb_num++, pdd->eb_size, &peb);
- if (rc != 0)
- goto err;
- read = fread(peb->data, 1, to_read, io->fp_pfi);
- if (read != to_read) {
- rc = -EIO;
- goto err;
- }
- pebs = append_elem(peb, pebs);
- bytes_left -= read;
- }
-
- }
- *raw_pebs = pebs;
- return 0;
-err:
- pebs = remove_all((free_func_t)&peb_free, pebs);
- return rc;
-}
-
-static int
-convert_ubi_volume(pfi_ubi_t ubi, pdd_data_t pdd, list_t raw_pebs,
- struct ubi_vtbl_record *vol_tab,
- size_t *ebs_written, io_t io)
-{
- int rc = 0;
- uint32_t i, j;
- peb_t raw_peb;
- peb_t cmp_peb;
- ubi_info_t u;
- size_t leb_total = 0;
- uint8_t vol_type;
-
- switch (ubi->type) {
- case pfi_ubi_static:
- vol_type = UBI_VID_STATIC; break;
- case pfi_ubi_dynamic:
- vol_type = UBI_VID_DYNAMIC; break;
- default:
- vol_type = UBI_VID_DYNAMIC;
- }
-
- rc = peb_new(0, 0, &cmp_peb);
- if (rc != 0)
- goto err;
-
- long old_file_pos = ftell(io->fp_pfi);
- for (i = 0; i < ubi->ids_size; i++) {
- rc = fseek(io->fp_pfi, old_file_pos, SEEK_SET);
- if (rc != 0)
- goto err;
- rc = ubigen_create(&u, ubi->ids[i], vol_type,
- pdd->eb_size, DEFAULT_ERASE_COUNT,
- ubi->alignment, UBI_VERSION,
- pdd->vid_hdr_offset, 0, ubi->data_size,
- io->fp_pfi, io->fp_out);
- if (rc != 0)
- goto err;
-
- rc = ubigen_get_leb_total(u, &leb_total);
- if (rc != 0)
- goto err;
-
- j = 0;
- while(j < leb_total) {
- cmp_peb->num = *ebs_written;
- raw_peb = is_in((cmp_func_t)peb_cmp, cmp_peb,
- raw_pebs);
- if (raw_peb) {
- rc = peb_write(io->fp_out, raw_peb);
- }
- else {
- rc = ubigen_write_leb(u, NO_ERROR);
- j++;
- }
- if (rc != 0)
- goto err;
- (*ebs_written)++;
- }
- /* memorize volume table entry */
- rc = ubigen_set_lvol_rec(u, ubi->size,
- ubi->names[i],
- (void*) &vol_tab[ubi->ids[i]]);
- if (rc != 0)
- goto err;
- ubigen_destroy(&u);
- }
-
- peb_free(&cmp_peb);
- return 0;
-
-err:
- peb_free(&cmp_peb);
- ubigen_destroy(&u);
- return rc;
-}
-
-
-static FILE*
-my_fmemopen (void *buf, size_t size, const char *opentype)
-{
- FILE* f;
- size_t ret;
-
- assert(strcmp(opentype, "r") == 0);
-
- f = tmpfile();
- ret = fwrite(buf, 1, size, f);
- rewind(f);
-
- return f;
-}
-
-/**
- * @brief Builds a UBI volume table from a volume entry list.
- * @return 0 On success.
- * else Error.
- */
-static int
-write_ubi_volume_table(pdd_data_t pdd, list_t raw_pebs,
- struct ubi_vtbl_record *vol_tab, size_t vol_tab_size,
- size_t *ebs_written, io_t io)
-{
- int rc = 0;
- ubi_info_t u;
- peb_t raw_peb;
- peb_t cmp_peb;
- size_t leb_size, leb_total, j = 0;
- uint8_t *ptr = NULL;
- FILE* fp_leb = NULL;
- int vt_slots;
- size_t vol_tab_size_limit;
-
- rc = peb_new(0, 0, &cmp_peb);
- if (rc != 0)
- goto err;
-
- /* @FIXME: Artem creates one volume with 2 LEBs.
- * IMO 2 volumes would be more convenient. In order
- * to get 2 reserved LEBs from ubigen, I have to
- * introduce this stupid mechanism. Until no final
- * decision of the VTAB structure is made... Good enough.
- */
- rc = ubigen_create(&u, UBI_LAYOUT_VOLUME_ID, UBI_VID_DYNAMIC,
- pdd->eb_size, DEFAULT_ERASE_COUNT,
- 1, UBI_VERSION,
- pdd->vid_hdr_offset, UBI_COMPAT_REJECT,
- vol_tab_size, stdin, io->fp_out);
- /* @FIXME stdin for fp_in is a hack */
- if (rc != 0)
- goto err;
- rc = ubigen_get_leb_size(u, &leb_size);
- if (rc != 0)
- goto err;
- ubigen_destroy(&u);
-
- /*
- * The number of supported volumes is restricted by the eraseblock size
- * and by the UBI_MAX_VOLUMES constant.
- */
- vt_slots = leb_size / UBI_VTBL_RECORD_SIZE;
- if (vt_slots > UBI_MAX_VOLUMES)
- vt_slots = UBI_MAX_VOLUMES;
- vol_tab_size_limit = vt_slots * UBI_VTBL_RECORD_SIZE;
-
- ptr = (uint8_t*) malloc(leb_size * sizeof(uint8_t));
- if (ptr == NULL)
- goto err;
-
- memset(ptr, 0xff, leb_size);
- memcpy(ptr, vol_tab, vol_tab_size_limit);
- fp_leb = my_fmemopen(ptr, leb_size, "r");
-
- rc = ubigen_create(&u, UBI_LAYOUT_VOLUME_ID, UBI_VID_DYNAMIC,
- pdd->eb_size, DEFAULT_ERASE_COUNT,
- 1, UBI_VERSION, pdd->vid_hdr_offset,
- UBI_COMPAT_REJECT, leb_size * UBI_LAYOUT_VOLUME_EBS,
- fp_leb, io->fp_out);
- if (rc != 0)
- goto err;
- rc = ubigen_get_leb_total(u, &leb_total);
- if (rc != 0)
- goto err;
-
- long old_file_pos = ftell(fp_leb);
- while(j < leb_total) {
- rc = fseek(fp_leb, old_file_pos, SEEK_SET);
- if (rc != 0)
- goto err;
-
- cmp_peb->num = *ebs_written;
- raw_peb = is_in((cmp_func_t)peb_cmp, cmp_peb,
- raw_pebs);
- if (raw_peb) {
- rc = peb_write(io->fp_out, raw_peb);
- }
- else {
- rc = ubigen_write_leb(u, NO_ERROR);
- j++;
- }
-
- if (rc != 0)
- goto err;
- (*ebs_written)++;
- }
-
-err:
- free(ptr);
- peb_free(&cmp_peb);
- ubigen_destroy(&u);
- fclose(fp_leb);
- return rc;
-}
-
-static int
-write_remaining_raw_ebs(pdd_data_t pdd, list_t raw_blocks, size_t *ebs_written,
- FILE* fp_out)
-{
- int rc = 0;
- uint32_t j, delta;
- list_t ptr;
- peb_t empty_eb, peb;
-
- /* create an empty 0xff EB (for padding) */
- rc = peb_new(0, pdd->eb_size, &empty_eb);
-
- foreach(peb, ptr, raw_blocks) {
- if (peb->num < *ebs_written) {
- continue; /* omit blocks which
- are already passed */
- }
-
- if (peb->num < *ebs_written) {
- err_msg("eb_num: %d\n", peb->num);
- err_msg("Bug: This should never happen. %d %s",
- __LINE__, __FILE__);
- goto err;
- }
-
- delta = peb->num - *ebs_written;
- if (((delta + *ebs_written) * pdd->eb_size) > pdd->flash_size) {
- err_msg("RAW block outside of flash_size.");
- goto err;
- }
- for (j = 0; j < delta; j++) {
- rc = peb_write(fp_out, empty_eb);
- if (rc != 0)
- goto err;
- (*ebs_written)++;
- }
- rc = peb_write(fp_out, peb);
- if (rc != 0)
- goto err;
- (*ebs_written)++;
- }
-
-err:
- peb_free(&empty_eb);
- return rc;
-}
-
-static int
-init_vol_tab(struct ubi_vtbl_record **vol_tab, size_t *vol_tab_size)
-{
- uint32_t crc;
- size_t i;
- struct ubi_vtbl_record* res = NULL;
-
- *vol_tab_size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE;
-
- res = (struct ubi_vtbl_record*) calloc(1, *vol_tab_size);
- if (vol_tab == NULL) {
- return -ENOMEM;
- }
-
- for (i = 0; i < UBI_MAX_VOLUMES; i++) {
- crc = clc_crc32(crc32_table, UBI_CRC32_INIT,
- &(res[i]), UBI_VTBL_RECORD_SIZE_CRC);
- res[i].crc = cpu_to_be32(crc);
- }
-
- *vol_tab = res;
- return 0;
-}
-
-static int
-create_raw(io_t io)
-{
- int rc = 0;
- size_t ebs_written = 0; /* eraseblocks written already... */
- size_t vol_tab_size;
- list_t ptr;
-
- list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */
- list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */
- list_t raw_pebs = mk_empty(); /* list of raw eraseblocks */
-
- struct ubi_vtbl_record *vol_tab = NULL;
- pdd_data_t pdd = NULL;
-
- rc = init_vol_tab (&vol_tab, &vol_tab_size);
- if (rc != 0) {
- err_msg("Cannot initialize volume table.");
- goto err;
- }
-
- rc = read_pdd_data(io->fp_pdd, &pdd,
- err_buf, ERR_BUF_SIZE);
- if (rc != 0) {
- err_msg("Cannot read necessary pdd_data: %s rc: %d",
- err_buf, rc);
- goto err;
- }
-
- rc = read_pfi_headers(&pfi_raws, &pfi_ubis, io->fp_pfi,
- err_buf, ERR_BUF_SIZE);
- if (rc != 0) {
- err_msg("Cannot read pfi header: %s rc: %d",
- err_buf, rc);
- goto err;
- }
-
- pfi_raw_t pfi_raw;
- foreach(pfi_raw, ptr, pfi_raws) {
- rc = memorize_raw_eb(pfi_raw, pdd, &raw_pebs,
- io);
- if (rc != 0) {
- err_msg("Cannot create raw_block in mem. rc: %d\n",
- rc);
- goto err;
- }
- }
-
- pfi_ubi_t pfi_ubi;
- foreach(pfi_ubi, ptr, pfi_ubis) {
- rc = convert_ubi_volume(pfi_ubi, pdd, raw_pebs,
- vol_tab, &ebs_written, io);
- if (rc != 0) {
- err_msg("Cannot convert UBI volume. rc: %d\n", rc);
- goto err;
- }
- }
-
- rc = write_ubi_volume_table(pdd, raw_pebs, vol_tab, vol_tab_size,
- &ebs_written, io);
- if (rc != 0) {
- err_msg("Cannot write UBI volume table. rc: %d\n", rc);
- goto err;
- }
-
- rc = write_remaining_raw_ebs(pdd, raw_pebs, &ebs_written, io->fp_out);
- if (rc != 0)
- goto err;
-
- if (io->fp_out != stdout)
- info_msg("Physical eraseblocks written: %8d\n", ebs_written);
-err:
- free(vol_tab);
- pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws);
- pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, pfi_ubis);
- raw_pebs = remove_all((free_func_t)&peb_free, raw_pebs);
- free_pdd_data(&pdd);
- return rc;
-}
-
-
-/* ------------------------------------------------------------------------- */
-static void
-open_io_handle(myargs *args, io_t io)
-{
- /* set PDD input */
- io->fp_pdd = fopen(args->f_in_pdd, "r");
- if (io->fp_pdd == NULL) {
- err_sys("Cannot open: %s", args->f_in_pdd);
- }
-
- /* set PFI input */
- io->fp_pfi = fopen(args->f_in_pfi, "r");
- if (io->fp_pfi == NULL) {
- err_sys("Cannot open PFI input file: %s", args->f_in_pfi);
- }
-
- /* set output prefix */
- if (strcmp(args->f_out,"") == 0)
- io->fp_out = stdout;
- else {
- io->fp_out = fopen(args->f_out, "wb");
- if (io->fp_out == NULL) {
- err_sys("Cannot open output file: %s", args->f_out);
- }
- }
-}
-
-static void
-close_io_handle(io_t io)
-{
- if (fclose(io->fp_pdd) != 0) {
- err_sys("Cannot close PDD file.");
- }
- if (fclose(io->fp_pfi) != 0) {
- err_sys("Cannot close PFI file.");
- }
- if (io->fp_out != stdout) {
- if (fclose(io->fp_out) != 0) {
- err_sys("Cannot close output file.");
- }
- }
-
- io->fp_pdd = NULL;
- io->fp_pfi = NULL;
- io->fp_out = NULL;
-}
-
-int
-main(int argc, char *argv[])
-{
- int rc = 0;
-
- ubigen_init();
- init_crc32_table(crc32_table);
-
- struct io io = {NULL, NULL, NULL};
- myargs args = {
- .action = ACT_RAW,
- .verbose = 0,
-
- .f_in_pfi = "",
- .f_in_pdd = "",
- .f_out = "",
-
- /* arguments */
- .arg1 = NULL,
- .options = NULL,
- };
-
- /* parse arguments */
- parse_opt(argc, argv, &args);
-
- if (strcmp(args.f_in_pfi, "") == 0) {
- err_quit("No PFI input file specified!");
- }
-
- if (strcmp(args.f_in_pdd, "") == 0) {
- err_quit("No PDD input file specified!");
- }
-
- open_io_handle(&args, &io);
-
- info_msg("[ Creating RAW...");
- rc = create_raw(&io);
- if (rc != 0) {
- err_msg("Creating RAW failed.");
- goto err;
- }
-
-err:
- close_io_handle(&io);
- if (rc != 0) {
- remove(args.f_out);
- }
-
- return rc;
-}
diff --git a/ubi-utils/src/pfiflash.c b/ubi-utils/src/pfiflash.c
deleted file mode 100644
index 754fe33..0000000
--- a/ubi-utils/src/pfiflash.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * 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.
- *
- * Author: Oliver Lohmann
- * Frank Haverkamp
- *
- * Process a PFI (partial flash image) and write the data to the
- * specified UBI volumes. This tool is intended to be used for system
- * update using PFI files.
- *
- * 1.1 fixed output to stderr and stdout in logfile mode.
- * 1.2 updated.
- * 1.3 removed argp parsing to be able to use uClib.
- * 1.4 Minor cleanups.
- * 1.5 Forgot to delete raw block before updating it.
- * 1.6 Migrated to new libubi.
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <pfiflash.h>
-#undef DEBUG
-#include "error.h"
-#include "config.h"
-
-#define PROGRAM_VERSION "1.6"
-
-static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
- "pfiflash - a tool for updating a controller with PFI files.\n";
-
-static const char *optionsstr =
-" Standard options:\n"
-" -c, --copyright Print copyright information.\n"
-" -l, --logfile=<file> Write a logfile to <file>.\n"
-" -v, --verbose Be verbose during program execution.\n"
-"\n"
-" Process options:\n"
-" -C, --complete Execute a complete system update. Updates both\n"
-" sides.\n"
-" -p, --pdd-update=<type> Specify the pdd-update algorithm. <type> is either\n"
-" 'keep', 'merge' or 'overwrite'.\n"
-" -r, --raw-flash=<dev> Flash the raw data. Use the specified mtd device.\n"
-" -s, --side=<seqnum> Select the side which shall be updated.\n"
-" -x, --compare Only compare on-flash and pfi data, print info if\n"
-" an update is neccessary and return appropriate\n"
-" error code.\n"
-"\n"
-" -?, --help Give this help list\n"
-" --usage Give a short usage message\n"
-" -V, --version Print program version\n";
-
-static const char *usage =
-"Usage: pfiflash [-cvC?V] [-l <file>] [-p <type>] [-r <dev>] [-s <seqnum>]\n"
-" [--copyright] [--logfile=<file>] [--verbose] [--complete]\n"
-" [--pdd-update=<type>] [--raw-flash=<dev>] [--side=<seqnum>]\n"
-" [--compare] [--help] [--usage] [--version] [pfifile]\n";
-
-static const char copyright [] __attribute__((unused)) =
- "Copyright IBM Corp 2006";
-
-struct option long_options[] = {
- { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' },
- { .name = "logfile", .has_arg = 1, .flag = NULL, .val = 'l' },
- { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' },
- { .name = "complete", .has_arg = 0, .flag = NULL, .val = 'C' },
- { .name = "pdd-update", .has_arg = 1, .flag = NULL, .val = 'p' },
- { .name = "raw-flash", .has_arg = 1, .flag = NULL, .val = 'r' },
- { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' },
- { .name = "compare", .has_arg = 0, .flag = NULL, .val = 'x' },
- { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
- { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
- { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
- { NULL, 0, NULL, 0}
-};
-
-typedef struct myargs {
- int verbose;
- const char *logfile;
- const char *raw_dev;
-
- pdd_handling_t pdd_handling;
- int seqnum;
- int compare;
- int complete;
-
- FILE* fp_in;
-
- /* special stuff needed to get additional arguments */
- char *arg1;
- char **options; /* [STRING...] */
-} myargs;
-
-static pdd_handling_t
-get_pdd_handling(const char* str)
-{
- if (strcmp(str, "keep") == 0) {
- return PDD_KEEP;
- }
- if (strcmp(str, "merge") == 0) {
- return PDD_MERGE;
- }
- if (strcmp(str, "overwrite") == 0) {
- return PDD_OVERWRITE;
- }
-
- return -1;
-}
-
-static int
-get_update_seqnum(const char* str)
-{
- uint32_t i = strtoul(str, NULL, 0);
-
- if ((i != 0) && (i != 1)) {
- return -1;
- }
-
- return i;
-}
-
-
-static int
-parse_opt(int argc, char **argv, myargs *args)
-{
- while (1) {
- int key;
-
- key = getopt_long(argc, argv, "cl:vCp:r:s:x?V",
- long_options, NULL);
- if (key == -1)
- break;
-
- switch (key) {
- /* standard options */
- case 'c':
- err_msg("%s\n", copyright);
- exit(0);
- break;
- case 'v':
- args->verbose = 1;
- break;
- case 'l':
- args->logfile = optarg;
- break;
- /* process options */
- case 'C':
- args->complete = 1;
- break;
- case 'p':
- args->pdd_handling = get_pdd_handling(optarg);
- if ((int)args->pdd_handling < 0) {
- err_quit("Unknown PDD handling: %s.\n"
- "Please use either "
- "'keep', 'merge' or"
- "'overwrite'.\n'");
- }
- break;
- case 's':
- args->seqnum = get_update_seqnum(optarg);
- if (args->seqnum < 0) {
- err_quit("Unsupported side: %s.\n"
- "Supported sides are '0' "
- "and '1'\n", optarg);
- }
- break;
- case 'x':
- args->compare = 1;
- break;
- case 'r':
- args->raw_dev = optarg;
- break;
- case '?': /* help */
- err_msg("Usage: pfiflash [OPTION...] [pfifile]");
- err_msg("%s", doc);
- err_msg("%s", optionsstr);
- err_msg("\nReport bugs to %s\n",
- PACKAGE_BUGREPORT);
- exit(0);
- break;
- case 'V':
- err_msg("%s", PROGRAM_VERSION);
- exit(0);
- break;
- default:
- err_msg("%s", usage);
- exit(-1);
-
- }
- }
-
- if (optind < argc) {
- args->fp_in = fopen(argv[optind++], "r");
- if ((args->fp_in) == NULL) {
- err_sys("Cannot open PFI file %s for input",
- argv[optind]);
- }
- }
-
- return 0;
-}
-
-int main (int argc, char** argv)
-{
- int rc = 0;
- char err_buf[PFIFLASH_MAX_ERR_BUF_SIZE];
- memset(err_buf, '\0', PFIFLASH_MAX_ERR_BUF_SIZE);
-
- myargs args = {
- .verbose = 0,
- .seqnum = -1,
- .compare = 0,
- .complete = 0,
- .logfile = NULL, /* "/tmp/pfiflash.log", */
- .pdd_handling = PDD_KEEP,
- .fp_in = stdin,
- .raw_dev = NULL,
- };
-
- parse_opt(argc, argv, &args);
- error_initlog(args.logfile);
-
- if (!args.fp_in) {
- rc = -1;
- snprintf(err_buf, PFIFLASH_MAX_ERR_BUF_SIZE,
- "No PFI input file specified!\n");
- goto err;
- }
-
- rc = pfiflash_with_options(args.fp_in, args.complete, args.seqnum,
- args.compare, args.pdd_handling, args.raw_dev, err_buf,
- PFIFLASH_MAX_ERR_BUF_SIZE);
- if (rc < 0) {
- goto err_fp;
- }
-
- err_fp:
- if (args.fp_in != stdin)
- fclose(args.fp_in);
- err:
- if (rc != 0)
- err_msg("pfiflash: %s\nrc: %d\n", err_buf, rc);
- return rc;
-}
diff --git a/ubi-utils/src/pfiflash.h b/ubi-utils/src/pfiflash.h
deleted file mode 100644
index 039705d..0000000
--- a/ubi-utils/src/pfiflash.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef __PFIFLASH_H__
-#define __PFIFLASH_H__
-/*
- * 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.
- */
-
-/**
- *
- * @file pfi.h
- *
- * @author Oliver Lohmann <oliloh@de.ibm.com>
- *
- * @brief The pfiflash library offers an interface for using the
- * pfiflash * utility.
- */
-
-#include <stdio.h> /* FILE */
-
-#define PFIFLASH_MAX_ERR_BUF_SIZE 1024
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum pdd_handling_t
-{
- PDD_KEEP = 0,
- PDD_MERGE,
- PDD_OVERWRITE,
- PDD_HANDLING_NUM, /* always the last item */
-} pdd_handling_t; /**< Possible PDD handle algorithms. */
-
-/**
- * @brief Flashes a PFI file to UBI Device 0.
- * @param complete [0|1] Do a complete system update.
- * @param seqnum Index in a redundant group.
- * @param compare [0|1] Compare contents.
- * @param pdd_handling The PDD handling algorithm.
- * @param rawdev Device to use for raw flashing
- * @param err_buf An error buffer.
- * @param err_buf_size Size of the error buffer.
- */
-int pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare,
- pdd_handling_t pdd_handling, const char* rawdev,
- char *err_buf, size_t err_buf_size);
-
-/**
- * @brief Flashes a PFI file to UBI Device 0.
- * @param complete [0|1] Do a complete system update.
- * @param seqnum Index in a redundant group.
- * @param pdd_handling The PDD handling algorithm.
- * @param err_buf An error buffer.
- * @param err_buf_size Size of the error buffer.
- */
-int pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling,
- char *err_buf, size_t err_buf_size);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __PFIFLASH_H__ */
diff --git a/ubi-utils/src/pfiflash_error.h b/ubi-utils/src/pfiflash_error.h
deleted file mode 100644
index 0f27f4a..0000000
--- a/ubi-utils/src/pfiflash_error.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#ifndef __PFIFLASH_ERROR_H__
-#define __PFIFLASH_ERROR_H__
-/*
- * 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.
- */
-
-/*
- * Author: Drake Dowsett <dowsett@de.ibm.com>
- * Contact: Andreas Arnez <arnez@de.ibm.com>
- */
-
-enum pfiflash_err {
- PFIFLASH_ERR_EOF = 1,
- PFIFLASH_ERR_FIO,
- PFIFLASH_ERR_UBI_OPEN,
- PFIFLASH_ERR_UBI_CLOSE,
- PFIFLASH_ERR_UBI_MKVOL,
- PFIFLASH_ERR_UBI_RMVOL,
- PFIFLASH_ERR_UBI_VOL_UPDATE,
- PFIFLASH_ERR_UBI_VOL_FOPEN,
- PFIFLASH_ERR_UBI_UNKNOWN,
- PFIFLASH_ERR_UBI_VID_OOB,
- PFIFLASH_ERR_BOOTENV_CREATE,
- PFIFLASH_ERR_BOOTENV_READ,
- PFIFLASH_ERR_BOOTENV_SIZE,
- PFIFLASH_ERR_BOOTENV_WRITE,
- PFIFLASH_ERR_PDD_UNKNOWN,
- PFIFLASH_ERR_MTD_OPEN,
- PFIFLASH_ERR_MTD_CLOSE,
- PFIFLASH_ERR_CRC_CHECK,
- PFIFLASH_ERR_MTD_ERASE,
- PFIFLASH_ERR_COMPARE,
- PFIFLASH_CMP_DIFF
-};
-
-const char *const PFIFLASH_ERRSTR[] = {
- "",
- "unexpected EOF",
- "file I/O error",
- "couldn't open UBI",
- "couldn't close UBI",
- "couldn't make UBI volume %d",
- "couldn't remove UBI volume %d",
- "couldn't update UBI volume %d",
- "couldn't open UBI volume %d",
- "unknown UBI operation",
- "PFI data contains out of bounds UBI id %d",
- "couldn't create bootenv%s",
- "couldn't read bootenv",
- "couldn't resize bootenv",
- "couldn't write bootenv on ubi%d_%d",
- "unknown PDD handling algorithm",
- "couldn't open MTD device %s",
- "couldn't close MTD device %s",
- "CRC check failed: given=0x%08x, calculated=0x%08x",
- "couldn't erase raw mtd region",
- "couldn't compare volumes",
- "on-flash data differ from pfi data, update is neccessary"
-};
-
-#endif /* __PFIFLASH_ERROR_H__ */
diff --git a/ubi-utils/src/reader.c b/ubi-utils/src/reader.c
deleted file mode 100644
index 0ea8c6d..0000000
--- a/ubi-utils/src/reader.c
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * 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.
- *
- * Author: Oliver Lohmann
- *
- * Read in PFI (partial flash image) data and store it into internal
- * data structures for further processing. Take also care about
- * special handling if the data contains PDD (platform description
- * data/boot-parameters).
- */
-
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include "bootenv.h"
-#include "reader.h"
-
-#define __unused __attribute__((unused))
-
-/* @FIXME hard coded offsets right now - get them from Artem? */
-#define NAND2048_DEFAULT_VID_HDR_OFF 1984
-#define NAND512_DEFAULT_VID_HDR_OFF 448
-#define NOR_DEFAULT_VID_HDR_OFF 64
-
-#define EBUF_PFI(fmt...) \
- do { int i = snprintf(err_buf, err_buf_size, "%s\n", label); \
- snprintf(err_buf + i, err_buf_size - i, fmt); \
- } while (0)
-
-#define EBUF(fmt...) \
- do { snprintf(err_buf, err_buf_size, fmt); } while (0)
-
-
-int
-read_pdd_data(FILE* fp_pdd, pdd_data_t* pdd_data,
- char* err_buf, size_t err_buf_size)
-{
- int rc = 0;
- bootenv_t pdd = NULL;
- pdd_data_t res = NULL;
- const char* value;
-
- res = (pdd_data_t) malloc(sizeof(struct pdd_data));
- if (!res) {
- rc = -ENOMEM;
- goto err;
- }
- rc = bootenv_create(&pdd);
- if (rc != 0) {
- goto err;
- }
- rc = bootenv_read_txt(fp_pdd, pdd);
- if (rc != 0) {
- goto err;
- }
- rc = bootenv_get(pdd, "flash_type", &value);
- if (rc != 0) {
- goto err;
- }
-
- if (strcmp(value, "NAND") == 0) {
-
- rc = bootenv_get_num(pdd, "flash_page_size",
- &(res->flash_page_size));
- if (rc != 0) {
- EBUF("Cannot read 'flash_page_size' from pdd.");
- goto err;
- }
- res->flash_type = NAND_FLASH;
-
- switch (res->flash_page_size) {
- case 512:
- res->vid_hdr_offset = NAND512_DEFAULT_VID_HDR_OFF;
- break;
- case 2048:
- res->vid_hdr_offset = NAND2048_DEFAULT_VID_HDR_OFF;
- break;
- default:
- EBUF("Unsupported 'flash_page_size' %d.",
- res->flash_page_size);
- goto err;
- }
- }
- else if (strcmp(value, "NOR") == 0){
- res->flash_type = NOR_FLASH;
- res->vid_hdr_offset = NOR_DEFAULT_VID_HDR_OFF;
- }
- else {
- snprintf(err_buf, err_buf_size,
- "Unkown flash type: %s", value);
- goto err;
- }
-
- rc = bootenv_get_num(pdd, "flash_eraseblock_size",
- &(res->eb_size));
- if (rc != 0) {
- EBUF("Cannot read 'flash_eraseblock_size' from pdd.");
- goto err;
- }
-
- rc = bootenv_get_num(pdd, "flash_size",
- &(res->flash_size));
- if (rc != 0) {
- EBUF("Cannot read 'flash_size' from pdd.");
- goto err;
- }
-
- goto out;
- err:
- if (res) {
- free(res);
- res = NULL;
- }
- out:
- bootenv_destroy(&pdd);
- *pdd_data = res;
- return rc;
-}
-
-int
-read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_raw_t* pfi_raw,
- const char* label, char* err_buf, size_t err_buf_size)
-{
- int rc = 0;
- char tmp_str[PFI_KEYWORD_LEN];
- bootenv_list_t raw_start_list = NULL;
- pfi_raw_t res;
- size_t size;
-
- res = (pfi_raw_t) malloc(sizeof(struct pfi_raw));
- if (!res)
- return -ENOMEM;
-
- rc = pfi_header_getnumber(pfi_hd, "size", &(res->data_size));
- if (rc != 0) {
- EBUF_PFI("Cannot read 'size' from PFI.");
- goto err;
- }
-
- rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc));
- if (rc != 0) {
- EBUF_PFI("Cannot read 'crc' from PFI.");
- goto err;
- }
-
- rc = pfi_header_getstring(pfi_hd, "raw_starts",
- tmp_str, PFI_KEYWORD_LEN);
- if (rc != 0) {
- EBUF_PFI("Cannot read 'raw_starts' from PFI.");
- goto err;
- }
-
- rc = bootenv_list_create(&raw_start_list);
- if (rc != 0) {
- goto err;
- }
-
- rc = bootenv_list_import(raw_start_list, tmp_str);
- if (rc != 0) {
- EBUF_PFI("Cannot translate PFI value: %s", tmp_str);
- goto err;
- }
-
- rc = bootenv_list_to_num_vector(raw_start_list,
- &size, &(res->starts));
- res->starts_size = size;
-
- if (rc != 0) {
- EBUF_PFI("Cannot create numeric value array: %s", tmp_str);
- goto err;
- }
-
- goto out;
-
- err:
- if (res) {
- free(res);
- res = NULL;
- }
- out:
- bootenv_list_destroy(&raw_start_list);
- *pfi_raw = res;
- return rc;
-}
-
-int
-read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_ubi_t* pfi_ubi,
- const char *label, char* err_buf, size_t err_buf_size)
-{
- int rc = 0;
- const char** tmp_names = NULL;
- char tmp_str[PFI_KEYWORD_LEN];
- bootenv_list_t ubi_id_list = NULL;
- bootenv_list_t ubi_name_list = NULL;
- pfi_ubi_t res;
- uint32_t i;
- size_t size;
-
- res = (pfi_ubi_t) calloc(1, sizeof(struct pfi_ubi));
- if (!res)
- return -ENOMEM;
-
- rc = pfi_header_getnumber(pfi_hd, "size", &(res->data_size));
- if (rc != 0) {
- EBUF_PFI("Cannot read 'size' from PFI.");
- goto err;
- }
-
- rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc));
- if (rc != 0) {
- EBUF_PFI("Cannot read 'crc' from PFI.");
- goto err;
- }
-
- rc = pfi_header_getstring(pfi_hd, "ubi_ids", tmp_str, PFI_KEYWORD_LEN);
- if (rc != 0) {
- EBUF_PFI("Cannot read 'ubi_ids' from PFI.");
- goto err;
- }
-
- rc = bootenv_list_create(&ubi_id_list);
- if (rc != 0) {
- goto err;
- }
- rc = bootenv_list_create(&ubi_name_list);
- if (rc != 0) {
- goto err;
- }
-
- rc = bootenv_list_import(ubi_id_list, tmp_str);
- if (rc != 0) {
- EBUF_PFI("Cannot translate PFI value: %s", tmp_str);
- goto err;
- }
-
- rc = bootenv_list_to_num_vector(ubi_id_list, &size,
- &(res->ids));
- res->ids_size = size;
- if (rc != 0) {
- EBUF_PFI("Cannot create numeric value array: %s", tmp_str);
- goto err;
- }
-
- if (res->ids_size == 0) {
- rc = -1;
- EBUF_PFI("Sanity check failed: No ubi_ids specified.");
- goto err;
- }
-
- rc = pfi_header_getstring(pfi_hd, "ubi_type",
- tmp_str, PFI_KEYWORD_LEN);
- if (rc != 0) {
- EBUF_PFI("Cannot read 'ubi_type' from PFI.");
- goto err;
- }
- if (strcmp(tmp_str, "static") == 0)
- res->type = pfi_ubi_static;
- else if (strcmp(tmp_str, "dynamic") == 0)
- res->type = pfi_ubi_dynamic;
- else {
- EBUF_PFI("Unknown ubi_type in PFI.");
- goto err;
- }
-
- rc = pfi_header_getnumber(pfi_hd, "ubi_alignment", &(res->alignment));
- if (rc != 0) {
- EBUF_PFI("Cannot read 'ubi_alignment' from PFI.");
- goto err;
- }
-
- rc = pfi_header_getnumber(pfi_hd, "ubi_size", &(res->size));
- if (rc != 0) {
- EBUF_PFI("Cannot read 'ubi_size' from PFI.");
- goto err;
- }
-
- rc = pfi_header_getstring(pfi_hd, "ubi_names",
- tmp_str, PFI_KEYWORD_LEN);
- if (rc != 0) {
- EBUF_PFI("Cannot read 'ubi_names' from PFI.");
- goto err;
- }
-
- rc = bootenv_list_import(ubi_name_list, tmp_str);
- if (rc != 0) {
- EBUF_PFI("Cannot translate PFI value: %s", tmp_str);
- goto err;
- }
- rc = bootenv_list_to_vector(ubi_name_list, &size,
- &(tmp_names));
- res->names_size = size;
- if (rc != 0) {
- EBUF_PFI("Cannot create string array: %s", tmp_str);
- goto err;
- }
-
- if (res->names_size != res->ids_size) {
- EBUF_PFI("Sanity check failed: ubi_ids list does not match "
- "sizeof ubi_names list.");
- rc = -1;
- }
-
- /* copy tmp_names to own structure */
- res->names = (char**) calloc(1, res->names_size * sizeof (char*));
- if (res->names == NULL)
- goto err;
-
- for (i = 0; i < res->names_size; i++) {
- res->names[i] = calloc(PFI_UBI_VOL_NAME_LEN + 1, sizeof(char));
- if (res->names[i] == NULL)
- goto err;
- strncpy(res->names[i], tmp_names[i], PFI_UBI_VOL_NAME_LEN + 1);
- }
-
- goto out;
-
- err:
- if (res) {
- if (res->names) {
- for (i = 0; i < res->names_size; i++) {
- if (res->names[i]) {
- free(res->names[i]);
- }
- }
- free(res->names);
- }
- if (res->ids) {
- free(res->ids);
- }
- free(res);
- res = NULL;
- }
-
- out:
- bootenv_list_destroy(&ubi_id_list);
- bootenv_list_destroy(&ubi_name_list);
- if (tmp_names != NULL)
- free(tmp_names);
- *pfi_ubi = res;
- return rc;
-}
-
-
-int
-free_pdd_data(pdd_data_t* pdd_data)
-{
- if (*pdd_data) {
- free(*pdd_data);
- }
- *pdd_data = NULL;
-
- return 0;
-}
-
-int
-free_pfi_raw(pfi_raw_t* pfi_raw)
-{
- pfi_raw_t tmp = *pfi_raw;
- if (tmp) {
- if (tmp->starts)
- free(tmp->starts);
- free(tmp);
- }
- *pfi_raw = NULL;
-
- return 0;
-}
-
-int
-free_pfi_ubi(pfi_ubi_t* pfi_ubi)
-{
- size_t i;
- pfi_ubi_t tmp = *pfi_ubi;
- if (tmp) {
- if (tmp->ids)
- free(tmp->ids);
- if (tmp->names) {
- for (i = 0; i < tmp->names_size; i++) {
- if (tmp->names[i]) {
- free(tmp->names[i]);
- }
- }
- free(tmp->names);
- }
- free(tmp);
- }
- *pfi_ubi = NULL;
-
- return 0;
-}
-
-
-int
-read_pfi_headers(list_t *pfi_raws, list_t *pfi_ubis, FILE* fp_pfi,
- char* err_buf, size_t err_buf_size)
-{
- int rc = 0;
- char mode[PFI_KEYWORD_LEN];
- char label[PFI_LABEL_LEN];
-
- *pfi_raws = mk_empty(); pfi_raw_t raw = NULL;
- *pfi_ubis = mk_empty(); pfi_ubi_t ubi = NULL;
- pfi_header pfi_header = NULL;
-
- /* read all headers from PFI and store them in lists */
- rc = pfi_header_init(&pfi_header);
- if (rc != 0) {
- EBUF("Cannot initialize pfi header.");
- goto err;
- }
- while ((rc == 0) && !feof(fp_pfi)) {
- rc = pfi_header_read(fp_pfi, pfi_header);
- if (rc != 0) {
- if (rc == PFI_DATA_START) {
- rc = 0;
- break; /* data section starts,
- all headers read */
- }
- else {
- goto err;
- }
- }
- rc = pfi_header_getstring(pfi_header, "label", label,
- PFI_LABEL_LEN);
- if (rc != 0) {
- EBUF("Cannot read 'label' from PFI.");
- goto err;
- }
- rc = pfi_header_getstring(pfi_header, "mode", mode,
- PFI_KEYWORD_LEN);
- if (rc != 0) {
- EBUF("Cannot read 'mode' from PFI.");
- goto err;
- }
- if (strcmp(mode, "ubi") == 0) {
- rc = read_pfi_ubi(pfi_header, fp_pfi, &ubi, label,
- err_buf, err_buf_size);
- if (rc != 0) {
- goto err;
- }
- *pfi_ubis = append_elem(ubi, *pfi_ubis);
- }
- else if (strcmp(mode, "raw") == 0) {
- rc = read_pfi_raw(pfi_header, fp_pfi, &raw, label,
- err_buf, err_buf_size);
- if (rc != 0) {
- goto err;
- }
- *pfi_raws = append_elem(raw, *pfi_raws);
- }
- else {
- EBUF("Recvieved unknown mode from PFI: %s", mode);
- goto err;
- }
- }
- goto out;
-
- err:
- *pfi_raws = remove_all((free_func_t)&free_pfi_raw, *pfi_raws);
- *pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, *pfi_ubis);
- out:
- pfi_header_destroy(&pfi_header);
- return rc;
-
-}
diff --git a/ubi-utils/src/reader.h b/ubi-utils/src/reader.h
deleted file mode 100644
index 715e464..0000000
--- a/ubi-utils/src/reader.h
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifndef __READER_H__
-#define __READER_H__
-/*
- * 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.
- *
- * Author: Oliver Lohmann
- *
- * Read Platform Description Data (PDD).
- */
-
-#include <stdint.h>
-#include <stdio.h>
-
-#include "pfi.h"
-#include "bootenv.h"
-#include "list.h"
-
-typedef enum flash_type_t {
- NAND_FLASH = 0,
- NOR_FLASH,
-} flash_type_t;
-
-typedef struct pdd_data *pdd_data_t;
-typedef struct pfi_raw *pfi_raw_t;
-typedef struct pfi_ubi *pfi_ubi_t;
-
-struct pdd_data {
- uint32_t flash_size;
- uint32_t flash_page_size;
- uint32_t eb_size;
- uint32_t vid_hdr_offset;
- flash_type_t flash_type;
-};
-
-struct pfi_raw {
- uint32_t data_size;
- uint32_t *starts;
- uint32_t starts_size;
- uint32_t crc;
-};
-
-struct pfi_ubi {
- uint32_t data_size;
- uint32_t alignment;
- uint32_t *ids;
- uint32_t ids_size;
- char **names;
- uint32_t names_size;
- uint32_t size;
- enum { pfi_ubi_dynamic, pfi_ubi_static } type;
- int curr_seqnum; /* specifies the seqnum taken in an update,
- default: 0 (used by pfiflash, ubimirror) */
- uint32_t crc;
-};
-
-int read_pdd_data(FILE* fp_pdd, pdd_data_t *pdd_data,
- char *err_buf, size_t err_buf_size);
-int read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi, pfi_raw_t *pfi_raw,
- const char *label, char *err_buf, size_t err_buf_size);
-int read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi, pfi_ubi_t *pfi_ubi,
- const char *label, char *err_buf, size_t err_buf_size);
-
-/**
- * @brief Reads all pfi headers into list structures, separated by
- * RAW and UBI sections.
- */
-int read_pfi_headers(list_t *pfi_raws, list_t *pfi_ubis, FILE* fp_pfi,
- char* err_buf, size_t err_buf_size);
-int free_pdd_data(pdd_data_t *pdd_data);
-int free_pfi_raw(pfi_raw_t *raw_pfi);
-int free_pfi_ubi(pfi_ubi_t *pfi_ubi);
-
-#endif /* __READER_H__ */
diff --git a/ubi-utils/src/ubiattach.c b/ubi-utils/src/ubiattach.c
new file mode 100644
index 0000000..1f72620
--- /dev/null
+++ b/ubi-utils/src/ubiattach.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * 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
+ */
+
+/*
+ * An utility to attach MTD devices to UBI.
+ *
+ * Author: Artem Bityutskiy
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubiattach"
+
+/* The variables below are set by command line arguments */
+struct args {
+ int devn;
+ int mtdn;
+ int vidoffs;
+ const char *node;
+};
+
+static struct args args = {
+ .devn = UBI_DEV_NUM_AUTO,
+ .mtdn = -1,
+ .vidoffs = 0,
+ .node = NULL,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to attach MTD device to UBI.";
+
+static const char *optionsstr =
+"-d, --devn=<UBI device number> the number to assign to the newly created UBI device\n"
+" (the number is assigned automatically if this is not\n"
+" specified\n"
+"-m, --mtdn=<MTD device number> MTD device number to attach\n"
+"-O, --vid-hdr-offset VID header offset (do not specify this unless you\n"
+" really know what you do and the optimal defaults will\n"
+" be used)\n"
+"-h, --help print help message\n"
+"-V, --version print program version";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <UBI control device node file name> [-m <MTD device number>] [-d <UBI device number>]\n"
+"\t\t[--mtdn=<MTD device number>] [--devn <UBI device number>]\n"
+"Example 1: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 - attach MTD device 0 (mtd0) to UBI\n"
+"Example 2: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 -d 3 - attach MTD device 0 (mtd0) to UBI and\n"
+" and create UBI device number 3 (ubi3)";
+
+static const struct option long_options[] = {
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { .name = "mtdn", .has_arg = 1, .flag = NULL, .val = 'm' },
+ { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "m:d:O:hV", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'd':
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: \"%s\"", optarg);
+
+ break;
+
+ case 'm':
+ args.mtdn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.mtdn < 0)
+ return errmsg("bad MTD device number: \"%s\"", optarg);
+
+ break;
+
+ case 'O':
+ args.vidoffs = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.vidoffs <= 0)
+ return errmsg("bad VID header offset: \"%s\"", optarg);
+
+ break;
+
+ case 'h':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (optind == argc)
+ return errmsg("UBI control device name was not specified (use -h for help)");
+ else if (optind != argc - 1)
+ return errmsg("more then one UBI control device specified (use -h for help)");
+
+ if (args.mtdn == -1)
+ return errmsg("MTD device number was not specified (use -h for help)");
+
+ args.node = argv[optind];
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+ struct ubi_info ubi_info;
+ struct ubi_dev_info dev_info;
+ struct ubi_attach_request req;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ libubi = libubi_open(1);
+ if (libubi == NULL)
+ return sys_errmsg("cannot open libubi");
+
+ /*
+ * Make sure the kernel is fresh enough and this feature is supported.
+ */
+ err = ubi_get_info(libubi, &ubi_info);
+ if (err) {
+ sys_errmsg("cannot get UBI information");
+ goto out_libubi;
+ }
+
+ if (ubi_info.ctrl_major == -1) {
+ errmsg("MTD attach/detach feature is not supported by your kernel");
+ goto out_libubi;
+ }
+
+ req.dev_num = args.devn;
+ req.mtd_num = args.mtdn;
+ req.vid_hdr_offset = args.vidoffs;
+
+ err = ubi_attach_mtd(libubi, args.node, &req);
+ if (err) {
+ sys_errmsg("cannot attach mtd%d", args.mtdn);
+ goto out_libubi;
+ }
+
+ /* Print some information about the new UBI device */
+ err = ubi_get_dev_info1(libubi, req.dev_num, &dev_info);
+ if (err) {
+ sys_errmsg("cannot get information about newly created UBI device");
+ goto out_libubi;
+ }
+
+ printf("UBI device number %d, total %d LEBs (", dev_info.dev_num, dev_info.total_lebs);
+ ubiutils_print_bytes(dev_info.total_bytes, 0);
+ printf("), available %d LEBs (", dev_info.avail_lebs);
+ ubiutils_print_bytes(dev_info.avail_bytes, 0);
+ printf("), LEB size ");
+ ubiutils_print_bytes(dev_info.leb_size, 1);
+ printf("\n");
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
diff --git a/ubi-utils/src/ubicrc32.c b/ubi-utils/src/ubicrc32.c
new file mode 100644
index 0000000..d39af10
--- /dev/null
+++ b/ubi-utils/src/ubicrc32.c
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+/*
+ * Calculate CRC32 with UBI start value (0xFFFFFFFF) for a given binary image.
+ *
+ * Author: Oliver Lohmann
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <mtd/ubi-media.h>
+
+#include "crc32.h"
+#include "common.h"
+
+#define BUFSIZE 4096
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubicrc32"
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to calculate CRC32 with UBI start value (0xFFFFFFFF)";
+
+static const char *optionsstr =
+"-h, --help print help message\n"
+"-V, --version print program version";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <file to calculate CRC32 for> [-h] [--help]";
+
+static const struct option long_options[] = {
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "hV", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'h':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err = 0;
+ uint32_t crc = UBI_CRC32_INIT;
+ char buf[BUFSIZE];
+ FILE *fp;
+
+ if (argc > 1) {
+ fp = fopen(argv[1], "r");
+ if (!fp)
+ return sys_errmsg("cannot open \"%s\"", argv[1]);
+ } else
+ fp = stdin;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return err;
+
+ while (!feof(fp)) {
+ size_t read;
+
+ read = fread(buf, 1, BUFSIZE, fp);
+ if (ferror(fp)) {
+ sys_errmsg("cannot read input file");
+ err = -1;
+ goto out_close;
+ }
+ crc = crc32(crc, buf, read);
+ }
+
+ printf("0x%08x\n", crc);
+
+out_close:
+ if (fp != stdin)
+ fclose(fp);
+ return err;
+}
diff --git a/ubi-utils/src/ubidetach.c b/ubi-utils/src/ubidetach.c
new file mode 100644
index 0000000..50670d0
--- /dev/null
+++ b/ubi-utils/src/ubidetach.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * 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
+ */
+
+/*
+ * An utility to delete UBI devices (detach MTD devices from UBI).
+ *
+ * Author: Artem Bityutskiy
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubidetach"
+
+/* The variables below are set by command line arguments */
+struct args {
+ int devn;
+ int mtdn;
+ const char *node;
+};
+
+static struct args args = {
+ .devn = UBI_DEV_NUM_AUTO,
+ .mtdn = -1,
+ .node = NULL,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+" - a tool to remove UBI devices (detach MTD devices from UBI)";
+
+static const char *optionsstr =
+"-d, --devn=<UBI device number> UBI device number to delete\n"
+"-m, --mtdn=<MTD device number> or altrnatively, MTD device number to detach -\n"
+" this will delete corresponding UBI device\n"
+"-h, --help print help message\n"
+"-V, --version print program version";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME "<UBI control device node file name> [-d <UBI device number>] [-m <MTD device number>]\n"
+"\t\t[--devn <UBI device number>] [--mtdn=<MTD device number>]\n"
+"Example 1: " PROGRAM_NAME " /dev/ubi_ctrl -d 2 - delete UBI device 2 (ubi2)\n"
+"Example 2: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 - detach MTD device 0 (mtd0)";
+
+static const struct option long_options[] = {
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { .name = "mtdn", .has_arg = 1, .flag = NULL, .val = 'm' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "m:d:hV", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'd':
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: \"%s\"", optarg);
+
+ break;
+
+ case 'm':
+ args.mtdn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.mtdn < 0)
+ return errmsg("bad MTD device number: \"%s\"", optarg);
+
+ break;
+
+ case 'h':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (optind == argc)
+ return errmsg("UBI control device name was not specified (use -h for help)");
+ else if (optind != argc - 1)
+ return errmsg("more then one UBI control device specified (use -h for help)");
+
+ if (args.mtdn == -1 && args.devn == -1)
+ return errmsg("neither MTD nor UBI devices were specified (use -h for help)");
+
+ if (args.mtdn != -1 && args.devn != -1)
+ return errmsg("specify either MTD or UBI device (use -h for help)");
+
+ args.node = argv[optind];
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+ struct ubi_info ubi_info;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ libubi = libubi_open(1);
+ if (libubi == NULL)
+ return sys_errmsg("cannot open libubi");
+
+ /*
+ * Make sure the kernel is fresh enough and this feature is supported.
+ */
+ err = ubi_get_info(libubi, &ubi_info);
+ if (err) {
+ sys_errmsg("cannot get UBI information");
+ goto out_libubi;
+ }
+
+ if (ubi_info.ctrl_major == -1) {
+ errmsg("MTD detach/detach feature is not supported by your kernel");
+ goto out_libubi;
+ }
+
+ if (args.devn != -1) {
+ err = ubi_remove_dev(libubi, args.node, args.devn);
+ if (err) {
+ sys_errmsg("cannot remove ubi%d", args.devn);
+ goto out_libubi;
+ }
+ } else {
+ err = ubi_detach_mtd(libubi, args.node, args.mtdn);
+ if (err) {
+ sys_errmsg("cannot detach mtd%d", args.mtdn);
+ goto out_libubi;
+ }
+ }
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
+
diff --git a/ubi-utils/src/ubiformat.c b/ubi-utils/src/ubiformat.c
new file mode 100644
index 0000000..0074c7a
--- /dev/null
+++ b/ubi-utils/src/ubiformat.c
@@ -0,0 +1,780 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * 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.
+ */
+
+/*
+ * An utility to format MTD devices into UBI and flash UBI images.
+ *
+ * Author: Artem Bityutskiy
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <fcntl.h>
+
+#include <libubi.h>
+#include <libmtd.h>
+#include <libscan.h>
+#include <libubigen.h>
+#include <mtd_swab.h>
+#include "crc32.h"
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubiformat"
+
+/* The variables below are set by command line arguments */
+struct args {
+ unsigned int yes:1;
+ unsigned int quiet:1;
+ unsigned int verbose:1;
+ unsigned int override_ec:1;
+ unsigned int novtbl:1;
+ int subpage_size;
+ int vid_hdr_offs;
+ int ubi_ver;
+ off_t image_sz;
+ long long ec;
+ const char *image;
+ const char *node;
+};
+
+static struct args args =
+{
+ .ubi_ver = 1,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to format MTD devices and flash UBI images";
+
+static const char *optionsstr =
+"-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=<offs> offset if the VID header from start of the\n"
+" physical eraseblock (default is the next\n"
+" minimum I/O unit or sub-page after the EC\n"
+" header)\n"
+"-n, --no-volume-table only erase all eraseblock and preserve erase\n"
+" counters, do not write empty volume table\n"
+"-f, --flash-image=<file> flash image file, or '-' for stdin\n"
+"-S, --image-size=<bytes> bytes in input, if not reading from file\n"
+"-e, --erase-counter=<value> use <value> as the erase counter value for all\n"
+" eraseblocks\n"
+"-y, --yes assume the answer is \"yes\" for all question\n"
+" this program would otherwise ask\n"
+"-q, --quiet suppress progress percentage information\n"
+"-v, --verbose be verbose\n"
+"-x, --ubi-ver=<num> UBI version number to put to EC headers\n"
+" (default is 1)\n"
+"-h, -?, --help print help message\n"
+"-V, --version print program version\n";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <MTD device node file name> [-h] [-V] [-y] [-q] [-v]\n"
+"\t\t\t[-x <num>] [-E <value>] [-s <bytes>] [-O <offs>] [-n]\n"
+"\t\t\t[--help] [--version] [--yes] [--verbose] [--quiet]\n"
+"\t\t\t[--ec=<value>] [--vid-hdr-offset=<offs>]\n"
+"\t\t\t[--ubi-ver=<num>] [--no-volume-table]\n"
+"\t\t\t[--flash-image=<file>] [--image-size=<bytes>]\n\n"
+
+"Example 1: " PROGRAM_NAME " /dev/mtd0 -y - format MTD device number 0 and do\n"
+" not ask questions.\n"
+"Example 2: " PROGRAM_NAME " /dev/mtd0 -q -e 0 - format MTD device number 0,\n"
+" be quiet and force erase counter value 0.";
+
+static const struct option long_options[] = {
+ { .name = "sub-page-size", .has_arg = 1, .flag = NULL, .val = 's' },
+ { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' },
+ { .name = "no-volume-table", .has_arg = 0, .flag = NULL, .val = 'n' },
+ { .name = "flash-image", .has_arg = 1, .flag = NULL, .val = 'f' },
+ { .name = "image-size", .has_arg = 1, .flag = NULL, .val = 'S' },
+ { .name = "yes", .has_arg = 0, .flag = NULL, .val = 'y' },
+ { .name = "erase-counter", .has_arg = 1, .flag = NULL, .val = 'e' },
+ { .name = "quiet", .has_arg = 0, .flag = NULL, .val = 'q' },
+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' },
+ { .name = "ubi-ver", .has_arg = 1, .flag = NULL, .val = 'x' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "nh?Vyqve:x:s:O:f:S:", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 's':
+ args.subpage_size = ubiutils_get_bytes(optarg);
+ if (args.subpage_size <= 0)
+ return errmsg("bad sub-page size: \"%s\"", optarg);
+ if (!is_power_of_2(args.subpage_size))
+ return errmsg("sub-page size should be power of 2");
+ break;
+
+ case 'O':
+ args.vid_hdr_offs = strtoul(optarg, &endp, 0);
+ if (args.vid_hdr_offs <= 0 || *endp != '\0' || endp == optarg)
+ return errmsg("bad VID header offset: \"%s\"", optarg);
+ break;
+
+ case 'e':
+ args.ec = strtoull(optarg, &endp, 0);
+ if (args.ec <= 0 || *endp != '\0' || endp == optarg)
+ return errmsg("bad erase counter value: \"%s\"", optarg);
+ if (args.ec >= EC_MAX)
+ return errmsg("too high erase %llu, counter, max is %u", args.ec, EC_MAX);
+ args.override_ec = 1;
+ break;
+
+ case 'f':
+ args.image = optarg;
+ break;
+
+ case 'S':
+ args.image_sz = ubiutils_get_bytes(optarg);
+ if (args.image_sz <= 0)
+ return errmsg("bad image-size: \"%s\"", optarg);
+ break;
+
+ case 'n':
+ args.novtbl = 1;
+ break;
+
+ case 'y':
+ args.yes = 1;
+ break;
+
+ case 'q':
+ args.quiet = 1;
+ break;
+
+ case 'x':
+ args.ubi_ver = strtoul(optarg, &endp, 0);
+ if (args.ubi_ver < 0 || *endp != '\0' || endp == optarg)
+ return errmsg("bad UBI version: \"%s\"", optarg);
+ break;
+
+ case 'v':
+ args.verbose = 1;
+ break;
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case 'h':
+ case '?':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (args.quiet && args.verbose)
+ return errmsg("using \"-q\" and \"-v\" at the same time does not make sense");
+
+ if (optind == argc)
+ return errmsg("MTD device name was not specified (use -h for help)");
+ else if (optind != argc - 1)
+ return errmsg("more then one MTD device specified (use -h for help)");
+
+ if (args.image && args.novtbl)
+ return errmsg("-n cannot be used together with -f");
+
+ args.node = argv[optind];
+ return 0;
+}
+
+static int want_exit(void)
+{
+ char buf[4];
+
+ while (1) {
+ normsg_cont("continue? (yes/no) ");
+ if (scanf("%3s", buf) == EOF) {
+ sys_errmsg("scanf returned unexpected EOF, assume \"yes\"");
+ return 1;
+ }
+ if (!strncmp(buf, "yes", 3) || !strncmp(buf, "y", 1))
+ return 0;
+ if (!strncmp(buf, "no", 2) || !strncmp(buf, "n", 1))
+ return 1;
+ }
+}
+
+static int answer_is_yes(void)
+{
+ char buf[4];
+
+ while (1) {
+ if (scanf("%3s", buf) == EOF) {
+ sys_errmsg("scanf returned unexpected EOF, assume \"no\"");
+ return 0;
+ }
+ if (!strncmp(buf, "yes", 3) || !strncmp(buf, "y", 1))
+ return 1;
+ if (!strncmp(buf, "no", 2) || !strncmp(buf, "n", 1))
+ return 0;
+ }
+}
+
+static void print_bad_eraseblocks(const struct mtd_info *mtd,
+ const struct ubi_scan_info *si)
+{
+ int first = 1, eb;
+
+ if (si->bad_cnt == 0)
+ return;
+
+ normsg_cont("bad eraseblocks: ");
+ for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ if (si->ec[eb] != EB_BAD)
+ continue;
+ if (first) {
+ printf("%d", eb);
+ first = 0;
+ } else
+ printf(", %d", eb);
+ }
+ printf("\n");
+}
+
+static int change_ec(struct ubi_ec_hdr *hdr, long long ec)
+{
+ uint32_t crc;
+
+ /* Check the EC header */
+ if (be32_to_cpu(hdr->magic) != UBI_EC_HDR_MAGIC)
+ return errmsg("bad UBI magic %#08x, should be %#08x",
+ be32_to_cpu(hdr->magic), UBI_EC_HDR_MAGIC);
+
+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
+ if (be32_to_cpu(hdr->hdr_crc) != crc)
+ return errmsg("bad CRC %#08x, should be %#08x\n",
+ crc, be32_to_cpu(hdr->hdr_crc));
+
+ hdr->ec = cpu_to_be64(ec);
+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
+ hdr->hdr_crc = cpu_to_be32(crc);
+
+ return 0;
+}
+
+static int drop_ffs(const struct mtd_info *mtd, const void *buf, int len)
+{
+ int i;
+
+ for (i = len - 1; i >= 0; i--)
+ if (((const uint8_t *)buf)[i] != 0xFF)
+ break;
+
+ /* The resulting length must be aligned to the minimum flash I/O size */
+ len = i + 1;
+ len = (len + mtd->min_io_size - 1) / mtd->min_io_size;
+ len *= mtd->min_io_size;
+ return len;
+}
+
+static int open_file(off_t *sz)
+{
+ int fd;
+
+ if (!strcmp(args.image, "-")) {
+ if (args.image_sz == 0)
+ return errmsg("must use '-S' with non-zero value when reading from stdin");
+
+ *sz = args.image_sz;
+ fd = dup(STDIN_FILENO);
+ if (fd < 0)
+ return sys_errmsg("failed to dup stdin");
+ } else {
+ struct stat st;
+
+ if (stat(args.image, &st))
+ return sys_errmsg("cannot open \"%s\"", args.image);
+
+ *sz = st.st_size;
+ fd = open(args.image, O_RDONLY);
+ if (fd == -1)
+ return sys_errmsg("cannot open \"%s\"", args.image);
+ }
+
+ return fd;
+}
+
+static int read_all(int fd, void *buf, size_t len)
+{
+ while (len > 0) {
+ ssize_t l = read(fd, buf, len);
+ if (l == 0)
+ return errmsg("eof reached; %zu bytes remaining", len);
+ else if (l > 0) {
+ buf += l;
+ len -= l;
+ } else if (errno == EINTR || errno == EAGAIN)
+ continue;
+ else
+ return sys_errmsg("reading failed; %zu bytes remaining", len);
+ }
+
+ return 0;
+}
+
+static int flash_image(const struct mtd_info *mtd, struct ubi_scan_info *si)
+{
+ int fd, img_ebs, eb, written_ebs = 0, divisor;
+ off_t st_size;
+
+ fd = open_file(&st_size);
+ if (fd < 0)
+ return fd;
+
+ img_ebs = st_size / mtd->eb_size;
+
+ if (img_ebs > si->good_cnt) {
+ sys_errmsg("file \"%s\" is too large (%lld bytes)",
+ args.image, (long long)st_size);
+ goto out_close;
+ }
+
+ if (st_size % mtd->eb_size) {
+ return sys_errmsg("file \"%s\" (size %lld bytes) is not multiple of eraseblock size (%d bytes)",
+ args.image, (long long)st_size, mtd->eb_size);
+ goto out_close;
+ }
+
+ verbose(args.verbose, "will write %d eraseblocks", img_ebs);
+ divisor = img_ebs;
+ for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ int err, new_len;
+ char buf[mtd->eb_size];
+ long long ec;
+
+ if (!args.quiet && !args.verbose) {
+ printf("\r" PROGRAM_NAME ": flashing eraseblock %d -- %2lld %% complete ",
+ eb, (long long)(eb + 1) * 100 / divisor);
+ fflush(stdout);
+ }
+
+ if (si->ec[eb] == EB_BAD) {
+ divisor += 1;
+ continue;
+ }
+
+ if (args.verbose) {
+ normsg_cont("eraseblock %d: erase", eb);
+ fflush(stdout);
+ }
+
+ err = mtd_erase(mtd, eb);
+ if (err) {
+ sys_errmsg("failed to erase eraseblock %d", eb);
+ goto out_close;
+ }
+
+ err = read_all(fd, buf, mtd->eb_size);
+ if (err) {
+ sys_errmsg("failed to read eraseblock %d from \"%s\"",
+ written_ebs, args.image);
+ goto out_close;
+ }
+
+
+ if (si->ec[eb] <= EC_MAX)
+ ec = si->ec[eb] + 1;
+ else if (!args.override_ec)
+ ec = si->mean_ec;
+ else
+ ec = args.ec;
+
+ if (args.verbose) {
+ printf(", change EC to %lld", ec);
+ fflush(stdout);
+ }
+
+ err = change_ec((struct ubi_ec_hdr *)buf, ec);
+ if (err) {
+ errmsg("bad EC header at eraseblock %d of \"%s\"",
+ written_ebs, args.image);
+ goto out_close;
+ }
+
+ if (args.verbose) {
+ printf(", write data\n");
+ fflush(stdout);
+ }
+
+ new_len = drop_ffs(mtd, buf, mtd->eb_size);
+
+ err = mtd_write(mtd, eb, 0, buf, new_len);
+ if (err) {
+ sys_errmsg("cannot write eraseblock %d", eb);
+ goto out_close;
+ }
+ if (++written_ebs >= img_ebs)
+ break;
+ }
+
+ if (!args.quiet && !args.verbose)
+ printf("\n");
+ close(fd);
+ return eb + 1;
+
+out_close:
+ close(fd);
+ return -1;
+}
+
+static int format(const struct mtd_info *mtd, const struct ubigen_info *ui,
+ const struct ubi_scan_info *si, int start_eb, int novtbl)
+{
+ int eb, err, write_size;
+ struct ubi_ec_hdr *hdr;
+ struct ubi_vtbl_record *vtbl;
+ int eb1 = -1, eb2 = -1;
+ long long ec1 = -1, ec2 = -1;
+
+ write_size = UBI_EC_HDR_SIZE + mtd->subpage_size - 1;
+ write_size /= mtd->subpage_size;
+ write_size *= mtd->subpage_size;
+ hdr = malloc(write_size);
+ if (!hdr)
+ return sys_errmsg("cannot allocate %d bytes of memory", write_size);
+
+ memset(hdr, 0xFF, write_size);
+
+ for (eb = start_eb; eb < mtd->eb_cnt; eb++) {
+ long long ec;
+
+ if (!args.quiet && !args.verbose) {
+ printf("\r" PROGRAM_NAME ": formatting eraseblock %d -- %2lld %% complete ",
+ eb, (long long)(eb + 1 - start_eb) * 100 / (mtd->eb_cnt - start_eb));
+ fflush(stdout);
+ }
+
+ if (si->ec[eb] == EB_BAD)
+ continue;
+
+ if (si->ec[eb] <= EC_MAX)
+ ec = si->ec[eb] + 1;
+ else if (!args.override_ec)
+ ec = si->mean_ec;
+ else
+ ec = args.ec;
+ ubigen_init_ec_hdr(ui, hdr, ec);
+
+ if (args.verbose) {
+ normsg_cont("eraseblock %d: erase", eb);
+ fflush(stdout);
+ }
+
+ err = mtd_erase(mtd, eb);
+ if (err) {
+ if (!args.quiet)
+ printf("\n");
+ sys_errmsg("failed to erase eraseblock %d", eb);
+ goto out_free;
+ }
+
+ if ((eb1 == -1 || eb2 == -1) && !novtbl) {
+ if (eb1 == -1) {
+ eb1 = eb;
+ ec1 = ec;
+ } else if (eb2 == -1) {
+ eb2 = eb;
+ ec2 = ec;
+ }
+ if (args.verbose)
+ printf(", do not write EC, leave for vtbl\n");
+ continue;
+ }
+
+ if (args.verbose) {
+ printf(", write EC %lld\n", ec);
+ fflush(stdout);
+ }
+
+ err = mtd_write(mtd, eb, 0, hdr, write_size);
+ if (err) {
+ if (!args.quiet && !args.verbose)
+ printf("\n");
+ sys_errmsg("cannot write EC header (%d bytes buffer) to eraseblock %d",
+ write_size, eb);
+ if (args.subpage_size != mtd->min_io_size)
+ normsg("may be %d is incorrect?", args.subpage_size);
+ goto out_free;
+ }
+ }
+
+ if (!args.quiet && !args.verbose)
+ printf("\n");
+
+ if (!novtbl) {
+ if (eb1 == -1 || eb2 == -1) {
+ errmsg("no eraseblocks for volume table");
+ goto out_free;
+ }
+
+ verbose(args.verbose, "write volume table to eraseblocks %d and %d", eb1, eb2);
+ vtbl = ubigen_create_empty_vtbl(ui);
+ if (!vtbl)
+ goto out_free;
+
+ err = ubigen_write_layout_vol(ui, eb1, eb2, ec1, ec2, vtbl, mtd->fd);
+ free(vtbl);
+ if (err) {
+ errmsg("cannot write layout volume");
+ goto out_free;
+ }
+ }
+
+ free(hdr);
+ return 0;
+
+out_free:
+ free(hdr);
+ return -1;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err, verbose;
+ struct mtd_info mtd;
+ libubi_t libubi;
+ struct ubigen_info ui;
+ struct ubi_scan_info *si;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ err = mtd_get_info(args.node, &mtd);
+ if (err)
+ return errmsg("cannot get information about \"%s\"", args.node);
+
+ if (args.subpage_size == 0)
+ args.subpage_size = mtd.min_io_size;
+ else {
+ if (args.subpage_size > mtd.min_io_size) {
+ errmsg("sub-page cannot be larger than min. I/O unit");
+ goto out_close;
+ }
+
+ if (mtd.min_io_size % args.subpage_size) {
+ errmsg("min. I/O unit size should be multiple of sub-page size");
+ goto out_close;
+ }
+ }
+
+ /* Validate VID header offset if it was specified */
+ if (args.vid_hdr_offs != 0) {
+ if (args.vid_hdr_offs % 8) {
+ errmsg("VID header offset has to be multiple of min. I/O unit size");
+ goto out_close;
+ }
+ if (args.vid_hdr_offs + (int)UBI_VID_HDR_SIZE > mtd.eb_size) {
+ errmsg("bad VID header offset");
+ goto out_close;
+ }
+ }
+
+ /*
+ * Because of MTD interface limitations 'mtd_get_info()' cannot get
+ * sub-page so we force the user to pass it via the command line. Let's
+ * hope the user passed us something sane.
+ */
+ mtd.subpage_size = args.subpage_size;
+
+ if (mtd.rdonly) {
+ errmsg("mtd%d (%s) is a read-only device", mtd.num, args.node);
+ goto out_close;
+ }
+
+ /* Make sure this MTD device is not attached to UBI */
+ libubi = libubi_open(0);
+ if (libubi) {
+ int ubi_dev_num;
+
+ err = mtd_num2ubi_dev(libubi, mtd.num, &ubi_dev_num);
+ libubi_close(libubi);
+ if (!err) {
+ errmsg("please, first detach mtd%d (%s) from ubi%d",
+ mtd.num, args.node, ubi_dev_num);
+ goto out_close;
+ }
+ }
+
+ if (!args.quiet) {
+ normsg_cont("mtd%d (%s), size ", mtd.num, mtd.type_str);
+ ubiutils_print_bytes(mtd.size, 1);
+ printf(", %d eraseblocks of ", mtd.eb_size);
+ ubiutils_print_bytes(mtd.eb_size, 1);
+ printf(", min. I/O size %d bytes\n", mtd.min_io_size);
+ }
+
+ if (args.quiet)
+ verbose = 0;
+ else if (args.verbose)
+ verbose = 2;
+ else
+ verbose = 1;
+ err = ubi_scan(&mtd, &si, verbose);
+ if (err) {
+ errmsg("failed to scan mtd%d (%s)", mtd.num, args.node);
+ goto out_close;
+ }
+
+ if (si->good_cnt == 0) {
+ errmsg("all %d eraseblocks are bad", si->bad_cnt);
+ goto out_free;
+ }
+
+ if (si->good_cnt < 2 && (!args.novtbl || args.image)) {
+ errmsg("too few non-bad eraseblocks (%d) on mtd%d", si->good_cnt, mtd.num);
+ goto out_free;
+ }
+
+ if (!args.quiet) {
+ if (si->ok_cnt)
+ normsg("%d eraseblocks have valid erase counter, mean value is %lld",
+ si->ok_cnt, si->mean_ec);
+ if (si->empty_cnt)
+ normsg("%d eraseblocks are supposedly empty", si->empty_cnt);
+ if (si->corrupted_cnt)
+ normsg("%d corrupted erase counters", si->corrupted_cnt);
+ print_bad_eraseblocks(&mtd, si);
+ }
+
+ if (si->alien_cnt) {
+ if (!args.yes || !args.quiet)
+ warnmsg("%d of %d eraseblocks contain non-ubifs data",
+ si->alien_cnt, si->good_cnt);
+ if (!args.yes && want_exit()) {
+ if (args.yes && !args.quiet)
+ printf("yes\n");
+ goto out_free;
+ }
+ }
+
+ if (!args.override_ec && si->empty_cnt < si->good_cnt) {
+ int percent = ((double)si->ok_cnt)/si->good_cnt * 100;
+
+ /*
+ * Make sure the majority of eraseblocks have valid
+ * erase counters.
+ */
+ if (percent < 50) {
+ if (!args.yes || !args.quiet)
+ warnmsg("only %d of %d eraseblocks have valid erase counter",
+ si->ok_cnt, si->good_cnt);
+ normsg("erase counter 0 will be used for all eraseblocks");
+ normsg("note, arbitrary erase counter value may be specified using -e option");
+ if (!args.yes && want_exit()) {
+ if (args.yes && !args.quiet)
+ printf("yes\n");
+ goto out_free;
+ }
+ args.ec = 0;
+ args.override_ec = 1;
+ } else if (percent < 95) {
+ if (!args.yes || !args.quiet)
+ warnmsg("only %d of %d eraseblocks have valid erase counter",
+ si->ok_cnt, si->good_cnt);
+ normsg("mean erase counter %lld will be used for the rest of eraseblock",
+ si->mean_ec);
+ if (!args.yes && want_exit()) {
+ if (args.yes && !args.quiet)
+ printf("yes\n");
+ goto out_free;
+ }
+ args.ec = si->mean_ec;
+ args.override_ec = 1;
+ }
+ }
+
+ if (!args.quiet && args.override_ec)
+ normsg("use erase counter %lld for all eraseblocks", args.ec);
+
+ ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, args.subpage_size,
+ args.vid_hdr_offs, args.ubi_ver);
+
+ if (si->vid_hdr_offs != -1 && ui.vid_hdr_offs != si->vid_hdr_offs) {
+ /*
+ * Hmm, what we read from flash and what we calculated using
+ * min. I/O unit size and sub-page size differs.
+ */
+ if (!args.yes || !args.quiet) {
+ warnmsg("VID header and data offsets on flash are %d and %d, "
+ "which is different to calculated offsets %d and %d",
+ si->vid_hdr_offs, si->data_offs, ui.vid_hdr_offs,
+ ui.data_offs);
+ normsg_cont("use new offsets %d and %d? (yes/no) ",
+ si->vid_hdr_offs, si->data_offs);
+ }
+ if (args.yes || answer_is_yes()) {
+ if (args.yes && !args.quiet)
+ printf("yes\n");
+ } else {
+ ui.vid_hdr_offs = si->vid_hdr_offs;
+ ui.data_offs = si->data_offs;
+ }
+ }
+
+ if (args.image) {
+ err = flash_image(&mtd, si);
+ if (err < 0)
+ goto out_free;
+
+ err = format(&mtd, &ui, si, err, 1);
+ if (err)
+ goto out_free;
+ } else {
+ err = format(&mtd, &ui, si, 0, args.novtbl);
+ if (err)
+ goto out_free;
+ }
+
+ ubi_scan_free(si);
+ close(mtd.fd);
+ return 0;
+
+out_free:
+ ubi_scan_free(si);
+out_close:
+ close(mtd.fd);
+ return -1;
+}
diff --git a/ubi-utils/src/ubigen.c b/ubi-utils/src/ubigen.c
deleted file mode 100644
index bb55fa9..0000000
--- a/ubi-utils/src/ubigen.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * 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.
- *
- * Author: Oliver Lohmann
- *
- * Tool to add UBI headers to binary images.
- *
- * 1.0 Initial version
- * 1.1 Different CRC32 start value
- * 1.2 Removed argp because we want to use uClibc.
- * 1.3 Minor cleanups
- */
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <mtd/ubi-media.h>
-
-#include "ubigen.h"
-#include "config.h"
-
-#define PROGRAM_VERSION "1.3"
-
-typedef enum action_t {
- ACT_NORMAL = 0x00000001,
- ACT_BROKEN_UPDATE = 0x00000002,
-} action_t;
-
-static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
- "ubigen - a tool for adding UBI information to a binary input file.\n";
-
-static const char *optionsstr =
-" Common settings:\n"
-" -c, --copyright Print copyright information.\n"
-" -d, --debug\n"
-" -v, --verbose Print more progress information.\n"
-"\n"
-" UBI Settings:\n"
-" -A, --alignment=<num> Set the alignment size to <num> (default 1).\n"
-" Values can be specified as bytes, 'ki' or 'Mi'.\n"
-" -B, --blocksize=<num> Set the eraseblock size to <num> (default 128\n"
-" KiB).\n"
-" Values can be specified as bytes, 'ki' or 'Mi'.\n"
-" -E, --erasecount=<num> Set the erase count to <num> (default 0)\n"
-" -I, --id=<num> The UBI volume id.\n"
-" -O, --offset=<num> Offset from start of an erase block to the UBI\n"
-" volume header.\n"
-" -T, --type=<num> The UBI volume type:\n"
-" 1 = dynamic, 2 = static\n"
-" -X, --setver=<num> Set UBI version number to <num> (default 1)\n"
-"\n"
-" Input/Output:\n"
-" -i, --infile=<filename> Read input from file.\n"
-" -o, --outfile=<filename> Write output to file (default is stdout).\n"
-"\n"
-" Special options:\n"
-" -U, --broken-update=<leb> Create an ubi image which simulates a broken\n"
-" update.\n"
-" <leb> specifies the logical eraseblock number to\n"
-" update.\n"
-"\n"
-" -?, --help Give this help list\n"
-" --usage Give a short usage message\n"
-" -V, --version Print program version\n";
-
-static const char *usage =
-"Usage: ubigen [-cdv?V] [-A <num>] [-B <num>] [-E <num>] [-I <num>]\n"
-" [-O <num>] [-T <num>] [-X <num>] [-i <filename>] [-o <filename>]\n"
-" [-U <leb>] [--copyright] [--debug] [--verbose] [--alignment=<num>]\n"
-" [--blocksize=<num>] [--erasecount=<num>] [--id=<num>]\n"
-" [--offset=<num>] [--type=<num>] [--setver=<num>]\n"
-" [--infile=<filename>] [--outfile=<filename>]\n"
-" [--broken-update=<leb>] [--help] [--usage] [--version]\n";
-
-struct option long_options[] = {
- { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' },
- { .name = "debug", .has_arg = 0, .flag = NULL, .val = 'd' },
- { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' },
- { .name = "alignment", .has_arg = 1, .flag = NULL, .val = 'A' },
- { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'B' },
- { .name = "erasecount", .has_arg = 1, .flag = NULL, .val = 'E' },
- { .name = "id", .has_arg = 1, .flag = NULL, .val = 'I' },
- { .name = "offset", .has_arg = 1, .flag = NULL, .val = 'O' },
- { .name = "type", .has_arg = 1, .flag = NULL, .val = 'T' },
- { .name = "setver", .has_arg = 1, .flag = NULL, .val = 'X' },
- { .name = "infile", .has_arg = 1, .flag = NULL, .val = 'i' },
- { .name = "outfile", .has_arg = 1, .flag = NULL, .val = 'o' },
- { .name = "broken-update", .has_arg = 1, .flag = NULL, .val = 'U' },
- { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
- { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
- { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
- { NULL, 0, NULL, 0}
-};
-
-static const char copyright [] __attribute__((unused)) =
- "Copyright IBM Corp 2006";
-
-#define CHECK_ENDP(option, endp) do { \
- if (*endp) { \
- fprintf(stderr, \
- "Parse error option \'%s\'. " \
- "No correct numeric value.\n" \
- , option); \
- exit(EXIT_FAILURE); \
- } \
-} while(0)
-
-typedef struct myargs {
- /* common settings */
- action_t action;
- int verbose;
-
- int32_t id;
- uint8_t type;
- uint32_t eb_size;
- uint64_t ec;
- uint8_t version;
- uint32_t hdr_offset;
- uint32_t update_block;
- uint32_t alignment;
-
- FILE* fp_in;
- FILE* fp_out;
-
- /* special stuff needed to get additional arguments */
- char *arg1;
- char **options; /* [STRING...] */
-} myargs;
-
-
-static int ustrtoul(const char *cp, char **endp, unsigned int base)
-{
- unsigned long result = strtoul(cp, endp, base);
-
- switch (**endp) {
- case 'G':
- result *= 1024;
- case 'M':
- result *= 1024;
- case 'k':
- case 'K':
- result *= 1024;
- /* "Ki", "ki", "Mi" or "Gi" are to be used. */
- if ((*endp)[1] == 'i')
- (*endp) += 2;
- }
- return result;
-}
-
-static int
-parse_opt(int argc, char **argv, myargs *args)
-{
- int err = 0;
- char* endp;
-
- while (1) {
- int key;
-
- key = getopt_long(argc, argv, "cdvA:B:E:I:O:T:X:i:o:U:?V",
- long_options, NULL);
- if (key == -1)
- break;
-
- switch (key) {
- case 'c':
- fprintf(stderr, "%s\n", copyright);
- exit(0);
- break;
- case 'o': /* output */
- args->fp_out = fopen(optarg, "wb");
- if ((args->fp_out) == NULL) {
- fprintf(stderr, "Cannot open file %s "
- "for output\n", optarg);
- exit(1);
- }
- break;
- case 'i': /* input */
- args->fp_in = fopen(optarg, "rb");
- if ((args->fp_in) == NULL) {
- fprintf(stderr, "Cannot open file %s "
- "for input\n", optarg);
- exit(1);
- }
- break;
- case 'v': /* verbose */
- args->verbose = 1;
- break;
-
- case 'B': /* eb_size */
- args->eb_size =
- (uint32_t)ustrtoul(optarg, &endp, 0);
- CHECK_ENDP("B", endp);
- break;
- case 'E': /* erasecount */
- args->ec = (uint64_t)strtoul(optarg, &endp, 0);
- CHECK_ENDP("E", endp);
- break;
- case 'I': /* id */
- args->id = (uint16_t)strtoul(optarg, &endp, 0);
- CHECK_ENDP("I", endp);
- break;
- case 'T': /* type */
- args->type =
- (uint16_t)strtoul(optarg, &endp, 0);
- CHECK_ENDP("T", endp);
- break;
- case 'X': /* versionnr */
- args->version =
- (uint8_t)strtoul(optarg, &endp, 0);
- CHECK_ENDP("X", endp);
- break;
- case 'O': /* offset for volume hdr */
- args->hdr_offset =
- (uint32_t) strtoul(optarg, &endp, 0);
- CHECK_ENDP("O", endp);
- break;
-
- case 'U': /* broken update */
- args->action = ACT_BROKEN_UPDATE;
- args->update_block =
- (uint32_t) strtoul(optarg, &endp, 0);
- CHECK_ENDP("U", endp);
- break;
-
- case '?': /* help */
- fprintf(stderr, "Usage: ubigen [OPTION...]\n");
- fprintf(stderr, "%s", doc);
- fprintf(stderr, "%s", optionsstr);
- fprintf(stderr, "\nReport bugs to %s\n",
- PACKAGE_BUGREPORT);
- exit(0);
- break;
-
- case 'V':
- fprintf(stderr, "%s\n", PROGRAM_VERSION);
- exit(0);
- break;
-
- default:
- fprintf(stderr, "%s", usage);
- exit(-1);
- }
- }
-
- if (optind < argc) {
- if (!args->fp_in) {
- args->fp_in = fopen(argv[optind++], "rb");
- if ((args->fp_in) == NULL) {
- fprintf(stderr, "Cannot open file %s for "
- "input\n", argv[optind]);
- exit(1);
- }
- }
- }
- if (args->id < 0) {
- err = 1;
- fprintf(stderr,
- "Please specify an UBI Volume ID.\n");
- }
- if (args->type == 0) {
- err = 1;
- fprintf(stderr,
- "Please specify an UBI Volume type.\n");
- }
- if (err) {
- fprintf(stderr, "%s", usage);
- exit(1);
- }
-
- return 0;
-}
-
-
-int
-main(int argc, char **argv)
-{
- int rc = 0;
- ubi_info_t u;
- struct stat file_info;
- off_t input_len = 0; /* only used in static volumes */
-
- myargs args = {
- .action = ACT_NORMAL,
- .verbose = 0,
-
- .id = -1,
- .type = 0,
- .eb_size = 0,
- .update_block = 0,
- .ec = 0,
- .version = 0,
- .hdr_offset = (DEFAULT_PAGESIZE) - (UBI_VID_HDR_SIZE),
- .alignment = 1,
-
- .fp_in = NULL,
- .fp_out = stdout,
- /* arguments */
- .arg1 = NULL,
- .options = NULL,
- };
-
- ubigen_init(); /* Init CRC32 table in ubigen */
-
- /* parse arguments */
- parse_opt(argc, argv, &args);
-
- if (fstat(fileno(args.fp_in), &file_info) != 0) {
- fprintf(stderr, "Cannot fetch file size "
- "from input file.\n");
- }
- input_len = file_info.st_size;
-
- rc = ubigen_create(&u, (uint32_t)args.id, args.type,
- args.eb_size, args.ec, args.alignment,
- args.version, args.hdr_offset, 0 ,input_len,
- args.fp_in, args.fp_out);
-
- if (rc != 0) {
- fprintf(stderr, "Cannot create UBI info handler rc: %d\n", rc);
- exit(EXIT_FAILURE);
- }
-
- if (!args.fp_in || !args.fp_out) {
- fprintf(stderr, "Input/Output error.\n");
- exit(EXIT_FAILURE);
-
- }
-
- if (args.action & ACT_NORMAL) {
- rc = ubigen_write_complete(u);
- }
- else if (args.action & ACT_BROKEN_UPDATE) {
- rc = ubigen_write_broken_update(u, args.update_block);
- }
- if (rc != 0) {
- fprintf(stderr, "Error converting input data.\n");
- exit(EXIT_FAILURE);
- }
-
- rc = ubigen_destroy(&u);
- return rc;
-}
diff --git a/ubi-utils/src/ubigen.h b/ubi-utils/src/ubigen.h
deleted file mode 100644
index 8d29120..0000000
--- a/ubi-utils/src/ubigen.h
+++ /dev/null
@@ -1,149 +0,0 @@
-#ifndef __UBIGEN_H__
-#define __UBIGEN_H__
-/*
- * 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.
- *
- * Author: Frank Haverkamp
- *
- * An utility to update UBI volumes.
- */
-
-#include <stdio.h> /* FILE */
-#include <stdint.h>
-#include <mtd/ubi-media.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define DEFAULT_BLOCKSIZE (128 * 1024)
-#define DEFAULT_PAGESIZE (2*1024)
-
-#define EUBIGEN_INVALID_TYPE 1
-#define EUBIGEN_INVALID_HDR_OFFSET 2
-#define EUBIGEN_INVALID_ALIGNMENT 3
-#define EUBIGEN_TOO_SMALL_EB 4
-#define EUBIGEN_MAX_ERROR 5
-
-
-typedef enum action {
- NO_ERROR = 0x00000000,
- BROKEN_HDR_CRC = 0x00000001,
- BROKEN_DATA_CRC = 0x00000002,
- BROKEN_DATA_SIZE = 0x00000004,
- BROKEN_OMIT_BLK = 0x00000008,
- MARK_AS_UPDATE = 0x00000010,
-} ubigen_action_t;
-
-typedef struct ubi_info *ubi_info_t;
-
-/**
- * @brief Initialize the internal CRC32 table.
- * @note Necessary because of the used crc32 function in UBI.
- * A usage of CRC32, from e.g. zlib will fail.
- */
-void ubigen_init(void);
-
-/**
- * @brief Create an ubigen handle.
- * @param ...
- * @return 0 On sucess.
- * else Error.
- * @note This parameterlist is ugly. But we have to use
- * two big structs and meta information internally,
- * filling them would be even uglier.
- */
-int ubigen_create(ubi_info_t *u, uint32_t vol_id, uint8_t vol_type,
- uint32_t eb_size, uint64_t ec, uint32_t alignment,
- uint8_t version, uint32_t vid_hdr_offset,
- uint8_t compat_flag, size_t data_size,
- FILE* fp_in, FILE* fp_out);
-
-/**
- * @brief Destroy an ubigen handle.
- * @param u Handle to free.
- * @return 0 On success.
- * else Error.
- */
-int ubigen_destroy(ubi_info_t *u);
-
-/**
- * @brief Get number of total logical EBs, necessary for the
- * complete storage of data in the handle.
- * @param u The handle.
- * @return 0 On success.
- * else Error.
- */
-int ubigen_get_leb_total(ubi_info_t u, size_t* total);
-
-/**
- * @brief Get the size in bytes of one logical EB in the handle.
- * @param u The handle.
- * @return 0 On success.
- * else Error.
- */
-int ubigen_get_leb_size(ubi_info_t u, size_t* size);
-
-
-/**
- * @brief Write a logical EB (fits exactly into 1 physical EB).
- * @param u Handle which holds all necessary data.
- * @param action Additional operations which shall be applied on this
- * logical eraseblock. Mostly injecting artifical errors.
- * @return 0 On success.
- * else Error.
- */
-int ubigen_write_leb(ubi_info_t u, ubigen_action_t action);
-
-/**
- * @brief Write a complete array of logical eraseblocks at once.
- * @param u Handle which holds all necessary data.
- * @return 0 On success.
- * else Error.
- */
-int ubigen_write_complete(ubi_info_t u);
-
-/**
- * @brief Write a single block which is extracted from the
- * binary input data.
- * @param u Handle which holds all necessary data.
- * @param blk Logical eraseblock which shall hold a inc. copy entry
- * and a bad data crc.
- * @return 0 On success.
- * else Error.
- */
-int ubigen_write_broken_update(ubi_info_t u, uint32_t blk);
-
-/**
- * @brief Use the current ubi_info data and some additional data
- * to set an UBI volume table entry from it.
- * @param u Handle which holds some of the necessary data.
- * @param res_bytes Number of reserved bytes which is stored in the volume
- * table entry.
- * @param name A string which shall be used as a volume label.
- * @param lvol_r A pointer to a volume table entry.
- * @return 0 On success.
- * else Error.
- */
-int ubigen_set_lvol_rec(ubi_info_t u, size_t reserved_bytes,
- const char* name, struct ubi_vtbl_record *lvol_rec);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __UBIGEN_H__ */
diff --git a/ubi-utils/src/ubimirror.c b/ubi-utils/src/ubimirror.c
deleted file mode 100644
index da05a8b..0000000
--- a/ubi-utils/src/ubimirror.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * 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.
- *
- * Author: Oliver Lohmann
- *
- * 1.2 Removed argp because we want to use uClibc.
- * 1.3 Minor cleanups
- * 1.4 Migrated to new libubi
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <errno.h>
-#include <mtd/ubi-media.h>
-
-#include "config.h"
-#include "error.h"
-#include "example_ubi.h"
-#include "ubimirror.h"
-
-#define PROGRAM_VERSION "1.4"
-
-typedef enum action_t {
- ACT_NORMAL = 0,
- ACT_ARGP_ABORT,
- ACT_ARGP_ERR,
-} action_t;
-
-#define ABORT_ARGP do { \
- args->action = ACT_ARGP_ABORT; \
-} while (0)
-
-#define ERR_ARGP do { \
- args->action = ACT_ARGP_ERR; \
-} while (0)
-
-#define VOL_ARGS_MAX 2
-
-static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
- "ubimirror - mirrors ubi volumes.\n";
-
-static const char *optionsstr =
-" -c, --copyright Print copyright information.\n"
-" -s, --side=<seqnum> Use the side <seqnum> as source.\n"
-" -?, --help Give this help list\n"
-" --usage Give a short usage message\n"
-" -V, --version Print program version\n";
-
-static const char *usage =
-"Usage: ubimirror [-c?V] [-s <seqnum>] [--copyright] [--side=<seqnum>]\n"
-" [--help] [--usage] [--version] <source> <destination>\n";
-
-static const char copyright [] __attribute__((unused)) =
- "(C) IBM Coorporation 2007";
-
-struct option long_options[] = {
- { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' },
- { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' },
- { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
- { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
- { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
- { NULL, 0, NULL, 0}
-};
-
-typedef struct myargs {
- action_t action;
- int side;
- int vol_no; /* index of current volume */
- /* @FIXME replace by bootenv_list, makes live easier */
- /* @FIXME remove the constraint of two entries in the array */
- const char* vol[VOL_ARGS_MAX]; /* comma separated list of src/dst
- volumes */
- char *arg1;
- char **options; /* [STRING...] */
-} myargs;
-
-static int
-get_update_side(const char* str)
-{
- uint32_t i = strtoul(str, NULL, 0);
-
- if ((i != 0) && (i != 1)) {
- return -1;
- }
- return i;
-}
-
-
-static int
-parse_opt(int argc, char **argv, myargs *args)
-{
- while (1) {
- int key;
-
- key = getopt_long(argc, argv, "cs:?V", long_options, NULL);
- if (key == -1)
- break;
-
- switch (key) {
- case 'c':
- err_msg("%s", copyright);
- ABORT_ARGP;
- break;
- case 's':
- args->side = get_update_side(optarg);
- if (args->side < 0) {
- err_msg("Unsupported seqnum: %s.\n"
- "Supported seqnums are '0' "
- "and '1'\n", optarg);
- ERR_ARGP;
- }
- break;
- case '?': /* help */
- err_msg("Usage: ubimirror [OPTION...] "
- "<source> <destination>\n");
- err_msg("%s", doc);
- err_msg("%s", optionsstr);
- err_msg("\nReport bugs to %s\n",
- PACKAGE_BUGREPORT);
- exit(0);
- break;
- case 'V':
- err_msg("%s", PROGRAM_VERSION);
- exit(0);
- break;
- default:
- err_msg("%s", usage);
- exit(-1);
- }
- }
-
- while (optind < argc) {
- /* only two entries allowed */
- if (args->vol_no >= VOL_ARGS_MAX) {
- err_msg("%s", usage);
- ERR_ARGP;
- }
- args->vol[(args->vol_no)++] = argv[optind++];
- }
-
- return 0;
-}
-
-
-int
-main(int argc, char **argv) {
- int rc = 0;
- unsigned int ids[VOL_ARGS_MAX];
- char err_buf[1024];
-
- myargs args = {
- .action = ACT_NORMAL,
- .side = -1,
- .vol_no = 0,
- .vol = {"", ""},
- .options = NULL,
- };
-
- parse_opt(argc, argv, &args);
- if (args.action == ACT_ARGP_ERR) {
- rc = 127;
- goto err;
- }
- if (args.action == ACT_ARGP_ABORT) {
- rc = 126;
- goto out;
- }
- if (args.vol_no < VOL_ARGS_MAX) {
- fprintf(stderr, "missing volume number for %s\n",
- args.vol_no == 0 ? "source and target" : "target");
- rc = 125;
- goto out;
- }
- for( rc = 0; rc < args.vol_no; ++rc){
- char *endp;
- ids[rc] = strtoul(args.vol[rc], &endp, 0);
- if( *endp != '\0' ){
- fprintf(stderr, "invalid volume number %s\n",
- args.vol[rc]);
- rc = 125;
- goto out;
- }
- }
- rc = ubimirror(EXAMPLE_UBI_DEVICE, args.side, ids, args.vol_no,
- err_buf, sizeof(err_buf));
- if( rc ){
- err_buf[sizeof err_buf - 1] = '\0';
- fprintf(stderr, "%s", err_buf);
- if( rc < 0 )
- rc = -rc;
- }
- out:
- err:
- return rc;
-}
diff --git a/ubi-utils/src/ubimirror.h b/ubi-utils/src/ubimirror.h
deleted file mode 100644
index d7ae2ad..0000000
--- a/ubi-utils/src/ubimirror.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef __UBIMIRROR_H__
-#define __UBIMIRROR_H__
-/*
- * 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.
- *
- * Author: Oliver Lohmann
- *
- * An utility to mirror UBI volumes.
- */
-
-#include <stdint.h>
-
-/**
- * @def EUBIMIRROR_SRC_EQ_DST
- * @brief Given source volume is also in the set of destination volumes.
- */
-#define EUBIMIRROR_SRC_EQ_DST 20
-
-/**
- * @def EUBIMIRROR_NO_SRC
- * @brief The given source volume does not exist.
- */
-#define EUBIMIRROR_NO_SRC 21
-
-/**
- * @def EUBIMIRROR_NO_DST
- * @brief One of the given destination volumes does not exist.
- */
-#define EUBIMIRROR_NO_DST 22
-
-/**
- * @brief Mirrors UBI devices from a source device (specified by seqnum)
- * to n target devices.
- * @param devno Device number used by the UBI operations.
- * @param seqnum An index into ids (defines the src_id).
- * @param ids An array of ids.
- * @param ids_size The number of entries in the ids array.
- * @param err_buf A buffer to store verbose error messages.
- * @param err_buf_size The size of the error buffer.
- *
- * @note A seqnum of value < 0 defaults to a seqnum of 0.
- * @note A seqnum exceeding the range of ids_size defaults to 0.
- * @note An empty ids list results in a empty stmt.
- * @pre The UBI volume which shall be used as source volume exists.
- * @pre The UBI volumes which are defined as destination volumes exist.
- * @post The content of the UBI volume which was defined as source volume
- * equals the content of the volumes which were defined as destination.
- */
-int ubimirror(uint32_t devno, int seqnum, uint32_t* ids, ssize_t ids_size,
- char *err_buf, size_t err_buf_size);
-
-#endif /* __UBIMIRROR_H__ */
diff --git a/ubi-utils/src/ubimkvol.c b/ubi-utils/src/ubimkvol.c
new file mode 100644
index 0000000..820c9d8
--- /dev/null
+++ b/ubi-utils/src/ubimkvol.c
@@ -0,0 +1,313 @@
+/*
+ * 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.
+ */
+
+/*
+ * An utility to create UBI volumes.
+ *
+ * Authors: Artem Bityutskiy <dedekind@infradead.org>
+ * Frank Haverkamp <haver@vnet.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubimkvol"
+
+/* The variables below are set by command line arguments */
+struct args {
+ int vol_id;
+ int vol_type;
+ long long bytes;
+ int lebs;
+ int alignment;
+ const char *name;
+ const char *node;
+ int maxavs;
+ /* For deprecated -d option handling */
+ int devn;
+ char dev_name[256];
+};
+
+static struct args args = {
+ .vol_type = UBI_DYNAMIC_VOLUME,
+ .bytes = -1,
+ .lebs = -1,
+ .alignment = 1,
+ .vol_id = UBI_VOL_NUM_AUTO,
+ .devn = -1,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to create UBI volumes.";
+
+static const char *optionsstr =
+"-a, --alignment=<alignment> volume alignment (default is 1)\n"
+"-n, --vol_id=<volume ID> UBI volume ID, if not specified, the volume ID\n"
+" will be assigned automatically\n"
+"-N, --name=<name> volume name\n"
+"-s, --size=<bytes> volume size volume size in bytes, kilobytes (KiB)\n"
+" or megabytes (MiB)\n"
+"-S, --lebs=<LEBs count> alternative way to give volume size in logical\n"
+" eraseblocks\n"
+"-m, --maxavsize set volume size to maximum available size\n"
+"-t, --type=<static|dynamic> volume type (dynamic, static), default is dynamic\n"
+"-h, -?, --help print help message\n"
+"-V, --version print program version\n\n"
+"The following is a compatibility option which is deprecated, do not use it\n"
+"-d, --devn=<devn> UBI device number - may be used instead of the UBI\n"
+" device node name in which case the utility assumes\n"
+" that the device node is \"/dev/ubi<devn>\"";
+
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <UBI device node file name> [-h] [-a <alignment>] [-n <volume ID>] [-N <name>]\n"
+"\t\t\t[-s <bytes>] [-S <LEBs>] [-t <static|dynamic>] [-V] [-m]\n"
+"\t\t\t[--alignment=<alignment>][--vol_id=<volume ID>] [--name=<name>]\n"
+"\t\t\t[--size=<bytes>] [--lebs=<LEBs>] [--type=<static|dynamic>] [--help]\n"
+"\t\t\t[--version] [--maxavsize]\n\n"
+"Example: " PROGRAM_NAME " /dev/ubi0 -s 20MiB -N config_data - create a 20 Megabytes volume\n"
+" named \"config_data\" on UBI device /dev/ubi0.";
+
+static const struct option long_options[] = {
+ { .name = "alignment", .has_arg = 1, .flag = NULL, .val = 'a' },
+ { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' },
+ { .name = "name", .has_arg = 1, .flag = NULL, .val = 'N' },
+ { .name = "size", .has_arg = 1, .flag = NULL, .val = 's' },
+ { .name = "lebs", .has_arg = 1, .flag = NULL, .val = 'S' },
+ { .name = "type", .has_arg = 1, .flag = NULL, .val = 't' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { .name = "maxavsize", .has_arg = 0, .flag = NULL, .val = 'm' },
+ /* Deprecated -d option */
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { NULL, 0, NULL, 0},
+};
+
+static int param_sanity_check(void)
+{
+ int len;
+
+ if (args.bytes == -1 && !args.maxavs && args.lebs == -1)
+ return errmsg("volume size was not specified (use -h for help)");
+
+ if ((args.bytes != -1 && (args.maxavs || args.lebs != -1)) ||
+ (args.lebs != -1 && (args.maxavs || args.bytes != -1)) ||
+ (args.maxavs && (args.bytes != -1 || args.lebs != -1)))
+ return errmsg("size specified with more then one option");
+
+ if (args.name == NULL)
+ return errmsg("volume name was not specified (use -h for help)");
+
+ len = strlen(args.name);
+ if (len > UBI_MAX_VOLUME_NAME)
+ return errmsg("too long name (%d symbols), max is %d", len, UBI_MAX_VOLUME_NAME);
+
+ return 0;
+}
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "a:n:N:s:S:t:h?Vmd:", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 't':
+ if (!strcmp(optarg, "dynamic"))
+ args.vol_type = UBI_DYNAMIC_VOLUME;
+ else if (!strcmp(optarg, "static"))
+ args.vol_type = UBI_STATIC_VOLUME;
+ else
+ return errmsg("bad volume type: \"%s\"", optarg);
+ break;
+
+ case 's':
+ args.bytes = ubiutils_get_bytes(optarg);
+ if (args.bytes <= 0)
+ return errmsg("bad volume size: \"%s\"", optarg);
+ break;
+
+ case 'S':
+ args.lebs = strtoull(optarg, &endp, 0);
+ if (endp == optarg || args.lebs <= 0 || *endp != '\0')
+ return errmsg("bad LEB count: \"%s\"", optarg);
+ break;
+
+ case 'a':
+ args.alignment = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.alignment <= 0)
+ return errmsg("bad volume alignment: \"%s\"", optarg);
+ break;
+
+ case 'n':
+ args.vol_id = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.vol_id < 0)
+ return errmsg("bad volume ID: " "\"%s\"", optarg);
+ break;
+
+ case 'd':
+ /* Handle deprecated -d option */
+ warnmsg("-d is depricated and will be removed, do not use it");
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: " "\"%s\"", optarg);
+ break;
+
+ case 'N':
+ args.name = optarg;
+ break;
+
+ case 'h':
+ case '?':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case 'm':
+ args.maxavs = 1;
+ break;
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ /* Handle deprecated -d option */
+ if (args.devn != -1) {
+ sprintf(args.dev_name, "/dev/ubi%d", args.devn);
+ args.node = args.dev_name;
+ } else {
+ if (optind == argc)
+ return errmsg("UBI device name was not specified (use -h for help)");
+ else if (optind != argc - 1)
+ return errmsg("more then one UBI device specified (use -h for help)");
+
+ args.node = argv[optind];
+ }
+
+ if (param_sanity_check())
+ return -1;
+
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+ struct ubi_dev_info dev_info;
+ struct ubi_vol_info vol_info;
+ struct ubi_mkvol_request req;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return err;
+
+ libubi = libubi_open(1);
+ if (!libubi)
+ return sys_errmsg("cannot open libubi");
+
+ err = ubi_node_type(libubi, args.node);
+ if (err == 2) {
+ errmsg("\"%s\" is an UBI volume node, not an UBI device node",
+ args.node);
+ goto out_libubi;
+ } else if (err < 0) {
+ errmsg("\"%s\" is not an UBI device node", args.node);
+ goto out_libubi;
+ }
+
+ err = ubi_get_dev_info(libubi, args.node, &dev_info);
+ if (err) {
+ sys_errmsg("cannot get information about UBI device \"%s\"",
+ args.node);
+ goto out_libubi;
+ }
+
+ if (dev_info.avail_bytes == 0) {
+ errmsg("UBI device does not have free logical eraseblocks");
+ goto out_libubi;
+ }
+
+ if (args.maxavs) {
+ args.bytes = dev_info.avail_bytes;
+ printf("Set volume size to %lld\n", args.bytes);
+ }
+
+ if (args.lebs != -1) {
+ args.bytes = dev_info.leb_size;
+ args.bytes -= dev_info.leb_size % args.alignment;
+ args.bytes *= args.lebs;
+ }
+
+ req.vol_id = args.vol_id;
+ req.alignment = args.alignment;
+ req.bytes = args.bytes;
+ req.vol_type = args.vol_type;
+ req.name = args.name;
+
+ err = ubi_mkvol(libubi, args.node, &req);
+ if (err < 0) {
+ sys_errmsg("cannot UBI create volume");
+ goto out_libubi;
+ }
+
+ args.vol_id = req.vol_id;
+
+ /* Print information about the created device */
+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, args.vol_id, &vol_info);
+ if (err) {
+ sys_errmsg("cannot get information about newly created UBI volume");
+ goto out_libubi;
+ }
+
+ printf("Volume ID %d, size %d LEBs (", vol_info.vol_id, vol_info.rsvd_lebs);
+ ubiutils_print_bytes(vol_info.rsvd_bytes, 0);
+ printf("), LEB size ");
+ ubiutils_print_bytes(vol_info.leb_size, 1);
+ printf(", %s, name \"%s\", alignment %d\n",
+ req.vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static",
+ vol_info.name, vol_info.alignment);
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
diff --git a/ubi-utils/src/ubinfo.c b/ubi-utils/src/ubinfo.c
new file mode 100644
index 0000000..536ec01
--- /dev/null
+++ b/ubi-utils/src/ubinfo.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2007, 2008 Nokia Corporation.
+ *
+ * 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
+ */
+
+/*
+ * An utility to get UBI information.
+ *
+ * Author: Artem Bityutskiy
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubinfo"
+
+/* The variables below are set by command line arguments */
+struct args {
+ int devn;
+ int vol_id;
+ int all;
+ const char *node;
+};
+
+static struct args args = {
+ .vol_id = -1,
+ .devn = -1,
+ .all = 0,
+ .node = NULL,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to print UBI information.";
+
+static const char *optionsstr =
+"-d, --devn=<UBI device number> UBI device number to get information about\n"
+"-n, --vol_id=<volume ID> ID of UBI volume to print information about\n"
+"-a, --all print information about all devices and volumes,\n"
+" or about all volumes if the UBI device was\n"
+" specified\n"
+"-h, --help print help message\n"
+"-V, --version print program version";
+
+static const char *usage =
+"Usage 1: " PROGRAM_NAME " [-d <UBI device number>] [-n <volume ID>] [-a] [-h] [-V] [--vol_id=<volume ID>]\n"
+"\t\t[--devn <UBI device number>] [--all] [--help] [--version]\n"
+"Usage 2: " PROGRAM_NAME " <UBI device node file name> [-a] [-h] [-V] [--all] [--help] [--version]\n"
+"Usage 3: " PROGRAM_NAME " <UBI volume node file name> [-h] [-V] [--help] [--version]\n\n"
+"Example 1: " PROGRAM_NAME " - (no arguments) print general UBI information\n"
+"Example 2: " PROGRAM_NAME " -d 1 - print information about UBI device number 1\n"
+"Example 3: " PROGRAM_NAME " /dev/ubi0 -a - print information about all volumes of UBI\n"
+" device /dev/ubi0\n"
+"Example 4: " PROGRAM_NAME " /dev/ubi1_0 - print information about UBI volume /dev/ubi1_0\n"
+"Example 5: " PROGRAM_NAME " -a - print all information\n";
+
+static const struct option long_options[] = {
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' },
+ { .name = "all", .has_arg = 0, .flag = NULL, .val = 'a' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "an:d:hV", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'a':
+ args.all = 1;
+ break;
+
+ case 'n':
+ args.vol_id = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.vol_id < 0)
+ return errmsg("bad volume ID: " "\"%s\"", optarg);
+ break;
+
+ case 'd':
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: \"%s\"", optarg);
+
+ break;
+
+ case 'h':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (optind == argc - 1)
+ args.node = argv[optind];
+ else if (optind < argc)
+ return errmsg("more then one UBI devices specified (use -h for help)");
+
+ return 0;
+}
+
+static int translate_dev(libubi_t libubi, const char *node)
+{
+ int err;
+
+ err = ubi_node_type(libubi, node);
+ if (err == -1) {
+ if (errno)
+ return errmsg("unrecognized device node \"%s\"", node);
+ return errmsg("\"%s\" does not correspond to any UBI device or volume", node);
+ }
+
+ if (err == 1) {
+ struct ubi_dev_info dev_info;
+
+ err = ubi_get_dev_info(libubi, node, &dev_info);
+ if (err)
+ return sys_errmsg("cannot get information about UBI device \"%s\"", node);
+
+ args.devn = dev_info.dev_num;
+ } else {
+ struct ubi_vol_info vol_info;
+
+ err = ubi_get_vol_info(libubi, node, &vol_info);
+ if (err)
+ return sys_errmsg("cannot get information about UBI volume \"%s\"", node);
+
+ if (args.vol_id != -1)
+ return errmsg("both volume character device node (\"%s\") and "
+ "volume ID (%d) are specify, use only one of them"
+ "(use -h for help)", node, args.vol_id);
+
+ args.devn = vol_info.dev_num;
+ args.vol_id = vol_info.vol_id;
+ }
+
+ return 0;
+}
+
+static int print_vol_info(libubi_t libubi, int dev_num, int vol_id)
+{
+ int err;
+ struct ubi_vol_info vol_info;
+
+ err = ubi_get_vol_info1(libubi, dev_num, vol_id, &vol_info);
+ if (err)
+ return sys_errmsg("cannot get information about UBI volume %d on ubi%d",
+ vol_id, dev_num);
+
+ printf("Volume ID: %d (on ubi%d)\n", vol_info.vol_id, vol_info.dev_num);
+ printf("Type: %s\n",
+ vol_info.type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static");
+ printf("Alignment: %d\n", vol_info.alignment);
+
+ printf("Size: %d LEBs (", vol_info.rsvd_lebs);
+ ubiutils_print_bytes(vol_info.rsvd_bytes, 0);
+ printf(")\n");
+
+ if (vol_info.type == UBI_STATIC_VOLUME) {
+ printf("Data bytes: ");
+ ubiutils_print_bytes(vol_info.data_bytes, 1);
+ printf("\n");
+ }
+ printf("State: %s\n", vol_info.corrupted ? "corrupted" : "OK");
+ printf("Name: %s\n", vol_info.name);
+ printf("Character device major/minor: %d:%d\n",
+ vol_info.major, vol_info.minor);
+
+ return 0;
+}
+
+static int print_dev_info(libubi_t libubi, int dev_num, int all)
+{
+ int i, err, first = 1;
+ struct ubi_dev_info dev_info;
+ struct ubi_vol_info vol_info;
+
+ err = ubi_get_dev_info1(libubi, dev_num, &dev_info);
+ if (err)
+ return sys_errmsg("cannot get information about UBI device %d", dev_num);
+
+ printf("ubi%d:\n", dev_info.dev_num);
+ printf("Volumes count: %d\n", dev_info.vol_count);
+ printf("Logical eraseblock size: %d\n", dev_info.leb_size);
+
+ printf("Total amount of logical eraseblocks: %d (", dev_info.total_lebs);
+ ubiutils_print_bytes(dev_info.total_bytes, 0);
+ printf(")\n");
+
+ printf("Amount of available logical eraseblocks: %d (", dev_info.avail_lebs);
+ ubiutils_print_bytes(dev_info.avail_bytes, 0);
+ printf(")\n");
+
+ printf("Maximum count of volumes %d\n", dev_info.max_vol_count);
+ printf("Count of bad physical eraseblocks: %d\n", dev_info.bad_count);
+ printf("Count of reserved physical eraseblocks: %d\n", dev_info.bad_rsvd);
+ printf("Current maximum erase counter value: %lld\n", dev_info.max_ec);
+ printf("Minimum input/output unit size: %d bytes\n", dev_info.min_io_size);
+ printf("Character device major/minor: %d:%d\n",
+ dev_info.major, dev_info.minor);
+
+ if (dev_info.vol_count == 0)
+ return 0;
+
+ printf("Present volumes: ");
+ for (i = dev_info.lowest_vol_id;
+ i <= dev_info.highest_vol_id; i++) {
+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info);
+ if (err == -1) {
+ if (errno == ENOENT)
+ continue;
+
+ return sys_errmsg("libubi failed to probe volume %d on ubi%d",
+ i, dev_info.dev_num);
+ }
+
+ if (!first)
+ printf(", %d", i);
+ else {
+ printf("%d", i);
+ first = 0;
+ }
+ }
+ printf("\n");
+
+ if (!all)
+ return 0;
+
+ first = 1;
+ printf("\n");
+
+ for (i = dev_info.lowest_vol_id;
+ i <= dev_info.highest_vol_id; i++) {
+ if(!first)
+ printf("-----------------------------------\n");
+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info);
+ if (err == -1) {
+ if (errno == ENOENT)
+ continue;
+
+ return sys_errmsg("libubi failed to probe volume %d on ubi%d",
+ i, dev_info.dev_num);
+ }
+ first = 0;
+
+ err = print_vol_info(libubi, dev_info.dev_num, i);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int print_general_info(libubi_t libubi, int all)
+{
+ int i, err, first = 1;
+ struct ubi_info ubi_info;
+ struct ubi_dev_info dev_info;
+
+ err = ubi_get_info(libubi, &ubi_info);
+ if (err)
+ return sys_errmsg("cannot get UBI information");
+
+ printf("UBI version: %d\n", ubi_info.version);
+ printf("Count of UBI devices: %d\n", ubi_info.dev_count);
+ if (ubi_info.ctrl_major != -1)
+ printf("UBI control device major/minor: %d:%d\n",
+ ubi_info.ctrl_major, ubi_info.ctrl_minor);
+ else
+ printf("UBI control device is not supported by this kernel\n");
+
+ if (ubi_info.dev_count == 0)
+ return 0;
+
+ printf("Present UBI devices: ");
+ for (i = ubi_info.lowest_dev_num;
+ i <= ubi_info.highest_dev_num; i++) {
+ err = ubi_get_dev_info1(libubi, i, &dev_info);
+ if (err == -1) {
+ if (errno == ENOENT)
+ continue;
+
+ return sys_errmsg("libubi failed to probe UBI device %d", i);
+ }
+
+ if (!first)
+ printf(", ubi%d", i);
+ else {
+ printf("ubi%d", i);
+ first = 0;
+ }
+ }
+ printf("\n");
+
+ if (!all)
+ return 0;
+
+ first = 1;
+ printf("\n");
+
+ for (i = ubi_info.lowest_dev_num;
+ i <= ubi_info.highest_dev_num; i++) {
+ if(!first)
+ printf("\n===================================\n\n");
+ err = ubi_get_dev_info1(libubi, i, &dev_info);
+ if (err == -1) {
+ if (errno == ENOENT)
+ continue;
+
+ return sys_errmsg("libubi failed to probe UBI device %d", i);
+ }
+ first = 0;
+
+ err = print_dev_info(libubi, i, all);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ if (!args.node && args.devn != -1)
+ return errmsg("specify either device number or node file (use -h for help)");
+
+ libubi = libubi_open(1);
+ if (libubi == NULL)
+ return sys_errmsg("cannot open libubi");
+
+ if (args.node) {
+ /*
+ * A character device was specified, translate this into UBI
+ * device number and volume ID.
+ */
+ err = translate_dev(libubi, args.node);
+ if (err)
+ goto out_libubi;
+ }
+
+ if (args.vol_id != -1 && args.devn == -1) {
+ errmsg("volume ID is specified, but UBI device number is not "
+ "(use -h for help)\n");
+ goto out_libubi;
+ }
+
+ if (args.devn != -1 && args.vol_id != -1) {
+ print_vol_info(libubi, args.devn, args.vol_id);
+ goto out;
+ }
+
+ if (args.devn == -1 && args.vol_id == -1)
+ err = print_general_info(libubi, args.all);
+ else if (args.devn != -1 && args.vol_id == -1)
+ err = print_dev_info(libubi, args.devn, args.all);
+
+ if (err)
+ goto out_libubi;
+
+out:
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
diff --git a/ubi-utils/src/ubinize.c b/ubi-utils/src/ubinize.c
new file mode 100644
index 0000000..0762aa8
--- /dev/null
+++ b/ubi-utils/src/ubinize.c
@@ -0,0 +1,612 @@
+/*
+ * 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 <sys/stat.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <mtd/ubi-media.h>
+#include <libubigen.h>
+#include <libiniparser.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.1"
+#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\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 next\n"
+" minimum I/O unit or sub-page after the EC\n"
+" header)\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 ubi.img -p 16KiB -m 512 -s 256 cfg.ini - create UBI image\n"
+" 'ubi.img' as described by configuration file '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 = 0, .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;
+ int out_fd;
+ 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 = {
+ .peb_size = -1,
+ .min_io_size = -1,
+ .subpage_size = -1,
+ .ubi_ver = 1,
+};
+
+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.out_fd = open(optarg, O_CREAT | O_TRUNC | O_WRONLY,
+ S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ if (args.out_fd == -1)
+ return sys_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);
+ if (!is_power_of_2(args.min_io_size))
+ return errmsg("min. I/O unit size should be power of 2");
+ break;
+
+ case 's':
+ args.subpage_size = ubiutils_get_bytes(optarg);
+ if (args.subpage_size <= 0)
+ return errmsg("bad sub-page size: \"%s\"", optarg);
+ if (!is_power_of_2(args.subpage_size))
+ return errmsg("sub-page size should be power of 2");
+ break;
+
+ case 'O':
+ args.vid_hdr_offs = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || 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 != '\0' || 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 != '\0' || 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 configuration file was not specified (use -h for help)");
+
+ if (optind != argc - 1)
+ return errmsg("more then one configuration 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.peb_size > 1024*1024)
+ return errmsg("too high physical eraseblock size %d", args.peb_size);
+
+ 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.subpage_size > args.min_io_size)
+ return errmsg("sub-page cannot be larger then min. I/O unit");
+
+ if (args.peb_size % args.min_io_size)
+ return errmsg("physical eraseblock should be multiple of min. I/O units");
+
+ if (args.min_io_size % args.subpage_size)
+ return errmsg("min. I/O unit size should be multiple of sub-page size");
+
+ if (!args.f_out)
+ return errmsg("output file was not specified (use -h for help)");
+
+ if (args.vid_hdr_offs) {
+ if (args.vid_hdr_offs + (int)UBI_VID_HDR_SIZE >= args.peb_size)
+ return errmsg("bad VID header position");
+ if (args.vid_hdr_offs % 8)
+ return errmsg("VID header offset has to be multiple of min. I/O unit size");
+ }
+
+ return 0;
+}
+
+static int read_section(const struct ubigen_info *ui, const char *sname,
+ struct ubigen_vol_info *vi, const char **img,
+ struct stat *st)
+{
+ 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 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\" in section \"%s\"",
+ p, sname);
+ }
+
+ verbose(args.verbose, "volume type: %s",
+ vi->type == UBI_VID_DYNAMIC ? "dynamic" : "static");
+
+ /* Fetch the name of the volume image file */
+ sprintf(buf, "%s:image", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (p) {
+ *img = p;
+ if (stat(p, st))
+ return sys_errmsg("cannot stat \"%s\" referred from section \"%s\"",
+ p, sname);
+ if (st->st_size == 0)
+ return errmsg("empty file \"%s\" referred from section \"%s\"",
+ p, sname);
+ } else if (vi->type == UBI_VID_STATIC)
+ return errmsg("image is not specified for static volume in section \"%s\"",
+ sname);
+
+ /* 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 in section \"%s\"",
+ vi->id, sname);
+ if (vi->id >= ui->max_volumes)
+ return errmsg("too high volume ID %d in section \"%s\", max. is %d",
+ vi->id, sname, ui->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 value \"%s\" (section \"%s\")",
+ p, sname);
+
+ /* Make sure the image size is not larger than volume size */
+ if (*img && st->st_size > vi->bytes)
+ return errmsg("error in section \"%s\": size of the image file "
+ "\"%s\" is %lld, which is larger than volume size %lld",
+ sname, *img, (long long)st->st_size, vi->bytes);
+ 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 in section \"%s\"", sname);
+
+ 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);
+
+ normsg_cont("volume size was not specified in section \"%s\", assume"
+ " minimum to fit image \"%s\"", sname, *img);
+ ubiutils_print_bytes(vi->bytes, 1);
+ printf("\n");
+ }
+
+ /* 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)
+ vi->alignment = 1;
+ else if (vi->id < 0)
+ return errmsg("negative volume alignement %d in section \"%s\"",
+ vi->alignment, sname);
+
+ 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);
+ }
+ }
+
+ /* Initialize the rest of the volume information */
+ vi->data_pad = ui->leb_size % vi->alignment;
+ vi->usable_leb_size = ui->leb_size - vi->data_pad;
+ if (vi->type == UBI_VID_DYNAMIC)
+ vi->used_ebs = (vi->bytes + vi->usable_leb_size - 1) / vi->usable_leb_size;
+ else
+ vi->used_ebs = (st->st_size + vi->usable_leb_size - 1) / vi->usable_leb_size;
+ vi->compat = 0;
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err = -1, sects, i, autoresize_was_already = 0;
+ struct ubigen_info ui;
+ struct ubi_vtbl_record *vtbl;
+ struct ubigen_vol_info *vi;
+ off_t seek;
+
+ 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);
+
+ verbose(args.verbose, "LEB size: %d", ui.leb_size);
+ verbose(args.verbose, "PEB size: %d", ui.peb_size);
+ verbose(args.verbose, "min. I/O size: %d", ui.min_io_size);
+ verbose(args.verbose, "sub-page size: %d", args.subpage_size);
+ verbose(args.verbose, "VID offset: %d", ui.vid_hdr_offs);
+ verbose(args.verbose, "data offset: %d", ui.data_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;
+ }
+
+ if (sects > ui.max_volumes) {
+ errmsg("too many sections (%d) in the ini-file \"%s\"",
+ sects, args.f_in);
+ normsg("each section corresponds to an UBI volume, maximum "
+ "count of volumes is %d", ui.max_volumes);
+ goto out_dict;
+ }
+
+ vi = calloc(sizeof(struct ubigen_vol_info), sects);
+ if (!vi) {
+ errmsg("cannot allocate memory");
+ goto out_dict;
+ }
+
+ /*
+ * Skip 2 PEBs at the beginning of the file for the volume table which
+ * will be written later.
+ */
+ seek = ui.peb_size * 2;
+ if (lseek(args.out_fd, seek, SEEK_SET) != seek) {
+ sys_errmsg("cannot seek file \"%s\"", args.f_out);
+ goto out_free;
+ }
+
+ for (i = 0; i < sects; i++) {
+ const char *sname = iniparser_getsecname(args.dict, i);
+ const char *img = NULL;
+ struct stat st;
+ int fd, j;
+
+ if (!sname) {
+ errmsg("ini-file parsing error (iniparser_getsecname)");
+ goto out_free;
+ }
+
+ if (args.verbose)
+ printf("\n");
+ verbose(args.verbose, "parsing section \"%s\"", sname);
+
+ err = read_section(&ui, sname, &vi[i], &img, &st);
+ if (err == -1)
+ goto out_free;
+
+ verbose(args.verbose, "adding volume %d", vi[i].id);
+
+ /*
+ * Make sure that volume ID and name is unique and that only
+ * one volume has auto-resize flag
+ */
+ for (j = 0; j < i; j++) {
+ if (vi[i].id == vi[j].id) {
+ errmsg("volume IDs must be unique, but ID %d "
+ "in section \"%s\" is not",
+ vi[i].id, sname);
+ goto out_free;
+ }
+
+ if (!strcmp(vi[i].name, vi[j].name)) {
+ errmsg("volume name must be unique, but name "
+ "\"%s\" in section \"%s\" is not",
+ vi[i].name, sname);
+ goto out_free;
+ }
+ }
+
+ if (vi[i].flags & UBI_VTBL_AUTORESIZE_FLG) {
+ if (autoresize_was_already)
+ return errmsg("only one volume is allowed "
+ "to have auto-resize flag");
+ autoresize_was_already = 1;
+ }
+
+ err = ubigen_add_volume(&ui, &vi[i], vtbl);
+ if (err) {
+ errmsg("cannot add volume for section \"%s\"", sname);
+ goto out_free;
+ }
+
+ if (img) {
+ fd = open(img, O_RDONLY);
+ if (fd == -1) {
+ sys_errmsg("cannot open \"%s\"", img);
+ goto out_free;
+ }
+
+ verbose(args.verbose, "writing volume %d", vi[i].id);
+ verbose(args.verbose, "image file: %s", img);
+
+ err = ubigen_write_volume(&ui, &vi[i], args.ec, st.st_size, fd, args.out_fd);
+ close(fd);
+ if (err) {
+ errmsg("cannot write volume for section \"%s\"", sname);
+ goto out_free;
+ }
+ }
+
+ if (args.verbose)
+ printf("\n");
+ }
+
+ verbose(args.verbose, "writing layout volume");
+
+ err = ubigen_write_layout_vol(&ui, 0, 1, args.ec, args.ec, vtbl, args.out_fd);
+ if (err) {
+ errmsg("cannot write layout volume");
+ goto out_free;
+ }
+
+ verbose(args.verbose, "done");
+
+ free(vi);
+ iniparser_freedict(args.dict);
+ free(vtbl);
+ close(args.out_fd);
+ return 0;
+
+out_free:
+ free(vi);
+out_dict:
+ iniparser_freedict(args.dict);
+out_vtbl:
+ free(vtbl);
+out:
+ close(args.out_fd);
+ remove(args.f_out);
+ return err;
+}
diff --git a/ubi-utils/src/ubirename.c b/ubi-utils/src/ubirename.c
new file mode 100644
index 0000000..8f33718
--- /dev/null
+++ b/ubi-utils/src/ubirename.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2008 Logitech.
+ *
+ * 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
+ */
+
+/*
+ * An utility to get rename UBI volumes.
+ *
+ * Author: Richard Titmuss
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubirename"
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <UBI device node file name> [<old name> <new name>|...]\n\n"
+"Example: " PROGRAM_NAME "/dev/ubi0 A B C D - rename volume A to B, and C to D\n\n"
+"This utility allows re-naming several volumes in one go atomically.\n"
+"For example, if you have volumes A and B, then you may rename A into B\n"
+"and B into A at one go, and the operation will be atomic. This allows\n"
+"implementing atomic UBI volumes upgrades. E.g., if you have volume A\n"
+"and want to upgrade it atomically, you create a temporary volume B,\n"
+"put your new data to B, then rename A to B and B to A, and then you\n"
+"may remove old volume B.\n"
+"It is also allowed to re-name multiple volumes at a time, but 16 max.\n"
+"renames at once, which means you may specify up to 32 volume names.\n"
+"If you have volumes A and B, and re-name A to B, bud do not re-name\n"
+"B to something else in the same request, old volume B will be removed\n"
+"and A will be renamed into B.\n";
+
+static int get_vol_id(libubi_t libubi, struct ubi_dev_info *dev_info,
+ char *name)
+{
+ int err, i;
+ struct ubi_vol_info vol_info;
+
+ for (i=dev_info->lowest_vol_id; i<=dev_info->highest_vol_id; i++) {
+ err = ubi_get_vol_info1(libubi, dev_info->dev_num, i, &vol_info);
+ if (err == -1) {
+ if (errno == ENOENT)
+ continue;
+ return -1;
+ }
+
+ if (strcmp(name, vol_info.name) == 0)
+ return vol_info.vol_id;
+ }
+
+ return -1;
+}
+
+int main(int argc, char * const argv[])
+{
+ int i, err;
+ int count = 0;
+ libubi_t libubi;
+ struct ubi_dev_info dev_info;
+ struct ubi_rnvol_req rnvol;
+ const char *node;
+
+ if (argc < 3 || (argc & 1) == 1) {
+ errmsg("too few arguments");
+ fprintf(stderr, "%s\n", usage);
+ return -1;
+ }
+
+ if (argc > UBI_MAX_RNVOL + 2) {
+ errmsg("too many volumes to re-name, max. is %d",
+ UBI_MAX_RNVOL);
+ return -1;
+ }
+
+ node = argv[1];
+ libubi = libubi_open(1);
+ if (!libubi)
+ return sys_errmsg("cannot open libubi");
+
+ err = ubi_node_type(libubi, node);
+ if (err == 2) {
+ errmsg("\"%s\" is an UBI volume node, not an UBI device node",
+ node);
+ goto out_libubi;
+ } else if (err < 0) {
+ errmsg("\"%s\" is not an UBI device node", node);
+ goto out_libubi;
+ }
+
+ err = ubi_get_dev_info(libubi, node, &dev_info);
+ if (err == -1) {
+ sys_errmsg("cannot get information about UBI device \"%s\"", node);
+ goto out_libubi;
+ }
+
+ for (i = 2; i < argc; i += 2) {
+ err = get_vol_id(libubi, &dev_info, argv[i]);
+ if (err == -1) {
+ errmsg("\"%s\" volume not found", argv[i]);
+ goto out_libubi;
+ }
+
+ rnvol.ents[count].vol_id = err;
+ rnvol.ents[count].name_len = strlen(argv[i + 1]);
+ strcpy(rnvol.ents[count++].name, argv[i + 1]);
+ }
+
+ rnvol.count = count;
+
+ err = ubi_rnvols(libubi, node, &rnvol);
+ if (err == -1) {
+ sys_errmsg("cannot rename volumes");
+ goto out_libubi;
+ }
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
diff --git a/ubi-utils/src/ubirmvol.c b/ubi-utils/src/ubirmvol.c
new file mode 100644
index 0000000..a4cf1df
--- /dev/null
+++ b/ubi-utils/src/ubirmvol.c
@@ -0,0 +1,230 @@
+/*
+ * 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.
+ */
+
+/*
+ * An utility to remove UBI volumes.
+ *
+ * Authors: Artem Bityutskiy <dedekind@infradead.org>
+ * Frank Haverkamp <haver@vnet.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubirmvol"
+
+/* The variables below are set by command line arguments */
+struct args {
+ int vol_id;
+ const char *node;
+ const char *name;
+ /* For deprecated -d option handling */
+ int devn;
+ char dev_name[256];
+};
+
+static struct args args = {
+ .vol_id = -1,
+ .devn = -1,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to remove UBI volumes.";
+
+static const char *optionsstr =
+"-n, --vol_id=<volume id> volume ID to remove\n"
+"-N, --name=<volume name> volume name to remove\n"
+"-h, -?, --help print help message\n"
+"-V, --version print program version\n\n"
+"The following is a compatibility option which is deprecated, do not use it\n"
+"-d, --devn=<devn> UBI device number - may be used instead of the UBI\n"
+" device node name in which case the utility assumes\n"
+" that the device node is \"/dev/ubi<devn>\"";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <UBI device node file name> [-n <volume id>] [--vol_id=<volume id>]\n\n"
+" [-N <volume name>] [--name=<volume name>] [-h] [--help]\n\n"
+"Example: " PROGRAM_NAME "/dev/ubi0 -n 1 - remove UBI volume 1 from UBI device corresponding\n"
+" to /dev/ubi0\n"
+" " PROGRAM_NAME "/dev/ubi0 -N my_vol - remove UBI named \"my_vol\" from UBI device\n"
+" corresponding to /dev/ubi0";
+
+static const struct option long_options[] = {
+ { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' },
+ { .name = "name", .has_arg = 1, .flag = NULL, .val = 'N' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ /* Deprecated -d option */
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { NULL, 0, NULL, 0},
+};
+
+static int param_sanity_check(void)
+{
+ if (args.vol_id == -1 && !args.name) {
+ errmsg("please, specify either volume ID or volume name");
+ return -1;
+ }
+
+ if (args.vol_id != -1 && args.name) {
+ errmsg("please, specify either volume ID or volume name, not both");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "n:N:h?Vd:", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+
+ case 'n':
+ args.vol_id = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.vol_id < 0) {
+ errmsg("bad volume ID: " "\"%s\"", optarg);
+ return -1;
+ }
+ break;
+
+ case 'N':
+ args.name = optarg;
+ break;
+
+ case 'h':
+ case '?':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'd':
+ /* Handle deprecated -d option */
+ warnmsg("-d is depricated and will be removed, do not use it");
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: " "\"%s\"", optarg);
+ break;
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ errmsg("parameter is missing");
+ return -1;
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ /* Handle deprecated -d option */
+ if (args.devn != -1) {
+ sprintf(args.dev_name, "/dev/ubi%d", args.devn);
+ args.node = args.dev_name;
+ } else {
+ if (optind == argc) {
+ errmsg("UBI device name was not specified (use -h for help)");
+ return -1;
+ } else if (optind != argc - 1) {
+ errmsg("more then one UBI device specified (use -h for help)");
+ return -1;
+ }
+
+ args.node = argv[optind];
+ }
+
+ if (param_sanity_check())
+ return -1;
+
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ libubi = libubi_open(1);
+ if (libubi == NULL)
+ return sys_errmsg("cannot open libubi");
+
+ err = ubi_node_type(libubi, args.node);
+ if (err == 2) {
+ errmsg("\"%s\" is an UBI volume node, not an UBI device node",
+ args.node);
+ goto out_libubi;
+ } else if (err < 0) {
+ errmsg("\"%s\" is not an UBI device node", args.node);
+ goto out_libubi;
+ }
+
+ if (args.name) {
+ struct ubi_dev_info dev_info;
+ struct ubi_vol_info vol_info;
+
+ err = ubi_get_dev_info(libubi, args.node, &dev_info);
+ if (err) {
+ sys_errmsg("cannot get information about UBI device \"%s\"",
+ args.node);
+ goto out_libubi;
+ }
+
+ err = ubi_get_vol_info1_nm(libubi, dev_info.dev_num,
+ args.name, &vol_info);
+ if (err) {
+ sys_errmsg("cannot find UBI volume \"%s\"", args.name);
+ goto out_libubi;
+ }
+
+ args.vol_id = vol_info.vol_id;
+ }
+
+ err = ubi_rmvol(libubi, args.node, args.vol_id);
+ if (err) {
+ sys_errmsg("cannot UBI remove volume");
+ goto out_libubi;
+ }
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
diff --git a/ubi-utils/src/ubiupdatevol.c b/ubi-utils/src/ubiupdatevol.c
new file mode 100644
index 0000000..c83731c
--- /dev/null
+++ b/ubi-utils/src/ubiupdatevol.c
@@ -0,0 +1,355 @@
+/*
+ * 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.
+ */
+
+/*
+ * An utility to update UBI volumes.
+ *
+ * Authors: Frank Haverkamp
+ * Joshua W. Boyer
+ * Artem Bityutskiy
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.1"
+#define PROGRAM_NAME "ubiupdatevol"
+
+struct args {
+ int truncate;
+ const char *node;
+ const char *img;
+ /* For deprecated -d and -B options handling */
+ int devn;
+ char dev_name[256];
+ int broken_update;
+ int size;
+ int use_stdin;
+};
+
+static struct args args = {
+ .devn = -1,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to write data to UBI volumes.";
+
+static const char *optionsstr =
+"-t, --truncate truncate volume (wipe it out)\n"
+"-h, --help print help message\n"
+"-V, --version print program version\n\n"
+"-s, --size=<bytes> bytes in input, if not reading from file\n"
+"The following are compatibility options which are deprecated, do not use them\n"
+"-d, --devn=<devn> UBI device number - may be used instead of the UBI\n"
+" device node name in which case the utility assumes\n"
+" that the device node is \"/dev/ubi<devn>\"\n"
+"-B, --broken-update broken update, this is for testing";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <UBI volume node file name> [-t] [-h] [-V] [--truncate] [--size=x] [--help]\n"
+"\t\t\t[--version] <image file>\n\n"
+"Example 1: " PROGRAM_NAME " /dev/ubi0_1 fs.img - write file \"fs.img\" to UBI volume /dev/ubi0_1\n"
+"Example 2: " PROGRAM_NAME " /dev/ubi0_1 -t - wipe out UBI volume /dev/ubi0_1";
+
+struct option long_options[] = {
+ { .name = "truncate", .has_arg = 0, .flag = NULL, .val = 't' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { .name = "size", .has_arg = 1, .flag = NULL, .val = 's' },
+ /* Deprecated -d and -B options */
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { .name = "broken-update", .has_arg = 1, .flag = NULL, .val = 'B' },
+ { NULL, 0, NULL, 0}
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "n:th?Vd:s:", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 't':
+ args.truncate = 1;
+ break;
+
+ case 's':
+ args.size = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.size < 0)
+ return errmsg("bad size: " "\"%s\"", optarg);
+ break;
+
+ case 'h':
+ case '?':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'd':
+ /* Handle deprecated -d option */
+ warnmsg("-d is depricated and will be removed, do not use it");
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: " "\"%s\"", optarg);
+ break;
+
+ case 'B':
+ /* Handle deprecated -B option */
+ warnmsg("-B is depricated and will be removed, do not use it");
+ args.broken_update = 1;
+ break;
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ /* Handle deprecated -d option */
+ if (args.devn != -1) {
+ sprintf(args.dev_name, "/dev/ubi%d", args.devn);
+ args.node = args.dev_name;
+ } else {
+ if (optind == argc)
+ return errmsg("UBI device name was not specified (use -h for help)");
+ else if (optind != argc - 2 && !args.truncate)
+ return errmsg("specify UBI device name and image file name as first 2 "
+ "parameters (use -h for help)");
+ }
+
+ args.node = argv[optind];
+ args.img = argv[optind + 1];
+
+ if (args.img && args.truncate)
+ return errmsg("You can't truncate and specify an image (use -h for help)");
+
+ if (args.img && !args.truncate) {
+ if (strcmp(args.img, "-") == 0)
+ args.use_stdin = 1;
+ if (args.use_stdin && !args.size)
+ return errmsg("file size must be specified if input is stdin");
+ }
+
+ return 0;
+}
+
+static int truncate_volume(libubi_t libubi)
+{
+ int err, fd;
+
+ fd = open(args.node, O_RDWR);
+ if (fd == -1)
+ return sys_errmsg("cannot open \"%s\"", args.node);
+
+ err = ubi_update_start(libubi, fd, 0);
+ if (err) {
+ sys_errmsg("cannot truncate volume \"%s\"", args.node);
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+static int ubi_write(int fd, const void *buf, int len)
+{
+ int ret;
+
+ while (len) {
+ ret = write(fd, buf, len);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ warnmsg("do not interrupt me!");
+ continue;
+ }
+ return sys_errmsg("cannot write %d bytes to volume \"%s\"",
+ len, args.node);
+ }
+
+ if (ret == 0)
+ return errmsg("cannot write %d bytes to volume \"%s\"", len, args.node);
+
+ len -= ret;
+ buf += ret;
+ }
+
+ return 0;
+}
+
+static int update_volume(libubi_t libubi, struct ubi_vol_info *vol_info)
+{
+ int err, fd, ifd;
+ long long bytes;
+ char *buf;
+
+ buf = malloc(vol_info->leb_size);
+ if (!buf)
+ return errmsg("cannot allocate %d bytes of memory", vol_info->leb_size);
+
+ if (!args.size) {
+ struct stat st;
+ err = stat(args.img, &st);
+ if (err < 0) {
+ errmsg("stat failed on \"%s\"", args.img);
+ goto out_free;
+ }
+
+ bytes = st.st_size;
+ } else
+ bytes = args.size;
+
+ if (bytes > vol_info->rsvd_bytes) {
+ errmsg("\"%s\" (size %lld) will not fit volume \"%s\" (size %lld)",
+ args.img, bytes, args.node, vol_info->rsvd_bytes);
+ goto out_free;
+ }
+
+ /* A hack to handle deprecated -B option */
+ if (args.broken_update)
+ bytes = 1;
+
+ fd = open(args.node, O_RDWR);
+ if (fd == -1) {
+ sys_errmsg("cannot open UBI volume \"%s\"", args.node);
+ goto out_free;
+ }
+
+ if (args.use_stdin)
+ ifd = STDIN_FILENO;
+ else {
+ ifd = open(args.img, O_RDONLY);
+ if (ifd == -1) {
+ sys_errmsg("cannot open \"%s\"", args.img);
+ goto out_close1;
+ }
+ }
+
+ err = ubi_update_start(libubi, fd, bytes);
+ if (err) {
+ sys_errmsg("cannot start volume \"%s\" update", args.node);
+ goto out_close;
+ }
+
+ while (bytes) {
+ int ret, to_copy = vol_info->leb_size;
+
+ if (to_copy > bytes)
+ to_copy = bytes;
+
+ ret = read(ifd, buf, to_copy);
+ if (ret <= 0) {
+ if (errno == EINTR) {
+ warnmsg("do not interrupt me!");
+ continue;
+ } else {
+ sys_errmsg("cannot read %d bytes from \"%s\"",
+ to_copy, args.img);
+ goto out_close;
+ }
+ }
+
+ err = ubi_write(fd, buf, ret);
+ if (err)
+ goto out_close;
+ bytes -= ret;
+ }
+
+ close(ifd);
+ close(fd);
+ free(buf);
+ return 0;
+
+out_close:
+ close(ifd);
+out_close1:
+ close(fd);
+out_free:
+ free(buf);
+ return -1;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+ struct ubi_vol_info vol_info;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ libubi = libubi_open(1);
+ if (libubi == NULL) {
+ sys_errmsg("cannot open libubi");
+ goto out_libubi;
+ }
+
+ err = ubi_node_type(libubi, args.node);
+ if (err == 1) {
+ errmsg("\"%s\" is an UBI device node, not an UBI volume node",
+ args.node);
+ goto out_libubi;
+ } else if (err < 0) {
+ errmsg("\"%s\" is not an UBI volume node", args.node);
+ goto out_libubi;
+ }
+
+ err = ubi_get_vol_info(libubi, args.node, &vol_info);
+ if (err) {
+ sys_errmsg("cannot get information about UBI volume \"%s\"",
+ args.node);
+ goto out_libubi;
+ }
+
+ if (args.truncate)
+ err = truncate_volume(libubi);
+ else
+ err = update_volume(libubi, &vol_info);
+ if (err)
+ goto out_libubi;
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
diff --git a/ubi-utils/src/unubi.c b/ubi-utils/src/unubi.c
deleted file mode 100644
index 0f72b18..0000000
--- a/ubi-utils/src/unubi.c
+++ /dev/null
@@ -1,1024 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2006, 2007
- *
- * 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.
- */
-
-/*
- * Authors: Drake Dowsett, dowsett@de.ibm.com
- * Frank Haverkamp, haver@vnet.ibm.com
- *
- * 1.2 Removed argp because we want to use uClibc.
- * 1.3 Minor cleanups.
- * 1.4 Meanwhile Drake had done a lot of changes, syncing those.
- * 1.5 Bugfixes, simplifications
- */
-
-/*
- * unubi reads an image file containing blocks of UBI headers and data
- * (such as produced from nand2bin) and rebuilds the volumes within. The
- * default operation (when no flags are given) is to rebuild all valid
- * volumes found in the image. unubi can also read straight from the
- * onboard MTD device (ex. /dev/mtdblock/NAND).
- */
-
-/* TODO: consideration for dynamic vs. static volumes */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <getopt.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <limits.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <mtd/ubi-media.h>
-#include <mtd_swab.h>
-
-#include "crc32.h"
-#include "unubi_analyze.h"
-
-#define EXEC "unubi"
-#define CONTACT "haver@vnet.ibm.com"
-#define VERSION "1.5"
-
-static char doc[] = "\nVersion: " VERSION "\n";
-static int debug = 0;
-
-static const char *optionsstr =
-"Extract volumes and/or analysis information from an UBI data file.\n"
-"When no parameters are flagged or given, the default operation is\n"
-"to rebuild all valid complete UBI volumes found within the image.\n"
-"\n"
-" OPERATIONS\n"
-" -a, --analyze Analyze image and create gnuplot graphs\n"
-" -i, --info-table Extract volume information tables\n"
-" -r, --rebuild=<volume-id> Extract and rebuild volume\n"
-"\n"
-" OPTIONS\n"
-" -b, --blocksize=<block-size> Specify size of eraseblocks in image in bytes\n"
-" (default 128KiB)\n"
-" -d, --dir=<output-dir> Specify output directory\n"
-" -D, --debug Enable debug output\n"
-" -s, --headersize=<header-size> Specify size reserved for metadata in eraseblock\n"
- " in bytes (default 2048 Byte)\n"
- /* the -s option might be insufficient when using different vid
- offset than what we used when writing this tool ... Better would
- probably be --vid-hdr-offset or alike */
-"\n"
-" ADVANCED\n"
-" -e, --eb-split Generate individual eraseblock images (all\n"
-" eraseblocks)\n"
-" -v, --vol-split Generate individual eraseblock images (valid\n"
-" eraseblocks only)\n"
-" -V, --vol-split! Raw split by eraseblock (valid eraseblocks only)\n"
-"\n"
-" -?, --help Give this help list\n"
-" --usage Give a short usage message\n"
-" --version Print program version\n"
-"\n";
-
-static const char *usage =
-"Usage: unubi [-aievV?] [-r <volume-id>] [-b <block-size>] [-d <output-dir>]\n"
-" [-s <header-size>] [--analyze] [--info-table]\n"
-" [--rebuild=<volume-id>] [--blocksize=<block-size>]\n"
-" [--dir=<output-dir>] [--headersize=<header-size>] [--eb-split]\n"
-" [--vol-split] [--vol-split!] [--help] [--usage] [--version]\n"
-" image-file\n";
-
-#define ERR_MSG(fmt...) \
- fprintf(stderr, EXEC ": " fmt)
-
-#define SPLIT_DATA 1
-#define SPLIT_RAW 2
-
-#define DIR_FMT "unubi_%s"
-#define KIB 1024
-#define MIB (KIB * KIB)
-#define MAXPATH KIB
-
-/* filenames */
-#define FN_INVAL "%s/eb%04u%s" /* invalid eraseblock */
-#define FN_NSURE "%s/eb%04u_%03u_%03u_%03x%s" /* unsure eraseblock */
-#define FN_VALID "%s/eb%04u_%03u_%03u_%03x%s" /* valid eraseblock */
-#define FN_VOLSP "%s/vol%03u_%03u_%03u_%04zu" /* split volume */
-#define FN_VOLWH "%s/volume%03u" /* whole volume */
-#define FN_VITBL "%s/vol_info_table%zu" /* vol info table */
-
-static uint32_t crc32_table[256];
-
-/* struct args:
- * bsize int, blocksize of image blocks
- * hsize int, eraseblock header size
- * analyze flag, when non-zero produce analysis
- * eb_split flag, when non-zero output eb####
- * note: SPLIT_DATA vs. SPLIT_RAW
- * vol_split flag, when non-zero output vol###_####
- * note: SPLIT_DATA vs. SPLIT_RAW
- * odir_path string, directory to place volumes in
- * img_path string, file to read as ubi image
- * vols int array of size UBI_MAX_VOLUMES, where a 1 can be
- * written for each --rebuild flag in the index specified
- * then the array can be counted and collapsed using
- * count_set() and collapse()
- */
-struct args {
- int analyze;
- int itable;
- uint32_t *vols;
-
- size_t vid_hdr_offset;
- size_t data_offset;
- size_t bsize; /* FIXME replace by vid_hdr/data offs? */
- size_t hsize;
-
- char *odir_path;
- int eb_split;
- int vol_split;
- char *img_path;
-
- char **options;
-};
-
-struct option long_options[] = {
- { .name = "rebuild", .has_arg = 1, .flag = NULL, .val = 'r' },
- { .name = "dir", .has_arg = 1, .flag = NULL, .val = 'd' },
- { .name = "analyze", .has_arg = 0, .flag = NULL, .val = 'a' },
- { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'b' },
- { .name = "eb-split", .has_arg = 0, .flag = NULL, .val = 'e' },
- { .name = "vol-split", .has_arg = 0, .flag = NULL, .val = 'v' },
- { .name = "vol-split!", .has_arg = 0, .flag = NULL, .val = 'e' },
- { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
- { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
- { .name = "version", .has_arg = 0, .flag = NULL, .val = 'J' },
- { NULL, 0, NULL, 0}
-};
-
-/**
- * parses out a numerical value from a string of numbers followed by:
- * k, K, kib, KiB for kibibyte
- * m, M, mib, MiB for mebibyte
- **/
-static uint32_t
-str_to_num(char *str)
-{
- char *s;
- ulong num;
-
- s = str;
- num = strtoul(s, &s, 0);
-
- if (*s != '\0') {
- if ((strcmp(s, "KiB") == 0) || (strcmp(s, "K") == 0) ||
- (strcmp(s, "kib") == 0) || (strcmp(s, "k") == 0))
- num *= KIB;
- else if ((strcmp(s, "MiB") == 0) || (strcmp(s, "M") == 0) ||
- (strcmp(s, "mib") == 0) || (strcmp(s, "m") == 0))
- num *= MIB;
- else
- ERR_MSG("couldn't parse '%s', assuming %lu\n",
- s, num);
- }
- return num;
-}
-
-static int
-parse_opt(int argc, char **argv, struct args *args)
-{
- uint32_t i;
-
- while (1) {
- int key;
-
- key = getopt_long(argc, argv, "ab:s:d:Deir:vV?J",
- long_options, NULL);
- if (key == -1)
- break;
-
- switch (key) {
- case 'a': /* --analyze */
- args->analyze = 1;
- break;
- case 'b': /* --block-size=<block-size> */
- args->bsize = str_to_num(optarg);
- break;
- case 's': /* --header-size=<header-size> */
- args->hsize = str_to_num(optarg);
- break;
- case 'd': /* --dir=<output-dir> */
- args->odir_path = optarg;
- break;
- case 'D': /* --debug */
- /* I wanted to use -v but that was already
- used ... */
- debug = 1;
- break;
- case 'e': /* --eb-split */
- args->eb_split = SPLIT_RAW;
- break;
- case 'i': /* --info-table */
- args->itable = 1;
- break;
- case 'r': /* --rebuild=<volume-id> */
- i = str_to_num(optarg);
- if (i < UBI_MAX_VOLUMES)
- args->vols[str_to_num(optarg)] = 1;
- else {
- ERR_MSG("volume-id out of bounds\n");
- return -1;
- }
- break;
- case 'v': /* --vol-split */
- if (args->vol_split != SPLIT_RAW)
- args->vol_split = SPLIT_DATA;
- break;
- case 'V': /* --vol-split! */
- args->vol_split = SPLIT_RAW;
- break;
- case '?': /* help */
- fprintf(stderr, "Usage: unubi [OPTION...] "
- "image-file\n%s%s\nReport bugs to %s\n",
- doc, optionsstr, CONTACT);
- exit(0);
- break;
- case 'J':
- fprintf(stderr, "%s\n", VERSION);
- exit(0);
- break;
- default:
- fprintf(stderr, "%s", usage);
- exit(-1);
- }
- }
-
- /* FIXME I suppose hsize should be replaced! */
- args->vid_hdr_offset = args->hsize - UBI_VID_HDR_SIZE;
- args->data_offset = args->hsize;
-
- if (optind < argc)
- args->img_path = argv[optind++];
- return 0;
-}
-
-
-/**
- * counts the number of indicies which are flagged in full_array;
- * full_array is an array of flags (1/0);
- **/
-static size_t
-count_set(uint32_t *full_array, size_t full_len)
-{
- size_t count, i;
-
- if (full_array == NULL)
- return 0;
-
- for (i = 0, count = 0; i < full_len; i++)
- if (full_array[i] != 0)
- count++;
-
- return count;
-}
-
-
-/**
- * generates coll_array from full_array;
- * full_array is an array of flags (1/0);
- * coll_array is an array of the indicies in full_array which are flagged (1);
- **/
-static size_t
-collapse(uint32_t *full_array, size_t full_len,
- uint32_t *coll_array, size_t coll_len)
-{
- size_t i, j;
-
- if ((full_array == NULL) || (coll_array == NULL))
- return 0;
-
- for (i = 0, j = 0; (i < full_len) && (j < coll_len); i++)
- if (full_array[i] != 0) {
- coll_array[j] = i;
- j++;
- }
-
- return j;
-}
-
-/**
- * data_crc: save the FILE* position, calculate the crc over a span,
- * reset the position
- * returns non-zero when EOF encountered
- **/
-static int
-data_crc(FILE* fpin, size_t length, uint32_t *ret_crc)
-{
- int rc;
- size_t i;
- char buf[length];
- uint32_t crc;
- fpos_t start;
-
- rc = fgetpos(fpin, &start);
- if (rc < 0)
- return -1;
-
- for (i = 0; i < length; i++) {
- int c = fgetc(fpin);
- if (c == EOF) {
- ERR_MSG("unexpected EOF\n");
- return -1;
- }
- buf[i] = (char)c;
- }
-
- rc = fsetpos(fpin, &start);
- if (rc < 0)
- return -1;
-
- crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, length);
- *ret_crc = crc;
- return 0;
-}
-
-
-/**
- * reads data of size len from fpin and writes it to path
- **/
-static int
-extract_data(FILE* fpin, size_t len, const char *path)
-{
- int rc;
- size_t i;
- FILE* fpout;
-
- rc = 0;
- fpout = NULL;
-
- fpout = fopen(path, "wb");
- if (fpout == NULL) {
- ERR_MSG("couldn't open file for writing: %s\n", path);
- rc = -1;
- goto err;
- }
-
- for (i = 0; i < len; i++) {
- int c = fgetc(fpin);
- if (c == EOF) {
- ERR_MSG("unexpected EOF while writing: %s\n", path);
- rc = -2;
- goto err;
- }
- c = fputc(c, fpout);
- if (c == EOF) {
- ERR_MSG("couldn't write: %s\n", path);
- rc = -3;
- goto err;
- }
- }
-
- err:
- if (fpout != NULL)
- fclose(fpout);
- return rc;
-}
-
-
-/**
- * extract volume information table from block. saves and reloads fpin
- * position
- * returns -1 when a fpos set or get fails, otherwise <= -2 on other
- * failure and 0 on success
- **/
-static int
-extract_itable(FILE *fpin, struct eb_info *cur, size_t bsize, size_t num,
- const char *path)
-{
- char filename[MAXPATH + 1];
- int rc;
- size_t i, max;
- fpos_t temp;
- FILE* fpout = NULL;
- struct ubi_vtbl_record rec;
-
- if (fpin == NULL || cur == NULL || path == NULL)
- return -2;
-
- /* remember position */
- rc = fgetpos(fpin, &temp);
- if (rc < 0)
- return -1;
-
- /* jump to top of eraseblock, skip to data section */
- fsetpos(fpin, &cur->eb_top);
- if (rc < 0)
- return -1;
- fseek(fpin, be32_to_cpu(cur->ec.data_offset), SEEK_CUR);
-
- /* prepare output file */
- if (be32_to_cpu(cur->vid.vol_id) != UBI_LAYOUT_VOLUME_ID)
- return -2;
- memset(filename, 0, MAXPATH + 1);
- snprintf(filename, MAXPATH, FN_VITBL, path, num);
- fpout = fopen(filename, "w");
- if (fpout == NULL)
- return -2;
-
- /* loop through entries */
- fprintf(fpout,
- "index\trpebs\talign\ttype\tcrc\t\tname\n");
- max = bsize - be32_to_cpu(cur->ec.data_offset);
- for (i = 0; i < (max / sizeof(rec)); i++) {
- int blank = 1;
- char *ptr, *base;
- char name[UBI_VOL_NAME_MAX + 1];
- const char *type = "unknown\0";
- uint32_t crc;
-
- /* read record */
- rc = fread(&rec, 1, sizeof(rec), fpin);
- if (rc == 0)
- break;
- if (rc != sizeof(rec)) {
- ERR_MSG("reading volume information "
- "table record failed\n");
- rc = -3;
- goto exit;
- }
-
- /* check crc */
- crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &rec,
- UBI_VTBL_RECORD_SIZE_CRC);
- if (crc != be32_to_cpu(rec.crc))
- continue;
-
- /* check for empty */
- base = (char *)&rec;
- ptr = base;
- while (blank &&
- ((unsigned)(ptr - base) < UBI_VTBL_RECORD_SIZE_CRC)) {
- if (*ptr != 0)
- blank = 0;
- ptr++;
- }
-
- if (blank)
- continue;
-
- /* prep type string */
- if (rec.vol_type == UBI_VID_DYNAMIC)
- type = "dynamic\0";
- else if (rec.vol_type == UBI_VID_STATIC)
- type = "static\0";
-
- /* prep name string */
- rec.name[be16_to_cpu(rec.name_len)] = '\0';
- sprintf(name, "%s", rec.name);
-
- /* print record line to fpout */
- fprintf(fpout, "%zu\t%u\t%u\t%s\t0x%08x\t%s\n",
- i,
- be32_to_cpu(rec.reserved_pebs),
- be32_to_cpu(rec.alignment),
- type,
- be32_to_cpu(rec.crc),
- name);
- }
-
- exit:
- /* reset position */
- if (fsetpos(fpin, &temp) < 0)
- rc = -1;
-
- if (fpout != NULL)
- fclose(fpout);
-
- return rc;
-}
-
-
-/**
- * using eb chain, tries to rebuild the data of volume at vol_id, or for all
- * the known volumes, if vol_id is NULL;
- **/
-static int
-rebuild_volume(FILE * fpin, uint32_t *vol_id, struct eb_info **head,
- const char *path, size_t block_size, size_t header_size)
-{
- char filename[MAXPATH];
- int rc;
- uint32_t vol, num, data_size;
- FILE* fpout;
- struct eb_info *cur;
-
- rc = 0;
-
- if ((fpin == NULL) || (head == NULL) || (*head == NULL))
- return 0;
-
- /* when vol_id is null, then do all */
- if (vol_id == NULL) {
- cur = *head;
- vol = be32_to_cpu(cur->vid.vol_id);
- } else {
- vol = *vol_id;
- eb_chain_position(head, vol, NULL, &cur);
- if (cur == NULL) {
- if (debug)
- ERR_MSG("no valid volume %d was found\n", vol);
- return -1;
- }
- }
-
- num = 0;
- snprintf(filename, MAXPATH, FN_VOLWH, path, vol);
- fpout = fopen(filename, "wb");
- if (fpout == NULL) {
- ERR_MSG("couldn't open file for writing: %s\n", filename);
- return -1;
- }
-
- while (cur != NULL) {
- size_t i;
-
- if (be32_to_cpu(cur->vid.vol_id) != vol) {
- /* close out file */
- fclose(fpout);
-
- /* only stay around if that was the only volume */
- if (vol_id != NULL)
- goto out;
-
- /* begin with next */
- vol = be32_to_cpu(cur->vid.vol_id);
- num = 0;
- snprintf(filename, MAXPATH, FN_VOLWH, path, vol);
- fpout = fopen(filename, "wb");
- if (fpout == NULL) {
- ERR_MSG("couldn't open file for writing: %s\n",
- filename);
- return -1;
- }
- }
-
- while (num < be32_to_cpu(cur->vid.lnum)) {
- /* FIXME haver: I hope an empty block is
- written out so that the binary has no holes
- ... */
- if (debug)
- ERR_MSG("missing valid block %d for volume %d\n",
- num, vol);
- num++;
- }
-
- rc = fsetpos(fpin, &(cur->eb_top));
- if (rc < 0)
- goto out;
- fseek(fpin, be32_to_cpu(cur->ec.data_offset), SEEK_CUR);
-
- if (cur->vid.vol_type == UBI_VID_DYNAMIC)
- /* FIXME It might be that alignment has influence */
- data_size = block_size - header_size;
- else
- data_size = be32_to_cpu(cur->vid.data_size);
-
- for (i = 0; i < data_size; i++) {
- int c = fgetc(fpin);
- if (c == EOF) {
- ERR_MSG("unexpected EOF while writing: %s\n",
- filename);
- rc = -2;
- goto out;
- }
- c = fputc(c, fpout);
- if (c == EOF) {
- ERR_MSG("couldn't write: %s\n", filename);
- rc = -3;
- goto out;
- }
- }
-
- cur = cur->next;
- num++;
- }
-
- out:
- if (vol_id == NULL)
- fclose(fpout);
- return rc;
-}
-
-
-/**
- * traverses FILE* trying to load complete, valid and accurate header data
- * into the eb chain;
- **/
-static int
-unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a)
-{
- char filename[MAXPATH + 1];
- char reason[MAXPATH + 1];
- int rc;
- size_t i, count, itable_num;
- /* relations:
- * cur ~ head
- * next ~ first */
- struct eb_info *head, *cur, *first, *next;
- struct eb_info **next_ptr;
-
- rc = 0;
- count = 0;
- itable_num = 0;
- head = NULL;
- first = NULL;
- next = NULL;
- cur = malloc(sizeof(*cur));
- if (cur == NULL) {
- ERR_MSG("out of memory\n");
- rc = -ENOMEM;
- goto err;
- }
- memset(cur, 0, sizeof(*cur));
-
- fgetpos(fpin, &(cur->eb_top));
- while (1) {
- const char *raw_path;
- uint32_t crc;
-
- cur->phys_addr = ftell(fpin);
- cur->phys_block = cur->phys_addr / a->bsize;
- cur->data_crc_ok = 0;
- cur->ec_crc_ok = 0;
- cur->vid_crc_ok = 0;
-
- memset(filename, 0, MAXPATH + 1);
- memset(reason, 0, MAXPATH + 1);
-
- /* in case of an incomplete ec header */
- raw_path = FN_INVAL;
-
- /* read erasecounter header */
- rc = fread(&cur->ec, 1, sizeof(cur->ec), fpin);
- if (rc == 0)
- goto out; /* EOF */
- if (rc != sizeof(cur->ec)) {
- ERR_MSG("reading ec-hdr failed\n");
- rc = -1;
- goto err;
- }
-
- /* check erasecounter header magic */
- if (be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) {
- snprintf(reason, MAXPATH, ".invalid.ec_magic");
- goto invalid;
- }
-
- /* check erasecounter header crc */
- crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &(cur->ec),
- UBI_EC_HDR_SIZE_CRC);
- if (be32_to_cpu(cur->ec.hdr_crc) != crc) {
- snprintf(reason, MAXPATH, ".invalid.ec_hdr_crc");
- goto invalid;
- }
-
- /* read volume id header */
- rc = fsetpos(fpin, &(cur->eb_top));
- if (rc != 0)
- goto err;
- fseek(fpin, be32_to_cpu(cur->ec.vid_hdr_offset), SEEK_CUR);
- rc = fread(&cur->vid, 1, sizeof(cur->vid), fpin);
- if (rc == 0)
- goto out; /* EOF */
- if (rc != sizeof(cur->vid)) {
- ERR_MSG("reading vid-hdr failed\n");
- rc = -1;
- goto err;
- }
-
- /* if the magic number is 0xFFFFFFFF, then it's very likely
- * that the volume is empty */
- if (be32_to_cpu(cur->vid.magic) == 0xffffffff) {
- snprintf(reason, MAXPATH, ".empty");
- goto invalid;
- }
-
- /* vol_id should be in bounds */
- if ((be32_to_cpu(cur->vid.vol_id) >= UBI_MAX_VOLUMES) &&
- (be32_to_cpu(cur->vid.vol_id) <
- UBI_INTERNAL_VOL_START)) {
- snprintf(reason, MAXPATH, ".invalid");
- goto invalid;
- } else
- raw_path = FN_NSURE;
-
- /* check volume id header magic */
- if (be32_to_cpu(cur->vid.magic) != UBI_VID_HDR_MAGIC) {
- snprintf(reason, MAXPATH, ".invalid.vid_magic");
- goto invalid;
- }
- cur->ec_crc_ok = 1;
-
- /* check volume id header crc */
- crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &(cur->vid),
- UBI_VID_HDR_SIZE_CRC);
- if (be32_to_cpu(cur->vid.hdr_crc) != crc) {
- snprintf(reason, MAXPATH, ".invalid.vid_hdr_crc");
- goto invalid;
- }
- cur->vid_crc_ok = 1;
-
- /* check data crc, but only for a static volume */
- if (cur->vid.vol_type == UBI_VID_STATIC) {
- rc = data_crc(fpin, be32_to_cpu(cur->vid.data_size),
- &crc);
- if (rc < 0)
- goto err;
- if (be32_to_cpu(cur->vid.data_crc) != crc) {
- snprintf(reason, MAXPATH, ".invalid.data_crc");
- goto invalid;
- }
- cur->data_crc_ok = 1;
- }
-
- /* enlist this vol, it's valid */
- raw_path = FN_VALID;
- cur->linear = count;
- rc = eb_chain_insert(&head, cur);
- if (rc < 0) {
- if (rc == -ENOMEM) {
- ERR_MSG("out of memory\n");
- goto err;
- }
- ERR_MSG("unknown and unexpected error, please contact "
- CONTACT "\n");
- goto err;
- }
-
- /* extract info-table */
- if (a->itable &&
- (be32_to_cpu(cur->vid.vol_id) == UBI_LAYOUT_VOLUME_ID)) {
- extract_itable(fpin, cur, a->bsize,
- itable_num, a->odir_path);
- itable_num++;
- }
-
- /* split volumes */
- if (a->vol_split) {
- size_t size = 0;
-
- rc = fsetpos(fpin, &(cur->eb_top));
- if (rc != 0)
- goto err;
-
- /*
- * FIXME For dynamic UBI volumes we must write
- * the maximum available data. The
- * vid.data_size field is not used in this
- * case. The dynamic volume user is
- * responsible for the content.
- */
- if (a->vol_split == SPLIT_DATA) {
- /* Write only data section */
- if (cur->vid.vol_type == UBI_VID_DYNAMIC) {
- /* FIXME Formular is not
- always right ... */
- size = a->bsize - a->hsize;
- } else
- size = be32_to_cpu(cur->vid.data_size);
-
- fseek(fpin,
- be32_to_cpu(cur->ec.data_offset),
- SEEK_CUR);
- }
- else if (a->vol_split == SPLIT_RAW)
- /* write entire eraseblock */
- size = a->bsize;
-
- snprintf(filename, MAXPATH, FN_VOLSP,
- a->odir_path,
- be32_to_cpu(cur->vid.vol_id),
- be32_to_cpu(cur->vid.lnum),
- be32_to_cpu(cur->vid.leb_ver), count);
- rc = extract_data(fpin, size, filename);
- if (rc < 0)
- goto err;
- }
-
- invalid:
- /* split eraseblocks */
- if (a->eb_split) {
- /* jump to top of block */
- rc = fsetpos(fpin, &(cur->eb_top));
- if (rc != 0)
- goto err;
-
- if (strcmp(raw_path, FN_INVAL) == 0)
- snprintf(filename, MAXPATH, raw_path,
- a->odir_path, count, reason);
- else
- snprintf(filename, MAXPATH, raw_path,
- a->odir_path,
- count,
- be32_to_cpu(cur->vid.vol_id),
- be32_to_cpu(cur->vid.lnum),
- be32_to_cpu(cur->vid.leb_ver),
- reason);
-
- rc = extract_data(fpin, a->bsize, filename);
- if (rc < 0)
- goto err;
- }
-
- /* append to simple linked list */
- if (first == NULL)
- next_ptr = &first;
- else
- next_ptr = &next->next;
-
- *next_ptr = malloc(sizeof(**next_ptr));
- if (*next_ptr == NULL) {
- ERR_MSG("out of memory\n");
- rc = -ENOMEM;
- goto err;
- }
- memset(*next_ptr, 0, sizeof(**next_ptr));
-
- next = *next_ptr;
- memcpy(next, cur, sizeof(*next));
- next->next = NULL;
-
- count++;
- rc = fsetpos(fpin, &(cur->eb_top));
- if (rc != 0)
- goto err;
- fseek(fpin, a->bsize, SEEK_CUR);
- memset(cur, 0, sizeof(*cur));
-
- fgetpos(fpin, &(cur->eb_top));
- }
-
- out:
- for (i = 0; i < vc; i++) {
- rc = rebuild_volume(fpin, &vols[i], &head, a->odir_path,
- a->bsize, a->hsize);
- if (rc < 0)
- goto err;
- }
-
- /* if there were no volumes specified, rebuild them all,
- * UNLESS eb_ or vol_ split or analyze was specified */
- if ((vc == 0) && (!a->eb_split) && (!a->vol_split) &&
- (!a->analyze) && (!a->itable)) {
- rc = rebuild_volume(fpin, NULL, &head, a->odir_path, a->bsize,
- a->hsize);
- if (rc < 0)
- goto err;
- }
-
- err:
- free(cur);
-
- if (a->analyze) {
- char fname[PATH_MAX + 1];
- FILE *fp;
-
- unubi_analyze(&head, first, a->odir_path);
-
- /* prepare output files */
- memset(fname, 0, PATH_MAX + 1);
- snprintf(fname, PATH_MAX, "%s/%s", a->odir_path, FN_EH_STAT);
- fp = fopen(fname, "w");
- if (fp != NULL) {
- eb_chain_print(fp, head);
- fclose(fp);
- }
- }
- eb_chain_destroy(&head);
- eb_chain_destroy(&first);
-
- return rc;
-}
-
-
-/**
- * handles command line arguments, then calls unubi_volumes
- **/
-int
-main(int argc, char *argv[])
-{
- int rc, free_a_odir;
- size_t vols_len;
- uint32_t *vols;
- FILE* fpin;
- struct args a;
-
- rc = 0;
- free_a_odir = 0;
- vols_len = 0;
- vols = NULL;
- fpin = NULL;
- init_crc32_table(crc32_table);
-
- /* setup struct args a */
- memset(&a, 0, sizeof(a));
- a.bsize = 128 * KIB;
- a.hsize = 2 * KIB;
- a.vols = malloc(sizeof(*a.vols) * UBI_MAX_VOLUMES);
- if (a.vols == NULL) {
- ERR_MSG("out of memory\n");
- rc = ENOMEM;
- goto err;
- }
- memset(a.vols, 0, sizeof(*a.vols) * UBI_MAX_VOLUMES);
-
- /* parse args and check for validity */
- parse_opt(argc, argv, &a);
- if (a.img_path == NULL) {
- ERR_MSG("no image file specified\n");
- rc = EINVAL;
- goto err;
- }
- else if (a.odir_path == NULL) {
- char *ptr;
- int len;
-
- ptr = strrchr(a.img_path, '/');
- if (ptr == NULL)
- ptr = a.img_path;
- else
- ptr++;
-
- len = strlen(DIR_FMT) + strlen(ptr);
- free_a_odir = 1;
- a.odir_path = malloc(sizeof(*a.odir_path) * len);
- if (a.odir_path == NULL) {
- ERR_MSG("out of memory\n");
- rc = ENOMEM;
- goto err;
- }
- snprintf(a.odir_path, len, DIR_FMT, ptr);
- }
-
- fpin = fopen(a.img_path, "rb");
- if (fpin == NULL) {
- ERR_MSG("couldn't open file for reading: "
- "%s\n", a.img_path);
- rc = EINVAL;
- goto err;
- }
-
- rc = mkdir(a.odir_path, 0777);
- if ((rc < 0) && (errno != EEXIST)) {
- ERR_MSG("couldn't create ouput directory: "
- "%s\n", a.odir_path);
- rc = -rc;
- goto err;
- }
-
- /* fill in vols array */
- vols_len = count_set(a.vols, UBI_MAX_VOLUMES);
- if (vols_len > 0) {
- vols = malloc(sizeof(*vols) * vols_len);
- if (vols == NULL) {
- ERR_MSG("out of memory\n");
- rc = ENOMEM;
- goto err;
- }
- collapse(a.vols, UBI_MAX_VOLUMES, vols, vols_len);
- }
-
- /* unubi volumes */
- rc = unubi_volumes(fpin, vols, vols_len, &a);
- if (rc < 0) {
- /* ERR_MSG("error encountered while working on image file: "
- "%s\n", a.img_path); */
- rc = -rc;
- goto err;
- }
-
- err:
- free(a.vols);
- if (free_a_odir != 0)
- free(a.odir_path);
- if (fpin != NULL)
- fclose(fpin);
- if (vols_len > 0)
- free(vols);
- return rc;
-}
diff --git a/ubi-utils/src/unubi_analyze.c b/ubi-utils/src/unubi_analyze.c
deleted file mode 100644
index ceaa85f..0000000
--- a/ubi-utils/src/unubi_analyze.c
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2006, 2007
- *
- * 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.
- */
-
-/*
- * Authors: Drake Dowsett, dowsett@de.ibm.com
- * Contact: Andreas Arnez, arnez@de.ibm.com
- *
- * unubi uses the following functions to generate analysis output based on
- * the header information in a raw-UBI image
- */
-
-/*
- * TODO: use OOB data to check for eraseblock validity in NAND images
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <mtd_swab.h>
-
-#include "unubi_analyze.h"
-#include "crc32.h"
-
-#define EC_X_INT 50
-
-/**
- * intcmp - function needed by qsort to order integers
- **/
-int intcmp(const void *a, const void *b)
-{
- int A = *(int *)a;
- int B = *(int *)b;
- return A - B;
-}
-
-int longcmp(const void *a, const void *b)
-{
- long long A = *(long long *)a;
- long long B = *(long long *)b;
- return A - B;
-}
-
-
-/**
- * unubi_analyze_group_index - finds the normalized index in an array
- * item: look for this item in the array
- * array: array to search through
- * size: length of the array
- * array should be sorted for this algorithm to perform properly;
- * if the item is not found returns -1, otherwise return value is the
- * index in the array (note this contricts the array size to 2^32-1);
- **/
-int
-norm_index(uint32_t item, uint32_t *array, size_t length)
-{
- size_t i, index;
-
- for (index = 0, i = 0; i < length; i++) {
- if ((i != 0) && (array[i] != array[i - 1]))
- index++;
-
- if (item == array[i])
- return index;
- }
-
- return -1;
-}
-
-
-/**
- * unubi_analyze_ec_hdr - generate data table and plot script
- * first: head of simple linked list
- * path: folder to write into
- * generates a data file containing the eraseblock index in the image
- * and the erase counter found in its ec header;
- * if the crc check fails, the line is commented out in the data file;
- * also generates a simple gnuplot sript for quickly viewing one
- * display of the data file;
- **/
-int
-unubi_analyze_ec_hdr(struct eb_info *first, const char *path)
-{
- char filename[PATH_MAX + 1];
- size_t count, eraseblocks;
- uint32_t crc, crc32_table[256];
- uint64_t *erase_counts;
- FILE* fpdata;
- FILE* fpplot;
- struct eb_info *cur;
-
- if (first == NULL)
- return -1;
-
- /* crc check still needed for `first' linked list */
- init_crc32_table(crc32_table);
-
- /* prepare output files */
- memset(filename, 0, PATH_MAX + 1);
- snprintf(filename, PATH_MAX, "%s/%s", path, FN_EH_DATA);
- fpdata = fopen(filename, "w");
- if (fpdata == NULL)
- return -1;
-
- memset(filename, 0, PATH_MAX + 1);
- snprintf(filename, PATH_MAX, "%s/%s", path, FN_EH_PLOT);
- fpplot = fopen(filename, "w");
- if (fpplot == NULL) {
- fclose(fpdata);
- return -1;
- }
-
- /* make executable */
- chmod(filename, 0755);
-
- /* first run: count elements */
- count = 0;
- cur = first;
- while (cur != NULL) {
- cur = cur->next;
- count++;
- }
- eraseblocks = count;
-
- erase_counts = malloc(eraseblocks * sizeof(*erase_counts));
- if (!erase_counts) {
- perror("out of memory");
- exit(EXIT_FAILURE);
- }
-
- memset(erase_counts, 0, eraseblocks * sizeof(*erase_counts));
-
- /* second run: populate array to sort */
- count = 0;
- cur = first;
- while (cur != NULL) {
- erase_counts[count] = be64_to_cpu(cur->ec.ec);
- cur = cur->next;
- count++;
- }
- qsort(erase_counts, eraseblocks, sizeof(*erase_counts),
- (void *)longcmp);
-
- /* third run: generate data file */
- count = 0;
- cur = first;
- fprintf(fpdata, "# eraseblock_no actual_erase_count "
- "sorted_erase_count\n");
- while (cur != NULL) {
- crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &cur->ec,
- UBI_EC_HDR_SIZE_CRC);
-
- if ((be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) ||
- (crc != be32_to_cpu(cur->ec.hdr_crc)))
- fprintf(fpdata, "# ");
-
- fprintf(fpdata, "%zu %llu %llu", count,
- (unsigned long long)be64_to_cpu(cur->ec.ec),
- (unsigned long long)erase_counts[count]);
-
- if (be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC)
- fprintf(fpdata, " ## bad magic: %08x",
- be32_to_cpu(cur->ec.magic));
-
- if (crc != be32_to_cpu(cur->ec.hdr_crc))
- fprintf(fpdata, " ## CRC mismatch: given=%08x, "
- "calc=%08x", be32_to_cpu(cur->ec.hdr_crc),
- crc);
-
- fprintf(fpdata, "\n");
-
- cur = cur->next;
- count++;
- }
- fclose(fpdata);
-
- fprintf(fpplot, "#!/usr/bin/gnuplot -persist\n");
- fprintf(fpplot, "set xlabel \"eraseblock\"\n");
-
- /* fourth run: generate plot file xtics */
- count = 0;
- cur = first;
- fprintf(fpplot, "set xtics (");
- while (cur != NULL) {
- if ((count % EC_X_INT) == 0) {
- if (count > 0)
- fprintf(fpplot, ", ");
- fprintf(fpplot, "%zd", count);
- }
-
- cur = cur->next;
- count++;
- }
- fprintf(fpplot, ")\n");
-
- fprintf(fpplot, "set ylabel \"erase count\"\n");
- fprintf(fpplot, "set xrange [-1:%zu]\n", eraseblocks + 1);
- fprintf(fpplot, "# set yrange [-1:%llu]\n",
- (unsigned long long)erase_counts[eraseblocks - 1] + 1);
- fprintf(fpplot, "plot \"%s\" u 1:2 t \"unsorted: %s\" with boxes\n",
- FN_EH_DATA, FN_EH_DATA);
- fprintf(fpplot, "# replot \"%s\" u 1:3 t \"sorted: %s\" with lines\n",
- FN_EH_DATA, FN_EH_DATA);
- fprintf(fpplot, "pause -1 \"press ENTER\"\n");
-
- fclose(fpplot);
-
- return 0;
-}
-
-
-/**
- * unubi_analyze_vid_hdr - generate data table and plot script
- * head: head of complex linked list (eb_chain)
- * path: folder to write into
- * generates a data file containing the volume id, logical number, leb version,
- * and data size from the vid header;
- * all eraseblocks listed in the eb_chain are valid (checked in unubi);
- * also generates a simple gnuplot sript for quickly viewing one
- * display of the data file;
- **/
-int
-unubi_analyze_vid_hdr(struct eb_info **head, const char *path)
-{
- char filename[PATH_MAX + 1];
- int rc, y1, y2;
- size_t count, step, breadth;
- uint32_t *leb_versions, *data_sizes;
- FILE* fpdata;
- FILE* fpplot;
- struct eb_info *cur;
-
- if (head == NULL || *head == NULL)
- return -1;
-
- rc = 0;
- fpdata = NULL;
- fpplot = NULL;
- data_sizes = NULL;
- leb_versions = NULL;
-
- /* prepare output files */
- memset(filename, 0, PATH_MAX + 1);
- snprintf(filename, PATH_MAX, "%s/%s", path, FN_VH_DATA);
- fpdata = fopen(filename, "w");
- if (fpdata == NULL) {
- rc = -1;
- goto exit;
- }
-
- memset(filename, 0, PATH_MAX + 1);
- snprintf(filename, PATH_MAX, "%s/%s", path, FN_VH_PLOT);
- fpplot = fopen(filename, "w");
- if (fpplot == NULL) {
- rc = -1;
- goto exit;
- }
-
- /* make executable */
- chmod(filename, 0755);
-
- /* first run: count elements */
- count = 0;
- cur = *head;
- while (cur != NULL) {
- cur = cur->next;
- count++;
- }
- breadth = count;
-
- leb_versions = malloc(breadth * sizeof(uint32_t));
- if (leb_versions == NULL) {
- rc = -1;
- goto exit;
- }
- memset(leb_versions, 0, breadth * sizeof(uint32_t));
-
- data_sizes = malloc(breadth * sizeof(uint32_t));
- if (data_sizes == NULL) {
- rc = -1;
- goto exit;
- }
- memset(data_sizes, 0, breadth * sizeof(*data_sizes));
-
- /* second run: populate arrays to sort */
- count = 0;
- cur = *head;
- while (cur != NULL) {
- leb_versions[count] = be32_to_cpu(cur->vid.leb_ver);
- data_sizes[count] = be32_to_cpu(cur->vid.data_size);
- cur = cur->next;
- count++;
- }
- qsort(leb_versions, breadth, sizeof(*leb_versions), (void *)intcmp);
- qsort(data_sizes, breadth, sizeof(*data_sizes), (void *)intcmp);
-
- /* third run: generate data file */
- count = 0;
- cur = *head;
- fprintf(fpdata, "# x_axis vol_id lnum y1_axis leb_ver "
- "y2_axis data_size\n");
- while (cur != NULL) {
- y1 = norm_index(be32_to_cpu(cur->vid.leb_ver), leb_versions,
- breadth);
- y2 = norm_index(be32_to_cpu(cur->vid.data_size), data_sizes,
- breadth);
-
- if ((y1 == -1) || (y2 == -1)) {
- rc = -1;
- goto exit;
- }
-
- fprintf(fpdata, "%zu %u %u %u %u %u %u\n",
- count,
- be32_to_cpu(cur->vid.vol_id),
- be32_to_cpu(cur->vid.lnum),
- y1,
- be32_to_cpu(cur->vid.leb_ver),
- y2,
- be32_to_cpu(cur->vid.data_size));
- cur = cur->next;
- count++;
- }
-
- fprintf(fpplot, "#!/usr/bin/gnuplot -persist\n");
- fprintf(fpplot, "set xlabel \"volume\"\n");
-
- /* fourth run: generate plot file xtics */
- count = 0;
- step = 0;
- cur = *head;
- fprintf(fpplot, "set xtics (");
- while (cur != NULL) {
- if (count > 0)
- fprintf(fpplot, ", ");
- if (step != be32_to_cpu(cur->vid.vol_id)) {
- step = be32_to_cpu(cur->vid.vol_id);
- fprintf(fpplot, "\"%zd\" %zd 0", step, count);
- }
- else
- fprintf(fpplot, "\"%d\" %zd 1",
- be32_to_cpu(cur->vid.lnum), count);
- cur = cur->next;
- count++;
- }
- fprintf(fpplot, ")\n");
- fprintf(fpplot, "set nox2tics\n");
-
- /* fifth run: generate plot file ytics */
- count = 0;
- cur = *head;
- fprintf(fpplot, "set ylabel \"leb version\"\n");
- fprintf(fpplot, "set ytics (");
- while (cur->next != NULL) {
- y1 = norm_index(be32_to_cpu(cur->vid.leb_ver), leb_versions,
- breadth);
-
- if (y1 == -1) {
- rc = -1;
- goto exit;
- }
-
- if (count > 0)
- fprintf(fpplot, ", ");
-
- fprintf(fpplot, "\"%u\" %u", be32_to_cpu(cur->vid.leb_ver),
- y1);
-
- cur = cur->next;
- count++;
- }
- fprintf(fpplot, ")\n");
-
- /* sixth run: generate plot file y2tics */
- count = 0;
- cur = *head;
- fprintf(fpplot, "set y2label \"data size\"\n");
- fprintf(fpplot, "set y2tics (");
- while (cur != NULL) {
- y2 = norm_index(be32_to_cpu(cur->vid.data_size),
- data_sizes, breadth);
-
- if (y2 == -1) {
- rc = -1;
- goto exit;
- }
-
- if (count > 0)
- fprintf(fpplot, ", ");
-
- fprintf(fpplot, "\"%u\" %u", be32_to_cpu(cur->vid.data_size),
- y2);
-
- cur = cur->next;
- count++;
- }
- fprintf(fpplot, ")\n");
-
- y1 = norm_index(leb_versions[breadth - 1], leb_versions, breadth);
- y2 = norm_index(data_sizes[breadth - 1], data_sizes, breadth);
- fprintf(fpplot, "set xrange [-1:%zu]\n", count + 1);
- fprintf(fpplot, "set yrange [-1:%u]\n", y1 + 1);
- fprintf(fpplot, "set y2range [-1:%u]\n", y2 + 1);
- fprintf(fpplot, "plot \"%s\" u 1:4 t \"leb version: %s\" "
- "axes x1y1 with lp\n", FN_VH_DATA, FN_VH_DATA);
- fprintf(fpplot, "replot \"%s\" u 1:6 t \"data size: %s\" "
- "axes x1y2 with lp\n", FN_VH_DATA, FN_VH_DATA);
- fprintf(fpplot, "pause -1 \"press ENTER\"\n");
-
- exit:
- if (fpdata != NULL)
- fclose(fpdata);
- if (fpplot != NULL)
- fclose(fpplot);
- if (data_sizes != NULL)
- free(data_sizes);
- if (leb_versions != NULL)
- free(leb_versions);
-
- return rc;
-}
-
-
-/**
- * unubi_analyze - run all analyses
- * head: eb_chain head
- * first: simple linked list of eraseblock headers (use .next)
- * path: directory (without trailing slash) to output to
- * returns 0 upon successful completion, or -1 otherwise
- **/
-int
-unubi_analyze(struct eb_info **head, struct eb_info *first, const char *path)
-{
- int ec_rc, vid_rc;
-
- if (path == NULL)
- return -1;
-
- ec_rc = unubi_analyze_ec_hdr(first, path);
- vid_rc = unubi_analyze_vid_hdr(head, path);
- if (ec_rc < 0 || vid_rc < 0)
- return -1;
-
- return 0;
-}
diff --git a/ubi-utils/src/unubi_analyze.h b/ubi-utils/src/unubi_analyze.h
deleted file mode 100644
index c478f53..0000000
--- a/ubi-utils/src/unubi_analyze.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2006, 2007
- *
- * 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.
- */
-
-#ifndef __UNUBI_ANALYZE_H__
-#define __UNUBI_ANALYZE_H__
-
-/*
- * Author: Drake Dowsett
- * Contact: Andreas Arnez (arnez@de.ibm.com)
- *
- * Eraseblock Chain
- *
- * A linked list structure to order eraseblocks by volume and logical number
- * and to update by version number. Doesn't contain actual eraseblock data
- * but rather the erasecounter and volume id headers as well as a position
- * indicator.
- *
- * Diagram Example:
- *
- * [V1.0v0]->[V1.1v2]->[V1.2v1]->[V2.0v2]->[V2.1v0]->[V2.2v1]->NULL
- * | | | | | |
- * NULL [V1.1v1] [V1.2v0] [V2.0v1] NULL [V2.2v0]
- * | | | |
- * [V1.1v0] NULL [V2.0v0] NULL
- * | |
- * NULL NULL
- *
- * [VA.BvC] represents the eb_info for the eraseblock with the vol_id A,
- * lnum B and leb_ver C
- * -> represents the `next' pointer
- * | represents the `older' pointer
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <mtd/ubi-media.h>
-
-#define FN_EH_STAT "analysis_blocks.txt"
-#define FN_EH_DATA "analysis_ec_hdr.data"
-#define FN_EH_PLOT "analysis_ec_hdr.plot"
-#define FN_VH_DATA "analysis_vid_hdr.data"
-#define FN_VH_PLOT "analysis_vid_hdr.plot"
-
-struct eb_info {
- struct ubi_ec_hdr ec;
- struct ubi_vid_hdr vid;
-
- fpos_t eb_top;
- uint32_t linear;
- int ec_crc_ok;
- int vid_crc_ok;
- int data_crc_ok;
- uint32_t phys_addr;
- int phys_block;
-
- struct eb_info *next;
- struct eb_info *older;
-};
-
-int eb_chain_insert(struct eb_info **head, struct eb_info *item);
-
-int eb_chain_position(struct eb_info **head, uint32_t vol_id, uint32_t *lnum,
- struct eb_info **pos);
-
-int eb_chain_print(FILE *stream, struct eb_info *head);
-
-int eb_chain_destroy(struct eb_info **head);
-
-int unubi_analyze(struct eb_info **head, struct eb_info *first,
- const char *path);
-
-#endif /* __UNUBI_ANALYZE_H__ */