diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-01-23 19:34:52 +0200 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-01-23 19:34:52 +0200 |
commit | 3ad29ab55ad71d706152781b70a43d9f6be407b9 (patch) | |
tree | 4e5a41b23e771faef0f633c6570210a42bd9c037 /ubi-utils/src | |
parent | 22f5fe49d60ea43524a902408b3112a78f2c5aae (diff) |
ubi-utils: remove all old tools
Remove all old tools because I cannot maintain them and the original
authors do not seem to have time for this. Some of the tools do not
work properly, some are just vague and undocumented and seem to be
oriented to the environment of the IBM guys. Nevertheless, I'll
return the tool as is in the next commit, becouse they are still
useful.
This commit also adds a ubinize utility to generate UBI images.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'ubi-utils/src')
-rw-r--r-- | ubi-utils/src/bootenv.c | 1028 | ||||
-rw-r--r-- | ubi-utils/src/bootenv.h | 434 | ||||
-rw-r--r-- | ubi-utils/src/common.c | 59 | ||||
-rw-r--r-- | ubi-utils/src/common.h | 18 | ||||
-rw-r--r-- | ubi-utils/src/config.h | 28 | ||||
-rw-r--r-- | ubi-utils/src/dictionary.c | 405 | ||||
-rw-r--r-- | ubi-utils/src/dictionary.h | 174 | ||||
-rw-r--r-- | ubi-utils/src/eb_chain.c | 280 | ||||
-rw-r--r-- | ubi-utils/src/example_ubi.h | 28 | ||||
-rw-r--r-- | ubi-utils/src/hashmap.c | 412 | ||||
-rw-r--r-- | ubi-utils/src/hashmap.h | 49 | ||||
-rw-r--r-- | ubi-utils/src/libiniparser.c | 646 | ||||
-rw-r--r-- | ubi-utils/src/libpfi.c | 628 | ||||
-rw-r--r-- | ubi-utils/src/libubigen.c | 92 | ||||
-rw-r--r-- | ubi-utils/src/list.c | 143 | ||||
-rw-r--r-- | ubi-utils/src/list.h | 61 | ||||
-rw-r--r-- | ubi-utils/src/pfi2bin.c | 384 | ||||
-rw-r--r-- | ubi-utils/src/pfiflash.h | 76 | ||||
-rw-r--r-- | ubi-utils/src/ubinize.c | 615 | ||||
-rw-r--r-- | ubi-utils/src/unubi.c | 1017 | ||||
-rw-r--r-- | ubi-utils/src/unubi_analyze.c | 458 | ||||
-rw-r--r-- | ubi-utils/src/unubi_analyze.h | 87 |
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__ */ |