summaryrefslogtreecommitdiff
path: root/ubi-utils/src
diff options
context:
space:
mode:
Diffstat (limited to 'ubi-utils/src')
-rw-r--r--ubi-utils/src/bootenv.c1028
-rw-r--r--ubi-utils/src/bootenv.h434
-rw-r--r--ubi-utils/src/common.c59
-rw-r--r--ubi-utils/src/common.h18
-rw-r--r--ubi-utils/src/config.h28
-rw-r--r--ubi-utils/src/dictionary.c405
-rw-r--r--ubi-utils/src/dictionary.h174
-rw-r--r--ubi-utils/src/eb_chain.c280
-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/libpfi.c628
-rw-r--r--ubi-utils/src/libubigen.c92
-rw-r--r--ubi-utils/src/list.c143
-rw-r--r--ubi-utils/src/list.h61
-rw-r--r--ubi-utils/src/pfi2bin.c384
-rw-r--r--ubi-utils/src/pfiflash.h76
-rw-r--r--ubi-utils/src/ubinize.c615
-rw-r--r--ubi-utils/src/unubi.c1017
-rw-r--r--ubi-utils/src/unubi_analyze.c458
-rw-r--r--ubi-utils/src/unubi_analyze.h87
22 files changed, 1970 insertions, 5152 deletions
diff --git a/ubi-utils/src/bootenv.c b/ubi-utils/src/bootenv.c
deleted file mode 100644
index 5a4205f..0000000
--- a/ubi-utils/src/bootenv.c
+++ /dev/null
@@ -1,1028 +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 <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-header.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;
-
- 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) {
- *ret_crc = crc32(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;
-
- 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) {
- *ret_crc = crc32(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
index f8110c3..56244df 100644
--- a/ubi-utils/src/common.c
+++ b/ubi-utils/src/common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) Artem Bityutskiy, 2007
+ * 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
@@ -19,11 +19,13 @@
/*
* This file contains various common stuff used by UBI utilities.
*
- * Author: Artem Bityutskiy
+ * Authors: Artem Bityutskiy
+ * Adrian Hunter
*/
#include <stdio.h>
#include <string.h>
+#include <ctype.h>
/**
* ubiutils_bytes_multiplier - convert size specifier to an integer
@@ -87,3 +89,56 @@ void ubiutils_print_bytes(long long bytes, int bracket)
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
index 89094ab..3ee93ff 100644
--- a/ubi-utils/src/common.h
+++ b/ubi-utils/src/common.h
@@ -19,6 +19,8 @@
#ifndef __UBI_UTILS_COMMON_H__
#define __UBI_UTILS_COMMON_H__
+#include <stdio.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -26,18 +28,30 @@ extern "C" {
#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)
+
/* Error messages */
#define errmsg(fmt, ...) do { \
- fprintf(stderr, PROGRAM_NAME " error: " fmt "\n", ##__VA_ARGS__); \
+ fprintf(stderr, PROGRAM_NAME " error: " fmt "\n", ##__VA_ARGS__); \
} while(0)
/* Warnings */
#define warnmsg(fmt, ...) do { \
- fprintf(stderr, PROGRAM_NAME " warning: " fmt "\n", ##__VA_ARGS__); \
+ fprintf(stderr, PROGRAM_NAME " warning: " fmt "\n", ##__VA_ARGS__); \
} while(0)
int ubiutils_get_multiplier(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
}
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/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 a018ae6..0000000
--- a/ubi-utils/src/eb_chain.c
+++ /dev/null
@@ -1,280 +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 "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),
- __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),
- __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/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/libpfi.c b/ubi-utils/src/libpfi.c
deleted file mode 100644
index 6de24ea..0000000
--- a/ubi-utils/src/libpfi.c
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
- * 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
- * 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.
- */
-
-/*
- * A library to work with pfi files.
- *
- * Authors Oliver Lohmann
- * Andreas Arnez
- * Joern Engel
- * Frank Haverkamp
- * Artem Bityutskiy
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <errno.h>
-
-#include <mtd/ubi-header.h>
-#include <libpfi.h>
-#include "common.h"
-#include "bootenv.h"
-
-#define PROGRAM_NAME "libpfi"
-
-#define PFI_MAGIC "PFI!\n"
-#define PFI_MAGIC_LEN (sizeof(PFI_MAGIC) - 1)
-#define PFI_DATA "DATA\n"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-#define PFI_MANDATORY 0x0001
-#define PFI_STRING 0x0002
-#define PFI_LISTVALUE 0x0004
-#define PFI_MANDATORY_UBI 0x0008
-
-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,
- num_keys,
-};
-
-struct pfi_header {
- uint8_t 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];
-};
-
-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 },
-};
-
-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[] = {"ubi"};
-
-/* 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))
-
-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 (struct 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 { /* 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 (struct pfi_header **head)
-{
- int i;
- struct pfi_header *self = 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 (struct pfi_header **head)
-{
- int i;
- struct 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 (struct 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 (struct 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 (struct 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 (struct 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_read(FILE *in, struct pfi_header *head)
-{
- char mode[PFI_KEYWORD_LEN];
- char buf[256];
-
- if (fread(buf, 1, PFI_MAGIC_LEN, in) != PFI_MAGIC_LEN) {
- errmsg("cannot read %d bytes", PFI_MAGIC_LEN);
- perror("fread");
- return -1;
- }
-
- if (memcmp(buf, PFI_MAGIC, PFI_MAGIC_LEN) != 0) {
- if (memcmp(buf, PFI_DATA, PFI_MAGIC_LEN) == 0)
- return 1;
-
- errmsg("PFI magic \"%s\" not found", PFI_MAGIC);
- return -1;
- }
-
- 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
-read_pfi_ubi(struct pfi_header *pfi_hd, struct pfi_ubi **pfi_ubi,
- const char *label)
-{
- int err = 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;
- struct pfi_ubi *res;
- uint32_t i;
- size_t size;
-
- res = (struct pfi_ubi *) calloc(1, sizeof(struct pfi_ubi));
- if (!res)
- return -ENOMEM;
-
- err = pfi_header_getnumber(pfi_hd, "size", &(res->data_size));
- if (err != 0) {
- errmsg("cannot read 'size' from PFI.");
- goto err;
- }
-
- err = pfi_header_getnumber(pfi_hd, "crc", &(res->crc));
- if (err != 0) {
- errmsg("cannot read 'crc' from PFI.");
- goto err;
- }
-
- err = pfi_header_getstring(pfi_hd, "ubi_ids", tmp_str, PFI_KEYWORD_LEN);
- if (err != 0) {
- errmsg("cannot read 'ubi_ids' from PFI.");
- goto err;
- }
-
- err = bootenv_list_create(&ubi_id_list);
- if (err != 0) {
- goto err;
- }
- err = bootenv_list_create(&ubi_name_list);
- if (err != 0) {
- goto err;
- }
-
- err = bootenv_list_import(ubi_id_list, tmp_str);
- if (err != 0) {
- errmsg("cannot translate PFI value: %s", tmp_str);
- goto err;
- }
-
- err = bootenv_list_to_num_vector(ubi_id_list, &size,
- &(res->ids));
- res->ids_size = size;
- if (err != 0) {
- errmsg("cannot create numeric value array: %s", tmp_str);
- goto err;
- }
-
- if (res->ids_size == 0) {
- err = -1;
- errmsg("sanity check failed: No ubi_ids specified.");
- goto err;
- }
-
- err = pfi_header_getstring(pfi_hd, "ubi_type",
- tmp_str, PFI_KEYWORD_LEN);
- if (err != 0) {
- errmsg("cannot read 'ubi_type' from PFI.");
- goto err;
- }
- if (strcmp(tmp_str, "static") == 0)
- res->vol_type = UBI_VID_STATIC;
- else if (strcmp(tmp_str, "dynamic") == 0)
- res->vol_type = UBI_VID_DYNAMIC;
- else {
- errmsg("unknown ubi_type in PFI.");
- goto err;
- }
-
- err = pfi_header_getnumber(pfi_hd, "ubi_alignment", &(res->alignment));
- if (err != 0) {
- errmsg("cannot read 'ubi_alignment' from PFI.");
- goto err;
- }
-
- err = pfi_header_getnumber(pfi_hd, "ubi_size", &(res->size));
- if (err != 0) {
- errmsg("cannot read 'ubi_size' from PFI.");
- goto err;
- }
-
- err = pfi_header_getstring(pfi_hd, "ubi_names",
- tmp_str, PFI_KEYWORD_LEN);
- if (err != 0) {
- errmsg("cannot read 'ubi_names' from PFI.");
- goto err;
- }
-
- err = bootenv_list_import(ubi_name_list, tmp_str);
- if (err != 0) {
- errmsg("cannot translate PFI value: %s", tmp_str);
- goto err;
- }
- err = bootenv_list_to_vector(ubi_name_list, &size,
- &(tmp_names));
- res->names_size = size;
- if (err != 0) {
- errmsg("cannot create string array: %s", tmp_str);
- goto err;
- }
-
- if (res->names_size != res->ids_size) {
- errmsg("sanity check failed: ubi_ids list does not match "
- "sizeof ubi_names list.");
- err = -1;
- }
-
- /* copy tmp_names to own structure */
- res->names = 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 err;
-}
-
-int
-free_pfi_ubi(struct pfi_ubi **pfi_ubi)
-{
- size_t i;
- struct pfi_ubi *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(struct list_entry **ubi_list, FILE *fp_pfi)
-{
- int err = 0;
- long long data_offs = 0;
- long fpos;
- char mode[PFI_KEYWORD_LEN];
- char label[PFI_LABEL_LEN];
- struct list_entry *tmp;
-
- *ubi_list = list_empty(); struct pfi_ubi *ubi = NULL;
- struct pfi_header *pfi_header = NULL;
-
- /* read all headers from PFI and store them in lists */
- err = pfi_header_init(&pfi_header);
- if (err != 0) {
- errmsg("cannot initialize pfi header.");
- goto err;
- }
- while ((err == 0) && !feof(fp_pfi)) {
- err = pfi_header_read(fp_pfi, pfi_header);
- if (err != 0) {
- if (err == 1) {
- err = 0;
- break; /* data section starts,
- all headers read */
- }
- else {
- goto err;
- }
- }
- err = pfi_header_getstring(pfi_header, "label", label,
- PFI_LABEL_LEN);
- if (err != 0) {
- errmsg("cannot read 'label' from PFI.");
- goto err;
- }
- err = pfi_header_getstring(pfi_header, "mode", mode,
- PFI_KEYWORD_LEN);
- if (err != 0) {
- errmsg("cannot read 'mode' from PFI.");
- goto err;
- }
- if (strcmp(mode, "ubi") == 0) {
- err = read_pfi_ubi(pfi_header, &ubi, label);
- if (err != 0) {
- goto err;
- }
- *ubi_list = append_elem(ubi, *ubi_list);
- }
- else {
- errmsg("recvieved unknown mode from PFI: %s", mode);
- goto err;
- }
- ubi->data_offs = data_offs;
- data_offs += ubi->data_size;
- }
-
- fpos = ftell(fp_pfi);
- if (fpos == -1) {
- errmsg("ftell returned error");
- perror("ftell");
- goto err;
- }
-
- list_for_each(ubi, tmp, *ubi_list)
- ubi->data_offs += fpos;
-
- goto out;
-
- err:
- *ubi_list = remove_all((free_func_t)&free_pfi_ubi, *ubi_list);
- out:
- pfi_header_destroy(&pfi_header);
- return err;
-
-}
diff --git a/ubi-utils/src/libubigen.c b/ubi-utils/src/libubigen.c
index c3a0f9c..9cbd1b7 100644
--- a/ubi-utils/src/libubigen.c
+++ b/ubi-utils/src/libubigen.c
@@ -38,35 +38,6 @@
#define PROGRAM_NAME "libubigen"
/**
- * ubigen_create_empty_vtbl - creates empty volume table.
- * @size: physical eraseblock size on input, size of the volume table on output
- *
- * This function creates an empty volume table and returns a pointer to it in
- * case of success and %NULL in case of failure. The volume table size is
- * returned in @size which has to contain PEB size on input.
- */
-struct ubi_vtbl_record *ubigen_create_empty_vtbl(int *size)
-{
- struct ubi_vtbl_record *vtbl;
- int i;
-
- if (*size > UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE)
- *size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE;
-
- vtbl = calloc(1, *size);
- if (!vtbl)
- return NULL;
-
- for (i = 0; i < UBI_MAX_VOLUMES; i++) {
- uint32_t crc = crc32(UBI_CRC32_INIT, &vtbl[i],
- UBI_VTBL_RECORD_SIZE_CRC);
- vtbl[i].crc = __cpu_to_be32(crc);
- }
-
- return vtbl;
-}
-
-/**
* ubigen_info_init - initialize libubigen.
* @ui: libubigen information
* @peb_size: flash physical eraseblock size
@@ -93,28 +64,67 @@ void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
ui->leb_size = peb_size - ui->data_offs;
ui->ubi_ver = ubi_ver;
ui->ec = ec;
+
+ ui->vtbl_size = ui->leb_size;
+ if (ui->vtbl_size > UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE)
+ ui->vtbl_size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE;
+ ui->max_volumes = ui->vtbl_size / UBI_VTBL_RECORD_SIZE;
+}
+
+/**
+ * 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)
+{
+ struct ubi_vtbl_record *vtbl;
+ int i;
+
+ vtbl = calloc(1, ui->vtbl_size);
+ if (!vtbl) {
+ errmsg("cannot allocate %d bytes of memory", ui->vtbl_size);
+ return NULL;
+ }
+
+ for (i = 0; i < UBI_MAX_VOLUMES; i++) {
+ uint32_t crc = crc32(UBI_CRC32_INIT, &vtbl[i],
+ UBI_VTBL_RECORD_SIZE_CRC);
+ vtbl[i].crc = __cpu_to_be32(crc);
+ }
+
+ return vtbl;
}
/**
* ubigen_add_volume - add a volume to the volume table.
- * @vol_id: volume ID
- * @bytes: volume size in bytes
- * @alignment: volume alignment
- * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
- * @name: volume name
* @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.
*/
-void ubigen_add_volume(const struct ubigen_info *ui,
+int ubigen_add_volume(const struct ubigen_info *ui,
const struct ubigen_vol_info *vi,
struct ubi_vtbl_record *vtbl)
{
struct ubi_vtbl_record *vtbl_rec = &vtbl[vi->id];
uint32_t tmp;
+ if (vi->id >= ui->max_volumes) {
+ errmsg("too high volume id %d, max. volumes is %d",
+ vi->id, ui->max_volumes);
+ return -1;
+ }
+ if (vi->alignment >= ui->leb_size) {
+ errmsg("too large alignment %d, max is %d (LEB size)",
+ vi->alignment, ui->leb_size);
+ return -1;
+ }
+
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);
@@ -129,6 +139,7 @@ void ubigen_add_volume(const struct ubigen_info *ui,
tmp = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
vtbl_rec->crc = __cpu_to_be32(tmp);
+ return 0;
}
/**
@@ -213,6 +224,17 @@ int ubigen_write_volume(const struct ubigen_info *ui,
int len = vi->usable_leb_size, rd, lnum = 0;
char inbuf[ui->leb_size], outbuf[ui->peb_size];
+ if (vi->id >= ui->max_volumes) {
+ errmsg("too high volume id %d, max. volumes is %d",
+ vi->id, ui->max_volumes);
+ return -1;
+ }
+ if (vi->alignment >= ui->leb_size) {
+ errmsg("too large alignment %d, max is %d (LEB size)",
+ vi->alignment, ui->leb_size);
+ return -1;
+ }
+
memset(outbuf, 0xFF, ui->data_offs);
init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf);
diff --git a/ubi-utils/src/list.c b/ubi-utils/src/list.c
deleted file mode 100644
index a701158..0000000
--- a/ubi-utils/src/list.c
+++ /dev/null
@@ -1,143 +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"
-
-int
-is_empty(struct list_entry *l)
-{
- return l == NULL;
-}
-
-info_t
-head(struct list_entry *l)
-{
- assert(!is_empty(l));
- return l->info;
-}
-
-struct list_entry *
-tail(struct list_entry *l)
-{
- assert(!is_empty(l));
- return l->next;
-}
-
-struct list_entry *
-remove_head(struct list_entry *l)
-{
- struct list_entry *res;
- assert(!is_empty(l));
-
- res = l->next;
- free(l);
- return res;
-}
-
-struct list_entry *
-cons(info_t e, struct list_entry *l)
-{
- struct list_entry *res = malloc(sizeof(*l));
- if (!res)
- return NULL;
- res->info = e;
- res->next = l;
-
- return res;
-}
-
-struct list_entry *
-prepend_elem(info_t e, struct list_entry *l)
-{
- return cons(e,l);
-}
-
-struct list_entry *
-append_elem(info_t e, struct list_entry *l)
-{
- if (is_empty(l)) {
- return cons(e,l);
- }
- l->next = append_elem(e, l->next);
-
- return l;
-}
-
-struct list_entry *
-insert_sorted(cmp_func_t cmp, info_t e, struct list_entry *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;
-}
-
-struct list_entry *
-remove_all(free_func_t free_func, struct list_entry *l)
-{
- if (is_empty(l))
- return l;
- struct list_entry *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, struct list_entry *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, struct list_entry *l)
-{
- struct list_entry *ptr;
- void *i;
- list_for_each(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 58bfe7e..0000000
--- a/ubi-utils/src/list.h
+++ /dev/null
@@ -1,61 +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
- */
-
-#ifndef __UBIUTILS_LIST_H__
-#define __UBIUTILS_LIST_H__
-
-#include <stdint.h>
-
-#define list_for_each(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)
-
-static inline struct list_entry *list_empty(void)
-{
- return NULL;
-}
-
-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 list_entry {
- struct list_entry *next;
- info_t info;
-};
-
-struct list_entry *list_empty(void);
-int is_empty(struct list_entry *l);
-info_t is_in(cmp_func_t cmp, info_t e, struct list_entry *l);
-info_t head(struct list_entry *l);
-struct list_entry *tail(struct list_entry *l);
-struct list_entry *remove_head(struct list_entry *l);
-struct list_entry *cons(info_t e, struct list_entry *l);
-struct list_entry *prepend_elem(info_t e, struct list_entry *);
-struct list_entry *append_elem(info_t e, struct list_entry *);
-struct list_entry *remove_all(free_func_t free_func, struct list_entry *l);
-struct list_entry *insert_sorted(cmp_func_t cmp_func, info_t e, struct list_entry *l);
-void apply(process_func_t process_func, struct list_entry *l);
-
-#endif /* !__UBIUTILS_LIST_H__ */
diff --git a/ubi-utils/src/pfi2bin.c b/ubi-utils/src/pfi2bin.c
deleted file mode 100644
index 4289fca..0000000
--- a/ubi-utils/src/pfi2bin.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * 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
- * 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.
- */
-
-/*
- *
- * 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 one more step may be
- * needed to add the right OOB data to the binary image.
- *
- * Authors: Oliver Lohmann
- * Artem Bityutskiy
- */
-
-#include <stdlib.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include <mtd/ubi-header.h>
-#include <libubigen.h>
-#include <libpfi.h>
-#include "common.h"
-#include "list.h"
-
-#define PROGRAM_VERSION "1.5"
-#define PROGRAM_NAME "pfi2bin"
-
-static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
-" - a tool to convert PFI files into raw flash images. Note, if not\n"
-"sure about some of the parameters, do not specify them and let the utility to\n"
-"use default values.";
-
-static const char *optionsstr =
-"-o, --output=<file name> output file name (default is stdout)\n"
-"-p, --peb-size=<bytes> size of the physical eraseblock of the flash this\n"
-" UBI image is created for in bytes, kilobytes (KiB),\n"
-" or megabytes (MiB) (mandatory parameter)\n"
-"-m, --min-io-size=<bytes> minimum input/output unit size of the flash in bytes\n"
-"-s, --sub-page-size=<bytes> minimum input/output unit used for UBI headers, e.g.\n"
-" sub-page size in case of NAND flash (equivalent to\n"
-" the minimum input/output unit size by default)\n"
-"-O, --vid-hdr-offset=<num> offset if the VID header from start of the physical\n"
-" eraseblock (default is the second minimum I/O unit\n"
-" or sub-page, if it was specified)\n"
-"-e, --erase-counter=<num> the erase counter value to put to EC headers\n"
-" (default is 0)\n"
-"-x, --ubi-ver=<num> UBI version number to put to EC headers\n"
-" (default is 1)\n"
-"-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] [--version] pfifile\n"
-"Example:" PROGRAM_NAME "-o fs.raw fs.pfi";
-
-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 = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
- { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
- { NULL, 0, NULL, 0}
-};
-
-struct args {
- const char *f_in;
- const char *f_out;
- FILE *fp_in;
- FILE *fp_out;
- int peb_size;
- int min_io_size;
- int subpage_size;
- int vid_hdr_offs;
- int ec;
- int ubi_ver;
-};
-
-static struct args args = {
- .f_out = NULL,
- .peb_size = -1,
- .min_io_size = -1,
- .subpage_size = -1,
- .vid_hdr_offs = 0,
- .ec = 0,
- .ubi_ver = 1,
-};
-
-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:hV", long_options, NULL);
- if (key == -1)
- break;
-
- switch (key) {
- case 'o':
- args.fp_out = fopen(optarg, "wb");
- if (!args.fp_out) {
- errmsg("cannot open file \"%s\"", optarg);
- return -1;
- }
- args.f_out = optarg;
- break;
-
- case 'p':
- args.peb_size = strtoull(optarg, &endp, 0);
- if (endp == optarg || args.peb_size <= 0) {
- errmsg("bad physical eraseblock size: \"%s\"", optarg);
- return -1;
- }
- if (*endp != '\0') {
- int mult = ubiutils_get_multiplier(endp);
-
- if (mult == -1) {
- errmsg("bad size specifier: \"%s\" - "
- "should be 'KiB', 'MiB' or 'GiB'", endp);
- return -1;
- }
- args.peb_size *= mult;
- }
- break;
-
- case 'm':
- args.min_io_size = strtoull(optarg, &endp, 0);
- if (endp == optarg || args.min_io_size <= 0) {
- errmsg("bad min. I/O unit size: \"%s\"", optarg);
- return -1;
- }
- if (*endp != '\0') {
- int mult = ubiutils_get_multiplier(endp);
-
- if (mult == -1) {
- errmsg("bad size specifier: \"%s\" - "
- "should be 'KiB', 'MiB' or 'GiB'", endp);
- return -1;
- }
- args.min_io_size *= mult;
- }
- break;
-
- case 's':
- args.subpage_size = strtoull(optarg, &endp, 0);
- if (endp == optarg || args.subpage_size <= 0) {
- errmsg("bad sub-page size: \"%s\"", optarg);
- return -1;
- }
- if (*endp != '\0') {
- int mult = ubiutils_get_multiplier(endp);
-
- if (mult == -1) {
- errmsg("bad size specifier: \"%s\" - "
- "should be 'KiB', 'MiB' or 'GiB'", endp);
- return -1;
- }
- args.subpage_size *= mult;
- }
- break;
-
- case 'O':
- args.vid_hdr_offs = strtoul(optarg, &endp, 0);
- if (endp == optarg || args.vid_hdr_offs < 0) {
- errmsg("bad VID header offset: \"%s\"", optarg);
- return -1;
- }
- break;
-
- case 'e':
- args.ec = strtoul(optarg, &endp, 0);
- if (endp == optarg || args.ec < 0) {
- errmsg("bad erase counter value: \"%s\"", optarg);
- return -1;
- }
- break;
-
- case 'x':
- args.ubi_ver = strtoul(optarg, &endp, 0);
- if (endp == optarg || args.ubi_ver < 0) {
- errmsg("bad UBI version: \"%s\"", optarg);
- return -1;
- }
- 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);
-
- default:
- fprintf(stderr, "Use -h for help\n");
- return -1;
- }
- }
-
- if (optind == argc) {
- errmsg("input PFI file was not specified (use -h for help)");
- return -1;
- }
-
- if (optind != argc - 1) {
- errmsg("more then one input PFI file was specified (use -h for help)");
- return -1;
- }
-
- if (args.peb_size < 0) {
- errmsg("physical eraseblock size was not specified (use -h for help)");
- return -1;
- }
-
- if (args.min_io_size < 0) {
- errmsg("min. I/O unit size was not specified (use -h for help)");
- return -1;
- }
-
- if (args.subpage_size < 0)
- args.subpage_size = args.min_io_size;
-
- args.f_in = argv[optind++];
- args.fp_in = fopen(args.f_in, "rb");
- if (!args.fp_in) {
- errmsg("cannot open file \"%s\"", args.f_in);
- return -1;
- }
-
- if (!args.f_out) {
- args.f_out = "stdout";
- args.fp_out = stdout;
- }
-
- return 0;
-}
-
-/**
- * pfi2vol_info - convert PFI UBI volume information to libubigen.
- * @pfi: PFI UBI volume information
- * @n: PFI volume index to convert
- * @vi: libubigen volume information
- */
-static void pfi2vol_info(const struct pfi_ubi *pfi, int n,
- struct ubigen_vol_info *vi,
- const struct ubigen_info *ui)
-{
- vi->id = pfi->ids[n];
- vi->bytes = pfi->size;
- vi->alignment = pfi->alignment;
- vi->data_pad = ui->leb_size % vi->alignment;
- vi->usable_leb_size = ui->leb_size - vi->data_pad;
- vi->type = pfi->vol_type;
- vi->name = pfi->names[n];
- vi->name_len = strlen(vi->name);
- if (vi->name_len > UBI_VOL_NAME_MAX) {
- errmsg("too long name, cut to %d symbols: \"%s\"",
- UBI_VOL_NAME_MAX, vi->name);
- vi->name_len = UBI_VOL_NAME_MAX;
- }
-
- vi->used_ebs = (vi->bytes + vi->usable_leb_size - 1) / vi->usable_leb_size;
- vi->compat = 0;
-}
-
-static int create_flash_image(void)
-{
- int i, err, vtbl_size = args.peb_size;
- struct ubigen_info ui;
- struct list_entry *ubi_list = list_empty(), *ptr;
- struct ubi_vtbl_record *vtbl;
- struct pfi_ubi *pfi;
-
- vtbl = ubigen_create_empty_vtbl(&vtbl_size);
- if (!vtbl) {
- errmsg("cannot initialize volume table");
- return -1;
- }
-
- ubigen_info_init(&ui, args.peb_size, args.min_io_size,
- args.subpage_size, args.vid_hdr_offs, args.ubi_ver,
- args.ec);
-
- err = read_pfi_headers(&ubi_list, args.fp_in);
- if (err != 0) {
- errmsg("cannot read PFI headers, error %d", err);
- goto error;
- }
-
- /* Add all volumes to the volume table */
- list_for_each(pfi, ptr, ubi_list)
- for (i = 0; i < pfi->ids_size; i++) {
- struct ubigen_vol_info vi;
-
- pfi2vol_info(pfi, i, &vi, &ui);
- ubigen_add_volume(&ui, &vi, vtbl);
- }
-
- err = ubigen_write_layout_vol(&ui, vtbl, args.fp_out);
- if (err) {
- errmsg("cannot create layout volume");
- goto error;
- }
-
- /* Write all volumes */
- list_for_each(pfi, ptr, ubi_list)
- for (i = 0; i < pfi->ids_size; i++) {
- struct ubigen_vol_info vi;
-
- pfi2vol_info(pfi, i, &vi, &ui);
- err = fseek(args.fp_in, pfi->data_offs, SEEK_SET);
- if (err == -1) {
- errmsg("cannot seek input file");
- perror("fseek");
- goto error;
- }
-
- err = ubigen_write_volume(&ui, &vi, pfi->data_size,
- args.fp_in, args.fp_out);
- if (err) {
- errmsg("cannot write volume %d", vi.id);
- goto error;
- }
- }
-
- if (args.fp_out != stdout) {
- i = ftell(args.fp_out);
- if (i == -1) {
- errmsg("cannot seek output file");
- perror("ftell");
- goto error;
- }
-
- printf("physical eraseblocks written: %d (", i / ui.peb_size);
- ubiutils_print_bytes(i, 0);
- printf(")\n");
- }
-
-error:
- free(vtbl);
- ubi_list = remove_all((free_func_t)&free_pfi_ubi, ubi_list);
- return err;
-}
-
-int main(int argc, char * const argv[])
-{
- int err;
-
- err = parse_opt(argc, argv);
- if (err)
- return -1;
-
- err = create_flash_image();
- if (err)
- remove(args.f_out);
-
- return err;
-}
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/ubinize.c b/ubi-utils/src/ubinize.c
new file mode 100644
index 0000000..28991f9
--- /dev/null
+++ b/ubi-utils/src/ubinize.c
@@ -0,0 +1,615 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Generate UBI images.
+ *
+ * Authors: Artem Bityutskiy
+ * Oliver Lohmann
+ */
+
+#include <stdlib.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <mtd/ubi-header.h>
+#include <libubigen.h>
+#include <libiniparser.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.5"
+#define PROGRAM_NAME "ubinize"
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+" - a tool to generate UBI images. An UBI image may contain one or more UBI "
+"volumes which have to be defined in the input configuration ini-file. The "
+"ini file defines all the UBI volumes - their characteristics and the and the "
+"contents, but it does not define the characteristics of the flash the UBI "
+"image is generated for. Instead, the flash characteristics are defined via "
+"the comman-line options. "
+"Note, if not sure about some of the command-line parameters, do not specify "
+"them and let the utility to use default values.";
+
+static const char *optionsstr =
+"-o, --output=<file name> output file name (default is stdout)\n"
+"-p, --peb-size=<bytes> size of the physical eraseblock of the flash\n"
+" this UBI image is created for in bytes,\n"
+" kilobytes (KiB), or megabytes (MiB)\n"
+" (mandatory parameter)\n"
+"-m, --min-io-size=<bytes> minimum input/output unit size of the flash\n"
+" in bytes\n"
+"-s, --sub-page-size=<bytes> minimum input/output unit used for UBI\n"
+" headers, e.g. sub-page size in case of NAND\n"
+" flash (equivalent to the minimum input/output\n"
+" unit size by default)\n"
+"-O, --vid-hdr-offset=<num> offset if the VID header from start of the\n"
+" physical eraseblock (default is the second\n"
+" minimum I/O unit or sub-page, if it was\n"
+" specified)\n"
+"-e, --erase-counter=<num> the erase counter value to put to EC headers\n"
+" (default is 0)\n"
+"-x, --ubi-ver=<num> UBI version number to put to EC headers\n"
+" (default is 1)\n"
+"-v --verbose be verbose\n"
+"-h, --help print help message\n"
+"-V, --version print program version";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " [-o filename] [-h] [-V] [--output=<filename>] [--help]\n"
+"\t\t[--version] inifile\n"
+"Example: " PROGRAM_NAME "-o fs.raw cfg.ini";
+
+struct option long_options[] = {
+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
+ { .name = "peb-size", .has_arg = 1, .flag = NULL, .val = 'p' },
+ { .name = "min-io-size", .has_arg = 1, .flag = NULL, .val = 'm' },
+ { .name = "sub-page-size", .has_arg = 1, .flag = NULL, .val = 's' },
+ { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' },
+ { .name = "erase-counter", .has_arg = 1, .flag = NULL, .val = 'e' },
+ { .name = "ubi-ver", .has_arg = 1, .flag = NULL, .val = 'x' },
+ { .name = "verbose", .has_arg = 1, .flag = NULL, .val = 'v' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0}
+};
+
+struct args {
+ const char *f_in;
+ const char *f_out;
+ FILE *fp_out;
+ int peb_size;
+ int min_io_size;
+ int subpage_size;
+ int vid_hdr_offs;
+ int ec;
+ int ubi_ver;
+ int verbose;
+ dictionary *dict;
+};
+
+static struct args args = {
+ .f_out = NULL,
+ .peb_size = -1,
+ .min_io_size = -1,
+ .subpage_size = -1,
+ .vid_hdr_offs = 0,
+ .ec = 0,
+ .ubi_ver = 1,
+ .verbose = 0,
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "o:p:m:s:O:e:x:vhV", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'o':
+ args.fp_out = fopen(optarg, "wb");
+ if (!args.fp_out) {
+ errmsg("cannot open file \"%s\"", optarg);
+ return -1;
+ }
+ args.f_out = optarg;
+ break;
+
+ case 'p':
+ args.peb_size = strtoull(optarg, &endp, 0);
+ if (endp == optarg || args.peb_size <= 0) {
+ errmsg("bad physical eraseblock size: \"%s\"", optarg);
+ return -1;
+ }
+ if (*endp != '\0') {
+ int mult = ubiutils_get_multiplier(endp);
+
+ if (mult == -1) {
+ errmsg("bad size specifier: \"%s\" - "
+ "should be 'KiB', 'MiB' or 'GiB'", endp);
+ return -1;
+ }
+ args.peb_size *= mult;
+ }
+ break;
+
+ case 'm':
+ args.min_io_size = strtoull(optarg, &endp, 0);
+ if (endp == optarg || args.min_io_size <= 0) {
+ errmsg("bad min. I/O unit size: \"%s\"", optarg);
+ return -1;
+ }
+ if (*endp != '\0') {
+ int mult = ubiutils_get_multiplier(endp);
+
+ if (mult == -1) {
+ errmsg("bad size specifier: \"%s\" - "
+ "should be 'KiB', 'MiB' or 'GiB'", endp);
+ return -1;
+ }
+ args.min_io_size *= mult;
+ }
+ break;
+
+ case 's':
+ args.subpage_size = strtoull(optarg, &endp, 0);
+ if (endp == optarg || args.subpage_size <= 0) {
+ errmsg("bad sub-page size: \"%s\"", optarg);
+ return -1;
+ }
+ if (*endp != '\0') {
+ int mult = ubiutils_get_multiplier(endp);
+
+ if (mult == -1) {
+ errmsg("bad size specifier: \"%s\" - "
+ "should be 'KiB', 'MiB' or 'GiB'", endp);
+ return -1;
+ }
+ args.subpage_size *= mult;
+ }
+ break;
+
+ case 'O':
+ args.vid_hdr_offs = strtoul(optarg, &endp, 0);
+ if (endp == optarg || args.vid_hdr_offs < 0) {
+ errmsg("bad VID header offset: \"%s\"", optarg);
+ return -1;
+ }
+ break;
+
+ case 'e':
+ args.ec = strtoul(optarg, &endp, 0);
+ if (endp == optarg || args.ec < 0) {
+ errmsg("bad erase counter value: \"%s\"", optarg);
+ return -1;
+ }
+ break;
+
+ case 'x':
+ args.ubi_ver = strtoul(optarg, &endp, 0);
+ if (endp == optarg || args.ubi_ver < 0) {
+ errmsg("bad UBI version: \"%s\"", optarg);
+ return -1;
+ }
+ break;
+
+ case 'v':
+ args.verbose = 1;
+ break;
+
+ case 'h':
+ ubiutils_print_text(stderr, doc, 80);
+ fprintf(stderr, "\n\n%s\n\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) {
+ errmsg("input PFI file was not specified (use -h for help)");
+ return -1;
+ }
+
+ if (optind != argc - 1) {
+ errmsg("more then one input PFI file was specified (use -h for help)");
+ return -1;
+ }
+
+ args.f_in = argv[optind];
+
+ if (args.peb_size < 0) {
+ errmsg("physical eraseblock size was not specified (use -h for help)");
+ return -1;
+ }
+
+ if (args.min_io_size < 0) {
+ errmsg("min. I/O unit size was not specified (use -h for help)");
+ return -1;
+ }
+
+ if (args.subpage_size < 0)
+ args.subpage_size = args.min_io_size;
+
+ if (!args.f_out) {
+ args.f_out = "stdout";
+ args.fp_out = stdout;
+ }
+
+ return 0;
+}
+
+int read_section(const char *sname, struct ubigen_vol_info *vi,
+ const char **img)
+{
+ char buf[256];
+ const char *p;
+
+ *img = NULL;
+
+ if (strlen(sname) > 128) {
+ errmsg("too long section name \"%s\"", sname);
+ return -1;
+ }
+
+ /* Make sure mode is UBI, otherwise ignore this section */
+ sprintf(buf, "%s:mode", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (!p) {
+ errmsg("\"mode\" key not found in section \"%s\"", sname);
+ errmsg("the \"mode\" key is mandatory and has to be "
+ "\"mode=ubi\" if the section describes an UBI volume");
+ return -1;
+ }
+
+ /* If mode is not UBI, skip this section */
+ if (strcmp(p, "ubi")) {
+ verbose(args.verbose, "skip non-ubi section \"%s\"", sname);
+ return 1;
+ }
+
+ verbose(args.verbose, "mode=ubi, keep parsing");
+
+ /* Fetch the name of the volume image file */
+ sprintf(buf, "%s:image", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (p)
+ *img = p;
+
+ /* Fetch volume id */
+ sprintf(buf, "%s:vol_id", sname);
+ vi->id = iniparser_getint(args.dict, buf, -1);
+ if (vi->id == -1) {
+ errmsg("\"vol_id\" key not found in section \"%s\"", sname);
+ return -1;
+ }
+
+ if (vi->id < 0) {
+ errmsg("negative volume ID %d", vi->id);
+ return -1;
+ }
+
+ if (vi->id >= UBI_MAX_VOLUMES) {
+ errmsg("too highe volume ID %d, max. is %d",
+ vi->id, UBI_MAX_VOLUMES);
+ return -1;
+ }
+
+ 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) {
+ char *endp;
+
+ vi->bytes = strtoull((char *)p, &endp, 0);
+ if (endp == p || vi->bytes <= 0) {
+ errmsg("bad \"vol_size\" key: \"%s\"", p);
+ return -1;
+ }
+
+ if (*endp != '\0') {
+ int mult = ubiutils_get_multiplier(endp);
+
+ if (mult == -1) {
+ errmsg("bad size specifier: \"%s\" - "
+ "should be 'KiB', 'MiB' or 'GiB'", endp);
+ return -1;
+ }
+ vi->bytes *= mult;
+ }
+
+ verbose(args.verbose, "volume size: %lld bytes", vi->bytes);
+ } else {
+ struct stat st;
+
+ if (!*img) {
+ errmsg("neither image file (\"image=\") nor volume size"
+ " (\"vol_size=\") specified");
+ return -1;
+ }
+
+ if (stat(*img, &st)) {
+ errmsg("cannot stat \"%s\"", *img);
+ perror("stat");
+ return -1;
+ }
+
+ vi->bytes = st.st_size;
+
+ if (vi->bytes == 0) {
+ errmsg("file \"%s\" referred from section \"%s\" is empty",
+ *img, sname);
+ return -1;
+ }
+
+ printf(PROGRAM_NAME ": volume size was not specified in"
+ "section \"%s\", assume ", sname);
+ ubiutils_print_bytes(vi->bytes, 1);
+ printf("\n");
+ }
+
+ /* Fetch volume type */
+ sprintf(buf, "%s:vol_type", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (!p) {
+ normsg(": volume type was not specified in "
+ "section \"%s\", assume \"dynamic\"\n", sname);
+ vi->type = UBI_VID_DYNAMIC;
+ } else {
+ if (!strcmp(p, "static"))
+ vi->type = UBI_VID_STATIC;
+ else if (!strcmp(p, "dynamic"))
+ vi->type = UBI_VID_DYNAMIC;
+ else {
+ errmsg("invalid volume type \"%s\"", p);
+ return -1;
+ }
+ }
+
+ verbose(args.verbose, "volume type: %s",
+ vi->type == UBI_VID_DYNAMIC ? "dynamic" : "static");
+
+ /* Fetch volume name */
+ sprintf(buf, "%s:vol_name", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (!p) {
+ errmsg("\"vol_name\" key not found in section \"%s\"", sname);
+ return -1;
+ }
+
+ vi->name = p;
+ vi->name_len = strlen(p);
+ if (vi->name_len > UBI_VOL_NAME_MAX) {
+ errmsg("too long volume name in section \"%s\", max. is "
+ "%d characters", vi->name, UBI_VOL_NAME_MAX);
+ return -1;
+ }
+
+ verbose(args.verbose, "volume name: %s", p);
+
+ /* Fetch volume alignment */
+ sprintf(buf, "%s:vol_alignment", sname);
+ vi->alignment = iniparser_getint(args.dict, buf, -1);
+ if (vi->alignment == -1) {
+ normsg("volume alignment was not specified in section "
+ "\"%s\", assume 1", sname);
+ vi->alignment = 1;
+ } else if (vi->id < 0) {
+ errmsg("negative volume alignement %d", vi->alignment);
+ return -1;
+ }
+
+ verbose(args.verbose, "volume alignment: %d", vi->alignment);
+
+ return 0;
+}
+
+static void init_vol_info(const struct ubigen_info *ui,
+ struct ubigen_vol_info *vi)
+{
+ vi->data_pad = ui->leb_size % vi->alignment;
+ vi->usable_leb_size = ui->leb_size - vi->data_pad;
+ vi->used_ebs = (vi->bytes + vi->usable_leb_size - 1) / vi->usable_leb_size;
+ vi->compat = 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err = -1, sects, i, volumes;
+ struct ubigen_info ui;
+ struct ubi_vtbl_record *vtbl;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ ubigen_info_init(&ui, args.peb_size, args.min_io_size,
+ args.subpage_size, args.vid_hdr_offs,
+ args.ubi_ver, args.ec);
+
+ verbose(args.verbose, "LEB size: %d", ui.leb_size);
+ verbose(args.verbose, "PEB size: %d", ui.peb_size);
+ verbose(args.verbose, "min_io_size: %d", ui.min_io_size);
+ verbose(args.verbose, "VID offset: %d", ui.vid_hdr_offs);
+
+ vtbl = ubigen_create_empty_vtbl(&ui);
+ if (!vtbl)
+ goto out;
+
+ args.dict = iniparser_load(args.f_in);
+ if (!args.dict) {
+ errmsg("cannot load the input ini file \"%s\"", args.f_in);
+ goto out_vtbl;
+ }
+
+ verbose(args.verbose, "loaded the ini-file \"%s\"", args.f_in);
+
+ /* Each section describes one volume */
+ sects = iniparser_getnsec(args.dict);
+ if (sects == -1) {
+ errmsg("ini-file parsing error (iniparser_getnsec)");
+ goto out_dict;
+ }
+
+ verbose(args.verbose, "count of sections: %d", sects);
+ if (sects == 0) {
+ errmsg("no sections found the ini-file \"%s\"", args.f_in);
+ goto out_dict;
+ }
+
+ /*
+ * Skip 2 PEBs at the beginning of the file for the volume table which
+ * will be written later.
+ */
+ if (fseek(args.fp_out, ui.peb_size * 2, SEEK_SET) == -1) {
+ errmsg("cannot seek file \"%s\"", args.f_out);
+ goto out_dict;
+ }
+
+ for (i = 0; i < sects; i++) {
+ const char *sname = iniparser_getsecname(args.dict, i);
+ struct ubigen_vol_info vi;
+ const char *img = NULL;
+ struct stat st;
+ FILE *f;
+
+ if (!sname) {
+ errmsg("ini-file parsing error (iniparser_getsecname)");
+ goto out_dict;
+ }
+
+ if (args.verbose)
+ printf("\n");
+ verbose(args.verbose, "parsing section \"%s\"", sname);
+
+ err = read_section(sname, &vi, &img);
+ if (err == -1)
+ goto out_dict;
+ if (!err)
+ volumes += 1;
+ init_vol_info(&ui, &vi);
+
+ verbose(args.verbose, "adding volume %d", vi.id);
+
+ err = ubigen_add_volume(&ui, &vi, vtbl);
+ if (err) {
+ errmsg("cannot add volume for section \"%s\"", sname);
+ goto out_dict;
+ }
+
+ if (!img)
+ continue;
+
+ if (stat(img, &st)) {
+ errmsg("cannot stat \"%s\"", img);
+ perror("stat");
+ goto out_dict;
+ }
+
+ f = fopen(img, "r");
+ if (!f) {
+ errmsg("cannot open \"%s\"", img);
+ perror("fopen");
+ goto out_dict;
+ }
+
+ verbose(args.verbose, "writing volume %d", vi.id);
+ verbose(args.verbose, "image file: %s", img);
+
+ err = ubigen_write_volume(&ui, &vi, st.st_size, f, args.fp_out);
+ fclose(f);
+ if (err) {
+ errmsg("cannot write volume for section \"%s\"", sname);
+ goto out_dict;
+ }
+
+ if (args.verbose)
+ printf("\n");
+ }
+
+ verbose(args.verbose, "writing layout volume");
+
+ err = ubigen_write_layout_vol(&ui, vtbl, args.fp_out);
+ if (err) {
+ errmsg("cannot write layout volume");
+ goto out_dict;
+ }
+
+ verbose(args.verbose, "done");
+
+ iniparser_freedict(args.dict);
+ free(vtbl);
+ fclose(args.fp_out);
+ return 0;
+
+out_dict:
+ iniparser_freedict(args.dict);
+out_vtbl:
+ free(vtbl);
+out:
+ fclose(args.fp_out);
+ remove(args.f_out);
+ return err;
+}
+
+#if 0
+/**
+ * pfi2vol_info - convert PFI UBI volume information to libubigen.
+ * @pfi: PFI UBI volume information
+ * @n: PFI volume index to convert
+ * @vi: libubigen volume information
+ */
+static void pfi2vol_info(const struct pfi_ubi *pfi, int n,
+ struct ubigen_vol_info *vi,
+ const struct ubigen_info *ui)
+{
+ vi->id = pfi->ids[n];
+ vi->bytes = pfi->size;
+ vi->alignment = pfi->alignment;
+ vi->data_pad = ui->leb_size % vi->alignment;
+ vi->usable_leb_size = ui->leb_size - vi->data_pad;
+ vi->type = pfi->vol_type;
+ vi->name = pfi->names[n];
+ vi->name_len = strlen(vi->name);
+ if (vi->name_len > UBI_VOL_NAME_MAX) {
+ errmsg("too long name, cut to %d symbols: \"%s\"",
+ UBI_VOL_NAME_MAX, vi->name);
+ vi->name_len = UBI_VOL_NAME_MAX;
+ }
+
+ vi->used_ebs = (vi->bytes + vi->usable_leb_size - 1) / vi->usable_leb_size;
+ vi->compat = 0;
+}
+#endif
diff --git a/ubi-utils/src/unubi.c b/ubi-utils/src/unubi.c
deleted file mode 100644
index 1d4b35b..0000000
--- a/ubi-utils/src/unubi.c
+++ /dev/null
@@ -1,1017 +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-header.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_%04u" /* split volume */
-#define FN_VOLWH "%s/volume%03u" /* whole volume */
-#define FN_VITBL "%s/vol_info_table%u" /* vol info table */
-
-/* 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 = crc32(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_VOL_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 = crc32(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, "%u\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 = crc32(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 = crc32(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_VOL_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];
- 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;
-
- /* 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 3f3a480..0000000
--- a/ubi-utils/src/unubi_analyze.c
+++ /dev/null
@@ -1,458 +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 "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;
- uint64_t *erase_counts;
- FILE* fpdata;
- FILE* fpplot;
- struct eb_info *cur;
-
- if (first == NULL)
- return -1;
-
- /* 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 = crc32(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, "%u %llu %llu", count,
- __be64_to_cpu(cur->ec.ec),
- 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, "%d", count);
- }
-
- cur = cur->next;
- count++;
- }
- fprintf(fpplot, ")\n");
-
- fprintf(fpplot, "set ylabel \"erase count\"\n");
- fprintf(fpplot, "set xrange [-1:%u]\n", eraseblocks + 1);
- fprintf(fpplot, "# set yrange [-1:%llu]\n",
- 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, "%u %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, "\"%d\" %d 0", step, count);
- }
- else
- fprintf(fpplot, "\"%d\" %d 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:%u]\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 8588219..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-header.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__ */