diff options
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__ */ |