From 6ccd7242c4c1404dafb64cd937adc3c65ce02385 Mon Sep 17 00:00:00 2001 From: Frank Haverkamp Date: Wed, 21 Jun 2006 14:26:02 +0200 Subject: [MTD] UBI: Removed automake, autoconf, added ubi userspace headers. Signed-off-by: Frank Haverkamp --- ubi-utils/src/libpfiflash.c | 619 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 619 insertions(+) create mode 100644 ubi-utils/src/libpfiflash.c (limited to 'ubi-utils/src/libpfiflash.c') diff --git a/ubi-utils/src/libpfiflash.c b/ubi-utils/src/libpfiflash.c new file mode 100644 index 0000000..ed2af3c --- /dev/null +++ b/ubi-utils/src/libpfiflash.c @@ -0,0 +1,619 @@ +/* + * 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 pfiflash.c + * + * @author Oliver Lohmann + * + * @brief This library is provides an interface to the pfiflash utility. + * + * Wed Mar 15 11:39:19 CET 2006 Initial creation. + * + * @TODO Comare data before writing it. This implies that the volume + * parameters are compared first: size, alignment, name, type, ..., + * this is the same, compare the data. Volume deletion is deffered + * until the difference has been found out. + */ + +#include +#include +#include +#define __USE_GNU +#include + +#include +#include + +//#include /* FIXME Is this ok here!!?? */ + +#include "config.h" +#include "ubimirror.h" +#include "error.h" +#include "reader.h" +#include "example_ubi.h" +#include "bootenv.h" + +static const char copyright [] __attribute__((unused)) = + "Copyright (c) International Business Machines Corp., 2006"; + +#define EBUF(fmt...) do { \ + snprintf(err_buf, err_buf_size, fmt); \ + } while (0) + +static pdd_func_t pdd_funcs[PDD_HANDLING_NUM] = + { + &bootenv_pdd_keep, + &bootenv_pdd_merge, + &bootenv_pdd_overwrite + }; +/**< An array of PDD function pointers indexed by the algorithm. */ + + +typedef enum ubi_update_process_t { + UBI_REMOVE = 0, + UBI_WRITE, +} ubi_update_process_t; + +static int +skip_raw_sections(FILE* pfi, list_t pfi_raws, + char* err_buf, size_t err_buf_size) +{ + int rc = 0; + + void *i; + list_t ptr; + size_t j, skip_size; + + if (is_empty(pfi_raws)) + return 0; + + foreach(i, ptr, pfi_raws) { + skip_size = ((pfi_raw_t)i)->data_size; + for(j = 0; j < skip_size; j++) { + fgetc(pfi); + if (ferror(pfi)) { + EBUF("Cannot skip raw section in PFI."); + rc = -EIO; + goto err; + } + } + } + err: + return rc; +} + +/** + * @brief Wraps the ubi_mkvol functions and implements a hook for the bootenv + * update. + * @param devno UBI device number. + * @param s Current seqnum. + * @param u Information about the UBI volume from the PFI. + * @param err_buf An error buffer. + * @param err_buf_size The size of the error buffer. + * @return 0 On Sucess. + * @return else Error. + */ +static int +my_ubi_mkvol(int devno, int s, pfi_ubi_t u, char *err_buf, size_t err_buf_size) +{ + int rc = 0; + int type; + ubi_lib_t ulib = NULL; + + log_msg("%s(vol_id=%d, size=%d, data_size=%d, type=%d, " + "alig=%d, nlen=%d, name=%s)", __func__, + u->ids[s], u->size, u->data_size, u->type, u->alignment, + strnlen(u->names[s], PFI_UBI_VOL_NAME_LEN), u->names[s]); + + rc = ubi_open(&ulib); + if (rc != 0) { + goto err; + } + + switch (u->type) { + case pfi_ubi_static: + type = UBI_STATIC_VOLUME; break; + case pfi_ubi_dynamic: + type = UBI_DYNAMIC_VOLUME; break; + default: + type = UBI_DYNAMIC_VOLUME; + } + + rc = ubi_mkvol(ulib, devno, u->ids[s], type, u->size, u->alignment, + u->names[s]); + if (rc != 0) { + EBUF("Cannot create volume: %d", u->ids[s]); + goto err; + } + + err: + if (ulib != NULL) + ubi_close(&ulib); + return rc; +} + +/** + * @brief A wrapper around the UBI library function ubi_rmvol. + * @param devno UBI device number. + * @param s Current seqnum. + * @param u Information about the UBI volume from the PFI. + * @param err_buf An error buffer. + * @param err_buf_size The size of the error buffer. + * + * If the volume does not exist, the function will return success. + */ +static int +my_ubi_rmvol(int devno, uint32_t id, + char *err_buf __unused, size_t err_buf_size __unused) +{ + int rc = 0; + ubi_lib_t ulib = NULL; + int fd; + + log_msg("%s(id=%d)", __func__, id); + + rc = ubi_open(&ulib); + if (rc != 0) + goto err; + + /** + * Truncate if it exist or not. + */ + fd = ubi_vol_open(ulib, devno, id, O_RDWR); + if (fd == -1) + return 0; /* not existent, return */ + + rc = ubi_vol_update(fd, 0); + if (rc < 0) { + fprintf(stderr, "update failed rc=%d errno=%d\n", rc, errno); + ubi_vol_close(fd); + goto err; /* if EBUSY than empty device, continue */ + } + ubi_vol_close(fd); + + rc = ubi_rmvol(ulib, devno, id); + if (rc != 0) { + /* @TODO Define a ubi_rmvol return value which says + * sth like EUBI_NOSUCHDEV. In this case, a failed + * operation is acceptable. Everything else has to be + * classified as real error. But talk to Andreas Arnez + * before defining something odd... + */ + /* if ((errno == EINVAL) || (errno == ENODEV)) + return 0; */ /* currently it is EINVAL or ENODEV */ + + dbg_msg("Remove UBI volume %d returned with error: %d " + "errno=%d", id, rc, errno); + goto err; + } + err: + if (ulib != NULL) + ubi_close(&ulib); + return rc; +} + +static int +read_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, + char *err_buf, size_t err_buf_size) +{ + int rc = 0; + ubi_lib_t ulib = NULL; + FILE* fp_in = NULL; + + rc = ubi_open(&ulib); + if (rc) + return rc; + + fp_in = ubi_vol_fopen_read(ulib, devno, id); + if (!fp_in) { + EBUF("Cannot open bootenv volume"); + rc = -EIO; + goto err; + } + + log_msg("%s reading old bootenvs", __func__); + + /* Save old bootenvs for reference */ + rc = bootenv_read(fp_in, bootenv_old, BOOTENV_MAXSIZE); + if (rc) + EBUF("Cannot read bootenv_old"); + err: + if (fp_in) + fclose(fp_in); + if (ulib) + ubi_close(&ulib); + return rc; +} + +static int +write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, + pdd_func_t pdd_f, + FILE* fp_in, /* new pdd data contained in pfi */ + size_t fp_in_size, /* data size of new pdd data in pfi */ + char *err_buf, size_t err_buf_size) +{ + int rc = 0; + int warnings = 0; + ubi_lib_t ulib = NULL; + bootenv_t bootenv_new = NULL; + bootenv_t bootenv_res = NULL; + size_t update_size = 0; + FILE *fp_out = NULL; + + log_msg("%s(id=%d, fp_in=%p)", __func__, id, fp_in); + + /* Workflow: + * 1. Apply PDD operation and get the size of the returning + * bootenv_res section. Without the correct size it wouldn't + * be possible to call UBI update vol. + * 2. Call UBI update vol + * 3. Get FILE* to vol dev + * 4. Write to FILE* + */ + + rc = ubi_open(&ulib); + if (rc != 0) { + goto err; + } + + rc = bootenv_create(&bootenv_new); + if (rc != 0) + goto err; + rc = bootenv_create(&bootenv_res); + if (rc != 0) + goto err; + + rc = bootenv_read(fp_in, bootenv_new, fp_in_size); + if (rc != 0) + goto err; + + rc = pdd_f(bootenv_old, bootenv_new, &bootenv_res, &warnings, + err_buf, err_buf_size); + if (rc != 0) + goto err; + if (warnings) { + /* @TODO Do sth with the warning */ + dbg_msg("A warning in the PDD operation occured: %d", + warnings); + } + log_msg("... (2)"); + + rc = bootenv_size(bootenv_res, &update_size); + if (rc != 0) + goto err; + + fp_out = ubi_vol_fopen_update(ulib, devno, id, update_size); + if (fp_out == NULL) + goto err; + + rc = bootenv_write(fp_out, bootenv_res); + if (rc != 0) { + EBUF("Write operation on ubi%d_%d failed.", devno, id); + rc = -EIO; + goto err; + } + + err: + if (ulib != NULL) + ubi_close(&ulib); + if (bootenv_new != NULL) + bootenv_destroy(&bootenv_new); + if (bootenv_res != NULL) + bootenv_destroy(&bootenv_res); + if (fp_out) + fclose(fp_out); + return rc; +} + +static int +write_normal_volume(int devno, uint32_t id, size_t update_size, FILE* fp_in, + char *err_buf __unused, size_t err_buf_size __unused) +{ + int rc = 0; + ubi_lib_t ulib = NULL; + FILE* fp_out = NULL; + int c; + size_t i; + + log_msg("%s(id=%d, update_size=%d fp_in=%p)", + __func__, id, update_size, fp_in); + + rc = ubi_open(&ulib); + if (rc) + return rc; + + fp_out = ubi_vol_fopen_update(ulib, devno, id, update_size); + if (fp_out == NULL) { + rc = -1; + goto err; + } + + log_msg("starting the update ... "); /* FIXME DBG */ + for (i = 0; i < update_size; i++) { + c = getc(fp_in); + if (c == EOF && ferror(fp_in)) { + rc = -EIO; + goto err; + } + if (putc(c, fp_out) == EOF) { + rc = -EIO; + goto err; + } + /* FIXME DBG */ + /* if ((i & 0xFFF) == 0xFFF) log_msg("."); */ + } + /* log_msg("\n"); */ /* FIXME DBG */ + err: + if (fp_out) + fclose(fp_out); + if (ulib) + ubi_close(&ulib); + return rc; +} + + +/** + * @brief ... + * @precondition The PFI file contains at least one ubi_id entry. + * This is assured by the PFI read process. + * @postcondition The used seqnum number is set in the UBI PFI + * header list. + * The UBI volumes specified by seqnum are processed. + */ +static int +process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis, + bootenv_t bootenv_old, pdd_func_t pdd_f, + ubi_update_process_t ubi_update_process, + char *err_buf, size_t err_buf_size) +{ + int rc = 0; + pfi_ubi_t u; + list_t ptr; + + foreach(u, ptr, pfi_ubis) { + int s = seqnum; + if (seqnum > ((int)u->ids_size - 1)) { + s = 0; /* per default use the first */ + } + u->curr_seqnum = s; + + switch (ubi_update_process) { + case UBI_REMOVE: + if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || + (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { + rc =read_bootenv_volume(EXAMPLE_UBI_DEVICE, + u->ids[s], + bootenv_old, err_buf, + err_buf_size); + if (rc != 0) + goto err; + } + rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE, u->ids[s], + err_buf, err_buf_size); + if (rc != 0) + goto err; + break; + case UBI_WRITE: + rc = my_ubi_mkvol(EXAMPLE_UBI_DEVICE, s, u, + err_buf, err_buf_size); + if (rc != 0) + goto err; + if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || + (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { + rc = write_bootenv_volume(EXAMPLE_UBI_DEVICE, + u->ids[s], + bootenv_old, pdd_f, + pfi, + u->data_size, + err_buf, + err_buf_size); + } + else { + rc = write_normal_volume(EXAMPLE_UBI_DEVICE, + u->ids[s], + u->data_size, pfi, + err_buf, + err_buf_size); + } + if (rc != 0) + goto err; + break; + default: + EBUF("Invoked unknown UBI operation."); + rc = -1; + goto err; + + } + if (rc != 0) { + goto err; + } + } + err: + return rc; + +} + +static int +erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis, + char *err_buf, size_t err_buf_size) +{ + int rc = 0; + list_t ptr; + pfi_ubi_t u; + size_t i; + uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES]; + + for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) { + ubi_volumes[i] = 1; + } + + foreach(u, ptr, pfi_ubis) { + /* iterate over each vol_id */ + for(i = 0; i < u->ids_size; i++) { + if (u->ids[i] > PFI_UBI_MAX_VOLUMES) { + EBUF("PFI file contains an invalid " + "volume id: %d", u->ids[i]); + goto err; + } + /* remove from removal list */ + ubi_volumes[u->ids[i]] = 0; + } + } + + for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) { + if (ubi_volumes[i]) { + rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size); + if (rc != 0) + goto err; + } + } + err: + return rc; +} + +static int +mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis, + char *err_buf, size_t err_buf_size) +{ + int rc = 0; + list_t ptr; + uint32_t j; + pfi_ubi_t i; + ubi_lib_t ulib = NULL; + + log_msg("%s(...)", __func__); + + rc = ubi_open(&ulib); + if (rc != 0) + goto err; + + /** + * Execute all mirror operations on redundant groups. + * Create a volume within a redundant group if it does + * not exist already (this is a precondition of + * ubimirror). + */ + foreach(i, ptr, pfi_ubis) { + for(j = 0; j < i->ids_size; j++) { + /* skip self-match */ + if (i->ids[j] == i->ids[i->curr_seqnum]) + continue; + + rc = my_ubi_rmvol(devno, i->ids[j], err_buf, + err_buf_size); + if (rc != 0) + goto err; + + rc = my_ubi_mkvol(devno, j, i, err_buf, err_buf_size); + if (rc != 0) + goto err; + } + } + + foreach(i, ptr, pfi_ubis) { + rc = ubimirror(devno, i->curr_seqnum, i->ids, + i->ids_size, err_buf, err_buf_size); + if (rc != 0) + goto err; + } + + + err: + if (ulib != NULL) + ubi_close(&ulib); + return rc; +} + +int +pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, + char *err_buf, size_t err_buf_size) +{ + int rc = 0; + pdd_func_t pdd_f = NULL; + + if (pfi == NULL) + return -EINVAL; + + /** + * If the user didnt specify a seqnum we start per default + * with the index 0 + */ + int curr_seqnum = seqnum < 0 ? 0 : seqnum; + + list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */ + list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */ + + bootenv_t bootenv; + rc = bootenv_create(&bootenv); + if (rc != 0) { + EBUF("Cannot create bootenv variable"); + } + + rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi, + err_buf, err_buf_size); + if (rc != 0) { + EBUF("Cannot read PFI headers."); + goto err; + } + + /* @TODO: If you want to implement an IPL update - start here. */ + rc = skip_raw_sections(pfi, pfi_raws, err_buf, err_buf_size); + if (rc != 0) { + goto err; + } + + if (complete) { + rc = erase_unmapped_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, + err_buf, err_buf_size); + if (rc != 0) { + EBUF("Cannot delete unmapped UBI volumes."); + goto err; + } + } + + if (((int)pdd_handling >= 0) && (pdd_handling < PDD_HANDLING_NUM)) { + pdd_f = pdd_funcs[pdd_handling]; + } + else { + EBUF("Used unknown PDD handling algorithm (pdd_handling)"); + } + + rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, pdd_f, + UBI_REMOVE, err_buf, err_buf_size); + if (rc != 0) { + goto err; + } + rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, pdd_f, + UBI_WRITE, err_buf, err_buf_size); + if (rc != 0) { + goto err; + } + if (seqnum < 0) { /* mirror redundant pairs */ + rc = mirror_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, + err_buf, err_buf_size); + if (rc != 0) + goto err; + } + + err: + pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws); + pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, pfi_ubis); + bootenv_destroy(&bootenv); + return rc; +} -- cgit v1.2.3 From 31b015fc08a13a5b63245808f7d1a49eadd8193a Mon Sep 17 00:00:00 2001 From: Drake Dowsett Date: Mon, 6 Nov 2006 16:54:10 +0100 Subject: [MTD] UBI: pfiflash needs to flash raw sections and check CRC Flashing of raw partitions should be possible now. CRC checking of pfi files before flashing the content was added. Signed-off-by: Frank Haverkamp --- ubi-utils/Makefile | 8 +- ubi-utils/src/bootenv.c | 105 +++-- ubi-utils/src/bootenv.h | 9 + ubi-utils/src/error.c | 67 +++- ubi-utils/src/error.h | 2 +- ubi-utils/src/libpfiflash.c | 841 ++++++++++++++++++++++++++++++----------- ubi-utils/src/pfiflash.c | 37 +- ubi-utils/src/pfiflash.h | 13 + ubi-utils/src/pfiflash_error.h | 69 ++++ ubi-utils/src/reader.c | 15 +- ubi-utils/src/reader.h | 2 + 11 files changed, 890 insertions(+), 278 deletions(-) create mode 100644 ubi-utils/src/pfiflash_error.h (limited to 'ubi-utils/src/libpfiflash.c') diff --git a/ubi-utils/Makefile b/ubi-utils/Makefile index 6161f3d..2776c07 100644 --- a/ubi-utils/Makefile +++ b/ubi-utils/Makefile @@ -48,15 +48,15 @@ ubirmvol: ubirmvol.o error.o libubi.o libubi_sysfs.o $(CC) $(LDFLAGS) -o $@ $^ pddcustomize: pddcustomize.o error.o libubimirror.o bootenv.o hashmap.o \ - libubi.o libubi_sysfs.o + libubi.o libubi_sysfs.o crc32.o $(CC) $(LDFLAGS) -o $@ $^ pfiflash: pfiflash.o libpfiflash.o list.o reader.o error.o libubimirror.o \ - bootenv.o hashmap.o pfi.o libubi.o libubi_sysfs.o + bootenv.o hashmap.o pfi.o libubi.o libubi_sysfs.o crc32.o $(CC) $(LDFLAGS) -o $@ $^ ubimirror: ubimirror.o error.o libubimirror.o bootenv.o hashmap.o \ - libubi.o libubi_sysfs.o + libubi.o libubi_sysfs.o crc32.o $(CC) $(LDFLAGS) -o $@ $^ nand2bin: nand2bin.o nandecc.o nandcorr.o @@ -68,7 +68,7 @@ bin2nand: bin2nand.o error.o nandecc.o ubigen: ubigen.o libubigen.o crc32.o $(CC) $(LDFLAGS) -o $@ $^ -mkbootenv: mkbootenv.o bootenv.o hashmap.o error.o +mkbootenv: mkbootenv.o bootenv.o hashmap.o error.o crc32.o $(CC) $(LDFLAGS) -o $@ $^ unubi: unubi.o crc32.o diff --git a/ubi-utils/src/bootenv.c b/ubi-utils/src/bootenv.c index 8871d90..ed15dc7 100644 --- a/ubi-utils/src/bootenv.c +++ b/ubi-utils/src/bootenv.c @@ -27,10 +27,14 @@ #include #include -#include "config.h" #include "hashmap.h" #include "error.h" +#include +#include "crc32.h" + +#define __unused __attribute__((unused)) + #define BOOTENV_MAXLINE 512 /* max line size of a bootenv.txt file */ /* Structures */ @@ -189,9 +193,10 @@ extract_pair(const char *str, bootenv_t env) *val = '\0'; /* split strings */ val++; + rc = bootenv_set(env, key, val); -err: + err: free(key); return rc; } @@ -248,46 +253,36 @@ bootenv_create(bootenv_t* env) 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 = 0; /* current length */ - uint32_t j = 0; /* processed chars */ - uint32_t items = 0; /* processed items */ - int rc = 0; + const char *curr = buf; /* ptr to current key/value pair */ + uint32_t i, j; /* current length, chars processed */ - if (buf[size-1] != '\0') { + if (buf[size - 1] != '\0') /* must end in '\0' */ return BOOTENV_EFMT; - } - while ((i = strlen(curr)) != 0) { - /* there is a key value pair remaining */ - rc = extract_pair(curr, env); - if (rc != 0) { - rc = BOOTENV_EINVAL; - return rc; - } - items++; + 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; - j += i; - if (j >= size) - return 0; /* finished, end of buffer */ - curr += i + 1; + if (i == 1) + return 0; /* no string found */ + + if (extract_pair(curr, env) != 0) + return BOOTENV_EINVAL; } return 0; } -/** - * 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) +bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t* ret_crc) { int rc; char *buf = NULL; size_t i = 0; + uint32_t crc32_table[256]; if ((fp == NULL) || (env == NULL)) return -EINVAL; @@ -306,33 +301,47 @@ bootenv_read(FILE* fp, bootenv_t env, size_t size) */ 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 */ } - - /* log_msg("%c", c); */ /* FIXME DBG */ - - buf[i++] = c; if (ferror(fp)) { rc = -EIO; goto err; } + + buf[i++] = (char)c; + } + + /* calculate crc to return */ + if (ret_crc != NULL) { + init_crc32_table(crc32_table); + *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size); } /* transfer to hashmap */ rc = rd_buffer(env, buf, size); - /* FIXME DBG */ - /* log_msg("\n%s:%d rc=%d\n", __func__, __LINE__, rc); */ - 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) @@ -390,8 +399,8 @@ err: } static int -fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max, - size_t *written) +fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max __unused, + size_t *written) { int rc = 0; size_t keys_size, i; @@ -404,7 +413,7 @@ fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max, goto err; for (i = 0; i < keys_size; i++) { - if (wr > buf_size_max) { + if (wr > BOOTENV_MAXSIZE) { rc = -ENOSPC; goto err; } @@ -413,7 +422,7 @@ fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max, if (rc != 0) goto err; - wr += snprintf(buf + wr, buf_size_max - wr, + wr += snprintf(buf + wr, BOOTENV_MAXSIZE - wr, "%s=%s", keys[i], val); wr++; /* for \0 */ } @@ -428,11 +437,12 @@ err: } int -bootenv_write(FILE* fp, bootenv_t env) +bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc) { int rc = 0; size_t size = 0; char *buf = NULL; + uint32_t crc32_table[256]; if ((fp == NULL) || (env == NULL)) return -EINVAL; @@ -441,10 +451,17 @@ bootenv_write(FILE* fp, bootenv_t env) if (buf == NULL) return -ENOMEM; + rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, &size); if (rc != 0) goto err; + /* calculate crc to return */ + if (ret_crc != NULL) { + init_crc32_table(crc32_table); + *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size); + } + if (fwrite(buf, size, 1, fp) != 1) { rc = -EIO; goto err; @@ -456,6 +473,12 @@ err: return rc; } +int +bootenv_write(FILE* fp, bootenv_t env) +{ + return bootenv_write_crc(fp, env, NULL); +} + int bootenv_size(bootenv_t env, size_t *size) { diff --git a/ubi-utils/src/bootenv.h b/ubi-utils/src/bootenv.h index 86743ed..9003d70 100644 --- a/ubi-utils/src/bootenv.h +++ b/ubi-utils/src/bootenv.h @@ -230,6 +230,10 @@ int bootenv_size(bootenv_t env, size_t *size); */ 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. @@ -249,6 +253,11 @@ int bootenv_read_txt(FILE* fp, bootenv_t env); */ 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. diff --git a/ubi-utils/src/error.c b/ubi-utils/src/error.c index c8c623c..4aaedad 100644 --- a/ubi-utils/src/error.c +++ b/ubi-utils/src/error.c @@ -25,6 +25,7 @@ #include "error.h" #define MAXLINE 4096 +#define MAXWIDTH 80 static FILE *logfp = NULL; @@ -35,6 +36,9 @@ read_procfile(FILE *fp_out, const char *procfile) { FILE *fp; + if (!fp_out) + return -ENXIO; + fp = fopen(procfile, "r"); if (!fp) return -ENOENT; @@ -57,6 +61,9 @@ read_procfile(FILE *fp_out, const char *procfile) void error_initlog(const char *logfile) { + if (!logfile) + return; + logfp = fopen(logfile, "a+"); read_procfile(logfp, "/proc/cpuinfo"); } @@ -143,7 +150,11 @@ __err_dump(const char *fmt, ...) exit(EXIT_FAILURE); /* shouldn't get here */ } - +/** + * If a logfile is used we must not print on stderr and stdout + * anymore. Since pfilfash might be used in a server context, it is + * even dangerous to write to those descriptors. + */ static void err_doit(int errnoflag, int level __attribute__((unused)), const char *fmt, va_list ap) @@ -166,9 +177,61 @@ err_doit(int errnoflag, int level __attribute__((unused)), if (logfp) { fputs(buf, logfp); fflush(logfp); + return; /* exit when logging completes */ } - fputs(buf, fpout); + if (fpout == stderr) { + /* perform line wrap when outputting to stderr */ + int word_len, post_len, chars; + char *buf_ptr; + const char *frmt = "%*s%n %n"; + + chars = 0; + buf_ptr = buf; + while (sscanf(buf_ptr, frmt, &word_len, &post_len) != EOF) { + int i; + char word[word_len + 1]; + char post[post_len + 1]; + + strncpy(word, buf_ptr, word_len); + word[word_len] = '\0'; + buf_ptr += word_len; + post_len -= word_len; + + if (chars + word_len > MAXWIDTH) { + fputc('\n', fpout); + chars = 0; + } + fputs(word, fpout); + chars += word_len; + + if (post_len > 0) { + strncpy(post, buf_ptr, post_len); + post[post_len] = '\0'; + buf_ptr += post_len; + } + for (i = 0; i < post_len; i++) { + int inc = 1, chars_new; + + if (post[i] == '\t') + inc = 8; + if (post[i] == '\n') { + inc = 0; + chars_new = 0; + } else + chars_new = chars + inc; + + if (chars_new > MAXWIDTH) { + fputc('\n', fpout); + chars_new = inc; + } + fputc(post[i], fpout); + chars = chars_new; + } + } + } + else + fputs(buf, fpout); fflush(fpout); if (fpout != stderr) fclose(fpout); diff --git a/ubi-utils/src/error.h b/ubi-utils/src/error.h index e8d7137..05d8078 100644 --- a/ubi-utils/src/error.h +++ b/ubi-utils/src/error.h @@ -78,7 +78,7 @@ void info_msg(const char *fmt, ...); __err_msg(fmt, ##__VA_ARGS__); \ } while (0) #else -#define dbg_msg(fmt, ...) +#define dbg_msg(fmt, ...) do {} while (0) #endif #endif /* __ERROR_H__ */ diff --git a/ubi-utils/src/libpfiflash.c b/ubi-utils/src/libpfiflash.c index ed2af3c..1dc9f10 100644 --- a/ubi-utils/src/libpfiflash.c +++ b/ubi-utils/src/libpfiflash.c @@ -16,16 +16,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/** - * @file pfiflash.c - * - * @author Oliver Lohmann - * - * @brief This library is provides an interface to the pfiflash utility. - * - * Wed Mar 15 11:39:19 CET 2006 Initial creation. - * - * @TODO Comare data before writing it. This implies that the volume +/* + * Authors: Oliver Lohmann + * Drake Dowsett + * Contact: Andreas Arnez + */ + +/* TODO Compare data before writing it. This implies that the volume * parameters are compared first: size, alignment, name, type, ..., * this is the same, compare the data. Volume deletion is deffered * until the difference has been found out. @@ -40,89 +37,130 @@ #include #include -//#include /* FIXME Is this ok here!!?? */ +#include /* FIXME Is this ok here? */ -#include "config.h" +#include "pfiflash_error.h" #include "ubimirror.h" #include "error.h" #include "reader.h" #include "example_ubi.h" #include "bootenv.h" -static const char copyright [] __attribute__((unused)) = +/* ubi-header.h and crc32.h needed for CRC checking */ +#include /* FIXME Is this ok here? */ +#include "crc32.h" + +#define __unused __attribute__((unused)) + +static const char copyright [] __unused = "Copyright (c) International Business Machines Corp., 2006"; -#define EBUF(fmt...) do { \ - snprintf(err_buf, err_buf_size, fmt); \ +/* simply clear buffer, then write into front of it */ +#define EBUF(fmt...) \ + snprintf(err_buf, err_buf_size, fmt); + +/* make a history of buffer and then prepend something in front */ +#define EBUF_PREPEND(fmt) \ + do { \ + int EBUF_HISTORY_LENGTH = strlen(err_buf); \ + char EBUF_HISTORY[EBUF_HISTORY_LENGTH + 1]; \ + strncpy(EBUF_HISTORY, err_buf, EBUF_HISTORY_LENGTH + 1);\ + EBUF(fmt ": %s", EBUF_HISTORY); \ } while (0) +/* An array of PDD function pointers indexed by the algorithm. */ static pdd_func_t pdd_funcs[PDD_HANDLING_NUM] = { &bootenv_pdd_keep, &bootenv_pdd_merge, &bootenv_pdd_overwrite }; -/**< An array of PDD function pointers indexed by the algorithm. */ - typedef enum ubi_update_process_t { UBI_REMOVE = 0, UBI_WRITE, } ubi_update_process_t; + +/** + * skip_raw_volumes - reads data from pfi to advance fp past raw block + * @pfi: fp to pfi data + * @pfi_raws: header information + * + * Error handling): + * when early EOF in pfi data + * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err + * when file I/O error + * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err + **/ static int -skip_raw_sections(FILE* pfi, list_t pfi_raws, +skip_raw_volumes(FILE* pfi, list_t pfi_raws, char* err_buf, size_t err_buf_size) { - int rc = 0; - + int rc; void *i; list_t ptr; - size_t j, skip_size; if (is_empty(pfi_raws)) return 0; + rc = 0; foreach(i, ptr, pfi_raws) { - skip_size = ((pfi_raw_t)i)->data_size; - for(j = 0; j < skip_size; j++) { - fgetc(pfi); - if (ferror(pfi)) { - EBUF("Cannot skip raw section in PFI."); - rc = -EIO; + size_t j; + pfi_raw_t raw; + + raw = (pfi_raw_t)i; + for(j = 0; j < raw->data_size; j++) { + int c; + + c = fgetc(pfi); + if (c == EOF) + rc = -PFIFLASH_ERR_EOF; + else if (ferror(pfi)) + rc = -PFIFLASH_ERR_FIO; + + if (rc != 0) goto err; - } } } + err: + EBUF(PFIFLASH_ERRSTR[-rc]); return rc; } + /** - * @brief Wraps the ubi_mkvol functions and implements a hook for the bootenv - * update. - * @param devno UBI device number. - * @param s Current seqnum. - * @param u Information about the UBI volume from the PFI. - * @param err_buf An error buffer. - * @param err_buf_size The size of the error buffer. - * @return 0 On Sucess. - * @return else Error. - */ + * my_ubi_mkvol - wraps the ubi_mkvol functions and impl. bootenv update hook + * @devno: UBI device number. + * @s: Current seqnum. + * @u: Information about the UBI volume from the PFI. + * + * Error handling: + * when UBI system couldn't be opened + * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err + * when UBI system couldn't create a volume + * - returns -PFIFLASH_ERR_UBI_MKVOL, err_buf matches text to err + **/ static int -my_ubi_mkvol(int devno, int s, pfi_ubi_t u, char *err_buf, size_t err_buf_size) +my_ubi_mkvol(int devno, int s, pfi_ubi_t u, + char *err_buf, size_t err_buf_size) { - int rc = 0; - int type; - ubi_lib_t ulib = NULL; + int rc, type; + ubi_lib_t ulib; + + rc = 0; + ulib = NULL; - log_msg("%s(vol_id=%d, size=%d, data_size=%d, type=%d, " - "alig=%d, nlen=%d, name=%s)", __func__, + log_msg("[ ubimkvol id=%d, size=%d, data_size=%d, type=%d, " + "alig=%d, nlen=%d, name=%s", u->ids[s], u->size, u->data_size, u->type, u->alignment, strnlen(u->names[s], PFI_UBI_VOL_NAME_LEN), u->names[s]); rc = ubi_open(&ulib); if (rc != 0) { + rc = -PFIFLASH_ERR_UBI_OPEN; + EBUF(PFIFLASH_ERRSTR[-rc]); goto err; } @@ -130,7 +168,6 @@ my_ubi_mkvol(int devno, int s, pfi_ubi_t u, char *err_buf, size_t err_buf_size) case pfi_ubi_static: type = UBI_STATIC_VOLUME; break; case pfi_ubi_dynamic: - type = UBI_DYNAMIC_VOLUME; break; default: type = UBI_DYNAMIC_VOLUME; } @@ -138,58 +175,78 @@ my_ubi_mkvol(int devno, int s, pfi_ubi_t u, char *err_buf, size_t err_buf_size) rc = ubi_mkvol(ulib, devno, u->ids[s], type, u->size, u->alignment, u->names[s]); if (rc != 0) { - EBUF("Cannot create volume: %d", u->ids[s]); + rc = -PFIFLASH_ERR_UBI_MKVOL; + EBUF(PFIFLASH_ERRSTR[-rc], u->ids[s]); goto err; } err: if (ulib != NULL) ubi_close(&ulib); + return rc; } + /** - * @brief A wrapper around the UBI library function ubi_rmvol. - * @param devno UBI device number. - * @param s Current seqnum. - * @param u Information about the UBI volume from the PFI. - * @param err_buf An error buffer. - * @param err_buf_size The size of the error buffer. + * my_ubi_rmvol - a wrapper around the UBI library function ubi_rmvol + * @devno UBI device number + * @id UBI volume id to remove * * If the volume does not exist, the function will return success. - */ + * + * Error handling: + * when UBI system couldn't be opened + * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err + * when UBI system couldn't update (truncate) a volume + * - returns -PFIFLASH_ERR_UBI_VOL_UPDATE, err_buf matches text to err + * when UBI system couldn't remove a volume + * - returns -PFIFLASH_ERR_UBI_RMVOL, err_buf matches text to err + **/ static int my_ubi_rmvol(int devno, uint32_t id, - char *err_buf __unused, size_t err_buf_size __unused) + char *err_buf, size_t err_buf_size) { - int rc = 0; - ubi_lib_t ulib = NULL; - int fd; + int rc, fd; + ubi_lib_t ulib; - log_msg("%s(id=%d)", __func__, id); + rc = 0; + ulib = NULL; + + log_msg("[ ubirmvol id=%d", id); rc = ubi_open(&ulib); - if (rc != 0) + if (rc != 0) { + rc = -PFIFLASH_ERR_UBI_OPEN; + EBUF(PFIFLASH_ERRSTR[-rc]); goto err; + } - /** - * Truncate if it exist or not. - */ + /* truncate whether it exist or not */ fd = ubi_vol_open(ulib, devno, id, O_RDWR); if (fd == -1) - return 0; /* not existent, return */ + return 0; /* not existent, return 0 */ rc = ubi_vol_update(fd, 0); + ubi_vol_close(fd); if (rc < 0) { - fprintf(stderr, "update failed rc=%d errno=%d\n", rc, errno); - ubi_vol_close(fd); + rc = -PFIFLASH_ERR_UBI_VOL_UPDATE; + EBUF(PFIFLASH_ERRSTR[-rc], id); goto err; /* if EBUSY than empty device, continue */ } - ubi_vol_close(fd); rc = ubi_rmvol(ulib, devno, id); if (rc != 0) { - /* @TODO Define a ubi_rmvol return value which says +#ifdef DEBUG + int rc_old = rc; + dbg_msg("Remove UBI volume %d returned with error: %d " + "errno=%d", id, rc_old, errno); +#endif + + rc = -PFIFLASH_ERR_UBI_RMVOL; + EBUF(PFIFLASH_ERRSTR[-rc], id); + + /* TODO Define a ubi_rmvol return value which says * sth like EUBI_NOSUCHDEV. In this case, a failed * operation is acceptable. Everything else has to be * classified as real error. But talk to Andreas Arnez @@ -198,65 +255,128 @@ my_ubi_rmvol(int devno, uint32_t id, /* if ((errno == EINVAL) || (errno == ENODEV)) return 0; */ /* currently it is EINVAL or ENODEV */ - dbg_msg("Remove UBI volume %d returned with error: %d " - "errno=%d", id, rc, errno); goto err; } + err: if (ulib != NULL) ubi_close(&ulib); + return rc; } + +/** + * read_bootenv_volume - reads the current bootenv data from id into be_old + * @devno UBI device number + * @id UBI volume id to remove + * @bootenv_old to hold old boot_env data + * + * Error handling: + * when UBI system couldn't be opened + * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err + * when UBI system couldn't open a volume to read + * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err + * when couldn't read bootenv data + * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err + **/ static int read_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, char *err_buf, size_t err_buf_size) { - int rc = 0; - ubi_lib_t ulib = NULL; - FILE* fp_in = NULL; + int rc; + FILE* fp_in; + ubi_lib_t ulib; + + rc = 0; + fp_in = NULL; + ulib = NULL; rc = ubi_open(&ulib); - if (rc) - return rc; + if (rc != 0) { + rc = -PFIFLASH_ERR_UBI_OPEN; + EBUF(PFIFLASH_ERRSTR[-rc]); + goto err; + } fp_in = ubi_vol_fopen_read(ulib, devno, id); if (!fp_in) { - EBUF("Cannot open bootenv volume"); - rc = -EIO; + rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; + EBUF(PFIFLASH_ERRSTR[-rc], id); goto err; } - log_msg("%s reading old bootenvs", __func__); + log_msg("[ reading old bootenvs ..."); /* Save old bootenvs for reference */ rc = bootenv_read(fp_in, bootenv_old, BOOTENV_MAXSIZE); - if (rc) - EBUF("Cannot read bootenv_old"); + if (rc != 0) { + rc = -PFIFLASH_ERR_BOOTENV_READ; + EBUF(PFIFLASH_ERRSTR[-rc]); + goto err; + } + err: if (fp_in) fclose(fp_in); if (ulib) ubi_close(&ulib); + return rc; } + +/** + * write_bootenv_volume - writes data from PFI file int to bootenv UBI volume + * @devno UBI device number + * @id UBI volume id + * @bootend_old old PDD data from machine + * @pdd_f function to handle PDD with + * @fp_in new pdd data contained in PFI + * @fp_in_size data size of new pdd data in PFI + * @pfi_crc crc value from PFI header + * + * Error handling: + * when UBI system couldn't be opened + * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err + * when bootenv can't be created + * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err + * when bootenv can't be read + * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err + * when PDD handling function returns and error + * - passes rc and err_buf data + * when CRC check fails + * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err + * when bootenv can't be resized + * - returns -PFIFLASH_ERR_BOOTENV_SIZE, err_buf matches text to err + * when UBI system couldn't open a volume + * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err + * when couldn't write bootenv data + * - returns -PFIFLASH_ERR_BOOTENV_WRITE, err_buf matches text to err + **/ static int write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, - pdd_func_t pdd_f, - FILE* fp_in, /* new pdd data contained in pfi */ - size_t fp_in_size, /* data size of new pdd data in pfi */ + pdd_func_t pdd_f, FILE* fp_in, size_t fp_in_size, + uint32_t pfi_crc, char *err_buf, size_t err_buf_size) { - int rc = 0; - int warnings = 0; - ubi_lib_t ulib = NULL; - bootenv_t bootenv_new = NULL; - bootenv_t bootenv_res = NULL; - size_t update_size = 0; - FILE *fp_out = NULL; - - log_msg("%s(id=%d, fp_in=%p)", __func__, id, fp_in); + int rc, warnings; + uint32_t crc; + size_t update_size; + FILE *fp_out; + bootenv_t bootenv_new, bootenv_res; + ubi_lib_t ulib; + + rc = 0; + warnings = 0; + crc = 0; + update_size = 0; + fp_out = NULL; + bootenv_new = NULL; + bootenv_res = NULL; + ulib = NULL; + + log_msg("[ ubiupdatevol bootenv id=%d, fp_in=%p", id, fp_in); /* Workflow: * 1. Apply PDD operation and get the size of the returning @@ -269,43 +389,65 @@ write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, rc = ubi_open(&ulib); if (rc != 0) { + rc = -PFIFLASH_ERR_UBI_OPEN; + EBUF(PFIFLASH_ERRSTR[-rc]); goto err; } rc = bootenv_create(&bootenv_new); - if (rc != 0) + if (rc != 0) { + rc = -PFIFLASH_ERR_BOOTENV_CREATE; + EBUF(PFIFLASH_ERRSTR[-rc], " 'new'"); goto err; + } + rc = bootenv_create(&bootenv_res); - if (rc != 0) + if (rc != 0) { + rc = -PFIFLASH_ERR_BOOTENV_CREATE; + EBUF(PFIFLASH_ERRSTR[-rc], " 'res'"); goto err; + } - rc = bootenv_read(fp_in, bootenv_new, fp_in_size); - if (rc != 0) + rc = bootenv_read_crc(fp_in, bootenv_new, fp_in_size, &crc); + if (rc != 0) { + rc = -PFIFLASH_ERR_BOOTENV_READ; + EBUF(PFIFLASH_ERRSTR[-rc]); + goto err; + } else if (crc != pfi_crc) { + rc = -PFIFLASH_ERR_CRC_CHECK; + EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc); goto err; + } rc = pdd_f(bootenv_old, bootenv_new, &bootenv_res, &warnings, err_buf, err_buf_size); - if (rc != 0) + if (rc != 0) { + EBUF_PREPEND("handling PDD"); goto err; - if (warnings) { - /* @TODO Do sth with the warning */ + } + else if (warnings) + /* TODO do something with warnings */ dbg_msg("A warning in the PDD operation occured: %d", warnings); - } - log_msg("... (2)"); rc = bootenv_size(bootenv_res, &update_size); - if (rc != 0) + if (rc != 0) { + rc = -PFIFLASH_ERR_BOOTENV_SIZE; + EBUF(PFIFLASH_ERRSTR[-rc]); goto err; + } fp_out = ubi_vol_fopen_update(ulib, devno, id, update_size); - if (fp_out == NULL) + if (!fp_out) { + rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; + EBUF(PFIFLASH_ERRSTR[-rc], id); goto err; + } rc = bootenv_write(fp_out, bootenv_res); if (rc != 0) { - EBUF("Write operation on ubi%d_%d failed.", devno, id); - rc = -EIO; + rc = -PFIFLASH_ERR_BOOTENV_WRITE; + EBUF(PFIFLASH_ERRSTR[-rc], devno, id); goto err; } @@ -318,102 +460,327 @@ write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, bootenv_destroy(&bootenv_res); if (fp_out) fclose(fp_out); + return rc; } + +/** + * write_normal_volume - writes data from PFI file int to regular UBI volume + * @devno UBI device number + * @id UBI volume id + * @update_size size of data stream + * @fp_in PFI data file pointer + * @pfi_crc CRC data from PFI header + * + * Error handling: + * when UBI system couldn't be opened + * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err + * when UBI system couldn't open a volume + * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err + * when unexpected EOF is encountered + * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err + * when file I/O error + * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err + * when CRC check fails + * - retruns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err + **/ static int write_normal_volume(int devno, uint32_t id, size_t update_size, FILE* fp_in, - char *err_buf __unused, size_t err_buf_size __unused) + uint32_t pfi_crc, + char *err_buf, size_t err_buf_size) { - int rc = 0; - ubi_lib_t ulib = NULL; - FILE* fp_out = NULL; - int c; - size_t i; + int rc; + uint32_t crc, crc32_table[256]; + size_t bytes_left; + FILE* fp_out; + ubi_lib_t ulib; - log_msg("%s(id=%d, update_size=%d fp_in=%p)", - __func__, id, update_size, fp_in); + rc = 0; + crc = UBI_CRC32_INIT; + bytes_left = update_size; + fp_out = NULL; + ulib = NULL; + + log_msg("[ ubiupdatevol id=%d, update_size=%d fp_in=%p", + id, update_size, fp_in); rc = ubi_open(&ulib); - if (rc) - return rc; + if (rc != 0) { + rc = -PFIFLASH_ERR_UBI_OPEN; + EBUF(PFIFLASH_ERRSTR[-rc]); + goto err; + } fp_out = ubi_vol_fopen_update(ulib, devno, id, update_size); - if (fp_out == NULL) { - rc = -1; + if (!fp_out) { + rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; + EBUF(PFIFLASH_ERRSTR[-rc], id); goto err; } - log_msg("starting the update ... "); /* FIXME DBG */ - for (i = 0; i < update_size; i++) { - c = getc(fp_in); - if (c == EOF && ferror(fp_in)) { - rc = -EIO; + init_crc32_table(crc32_table); + while (bytes_left) { + char buf[1024]; + size_t to_rw = sizeof buf > bytes_left ? + bytes_left : sizeof buf; + if (fread(buf, 1, to_rw, fp_in) != to_rw) { + rc = -PFIFLASH_ERR_EOF; + EBUF(PFIFLASH_ERRSTR[-rc]); goto err; } - if (putc(c, fp_out) == EOF) { - rc = -EIO; + crc = clc_crc32(crc32_table, crc, buf, to_rw); + if (fwrite(buf, 1, to_rw, fp_out) != to_rw) { + rc = -PFIFLASH_ERR_FIO; + EBUF(PFIFLASH_ERRSTR[-rc]); goto err; } - /* FIXME DBG */ - /* if ((i & 0xFFF) == 0xFFF) log_msg("."); */ + bytes_left -= to_rw; } - /* log_msg("\n"); */ /* FIXME DBG */ + + if (crc != pfi_crc) { + rc = -PFIFLASH_ERR_CRC_CHECK; + EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc); + goto err; + } + err: if (fp_out) fclose(fp_out); if (ulib) ubi_close(&ulib); + return rc; } /** - * @brief ... - * @precondition The PFI file contains at least one ubi_id entry. - * This is assured by the PFI read process. - * @postcondition The used seqnum number is set in the UBI PFI - * header list. - * The UBI volumes specified by seqnum are processed. - */ + * process_raw_volumes - writes the raw sections of the PFI data + * @pfi PFI data file pointer + * @pfi_raws list of PFI raw headers + * @rawdev device to use to write raw data + * + * Error handling: + * when early EOF in PFI data + * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err + * when file I/O error + * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err + * when CRC check fails + * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err + * when opening MTD device fails + * - reutrns -PFIFLASH_ERR_MTD_OPEN, err_buf matches text to err + * when closing MTD device fails + * - returns -PFIFLASH_ERR_MTD_CLOSE, err_buf matches text to err + **/ +static int +process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev, + char* err_buf, size_t err_buf_size) +{ + int rc; + char *pfi_data; + void *i; + uint32_t crc, crc32_table[256]; + size_t j, k; + FILE* mtd; + list_t ptr; + + if (is_empty(pfi_raws)) + return 0; + + if (rawdev == NULL) + return 0; + + rc = 0; + + log_msg("[ rawupdate dev=%s", rawdev); + + crc = UBI_CRC32_INIT; + init_crc32_table(crc32_table); + + /* most likely only one element in list, but just in case */ + foreach(i, ptr, pfi_raws) { + pfi_raw_t r = (pfi_raw_t)i; + + /* read in pfi data */ + pfi_data = malloc(r->data_size * sizeof(char)); + for (j = 0; j < r->data_size; j++) { + int c = fgetc(pfi); + if (c == EOF) { + rc = -PFIFLASH_ERR_EOF; + EBUF(PFIFLASH_ERRSTR[-rc]); + goto err; + } else if (ferror(pfi)) { + rc = -PFIFLASH_ERR_FIO; + EBUF(PFIFLASH_ERRSTR[-rc]); + goto err; + } + pfi_data[j] = (char)c; + } + crc = clc_crc32(crc32_table, crc, pfi_data, r->data_size); + + /* check crc */ + if (crc != r->crc) { + rc = -PFIFLASH_ERR_CRC_CHECK; + EBUF(PFIFLASH_ERRSTR[-rc], r->crc, crc); + goto err; + } + + /* open device */ + mtd = fopen(rawdev, "r+"); + if (mtd == NULL) { + rc = PFIFLASH_ERR_MTD_OPEN; + EBUF(PFIFLASH_ERRSTR[-rc], rawdev); + goto err; + } + + for (j = 0; j < r->starts_size; j++) { + fseek(mtd, r->starts[j], SEEK_SET); + for (k = 0; k < r->data_size; k++) { + int c = fputc((int)pfi_data[k], mtd); + if (c == EOF) { + fclose(mtd); + rc = -PFIFLASH_ERR_EOF; + EBUF(PFIFLASH_ERRSTR[-rc]); + return rc; + } + if ((char)c != pfi_data[k]) { + fclose(mtd); + return -1; + } + } + } + rc = fclose(mtd); + if (rc != 0) { + rc = -PFIFLASH_ERR_MTD_CLOSE; + EBUF(PFIFLASH_ERRSTR[-rc], rawdev); + goto err; + } + } + + err: + return rc; +} + + +/** + * erase_unmapped_ubi_volumes - skip volumes provided by PFI file, clear rest + * @devno UBI device number + * @pfi_ubis list of UBI header data + * + * Error handling: + * when UBI id is out of bounds + * - returns -PFIFLASH_ERR_UBI_VID_OOB, err_buf matches text to err + * when UBI volume can't be removed + * - passes rc, prepends err_buf with contextual aid + **/ +static int +erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis, + char *err_buf, size_t err_buf_size) +{ + int rc; + uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES]; + size_t i; + list_t ptr; + pfi_ubi_t u; + + rc = 0; + + for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) + ubi_volumes[i] = 1; + + foreach(u, ptr, pfi_ubis) { + /* iterate over each vol_id */ + for(i = 0; i < u->ids_size; i++) { + if (u->ids[i] > PFI_UBI_MAX_VOLUMES) { + rc = -PFIFLASH_ERR_UBI_VID_OOB; + EBUF(PFIFLASH_ERRSTR[-rc], u->ids[i]); + goto err; + } + /* remove from removal list */ + ubi_volumes[u->ids[i]] = 0; + } + } + + for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) { + if (ubi_volumes[i]) { + rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size); + if (rc != 0) { + EBUF_PREPEND("remove volume failed"); + goto err; + } + } + } + + err: + return rc; +} + + +/** + * process_ubi_volumes - delegate tasks regarding UBI volumes + * @pfi PFI data file pointer + * @seqnum sequence number + * @pfi_ubis list of UBI header data + * @bootenv_old storage for current system PDD + * @pdd_f function to handle PDD + * @ubi_update_process whether reading or writing + * + * Error handling: + * when and unknown ubi_update_process is given + * - returns -PFIFLASH_ERR_UBI_UNKNOWN, err_buf matches text to err + * otherwise + * - passes rc and err_buf + **/ static int process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis, bootenv_t bootenv_old, pdd_func_t pdd_f, ubi_update_process_t ubi_update_process, char *err_buf, size_t err_buf_size) { - int rc = 0; + int rc; pfi_ubi_t u; list_t ptr; + rc = 0; + foreach(u, ptr, pfi_ubis) { int s = seqnum; - if (seqnum > ((int)u->ids_size - 1)) { + + if (s > ((int)u->ids_size - 1)) s = 0; /* per default use the first */ - } u->curr_seqnum = s; switch (ubi_update_process) { case UBI_REMOVE: + /* TODO are all these "EXAMPLE" vars okay? */ if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { - rc =read_bootenv_volume(EXAMPLE_UBI_DEVICE, - u->ids[s], - bootenv_old, err_buf, - err_buf_size); + rc = read_bootenv_volume(EXAMPLE_UBI_DEVICE, + u->ids[s], bootenv_old, + err_buf, err_buf_size); + /* it's okay if there is no bootenv + * we're going to write one */ + if ((rc == -PFIFLASH_ERR_UBI_VOL_FOPEN) || + (rc == -PFIFLASH_ERR_BOOTENV_READ)) + rc = 0; if (rc != 0) goto err; - } - rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE, u->ids[s], + } + + rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE, u->ids[s], err_buf, err_buf_size); if (rc != 0) goto err; + break; case UBI_WRITE: rc = my_ubi_mkvol(EXAMPLE_UBI_DEVICE, s, u, err_buf, err_buf_size); - if (rc != 0) + if (rc != 0) { + EBUF_PREPEND("creating volume"); goto err; + } + if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { rc = write_bootenv_volume(EXAMPLE_UBI_DEVICE, @@ -421,87 +788,67 @@ process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis, bootenv_old, pdd_f, pfi, u->data_size, + u->crc, err_buf, err_buf_size); - } - else { + if (rc != 0) + EBUF_PREPEND("bootenv volume"); + } else { rc = write_normal_volume(EXAMPLE_UBI_DEVICE, u->ids[s], u->data_size, pfi, + u->crc, err_buf, err_buf_size); + if (rc != 0) + EBUF_PREPEND("normal volume"); } if (rc != 0) goto err; + break; default: - EBUF("Invoked unknown UBI operation."); - rc = -1; - goto err; - - } - if (rc != 0) { + rc = -PFIFLASH_ERR_UBI_UNKNOWN; + EBUF(PFIFLASH_ERRSTR[-rc]); goto err; } } - err: - return rc; - -} - -static int -erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis, - char *err_buf, size_t err_buf_size) -{ - int rc = 0; - list_t ptr; - pfi_ubi_t u; - size_t i; - uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES]; - - for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) { - ubi_volumes[i] = 1; - } - - foreach(u, ptr, pfi_ubis) { - /* iterate over each vol_id */ - for(i = 0; i < u->ids_size; i++) { - if (u->ids[i] > PFI_UBI_MAX_VOLUMES) { - EBUF("PFI file contains an invalid " - "volume id: %d", u->ids[i]); - goto err; - } - /* remove from removal list */ - ubi_volumes[u->ids[i]] = 0; - } - } - for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) { - if (ubi_volumes[i]) { - rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size); - if (rc != 0) - goto err; - } - } err: return rc; } + +/** + * mirror_ubi_volumes - mirror redundant pairs of volumes + * @devno UBI device number + * @pfi_ubis list of PFI header data + * + * Error handling: + * when UBI system couldn't be opened + * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err + **/ static int mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis, char *err_buf, size_t err_buf_size) { - int rc = 0; - list_t ptr; + int rc; uint32_t j; + list_t ptr; pfi_ubi_t i; - ubi_lib_t ulib = NULL; + ubi_lib_t ulib; - log_msg("%s(...)", __func__); + rc = 0; + ulib = NULL; + + log_msg("[ mirror ..."); rc = ubi_open(&ulib); - if (rc != 0) + if (rc != 0) { + rc = -PFIFLASH_ERR_UBI_OPEN; + EBUF(PFIFLASH_ERRSTR[-rc]); goto err; + } /** * Execute all mirror operations on redundant groups. @@ -510,25 +857,26 @@ mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis, * ubimirror). */ foreach(i, ptr, pfi_ubis) { - for(j = 0; j < i->ids_size; j++) { + for (j = 0; j < i->ids_size; j++) { /* skip self-match */ if (i->ids[j] == i->ids[i->curr_seqnum]) continue; - rc = my_ubi_rmvol(devno, i->ids[j], err_buf, - err_buf_size); + rc = my_ubi_rmvol(devno, i->ids[j], + err_buf, err_buf_size); if (rc != 0) goto err; - rc = my_ubi_mkvol(devno, j, i, err_buf, err_buf_size); + rc = my_ubi_mkvol(devno, j, i, + err_buf, err_buf_size); if (rc != 0) goto err; } } foreach(i, ptr, pfi_ubis) { - rc = ubimirror(devno, i->curr_seqnum, i->ids, - i->ids_size, err_buf, err_buf_size); + rc = ubimirror(devno, i->curr_seqnum, i->ids, i->ids_size, + err_buf, err_buf_size); if (rc != 0) goto err; } @@ -537,44 +885,71 @@ mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis, err: if (ulib != NULL) ubi_close(&ulib); + return rc; } + +/** + * pfiflash_with_raw - exposed func to flash memory with a PFI file + * @pfi PFI data file pointer + * @complete flag to erase unmapped volumes + * @seqnum sequence number + * @pdd_handling method to handle pdd (keep, merge, overwrite...) + * + * Error handling: + * when bootenv can't be created + * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err + * when PFI headers can't be read, or + * when fail to skip raw sections, or + * when error occurs while processing raw volumes, or + * when fail to erase unmapped UBI vols, or + * when error occurs while processing UBI volumes, or + * when error occurs while mirroring UBI volumes + * - passes rc, prepends err_buf with contextual aid + **/ int -pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, - char *err_buf, size_t err_buf_size) +pfiflash_with_raw(FILE* pfi, int complete, int seqnum, + pdd_handling_t pdd_handling, const char* rawdev, + char *err_buf, size_t err_buf_size) { - int rc = 0; - pdd_func_t pdd_f = NULL; + int rc; + bootenv_t bootenv; + pdd_func_t pdd_f; if (pfi == NULL) return -EINVAL; - /** - * If the user didnt specify a seqnum we start per default - * with the index 0 - */ + rc = 0; + pdd_f = NULL; + + /* If the user didnt specify a seqnum we start per default + * with the index 0 */ int curr_seqnum = seqnum < 0 ? 0 : seqnum; list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */ list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */ - bootenv_t bootenv; rc = bootenv_create(&bootenv); if (rc != 0) { - EBUF("Cannot create bootenv variable"); + rc = -PFIFLASH_ERR_BOOTENV_CREATE; + EBUF(PFIFLASH_ERRSTR[-rc], ""); + goto err; } - rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi, - err_buf, err_buf_size); + rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi, err_buf, err_buf_size); if (rc != 0) { - EBUF("Cannot read PFI headers."); + EBUF_PREPEND("reading PFI header"); goto err; } - /* @TODO: If you want to implement an IPL update - start here. */ - rc = skip_raw_sections(pfi, pfi_raws, err_buf, err_buf_size); + if (rawdev == NULL) + rc = skip_raw_volumes(pfi, pfi_raws, err_buf, err_buf_size); + else + rc = process_raw_volumes(pfi, pfi_raws, rawdev, err_buf, + err_buf_size); if (rc != 0) { + EBUF_PREPEND("handling raw section"); goto err; } @@ -582,33 +957,41 @@ pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, rc = erase_unmapped_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, err_buf, err_buf_size); if (rc != 0) { - EBUF("Cannot delete unmapped UBI volumes."); + EBUF_PREPEND("deleting unmapped UBI volumes"); goto err; } } - if (((int)pdd_handling >= 0) && (pdd_handling < PDD_HANDLING_NUM)) { + if (((int)pdd_handling >= 0) && + (pdd_handling < PDD_HANDLING_NUM)) pdd_f = pdd_funcs[pdd_handling]; - } else { - EBUF("Used unknown PDD handling algorithm (pdd_handling)"); + rc = -PFIFLASH_ERR_PDD_UNKNOWN; + EBUF(PFIFLASH_ERRSTR[-rc]); + goto err; } rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, pdd_f, UBI_REMOVE, err_buf, err_buf_size); - if (rc != 0) { + if (rc != 0) { + EBUF_PREPEND("removing UBI volumes"); goto err; } + rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, pdd_f, UBI_WRITE, err_buf, err_buf_size); if (rc != 0) { + EBUF_PREPEND("writing UBI volumes"); goto err; } + if (seqnum < 0) { /* mirror redundant pairs */ rc = mirror_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, err_buf, err_buf_size); - if (rc != 0) + if (rc != 0) { + EBUF_PREPEND("mirroring UBI volumes"); goto err; + } } err: @@ -617,3 +1000,19 @@ pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, bootenv_destroy(&bootenv); return rc; } + + +/** + * pfiflash - passes to pfiflash_with_raw + * @pfi PFI data file pointer + * @complete flag to erase unmapped volumes + * @seqnum sequence number + * @pdd_handling method to handle pdd (keep, merge, overwrite...) + **/ +int +pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, + char *err_buf, size_t err_buf_size) +{ + return pfiflash_with_raw(pfi, complete, seqnum, pdd_handling, + NULL, err_buf, err_buf_size); +} diff --git a/ubi-utils/src/pfiflash.c b/ubi-utils/src/pfiflash.c index 04f62df..c49fb1e 100644 --- a/ubi-utils/src/pfiflash.c +++ b/ubi-utils/src/pfiflash.c @@ -21,6 +21,8 @@ * Process a PFI (partial flash image) and write the data to the * specified UBI volumes. This tool is intended to be used for system * update using PFI files. + * + * 1.1 fixed output to stderr and stdout in logfile mode. */ #include @@ -34,12 +36,15 @@ #include #include +#undef DEBUG #include "error.h" #include "config.h" -const char *argp_program_version = PACKAGE_VERSION; +#define PROGRAM_VERSION "1.2" + +const char *argp_program_version = PROGRAM_VERSION; const char *argp_program_bug_address = PACKAGE_BUGREPORT; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " +static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\tBuilt on " BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" "\n" "pfiflash - a tool for updating a controller with PFI files.\n"; @@ -83,12 +88,17 @@ static struct argp_option options[] = { "'keep', 'merge' or 'overwrite'.", group: 2 }, + { name: "raw-flash", key: 'r', arg: "", flags: 0, + doc: "Flash the raw data. Use the specified mtd device.", + group: 2 }, + { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, }; typedef struct myargs { int verbose; const char *logfile; + const char *raw_dev; pdd_handling_t pdd_handling; int seqnum; @@ -168,7 +178,9 @@ parse_opt(int key, char *arg, struct argp_state *state) "Supported sides are '0' and '1'\n", arg); } break; - + case 'r': + args->raw_dev = arg; + break; case ARGP_KEY_ARG: /* input file */ args->fp_in = fopen(arg, "r"); if ((args->fp_in) == NULL) { @@ -212,9 +224,10 @@ int main (int argc, char** argv) .verbose = 0, .seqnum = -1, .complete = 0, - .logfile = "/tmp/pfiflash.log", + .logfile = NULL, /* "/tmp/pfiflash.log", */ .pdd_handling = PDD_KEEP, - .fp_in = stdin, + .fp_in = stdin, + .raw_dev = NULL, }; argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args); @@ -227,8 +240,16 @@ int main (int argc, char** argv) goto err; } - rc = pfiflash(args.fp_in, args.complete, args.seqnum, - args.pdd_handling, err_buf, PFIFLASH_MAX_ERR_BUF_SIZE); + if (!args.raw_dev) { + rc = pfiflash(args.fp_in, args.complete, args.seqnum, + args.pdd_handling, err_buf, + PFIFLASH_MAX_ERR_BUF_SIZE); + } else { + rc = pfiflash_with_raw(args.fp_in, args.complete, args.seqnum, + args.pdd_handling, args.raw_dev, err_buf, + PFIFLASH_MAX_ERR_BUF_SIZE); + } + if (rc != 0) { goto err_fp; } @@ -238,6 +259,6 @@ int main (int argc, char** argv) fclose(args.fp_in); err: if (rc != 0) - err_msg("Error: %s\nrc: %d\n", err_buf, rc); + err_msg("pfiflash: %s\nrc: %d\n", err_buf, rc); return rc; } diff --git a/ubi-utils/src/pfiflash.h b/ubi-utils/src/pfiflash.h index fc2eede..a063e7f 100644 --- a/ubi-utils/src/pfiflash.h +++ b/ubi-utils/src/pfiflash.h @@ -44,6 +44,19 @@ typedef enum pdd_handling_t 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 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_raw(FILE* pfi, int complete, int seqnum, + 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. diff --git a/ubi-utils/src/pfiflash_error.h b/ubi-utils/src/pfiflash_error.h new file mode 100644 index 0000000..34b705e --- /dev/null +++ b/ubi-utils/src/pfiflash_error.h @@ -0,0 +1,69 @@ +#ifndef __PFIFLASH_ERROR_H__ +#define __PFIFLASH_ERROR_H__ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Author: Drake Dowsett + * Contact: Andreas Arnez + */ + +enum pfiflash_err { + PFIFLASH_ERR_EOF = 1, + PFIFLASH_ERR_FIO, + PFIFLASH_ERR_UBI_OPEN, + PFIFLASH_ERR_UBI_CLOSE, + PFIFLASH_ERR_UBI_MKVOL, + PFIFLASH_ERR_UBI_RMVOL, + PFIFLASH_ERR_UBI_VOL_UPDATE, + PFIFLASH_ERR_UBI_VOL_FOPEN, + PFIFLASH_ERR_UBI_UNKNOWN, + PFIFLASH_ERR_UBI_VID_OOB, + PFIFLASH_ERR_BOOTENV_CREATE, + PFIFLASH_ERR_BOOTENV_READ, + PFIFLASH_ERR_BOOTENV_SIZE, + PFIFLASH_ERR_BOOTENV_WRITE, + PFIFLASH_ERR_PDD_UNKNOWN, + PFIFLASH_ERR_MTD_OPEN, + PFIFLASH_ERR_MTD_CLOSE, + PFIFLASH_ERR_CRC_CHECK +}; + +const char *const PFIFLASH_ERRSTR[] = { + "", + "unexpected EOF", + "file I/O error", + "couldn't open UBI", + "couldn't close UBI", + "couldn't make UBI volume %d", + "couldn't remove UBI volume %d", + "couldn't update UBI volume %d", + "couldn't open UBI volume %d", + "unknown UBI operation", + "PFI data contains out of bounds UBI id %d", + "couldn't create bootenv%s", + "couldn't read bootenv", + "couldn't resize bootenv", + "couldn't write bootenv on ubi%d_%d", + "unknown PDD handling algorithm", + "couldn't open MTD device %s", + "couldn't close MTD device %s", + "CRC check failed: given=0x%08x, calculated=0x%08x" +}; + +#endif /* __PFIFLASH_ERROR_H__ */ diff --git a/ubi-utils/src/reader.c b/ubi-utils/src/reader.c index 5de06d5..975caa1 100644 --- a/ubi-utils/src/reader.c +++ b/ubi-utils/src/reader.c @@ -29,10 +29,11 @@ #include #include -#include "config.h" #include "bootenv.h" #include "reader.h" +#define __unused __attribute__((unused)) + /* @FIXME hard coded offsets right now - get them from Artem? */ #define NAND2048_DEFAULT_VID_HDR_OFF 1984 #define NAND512_DEFAULT_VID_HDR_OFF 448 @@ -152,6 +153,12 @@ read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_raw_t* pfi_raw, goto err; } + rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc)); + if (rc != 0) { + EBUF_PFI("Cannot read 'crc' from PFI."); + goto err; + } + rc = pfi_header_getstring(pfi_hd, "raw_starts", tmp_str, PFI_KEYWORD_LEN); if (rc != 0) { @@ -212,6 +219,12 @@ read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_ubi_t* pfi_ubi, goto err; } + rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc)); + if (rc != 0) { + EBUF_PFI("Cannot read 'crc' from PFI."); + goto err; + } + rc = pfi_header_getstring(pfi_hd, "ubi_ids", tmp_str, PFI_KEYWORD_LEN); if (rc != 0) { EBUF_PFI("Cannot read 'ubi_ids' from PFI."); diff --git a/ubi-utils/src/reader.h b/ubi-utils/src/reader.h index d00fa17..715e464 100644 --- a/ubi-utils/src/reader.h +++ b/ubi-utils/src/reader.h @@ -50,6 +50,7 @@ struct pfi_raw { uint32_t data_size; uint32_t *starts; uint32_t starts_size; + uint32_t crc; }; struct pfi_ubi { @@ -63,6 +64,7 @@ struct pfi_ubi { enum { pfi_ubi_dynamic, pfi_ubi_static } type; int curr_seqnum; /* specifies the seqnum taken in an update, default: 0 (used by pfiflash, ubimirror) */ + uint32_t crc; }; int read_pdd_data(FILE* fp_pdd, pdd_data_t *pdd_data, -- cgit v1.2.3 From fbd2f11e12df8fd142aed37c0c25c08a1a26e44d Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 11 Dec 2006 14:34:23 +0100 Subject: [PATCH 13/13] Include stdlib.h for malloc Signed-off-by: Josh Boyer Acked-by: Frank Haverkamp --- ubi-utils/src/libpfiflash.c | 1 + 1 file changed, 1 insertion(+) (limited to 'ubi-utils/src/libpfiflash.c') diff --git a/ubi-utils/src/libpfiflash.c b/ubi-utils/src/libpfiflash.c index 1dc9f10..dd55203 100644 --- a/ubi-utils/src/libpfiflash.c +++ b/ubi-utils/src/libpfiflash.c @@ -33,6 +33,7 @@ #include #define __USE_GNU #include +#include #include #include -- cgit v1.2.3 From 1fea122705bfecebf38e57774762663b7cd913d2 Mon Sep 17 00:00:00 2001 From: Frank Haverkamp Date: Mon, 11 Dec 2006 14:34:23 +0100 Subject: [MTD] UBI Utils: Fix pfiflash Various little fixes including some whitespace fixups. Signed-off-by: Frank Haverkamp --- ubi-utils/src/libpfiflash.c | 15 +++++++++++---- ubi-utils/src/pfiflash.c | 21 ++++++++++++++------- 2 files changed, 25 insertions(+), 11 deletions(-) (limited to 'ubi-utils/src/libpfiflash.c') diff --git a/ubi-utils/src/libpfiflash.c b/ubi-utils/src/libpfiflash.c index dd55203..0be1f2c 100644 --- a/ubi-utils/src/libpfiflash.c +++ b/ubi-utils/src/libpfiflash.c @@ -593,6 +593,8 @@ process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev, rc = 0; + pfi_data = NULL; + log_msg("[ rawupdate dev=%s", rawdev); crc = UBI_CRC32_INIT; @@ -603,6 +605,8 @@ process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev, pfi_raw_t r = (pfi_raw_t)i; /* read in pfi data */ + if (pfi_data != NULL) + free(pfi_data); pfi_data = malloc(r->data_size * sizeof(char)); for (j = 0; j < r->data_size; j++) { int c = fgetc(pfi); @@ -629,7 +633,7 @@ process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev, /* open device */ mtd = fopen(rawdev, "r+"); if (mtd == NULL) { - rc = PFIFLASH_ERR_MTD_OPEN; + rc = -PFIFLASH_ERR_MTD_OPEN; EBUF(PFIFLASH_ERRSTR[-rc], rawdev); goto err; } @@ -642,11 +646,12 @@ process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev, fclose(mtd); rc = -PFIFLASH_ERR_EOF; EBUF(PFIFLASH_ERRSTR[-rc]); - return rc; + goto err; } if ((char)c != pfi_data[k]) { fclose(mtd); - return -1; + rc = -1; + goto err; } } } @@ -659,6 +664,8 @@ process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev, } err: + if (pfi_data != NULL) + free(pfi_data); return rc; } @@ -692,7 +699,7 @@ erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis, foreach(u, ptr, pfi_ubis) { /* iterate over each vol_id */ for(i = 0; i < u->ids_size; i++) { - if (u->ids[i] > PFI_UBI_MAX_VOLUMES) { + if (u->ids[i] >= PFI_UBI_MAX_VOLUMES) { rc = -PFIFLASH_ERR_UBI_VID_OOB; EBUF(PFIFLASH_ERRSTR[-rc], u->ids[i]); goto err; diff --git a/ubi-utils/src/pfiflash.c b/ubi-utils/src/pfiflash.c index c654be9..259a647 100644 --- a/ubi-utils/src/pfiflash.c +++ b/ubi-utils/src/pfiflash.c @@ -23,6 +23,8 @@ * update using PFI files. * * 1.1 fixed output to stderr and stdout in logfile mode. + * 1.2 updated. + * 1.3 removed argp parsing to be able to use uClib. */ #include @@ -39,7 +41,7 @@ #include "error.h" #include "config.h" -#define PROGRAM_VERSION "1.2" +#define PROGRAM_VERSION "1.3" extern char *optarg; extern int optind; @@ -141,7 +143,8 @@ parse_opt(int argc, char **argv, myargs *args) while (1) { int key; - key = getopt_long(argc, argv, "cl:vCp:r:s:?V", long_options, NULL); + key = getopt_long(argc, argv, "cl:vCp:r:s:?V", + long_options, NULL); if (key == -1) break; @@ -165,15 +168,17 @@ parse_opt(int argc, char **argv, myargs *args) args->pdd_handling = get_pdd_handling(optarg); if ((int)args->pdd_handling < 0) { err_quit("Unknown PDD handling: %s.\n" - "Please use either 'keep', 'merge' or" - "'overwrite'.\n'"); + "Please use either " + "'keep', 'merge' or" + "'overwrite'.\n'"); } break; case 's': args->seqnum = get_update_seqnum(optarg); if (args->seqnum < 0) { err_quit("Unsupported side: %s.\n" - "Supported sides are '0' and '1'\n", optarg); + "Supported sides are '0' " + "and '1'\n", optarg); } break; case 'r': @@ -183,7 +188,8 @@ parse_opt(int argc, char **argv, myargs *args) err_msg("Usage: pfiflash [OPTION...] [pfifile]"); err_msg("%s", doc); err_msg("%s", optionsstr); - err_msg("\nReport bugs to %s\n", PACKAGE_BUGREPORT); + err_msg("\nReport bugs to %s\n", + PACKAGE_BUGREPORT); exit(0); break; case 'V': @@ -200,7 +206,8 @@ parse_opt(int argc, char **argv, myargs *args) if (optind < argc) { args->fp_in = fopen(argv[optind++], "r"); if ((args->fp_in) == NULL) { - err_sys("Cannot open PFI file %s for input", argv[optind]); + err_sys("Cannot open PFI file %s for input", + argv[optind]); } } -- cgit v1.2.3 From 04d0f33ea243f307e045605603b96419ea458a26 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Wed, 21 Feb 2007 10:40:13 +0100 Subject: UBI Utils: pfiflash did not erase block before writing to it Pfiflash should erase raw flash regions before overwriting them and check for bad blocks in case of NAND flash. Signed-off-by: Alexander Schmidt Signed-off-by: Frank Haverkamp Signed-off-by: Josh Boyer --- ubi-utils/src/libpfiflash.c | 52 +++++++++++++++++++++++++++++++++++++++++- ubi-utils/src/pfiflash_error.h | 6 +++-- 2 files changed, 55 insertions(+), 3 deletions(-) (limited to 'ubi-utils/src/libpfiflash.c') diff --git a/ubi-utils/src/libpfiflash.c b/ubi-utils/src/libpfiflash.c index 0be1f2c..4dfafea 100644 --- a/ubi-utils/src/libpfiflash.c +++ b/ubi-utils/src/libpfiflash.c @@ -34,11 +34,13 @@ #define __USE_GNU #include #include +#include #include #include #include /* FIXME Is this ok here? */ +#include #include "pfiflash_error.h" #include "ubimirror.h" @@ -554,6 +556,45 @@ write_normal_volume(int devno, uint32_t id, size_t update_size, FILE* fp_in, return rc; } +static int +erase_mtd_region(FILE* file_p, int start, int length) +{ + int rc, fd; + erase_info_t erase; + mtd_info_t mtdinfo; + loff_t offset = start; + loff_t end = offset + length; + + fd = fileno(file_p); + if (fd < 0) + return -PFIFLASH_ERR_MTD_ERASE; + + rc = ioctl(fd, MEMGETINFO, &mtdinfo); + if (rc) + return -PFIFLASH_ERR_MTD_ERASE; + + /* check for bad blocks in case of NAND flash */ + if (mtdinfo.type == MTD_NANDFLASH) { + while (offset < end) { + rc = ioctl(fd, MEMGETBADBLOCK, &offset); + if (rc > 0) { + return -PFIFLASH_ERR_MTD_ERASE; + } + + offset += mtdinfo.erasesize; + } + } + + erase.start = start; + erase.length = length; + + rc = ioctl(fd, MEMERASE, &erase); + if (rc) { + return -PFIFLASH_ERR_MTD_ERASE; + } + + return rc; +} /** * process_raw_volumes - writes the raw sections of the PFI data @@ -582,7 +623,7 @@ process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev, void *i; uint32_t crc, crc32_table[256]; size_t j, k; - FILE* mtd; + FILE* mtd = NULL; list_t ptr; if (is_empty(pfi_raws)) @@ -639,6 +680,12 @@ process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev, } for (j = 0; j < r->starts_size; j++) { + rc = erase_mtd_region(mtd, r->starts[j], r->data_size); + if (rc) { + EBUF(PFIFLASH_ERRSTR[-rc]); + goto err; + } + fseek(mtd, r->starts[j], SEEK_SET); for (k = 0; k < r->data_size; k++) { int c = fputc((int)pfi_data[k], mtd); @@ -656,6 +703,7 @@ process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev, } } rc = fclose(mtd); + mtd = NULL; if (rc != 0) { rc = -PFIFLASH_ERR_MTD_CLOSE; EBUF(PFIFLASH_ERRSTR[-rc], rawdev); @@ -664,6 +712,8 @@ process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev, } err: + if (mtd != NULL) + fclose(mtd); if (pfi_data != NULL) free(pfi_data); return rc; diff --git a/ubi-utils/src/pfiflash_error.h b/ubi-utils/src/pfiflash_error.h index 34b705e..c06232a 100644 --- a/ubi-utils/src/pfiflash_error.h +++ b/ubi-utils/src/pfiflash_error.h @@ -41,7 +41,8 @@ enum pfiflash_err { PFIFLASH_ERR_PDD_UNKNOWN, PFIFLASH_ERR_MTD_OPEN, PFIFLASH_ERR_MTD_CLOSE, - PFIFLASH_ERR_CRC_CHECK + PFIFLASH_ERR_CRC_CHECK, + PFIFLASH_ERR_MTD_ERASE }; const char *const PFIFLASH_ERRSTR[] = { @@ -63,7 +64,8 @@ const char *const PFIFLASH_ERRSTR[] = { "unknown PDD handling algorithm", "couldn't open MTD device %s", "couldn't close MTD device %s", - "CRC check failed: given=0x%08x, calculated=0x%08x" + "CRC check failed: given=0x%08x, calculated=0x%08x", + "couldn't erase raw mtd region" }; #endif /* __PFIFLASH_ERROR_H__ */ -- cgit v1.2.3 From 9c37b558705b776e51f7d522f376de019a6ea203 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 21 Mar 2007 11:53:25 +0200 Subject: UBI-Utils: Convert to new ubi library Signed-off-by: Adrian Hunter --- ubi-utils/Makefile | 20 +- ubi-utils/inc/libubi.h | 268 ++++++++++++ ubi-utils/src/libpfiflash.c | 2 +- ubi-utils/src/libubi.c | 917 ++++++++++++++++++++++++++++++++++++++++ ubi-utils/src/libubi_int.h | 129 ++++++ ubi-utils/src/libubimirror.c | 10 +- ubi-utils/src/libubiold.c | 6 +- ubi-utils/src/libubiold_sysfs.c | 2 +- ubi-utils/src/pddcustomize.c | 2 +- ubi-utils/src/reader.c | 13 +- ubi-utils/src/ubimkvol.c | 33 +- ubi-utils/src/ubirmvol.c | 24 +- ubi-utils/src/ubiupdatevol.c | 46 +- 13 files changed, 1409 insertions(+), 63 deletions(-) create mode 100644 ubi-utils/inc/libubi.h create mode 100644 ubi-utils/src/libubi.c create mode 100644 ubi-utils/src/libubi_int.h (limited to 'ubi-utils/src/libpfiflash.c') diff --git a/ubi-utils/Makefile b/ubi-utils/Makefile index 0818a9b..797807d 100644 --- a/ubi-utils/Makefile +++ b/ubi-utils/Makefile @@ -16,11 +16,12 @@ CFLAGS := -I./inc -I./src -I$(KERNELHDR) -O2 -g -Wall -Werror \ -Wwrite-strings -W -std=gnu99 \ -DHOST_OS_NAME=\"$(HOST_OS_NAME)\" \ -DHOST_VERSION_NAME=\"$(HOST_VERSION_NAME)\" \ - -DBUILD_CPU=\"$(BUILD_CPU)\" -DBUILD_OS=\"$(BUILD_OS)\" + -DBUILD_CPU=\"$(BUILD_CPU)\" -DBUILD_OS=\"$(BUILD_OS)\" \ + -DPACKAGE_VERSION=\"1.0\" PERLPROGS = mkpfi ubicrc32.pl TARGETS = ubiupdatevol ubimkvol ubirmvol pfiflash pddcustomize ubimirror \ - bin2nand nand2bin ubigen mkbootenv unubi pfi2bin + bin2nand nand2bin ubigen mkbootenv unubi pfi2bin ubicrc32 vpath %.c ./src @@ -38,25 +39,25 @@ IGNORE=${wildcard .*.c.dep} clean: rm -rf *.o $(TARGETS) .*.c.dep -ubiupdatevol: ubiupdatevol.o error.o libubi.o libubi_sysfs.o +ubiupdatevol: ubiupdatevol.o error.o libubi.o $(CC) $(LDFLAGS) -o $@ $^ -ubimkvol: ubimkvol.o error.o libubi.o libubi_sysfs.o +ubimkvol: ubimkvol.o error.o libubi.o $(CC) $(LDFLAGS) -o $@ $^ -ubirmvol: ubirmvol.o error.o libubi.o libubi_sysfs.o +ubirmvol: ubirmvol.o error.o libubi.o $(CC) $(LDFLAGS) -o $@ $^ pddcustomize: pddcustomize.o error.o libubimirror.o bootenv.o hashmap.o \ - libubi.o libubi_sysfs.o crc32.o + libubiold.o libubiold_sysfs.o crc32.o $(CC) $(LDFLAGS) -o $@ $^ pfiflash: pfiflash.o libpfiflash.o list.o reader.o error.o libubimirror.o \ - bootenv.o hashmap.o pfi.o libubi.o libubi_sysfs.o crc32.o + bootenv.o hashmap.o pfi.o libubiold.o libubiold_sysfs.o crc32.o $(CC) $(LDFLAGS) -o $@ $^ ubimirror: ubimirror.o error.o libubimirror.o bootenv.o hashmap.o \ - libubi.o libubi_sysfs.o crc32.o + libubiold.o libubiold_sysfs.o crc32.o $(CC) $(LDFLAGS) -o $@ $^ nand2bin: nand2bin.o nandecc.o nandcorr.o @@ -78,6 +79,9 @@ pfi2bin: pfi2bin.o peb.o error.o list.o crc32.o libubigen.o bootenv.o \ hashmap.o reader.o pfi.o $(CC) $(LDFLAGS) -o $@ $^ +ubicrc32: ubicrc32.o crc32.o + $(CC) $(LDFLAGS) -o $@ $^ + install: ${TARGETS} mkdir -p ${DESTDIR}/${SBINDIR} install -m0755 ${TARGETS} ${DESTDIR}/${SBINDIR}/ diff --git a/ubi-utils/inc/libubi.h b/ubi-utils/inc/libubi.h new file mode 100644 index 0000000..d39c1b9 --- /dev/null +++ b/ubi-utils/inc/libubi.h @@ -0,0 +1,268 @@ +/* + * 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: Artem B. Bityutskiy + * + * UBI (Unsorted Block Images) library. + */ + +#ifndef __LIBUBI_H__ +#define __LIBUBI_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* UBI version libubi is made for */ +#define LIBUBI_UBI_VERSION 1 + +/* UBI library descriptor */ +typedef void * libubi_t; + +/** + * struct ubi_mkvol_request - volume creation request. + * */ +struct ubi_mkvol_request +{ + int vol_id; + int alignment; + long long bytes; + int vol_type; + const char *name; +}; + +/** + * struct ubi_info - general UBI information. + * + * @dev_count count of UBI devices in system + * @lowest_dev_num lowest UBI device number + * @highest_dev_num highest UBI device number + * @version UBI version + */ +struct ubi_info +{ + int dev_count; + int lowest_dev_num; + int highest_dev_num; + int version; +}; + +/** + * struct ubi_dev_info - UBI device information. + * + * @vol_count count of volumes on this UBI device + * @lowest_vol_num lowest volume number + * @highest_vol_num highest volume number + * @total_ebs total number of eraseblocks on this UBI device + * @avail_ebs how many eraseblocks are not used and available for new + * volumes + * @total_bytes @total_ebs * @eb_size + * @avail_bytes @avail_ebs * @eb_size + * @bad_count count of bad eraseblocks + * @eb_size size of UBI eraseblock + * @max_ec current highest erase counter value + * @bad_rsvd how many physical eraseblocks of the underlying flash + * device are reserved for bad eraseblocks handling + * @max_vol_count maximum count of volumes on this UBI device + * @min_io_size minimum input/output size of the UBI device + */ +struct ubi_dev_info +{ + int dev_num; + int vol_count; + int lowest_vol_num; + int highest_vol_num; + int total_ebs; + int avail_ebs; + long long total_bytes; + long long avail_bytes; + int bad_count; + int eb_size; + long long max_ec; + int bad_rsvd; + int max_vol_count; + int min_io_size; +}; + +/** + * struct ubi_vol_info - UBI volume information. + * + * @dev_num UBI device number the volume resides on + * @vol_id ID of this volume + * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * @alignment alignemnt of this volume + * @data_bytes how many data bytes are stored on this volume (equivalent to + * @rsvd_bytes for dynamic volumes) + * @rsvd_bytes how many bytes are reserved for this volume + * @rsvd_ebs how many eraseblocks are reserved for this volume + * @eb_size logical eraseblock size of this volume (may be less then + * device's logical eraseblock size due to alignment) + * @corrupted the volume is corrupted if this flag is not zero + * @name volume name (null-terminated) + */ +struct ubi_vol_info +{ + int dev_num; + int vol_id; + int type; + int alignment; + long long data_bytes; + long long rsvd_bytes; + int rsvd_ebs; + int eb_size; + int corrupted; + char name[UBI_VOL_NAME_MAX + 1]; +}; + +/** + * libubi_open - open UBI library. + * + * This function initializes and opens the UBI library and returns UBI library + * descriptor in case of success and %NULL in case of failure. + */ +libubi_t libubi_open(void); + +/** + * libubi_close - close UBI library + * + * @desc UBI library descriptor + */ +void libubi_close(libubi_t desc); + +/** + * ubi_get_info - get general UBI information. + * + * @info pointer to the &struct ubi_info object to fill + * @desc UBI library descriptor + * + * This function fills the passed @info object with general UBI information and + * returns %0 in case of success and %-1 in case of failure. + */ +int ubi_get_info(libubi_t desc, struct ubi_info *info); + +/** + * ubi_mkvol - create an UBI volume. + * + * @desc UBI library descriptor + * @node name of the UBI character device to create a volume at + * @req UBI volume creation request (defined at ) + * + * This function creates a UBI volume as described at @req and returns %0 in + * case of success and %-1 in case of failure. The assigned volume ID is + * returned in @req->vol_id. + */ +int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req); + +/** + * ubi_rmvol - remove a UBI volume. + * + * @desc UBI library descriptor + * @node name of the UBI character device to remove a volume from + * @vol_id ID of the volume to remove + * + * This function removes volume @vol_id from UBI device @node and returns %0 in + * case of success and %-1 in case of failure. + */ +int ubi_rmvol(libubi_t desc, const char *node, int vol_id); + +/** + * ubi_rsvol - re-size UBI volume. + * + * @desc UBI library descriptor + * @node name of the UBI character device owning the volume which should be + * re-sized + * @vol_id volume ID to re-size + * @bytes new volume size in bytes + * + * This function returns %0 in case of success and %-1 in case of error. + */ +int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes); + +/** + * ubi_get_dev_info - get UBI device information. + * + * @desc UBI library descriptor + * @node name of the UBI character device to fetch information about + * @info pointer to the &struct ubi_dev_info object to fill + * + * This function fills the passed @info object with UBI device information and + * returns %0 in case of success and %-1 in case of failure. + */ +int ubi_get_dev_info(libubi_t desc, const char *node, + struct ubi_dev_info *info); + +/** + * ubi_get_dev_info1 - get UBI device information. + * + * @desc UBI library descriptor + * @dev_num UBI device number to fetch information about + * @info pointer to the &struct ubi_dev_info object to fill + * + * This function is identical to 'ubi_get_dev_info()' except that it accepts UBI + * device number, not UBI character device. + */ +int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info); + +/** + * ubi_get_vol_info - get UBI volume information. + * + * @desc UBI library descriptor + * @node name of the UBI volume character device to fetch information about + * @info pointer to the &struct ubi_vol_info object to fill + * + * This function fills the passed @info object with UBI volume information and + * returns %0 in case of success and %-1 in case of failure. + */ +int ubi_get_vol_info(libubi_t desc, const char *node, + struct ubi_vol_info *info); + +/** + * ubi_get_vol_info1 - get UBI volume information. + * + * @desc UBI library descriptor + * @dev_num UBI device number + * @vol_id ID of the UBI volume to fetch information about + * @info pointer to the &struct ubi_vol_info object to fill + * + * This function is identical to 'ubi_get_vol_info()' except that it accepts UBI + * volume number, not UBI volume character device. + */ +int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id, + struct ubi_vol_info *info); + +/** + * ubi_update_start - start UBI volume update. + * + * @desc UBI library descriptor + * @fd volume character devie file descriptor + * @bytes how many bytes will be written to the volume + * + * This function initiates UBI volume update and returns %0 in case of success + * and %-1 in case of error. + */ +int ubi_update_start(libubi_t desc, int fd, long long bytes); + +#ifdef __cplusplus +} +#endif + +#endif /* !__LIBUBI_H__ */ diff --git a/ubi-utils/src/libpfiflash.c b/ubi-utils/src/libpfiflash.c index 4dfafea..4f1f5cd 100644 --- a/ubi-utils/src/libpfiflash.c +++ b/ubi-utils/src/libpfiflash.c @@ -36,7 +36,7 @@ #include #include -#include +#include #include #include /* FIXME Is this ok here? */ diff --git a/ubi-utils/src/libubi.c b/ubi-utils/src/libubi.c new file mode 100644 index 0000000..17ab4ee --- /dev/null +++ b/ubi-utils/src/libubi.c @@ -0,0 +1,917 @@ +/* + * 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: Artem B. Bityutskiy + * + * UBI (Unsorted Block Images) library. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libubi.h" +#include "libubi_int.h" + +libubi_t libubi_open(void) +{ + int fd, version; + struct libubi *lib; + + lib = calloc(1, sizeof(struct libubi)); + if (!lib) + return NULL; + + /* TODO: this must be discovered instead */ + lib->sysfs = strdup("/sys"); + if (!lib->sysfs) + goto error; + + lib->sysfs_ubi = mkpath(lib->sysfs, SYSFS_UBI); + if (!lib->sysfs_ubi) + goto error; + + /* Make sure UBI is present */ + fd = open(lib->sysfs_ubi, O_RDONLY); + if (fd == -1) + goto error; + close(fd); + + lib->ubi_dev = mkpath(lib->sysfs_ubi, UBI_DEV_NAME_PATT); + if (!lib->ubi_dev) + goto error; + + lib->ubi_version = mkpath(lib->sysfs_ubi, UBI_VER); + if (!lib->ubi_version) + goto error; + + lib->dev_dev = mkpath(lib->ubi_dev, DEV_DEV); + if (!lib->dev_dev) + goto error; + + lib->dev_avail_ebs = mkpath(lib->ubi_dev, DEV_AVAIL_EBS); + if (!lib->dev_avail_ebs) + goto error; + + lib->dev_total_ebs = mkpath(lib->ubi_dev, DEV_TOTAL_EBS); + if (!lib->dev_total_ebs) + goto error; + + lib->dev_bad_count = mkpath(lib->ubi_dev, DEV_BAD_COUNT); + if (!lib->dev_bad_count) + goto error; + + lib->dev_eb_size = mkpath(lib->ubi_dev, DEV_EB_SIZE); + if (!lib->dev_eb_size) + goto error; + + lib->dev_max_ec = mkpath(lib->ubi_dev, DEV_MAX_EC); + if (!lib->dev_max_ec) + goto error; + + lib->dev_bad_rsvd = mkpath(lib->ubi_dev, DEV_MAX_RSVD); + if (!lib->dev_bad_rsvd) + goto error; + + lib->dev_max_vols = mkpath(lib->ubi_dev, DEV_MAX_VOLS); + if (!lib->dev_max_vols) + goto error; + + lib->dev_min_io_size = mkpath(lib->ubi_dev, DEV_MIN_IO_SIZE); + if (!lib->dev_min_io_size) + goto error; + + lib->ubi_vol = mkpath(lib->sysfs_ubi, UBI_VOL_NAME_PATT); + if (!lib->ubi_vol) + goto error; + + lib->vol_type = mkpath(lib->ubi_vol, VOL_TYPE); + if (!lib->vol_type) + goto error; + + lib->vol_dev = mkpath(lib->ubi_vol, VOL_DEV); + if (!lib->vol_dev) + goto error; + + lib->vol_alignment = mkpath(lib->ubi_vol, VOL_ALIGNMENT); + if (!lib->vol_alignment) + goto error; + + lib->vol_data_bytes = mkpath(lib->ubi_vol, VOL_DATA_BYTES); + if (!lib->vol_data_bytes) + goto error; + + lib->vol_rsvd_ebs = mkpath(lib->ubi_vol, VOL_RSVD_EBS); + if (!lib->vol_rsvd_ebs) + goto error; + + lib->vol_eb_size = mkpath(lib->ubi_vol, VOL_EB_SIZE); + if (!lib->vol_eb_size) + goto error; + + lib->vol_corrupted = mkpath(lib->ubi_vol, VOL_CORRUPTED); + if (!lib->vol_corrupted) + goto error; + + lib->vol_name = mkpath(lib->ubi_vol, VOL_NAME); + if (!lib->vol_name) + goto error; + + if (read_int(lib->ubi_version, &version)) + goto error; + if (version != LIBUBI_UBI_VERSION) { + fprintf(stderr, "LIBUBI: this library was made for UBI version " + "%d, but UBI version %d is detected\n", + LIBUBI_UBI_VERSION, version); + goto error; + } + + return lib; + +error: + free(lib->vol_corrupted); + free(lib->vol_eb_size); + free(lib->vol_rsvd_ebs); + free(lib->vol_data_bytes); + free(lib->vol_alignment); + free(lib->vol_dev); + free(lib->vol_type); + free(lib->ubi_vol); + free(lib->dev_min_io_size); + free(lib->dev_max_vols); + free(lib->dev_bad_rsvd); + free(lib->dev_max_ec); + free(lib->dev_eb_size); + free(lib->dev_bad_count); + free(lib->dev_total_ebs); + free(lib->dev_avail_ebs); + free(lib->dev_dev); + free(lib->ubi_version); + free(lib->ubi_dev); + free(lib->sysfs_ubi); + free(lib->sysfs); + free(lib); + return NULL; +} + +void libubi_close(libubi_t desc) +{ + struct libubi *lib = (struct libubi *)desc; + + free(lib->vol_name); + free(lib->vol_corrupted); + free(lib->vol_eb_size); + free(lib->vol_rsvd_ebs); + free(lib->vol_data_bytes); + free(lib->vol_alignment); + free(lib->vol_dev); + free(lib->vol_type); + free(lib->ubi_vol); + free(lib->dev_min_io_size); + free(lib->dev_max_vols); + free(lib->dev_bad_rsvd); + free(lib->dev_max_ec); + free(lib->dev_eb_size); + free(lib->dev_bad_count); + free(lib->dev_total_ebs); + free(lib->dev_avail_ebs); + free(lib->dev_dev); + free(lib->ubi_version); + free(lib->ubi_dev); + free(lib->sysfs_ubi); + free(lib->sysfs); + free(lib); +} + +int ubi_get_info(libubi_t desc, struct ubi_info *info) +{ + DIR *sysfs_ubi; + struct dirent *dirent; + struct libubi *lib = (struct libubi *)desc; + + memset(info, '\0', sizeof(struct ubi_info)); + + /* + * We have to scan the UBI sysfs directory to identify how many UBI + * devices are present. + */ + sysfs_ubi = opendir(lib->sysfs_ubi); + if (!sysfs_ubi) + return -1; + + info->lowest_dev_num = INT_MAX; + while ((dirent = readdir(sysfs_ubi))) { + char *name = &dirent->d_name[0]; + int dev_num, ret; + + ret = sscanf(name, UBI_DEV_NAME_PATT, &dev_num); + if (ret == 1) { + info->dev_count += 1; + if (dev_num > info->highest_dev_num) + info->highest_dev_num = dev_num; + if (dev_num < info->lowest_dev_num) + info->lowest_dev_num = dev_num; + } + } + + if (info->lowest_dev_num == INT_MAX) + info->lowest_dev_num = 0; + + if (read_int(lib->ubi_version, &info->version)) + goto close; + + return closedir(sysfs_ubi); + +close: + closedir(sysfs_ubi); + return -1; +} + +int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req) +{ + int fd, ret; + struct ubi_mkvol_req r; + size_t n; + + desc = desc; + r.vol_id = req->vol_id; + r.alignment = req->alignment; + r.bytes = req->bytes; + r.vol_type = req->vol_type; + + n = strlen(req->name); + if (n > UBI_MAX_VOLUME_NAME) + return -1; + + strncpy(r.name, req->name, UBI_MAX_VOLUME_NAME + 1); + r.name_len = n; + + fd = open(node, O_RDONLY); + if (fd == -1) + return -1; + + ret = ioctl(fd, UBI_IOCMKVOL, &r); + + if (!ret) + req->vol_id = r.vol_id; + + close(fd); + return ret; +} + +int ubi_rmvol(libubi_t desc, const char *node, int vol_id) +{ + int fd, ret; + + desc = desc; + fd = open(node, O_RDONLY); + if (fd == -1) + return -1; + + ret = ioctl(fd, UBI_IOCRMVOL, &vol_id); + close(fd); + return ret; +} + +int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes) +{ + int fd, ret; + struct ubi_rsvol_req req; + + desc = desc; + fd = open(node, O_RDONLY); + if (fd == -1) + return -1; + + req.bytes = bytes; + req.vol_id = vol_id; + + ret = ioctl(fd, UBI_IOCRSVOL, &req); + close(fd); + return ret; +} + +int ubi_update_start(libubi_t desc, int fd, long long bytes) +{ + desc = desc; + if (ioctl(fd, UBI_IOCVOLUP, &bytes)) + return -1; + return 0; +} + +int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info) +{ + int dev_num; + struct libubi *lib = (struct libubi *)desc; + + dev_num = find_dev_num(lib, node); + if (dev_num == -1) + return -1; + + return ubi_get_dev_info1(desc, dev_num, info); +} + +int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info) +{ + DIR *sysfs_ubi; + struct dirent *dirent; + struct libubi *lib = (struct libubi *)desc; + + memset(info, '\0', sizeof(struct ubi_dev_info)); + info->dev_num = dev_num; + + sysfs_ubi = opendir(lib->sysfs_ubi); + if (!sysfs_ubi) + return -1; + + info->lowest_vol_num = INT_MAX; + while ((dirent = readdir(sysfs_ubi))) { + char *name = &dirent->d_name[0]; + int vol_id, ret, devno; + + ret = sscanf(name, UBI_VOL_NAME_PATT, &devno, &vol_id); + if (ret == 2 && devno == dev_num) { + info->vol_count += 1; + if (vol_id > info->highest_vol_num) + info->highest_vol_num = vol_id; + if (vol_id < info->lowest_vol_num) + info->lowest_vol_num = vol_id; + } + } + + closedir(sysfs_ubi); + + if (info->lowest_vol_num == INT_MAX) + info->lowest_vol_num = 0; + + if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_ebs)) + return -1; + if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_ebs)) + return -1; + if (dev_read_int(lib->dev_bad_count, dev_num, &info->bad_count)) + return -1; + if (dev_read_int(lib->dev_eb_size, dev_num, &info->eb_size)) + return -1; + if (dev_read_int(lib->dev_bad_rsvd, dev_num, &info->bad_rsvd)) + return -1; + if (dev_read_ll(lib->dev_max_ec, dev_num, &info->max_ec)) + return -1; + if (dev_read_int(lib->dev_max_vols, dev_num, &info->max_vol_count)) + return -1; + if (dev_read_int(lib->dev_min_io_size, dev_num, &info->min_io_size)) + return -1; + + info->avail_bytes = info->avail_ebs * info->eb_size; + info->total_bytes = info->total_ebs * info->eb_size; + + return 0; +} + +int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info) +{ + int vol_id, dev_num; + struct libubi *lib = (struct libubi *)desc; + + dev_num = find_dev_num_vol(lib, node); + if (dev_num == -1) + return -1; + + vol_id = find_vol_num(lib, dev_num, node); + if (vol_id == -1) + return -1; + + return ubi_get_vol_info1(desc, dev_num, vol_id, info); +} + +int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id, + struct ubi_vol_info *info) +{ + int ret; + struct libubi *lib = (struct libubi *)desc; + char buf[50]; + + memset(info, '\0', sizeof(struct ubi_vol_info)); + info->dev_num = dev_num; + info->vol_id = vol_id; + + ret = vol_read_data(lib->vol_type, dev_num, vol_id, &buf[0], 50); + if (ret < 0) + return -1; + + if (strncmp(&buf[0], "static\n", ret) == 0) + info->type = UBI_STATIC_VOLUME; + else if (strncmp(&buf[0], "dynamic\n", ret) == 0) + info->type = UBI_DYNAMIC_VOLUME; + else { + fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); + errno = EINVAL; + return -1; + } + + ret = vol_read_int(lib->vol_alignment, dev_num, vol_id, + &info->alignment); + if (ret) + return -1; + ret = vol_read_ll(lib->vol_data_bytes, dev_num, vol_id, + &info->data_bytes); + if (ret) + return -1; + ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_ebs); + if (ret) + return -1; + ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->eb_size); + if (ret) + return -1; + ret = vol_read_int(lib->vol_corrupted, dev_num, vol_id, + &info->corrupted); + if (ret) + return -1; + info->rsvd_bytes = info->eb_size * info->rsvd_ebs; + + ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name, + UBI_VOL_NAME_MAX + 2); + if (ret < 0) + return -1; + + info->name[ret - 1] = '\0'; + + return 0; +} + +/** + * read_int - read an 'int' value from a file. + * + * @file the file to read from + * @value the result is stored here + * + * This function returns %0 in case of success and %-1 in case of failure. + */ +static int read_int(const char *file, int *value) +{ + int fd, rd; + char buf[50]; + + fd = open(file, O_RDONLY); + if (fd == -1) + return -1; + + rd = read(fd, &buf[0], 50); + if (rd == -1) + goto error; + + if (sscanf(&buf[0], "%d\n", value) != 1) { + /* This must be a UBI bug */ + fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); + errno = EINVAL; + goto error; + } + + close(fd); + return 0; + +error: + close(fd); + return -1; +} + +/** + * dev_read_int - read an 'int' value from an UBI device's sysfs file. + * + * @patt the file pattern to read from + * @dev_num UBI device number + * @value the result is stored here + * + * This function returns %0 in case of success and %-1 in case of failure. + */ +static int dev_read_int(const char *patt, int dev_num, int *value) +{ + int fd, rd; + char buf[50]; + char file[strlen(patt) + 50]; + + sprintf(&file[0], patt, dev_num); + fd = open(&file[0], O_RDONLY); + if (fd == -1) + return -1; + + rd = read(fd, &buf[0], 50); + if (rd == -1) + goto error; + + if (sscanf(&buf[0], "%d\n", value) != 1) { + /* This must be a UBI bug */ + fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); + errno = EINVAL; + goto error; + } + + close(fd); + return 0; + +error: + close(fd); + return -1; +} + +/** + * dev_read_ll - read a 'long long' value from an UBI device's sysfs file. + * + * @patt the file pattern to read from + * @dev_num UBI device number + * @value the result is stored here + * + * This function returns %0 in case of success and %-1 in case of failure. + */ +static int dev_read_ll(const char *patt, int dev_num, long long *value) +{ + int fd, rd; + char buf[50]; + char file[strlen(patt) + 50]; + + sprintf(&file[0], patt, dev_num); + fd = open(&file[0], O_RDONLY); + if (fd == -1) + return -1; + + rd = read(fd, &buf[0], 50); + if (rd == -1) + goto error; + + if (sscanf(&buf[0], "%lld\n", value) != 1) { + /* This must be a UBI bug */ + fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); + errno = EINVAL; + goto error; + } + + close(fd); + return 0; + +error: + close(fd); + return -1; +} + +/** + * dev_read_data - read data from an UBI device's sysfs file. + * + * @patt the file pattern to read from + * @dev_num UBI device number + * @buf buffer to read data to + * @buf_len buffer length + * + * This function returns number of read bytes in case of success and %-1 in + * case of failure. + */ +static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len) +{ + int fd, rd; + char file[strlen(patt) + 50]; + + sprintf(&file[0], patt, dev_num); + fd = open(&file[0], O_RDONLY); + if (fd == -1) + return -1; + + rd = read(fd, buf, buf_len); + if (rd == -1) { + close(fd); + return -1; + } + + close(fd); + return rd; +} + +/** + * vol_read_int - read an 'int' value from an UBI volume's sysfs file. + * + * @patt the file pattern to read from + * @dev_num UBI device number + * @vol_id volume identifier + * @value the result is stored here + * + * This function returns %0 in case of success and %-1 in case of failure. + */ +static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value) +{ + int fd, rd; + char buf[50]; + char file[strlen(patt) + 100]; + + sprintf(&file[0], patt, dev_num, vol_id); + fd = open(&file[0], O_RDONLY); + if (fd == -1) + return -1; + + rd = read(fd, &buf[0], 50); + if (rd == -1) + goto error; + + if (sscanf(&buf[0], "%d\n", value) != 1) { + /* This must be a UBI bug */ + fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); + errno = EINVAL; + goto error; + } + + close(fd); + return 0; + +error: + close(fd); + return -1; +} + +/** + * vol_read_ll - read a 'long long' value from an UBI volume's sysfs file. + * + * @patt the file pattern to read from + * @dev_num UBI device number + * @vol_id volume identifier + * @value the result is stored here + * + * This function returns %0 in case of success and %-1 in case of failure. + */ +static int vol_read_ll(const char *patt, int dev_num, int vol_id, + long long *value) +{ + int fd, rd; + char buf[50]; + char file[strlen(patt) + 100]; + + sprintf(&file[0], patt, dev_num, vol_id); + fd = open(&file[0], O_RDONLY); + if (fd == -1) + return -1; + + rd = read(fd, &buf[0], 50); + if (rd == -1) + goto error; + + if (sscanf(&buf[0], "%lld\n", value) != 1) { + /* This must be a UBI bug */ + fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); + errno = EINVAL; + goto error; + } + + close(fd); + return 0; + +error: + close(fd); + return -1; +} + +/** + * vol_read_data - read data from an UBI volume's sysfs file. + * + * @patt the file pattern to read from + * @dev_num UBI device number + * @vol_id volume identifier + * @buf buffer to read to + * @buf_len buffer length + * + * This function returns number of read bytes in case of success and %-1 in + * case of failure. + */ +static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf, + int buf_len) +{ + int fd, rd; + char file[strlen(patt) + 100]; + + sprintf(&file[0], patt, dev_num, vol_id); + fd = open(&file[0], O_RDONLY); + if (fd == -1) + return -1; + + rd = read(fd, buf, buf_len); + if (rd == -1) { + close(fd); + return -1; + } + + close(fd); + return rd; +} + +/** + * mkpath - compose full path from 2 given components. + * + * @path first component + * @name second component + * + * This function returns the resulting path in case of success and %NULL in + * case of failure. + */ +static char *mkpath(const char *path, const char *name) +{ + char *n; + int len1 = strlen(path); + int len2 = strlen(name); + + n = malloc(len1 + len2 + 2); + if (!n) + return NULL; + + memcpy(n, path, len1); + if (n[len1 - 1] != '/') + n[len1++] = '/'; + + memcpy(n + len1, name, len2 + 1); + return n; +} + +/** + * find_dev_num - find UBI device number by its character device node. + * + * @lib UBI library descriptor + * @node UBI character device node name + * + * This function returns positive UBI device number in case of success and %-1 + * in case of failure. + */ +static int find_dev_num(struct libubi *lib, const char *node) +{ + struct stat stat; + struct ubi_info info; + int i, major, minor; + + if (lstat(node, &stat)) + return -1; + + if (!S_ISCHR(stat.st_mode)) { + errno = EINVAL; + return -1; + } + + major = major(stat.st_rdev); + minor = minor(stat.st_rdev); + + if (minor != 0) { + errno = -EINVAL; + return -1; + } + + if (ubi_get_info((libubi_t *)lib, &info)) + return -1; + + for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { + int major1, minor1, ret; + char buf[50]; + + ret = dev_read_data(lib->dev_dev, i, &buf[0], 50); + if (ret < 0) + return -1; + + ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1); + if (ret != 2) { + fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); + errno = EINVAL; + return -1; + } + + if (minor1 == minor && major1 == major) + return i; + } + + errno = ENOENT; + return -1; +} + +/** + * find_dev_num_vol - find UBI device number by volume character device node. + * + * @lib UBI library descriptor + * @node UBI character device node name + * + * This function returns positive UBI device number in case of success and %-1 + * in case of failure. + */ +static int find_dev_num_vol(struct libubi *lib, const char *node) +{ + struct stat stat; + struct ubi_info info; + int i, major; + + if (lstat(node, &stat)) + return -1; + + if (!S_ISCHR(stat.st_mode)) { + errno = EINVAL; + return -1; + } + + major = major(stat.st_rdev); + + if (minor(stat.st_rdev) == 0) { + errno = -EINVAL; + return -1; + } + + if (ubi_get_info((libubi_t *)lib, &info)) + return -1; + + for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { + int major1, minor1, ret; + char buf[50]; + + ret = dev_read_data(lib->dev_dev, i, &buf[0], 50); + if (ret < 0) + return -1; + + ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1); + if (ret != 2) { + fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); + errno = EINVAL; + return -1; + } + + if (major1 == major) + return i; + } + + errno = ENOENT; + return -1; +} + +/** + * find_vol_num - find UBI volume number by its character device node. + * + * @lib UBI library descriptor + * @dev_num UBI device number + * @node UBI volume character device node name + * + * This function returns positive UBI volume number in case of success and %-1 + * in case of failure. + */ +static int find_vol_num(struct libubi *lib, int dev_num, const char *node) +{ + struct stat stat; + struct ubi_dev_info info; + int i, major, minor; + + if (lstat(node, &stat)) + return -1; + + if (!S_ISCHR(stat.st_mode)) { + errno = EINVAL; + return -1; + } + + major = major(stat.st_rdev); + minor = minor(stat.st_rdev); + + if (minor == 0) { + errno = -EINVAL; + return -1; + } + + if (ubi_get_dev_info1((libubi_t *)lib, dev_num, &info)) + return -1; + + for (i = info.lowest_vol_num; i <= info.highest_vol_num; i++) { + int major1, minor1, ret; + char buf[50]; + + ret = vol_read_data(lib->vol_dev, dev_num, i, &buf[0], 50); + if (ret < 0) + return -1; + + ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1); + if (ret != 2) { + fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); + errno = EINVAL; + return -1; + } + + if (minor1 == minor && major1 == major) + return i; + } + + errno = ENOENT; + return -1; +} diff --git a/ubi-utils/src/libubi_int.h b/ubi-utils/src/libubi_int.h new file mode 100644 index 0000000..e68b791 --- /dev/null +++ b/ubi-utils/src/libubi_int.h @@ -0,0 +1,129 @@ +/* + * 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: Artem B. Bityutskiy + * + * UBI (Unsorted Block Images) library. + */ + +#ifndef __LIBUBI_INT_H__ +#define __LIBUBI_INT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * UBI heavily makes use of the sysfs file system to interact with users-pace. + * The below are pre-define UBI file and directory names. + */ + +#define SYSFS_UBI "class/ubi" +#define UBI_DEV_NAME_PATT "ubi%d" +#define UBI_VER "version" +#define DEV_DEV "dev" +#define UBI_VOL_NAME_PATT "ubi%d_%d" +#define DEV_AVAIL_EBS "avail_eraseblocks" +#define DEV_TOTAL_EBS "total_eraseblocks" +#define DEV_BAD_COUNT "bad_peb_count" +#define DEV_EB_SIZE "eraseblock_size" +#define DEV_MAX_EC "max_ec" +#define DEV_MAX_RSVD "reserved_for_bad" +#define DEV_MAX_VOLS "max_vol_count" +#define DEV_MIN_IO_SIZE "min_io_size" +#define VOL_TYPE "type" +#define VOL_DEV "dev" +#define VOL_ALIGNMENT "alignment" +#define VOL_DATA_BYTES "data_bytes" +#define VOL_RSVD_EBS "reserved_ebs" +#define VOL_EB_SIZE "usable_eb_size" +#define VOL_CORRUPTED "corrupted" +#define VOL_NAME "name" + +/** + * libubi - UBI library description data structure. + * + * @sysfs sysfs file system path + * @sysfs_ubi UBI directory in sysfs + * @ubi_dev UBI device sysfs directory pattern + * @ubi_version UBI version file sysfs path + * @dev_dev UBI device's major/minor numbers file pattern + * @dev_avail_ebs count of available eraseblocks sysfs path pattern + * @dev_total_ebs total eraseblocks count sysfs path pattern + * @dev_bad_count count of bad eraseblocks sysfs path pattern + * @dev_eb_size size of UBI device's eraseblocks sysfs path pattern + * @dev_max_ec maximum erase counter sysfs path pattern + * @dev_bad_rsvd count of physical eraseblock reserved for bad eraseblocks + * handling + * @dev_max_vols maximum volumes number count sysfs path pattern + * @dev_min_io_size minimum I/O unit size sysfs path pattern + * @ubi_vol UBI volume sysfs directory pattern + * @vol_type volume type sysfs path pattern + * @vol_dev volume's major/minor numbers file pattern + * @vol_alignment volume alignment sysfs path pattern + * @vol_data_bytes volume data size sysfs path pattern + * @vol_rsvd_ebs volume reserved size sysfs path pattern + * @vol_eb_size volume eraseblock size sysfs path pattern + * @vol_corrupted volume corruption flag sysfs path pattern + * @vol_name volume name sysfs path pattern + */ +struct libubi +{ + char *sysfs; + char *sysfs_ubi; + char *ubi_dev; + char *ubi_version; + char *dev_dev; + char *dev_avail_ebs; + char *dev_total_ebs; + char *dev_bad_count; + char *dev_eb_size; + char *dev_max_ec; + char *dev_bad_rsvd; + char *dev_max_vols; + char *dev_min_io_size; + char *ubi_vol; + char *vol_type; + char *vol_dev; + char *vol_alignment; + char *vol_data_bytes; + char *vol_rsvd_ebs; + char *vol_eb_size; + char *vol_corrupted; + char *vol_name; + char *vol_max_count; +}; + +static int read_int(const char *file, int *value); +static int dev_read_int(const char *patt, int dev_num, int *value); +static int dev_read_ll(const char *patt, int dev_num, long long *value); +static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len); +static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value); +static int vol_read_ll(const char *patt, int dev_num, int vol_id, + long long *value); +static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf, + int buf_len); +static char *mkpath(const char *path, const char *name); +static int find_dev_num(struct libubi *lib, const char *node); +static int find_dev_num_vol(struct libubi *lib, const char *node); +static int find_vol_num(struct libubi *lib, int dev_num, const char *node); + +#ifdef __cplusplus +} +#endif + +#endif /* !__LIBUBI_INT_H__ */ diff --git a/ubi-utils/src/libubimirror.c b/ubi-utils/src/libubimirror.c index e5715fc..d8ea548 100644 --- a/ubi-utils/src/libubimirror.c +++ b/ubi-utils/src/libubimirror.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include "ubimirror.h" #define COMPARE_BUF_SIZE (128 * 1024) @@ -207,11 +207,11 @@ ubimirror(uint32_t devno, int seqnum, uint32_t *ids, ssize_t ids_size, fd_out = -1; } err: - if (ulib != NULL) - ubi_close(&ulib); - if (fd_in != -1) - ubi_vol_close(fd_in); if (fd_out != -1) ubi_vol_close(fd_out); + if (fd_in != -1) + ubi_vol_close(fd_in); + if (ulib != NULL) + ubi_close(&ulib); return rc; } diff --git a/ubi-utils/src/libubiold.c b/ubi-utils/src/libubiold.c index da4919b..0ff8bae 100644 --- a/ubi-utils/src/libubiold.c +++ b/ubi-utils/src/libubiold.c @@ -36,9 +36,9 @@ #include #include -#include "libubi.h" -#include "libubi_int.h" -#include "libubi_sysfs.h" +#include "libubiold.h" +#include "libubiold_int.h" +#include "libubiold_sysfs.h" /** * struct ubi_lib - UBI library descriptor. diff --git a/ubi-utils/src/libubiold_sysfs.c b/ubi-utils/src/libubiold_sysfs.c index 95fd3de..c4860f6 100644 --- a/ubi-utils/src/libubiold_sysfs.c +++ b/ubi-utils/src/libubiold_sysfs.c @@ -33,7 +33,7 @@ #include #include "config.h" -#include "libubi_int.h" +#include "libubiold_int.h" int sysfs_read_data(const char *file, void *buf, int len) diff --git a/ubi-utils/src/pddcustomize.c b/ubi-utils/src/pddcustomize.c index 764f2e7..a86e942 100644 --- a/ubi-utils/src/pddcustomize.c +++ b/ubi-utils/src/pddcustomize.c @@ -41,7 +41,7 @@ #include "bootenv.h" #include "error.h" #include "example_ubi.h" -#include "libubi.h" +#include "libubiold.h" #include "ubimirror.h" #define PROGRAM_VERSION "1.4" diff --git a/ubi-utils/src/reader.c b/ubi-utils/src/reader.c index 7935a15..0ea8c6d 100644 --- a/ubi-utils/src/reader.c +++ b/ubi-utils/src/reader.c @@ -142,6 +142,7 @@ read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_raw_t* pfi_raw, char tmp_str[PFI_KEYWORD_LEN]; bootenv_list_t raw_start_list = NULL; pfi_raw_t res; + size_t size; res = (pfi_raw_t) malloc(sizeof(struct pfi_raw)); if (!res) @@ -178,8 +179,9 @@ read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_raw_t* pfi_raw, } rc = bootenv_list_to_num_vector(raw_start_list, - (void *) &(res->starts_size), - &(res->starts)); + &size, &(res->starts)); + res->starts_size = size; + if (rc != 0) { EBUF_PFI("Cannot create numeric value array: %s", tmp_str); goto err; @@ -209,6 +211,7 @@ read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_ubi_t* pfi_ubi, bootenv_list_t ubi_name_list = NULL; pfi_ubi_t res; uint32_t i; + size_t size; res = (pfi_ubi_t) calloc(1, sizeof(struct pfi_ubi)); if (!res) @@ -247,8 +250,9 @@ read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_ubi_t* pfi_ubi, goto err; } - rc = bootenv_list_to_num_vector(ubi_id_list, (void *) &(res->ids_size), + rc = bootenv_list_to_num_vector(ubi_id_list, &size, &(res->ids)); + res->ids_size = size; if (rc != 0) { EBUF_PFI("Cannot create numeric value array: %s", tmp_str); goto err; @@ -299,8 +303,9 @@ read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_ubi_t* pfi_ubi, EBUF_PFI("Cannot translate PFI value: %s", tmp_str); goto err; } - rc = bootenv_list_to_vector(ubi_name_list, (void *) &(res->names_size), + rc = bootenv_list_to_vector(ubi_name_list, &size, &(tmp_names)); + res->names_size = size; if (rc != 0) { EBUF_PFI("Cannot create string array: %s", tmp_str); goto err; diff --git a/ubi-utils/src/ubimkvol.c b/ubi-utils/src/ubimkvol.c index 879dcb6..1368671 100644 --- a/ubi-utils/src/ubimkvol.c +++ b/ubi-utils/src/ubimkvol.c @@ -28,6 +28,7 @@ * 1.2 Reworked the user-interface to use argp. * 1.3 Removed argp because we want to use uClibc. * 1.4 Minor cleanups + * 1.5 Use a different libubi */ #include @@ -40,7 +41,7 @@ #include #include -#define PROGRAM_VERSION "1.4" +#define PROGRAM_VERSION "1.5" /* * The variables below are set by command line arguments. @@ -53,6 +54,7 @@ struct args { int alignment; char *name; int nlen; + char node[256]; /* special stuff needed to get additional arguments */ char *arg1; @@ -69,7 +71,7 @@ static struct args myargs = { .nlen = 0, }; -static int param_sanity_check(struct args *args, ubi_lib_t lib); +static int param_sanity_check(struct args *args, libubi_t libubi); static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\t" BUILD_OS" "BUILD_CPU" at "__DATE__" "__TIME__"\n" @@ -177,6 +179,7 @@ parse_opt(int argc, char **argv, struct args *args) "\"%s\"\n", optarg); goto out; } + sprintf(args->node, "/dev/ubi%d", args->devn); break; case 'n': /* --volid= */ args->vol_id = strtoul(optarg, &endp, 0); @@ -224,7 +227,7 @@ parse_opt(int argc, char **argv, struct args *args) return -1; } -static int param_sanity_check(struct args *args, ubi_lib_t lib) +static int param_sanity_check(struct args *args, libubi_t libubi) { int err, len; struct ubi_info ubi; @@ -239,7 +242,7 @@ static int param_sanity_check(struct args *args, ubi_lib_t lib) goto out; } - err = ubi_get_info(lib, &ubi); + err = ubi_get_info(libubi, &ubi); if (err) return -1; @@ -264,7 +267,8 @@ out: int main(int argc, char * const argv[]) { int err; - ubi_lib_t lib; + libubi_t libubi; + struct ubi_mkvol_request req; err = parse_opt(argc, (char **)argv, &myargs); if (err) { @@ -278,21 +282,26 @@ int main(int argc, char * const argv[]) return -1; } - err = ubi_open(&lib); - if (err) { + libubi = libubi_open(); + if (libubi == NULL) { perror("Cannot open libubi"); return -1; } - err = param_sanity_check(&myargs, lib); + err = param_sanity_check(&myargs, libubi); if (err) { perror("Input parameters check"); fprintf(stderr, "Use -h option for help\n"); goto out_libubi; } - err = ubi_mkvol(lib, myargs.devn, myargs.vol_id, myargs.vol_type, - myargs.bytes, myargs.alignment, myargs.name); + req.vol_id = myargs.vol_id; + req.alignment = myargs.alignment; + req.bytes = myargs.bytes; + req.vol_type = myargs.vol_type; + req.name = myargs.name; + + err = ubi_mkvol(libubi, myargs.node, &req); if (err < 0) { perror("Cannot create volume"); fprintf(stderr, " err=%d\n", err); @@ -304,10 +313,10 @@ int main(int argc, char * const argv[]) "dynamic" : "static", name); */ myargs.vol_id = err; - ubi_close(&lib); + libubi_close(libubi); return 0; out_libubi: - ubi_close(&lib); + libubi_close(libubi); return -1; } diff --git a/ubi-utils/src/ubirmvol.c b/ubi-utils/src/ubirmvol.c index f458e8a..f32cbe0 100644 --- a/ubi-utils/src/ubirmvol.c +++ b/ubi-utils/src/ubirmvol.c @@ -25,6 +25,7 @@ * 1.1 Reworked the userinterface to use argp. * 1.2 Removed argp because we want to use uClibc. * 1.3 Minor cleanups + * 1.4 Use a different libubi */ #include @@ -37,7 +38,7 @@ #include #include -#define PROGRAM_VERSION "1.3" +#define PROGRAM_VERSION "1.4" /* * The below variables are set by command line options. @@ -45,6 +46,7 @@ struct args { int devn; int vol_id; + char node[256]; /* special stuff needed to get additional arguments */ char *arg1; @@ -59,7 +61,7 @@ static struct args myargs = { .options = NULL, }; -static int param_sanity_check(struct args *args, ubi_lib_t lib); +static int param_sanity_check(struct args *args, libubi_t libubi); static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\t" BUILD_OS" "BUILD_CPU" at "__DATE__" "__TIME__"\n" @@ -118,6 +120,7 @@ parse_opt(int argc, char **argv, struct args *args) "\"%s\"\n", optarg); goto out; } + sprintf(args->node, "/dev/ubi%d", args->devn); break; case 'n': /* --volid= */ args->vol_id = strtoul(optarg, &endp, 0); @@ -156,7 +159,7 @@ parse_opt(int argc, char **argv, struct args *args) return -1; } -static int param_sanity_check(struct args *args, ubi_lib_t lib) +static int param_sanity_check(struct args *args, libubi_t libubi) { int err; struct ubi_info ubi; @@ -166,7 +169,7 @@ static int param_sanity_check(struct args *args, ubi_lib_t lib) goto out; } - err = ubi_get_info(lib, &ubi); + err = ubi_get_info(libubi, &ubi); if (err) return -1; @@ -185,7 +188,7 @@ out: int main(int argc, char * const argv[]) { int err, old_errno; - ubi_lib_t lib; + libubi_t libubi; err = parse_opt(argc, (char **)argv, &myargs); if (err) @@ -197,20 +200,20 @@ int main(int argc, char * const argv[]) return -1; } - err = ubi_open(&lib); - if (err) { + libubi = libubi_open(); + if (libubi == NULL) { perror("Cannot open libubi"); return -1; } - err = param_sanity_check(&myargs, lib); + err = param_sanity_check(&myargs, libubi); if (err) { perror("Input parameters check"); fprintf(stderr, "Use -h option for help\n"); goto out_libubi; } - err = ubi_rmvol(lib, myargs.devn, myargs.vol_id); + err = ubi_rmvol(libubi, myargs.node, myargs.vol_id); old_errno = errno; if (err < 0) { perror("Cannot remove volume"); @@ -218,9 +221,10 @@ int main(int argc, char * const argv[]) goto out_libubi; } + libubi_close(libubi); return 0; out_libubi: - ubi_close(&lib); + libubi_close(libubi); return -1; } diff --git a/ubi-utils/src/ubiupdatevol.c b/ubi-utils/src/ubiupdatevol.c index c0b4178..5401eb1 100644 --- a/ubi-utils/src/ubiupdatevol.c +++ b/ubi-utils/src/ubiupdatevol.c @@ -25,6 +25,7 @@ * 1.0 Reworked the userinterface to use argp. * 1.1 Removed argp parsing because we want to use uClib. * 1.2 Minor cleanups + * 1.3 Use a different libubi */ #include @@ -36,14 +37,12 @@ #include #include #include -#include #include -#include #include #include -#define PROGRAM_VERSION "1.2" +#define PROGRAM_VERSION "1.3" #define MAXPATH 1024 #define BUFSIZE 128 * 1024 @@ -174,7 +173,7 @@ parse_opt(int argc, char **argv, struct args *args) * some reason nothing is written. The volume is unusable after this. */ static int -ubi_truncate_volume(struct args *args, int64_t bytes) +ubi_truncate_volume(struct args *args, int64_t bytes,libubi_t libubi) { int rc, ofd; char path[MAXPATH]; @@ -188,7 +187,7 @@ ubi_truncate_volume(struct args *args, int64_t bytes) fprintf(stderr, "Cannot open volume %s\n", path); exit(EXIT_FAILURE); } - rc = ioctl(ofd, UBI_IOCVOLUP, &bytes); + rc = ubi_update_start(libubi, ofd, bytes); old_errno = errno; if (rc < 0) { perror("UBI volume update ioctl"); @@ -220,7 +219,7 @@ static ssize_t ubi_write(int fd, const void *buf, size_t count) } static int -ubi_update_volume(struct args *args) +ubi_update_volume(struct args *args, libubi_t libubi) { int rc, ofd; FILE *ifp = NULL; @@ -263,7 +262,7 @@ ubi_update_volume(struct args *args) exit(EXIT_FAILURE); } - rc = ioctl(ofd, UBI_IOCVOLUP, &bytes); + rc = ubi_update_start(libubi, ofd, bytes); old_errno = errno; if (rc < 0) { perror("UBI volume update ioctl"); @@ -304,24 +303,35 @@ int main(int argc, char *argv[]) { int rc; + libubi_t libubi; parse_opt(argc, argv, &myargs); + libubi = libubi_open(); + if (libubi == NULL) { + perror("Cannot open libubi"); + return -1; + } + if (myargs.truncate) { - rc = ubi_truncate_volume(&myargs, 0LL); + rc = ubi_truncate_volume(&myargs, 0LL, libubi); if (rc < 0) - exit(EXIT_FAILURE); - exit(EXIT_SUCCESS); + goto out_libubi; } - if (myargs.broken_update) { - rc = ubi_truncate_volume(&myargs, 1LL); + else if (myargs.broken_update) { + rc = ubi_truncate_volume(&myargs, 1LL, libubi); if (rc < 0) - exit(EXIT_FAILURE); - exit(EXIT_SUCCESS); + goto out_libubi; + } else { + rc = ubi_update_volume(&myargs, libubi); + if (rc < 0) + goto out_libubi; } - rc = ubi_update_volume(&myargs); - if (rc < 0) - exit(EXIT_FAILURE); - exit(EXIT_SUCCESS); + libubi_close(libubi); + return 0; + +out_libubi: + libubi_close(libubi); + return -1; } -- cgit v1.2.3