diff options
Diffstat (limited to 'ubi-utils/src')
-rw-r--r-- | ubi-utils/src/error.c | 240 | ||||
-rw-r--r-- | ubi-utils/src/error.h | 84 | ||||
-rw-r--r-- | ubi-utils/src/libpfiflash.c | 1325 | ||||
-rw-r--r-- | ubi-utils/src/libubimirror.c | 237 | ||||
-rw-r--r-- | ubi-utils/src/pfi2bin.c | 57 | ||||
-rw-r--r-- | ubi-utils/src/ubimirror.c | 213 | ||||
-rw-r--r-- | ubi-utils/src/ubimirror.h | 66 |
7 files changed, 26 insertions, 2196 deletions
diff --git a/ubi-utils/src/error.c b/ubi-utils/src/error.c deleted file mode 100644 index 4aaedad..0000000 --- a/ubi-utils/src/error.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <stdio.h> -#include <stdarg.h> -#include <syslog.h> -#include <stdlib.h> -#include <sys/errno.h> -#include <string.h> -#include "error.h" - -#define MAXLINE 4096 -#define MAXWIDTH 80 - -static FILE *logfp = NULL; - -static void err_doit(int, int, const char *, va_list); - -int -read_procfile(FILE *fp_out, const char *procfile) -{ - FILE *fp; - - if (!fp_out) - return -ENXIO; - - fp = fopen(procfile, "r"); - if (!fp) - return -ENOENT; - - while(!feof(fp)) { - int c = fgetc(fp); - - if (c == EOF) - return 0; - - if (putc(c, fp_out) == EOF) - return -EIO; - - if (ferror(fp)) - return -EIO; - } - return fclose(fp); -} - -void -error_initlog(const char *logfile) -{ - if (!logfile) - return; - - logfp = fopen(logfile, "a+"); - read_procfile(logfp, "/proc/cpuinfo"); -} - -void -info_msg(const char *fmt, ...) -{ - FILE* fpout; - char buf[MAXLINE + 1]; - va_list ap; - int n; - - fpout = stdout; - - va_start(ap, fmt); - vsnprintf(buf, MAXLINE, fmt, ap); - n = strlen(buf); - strcat(buf, "\n"); - - fputs(buf, fpout); - fflush(fpout); - if (fpout != stdout) - fclose(fpout); - - va_end(ap); - return; -} - -void -__err_ret(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(1, LOG_INFO, fmt, ap); - va_end(ap); - return; -} - -void -__err_sys(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(1, LOG_ERR, fmt, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - - -void -__err_msg(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(0, LOG_INFO, fmt, ap); - va_end(ap); - - return; -} - -void -__err_quit(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(0, LOG_ERR, fmt, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - -void -__err_dump(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(1, LOG_ERR, fmt, ap); - va_end(ap); - abort(); /* dump core and terminate */ - exit(EXIT_FAILURE); /* shouldn't get here */ -} - -/** - * If a logfile is used we must not print on stderr and stdout - * anymore. Since pfilfash might be used in a server context, it is - * even dangerous to write to those descriptors. - */ -static void -err_doit(int errnoflag, int level __attribute__((unused)), - const char *fmt, va_list ap) -{ - FILE* fpout; - int errno_save, n; - char buf[MAXLINE + 1]; - fpout = stderr; - - errno_save = errno; /* value caller might want printed */ - - vsnprintf(buf, MAXLINE, fmt, ap); /* safe */ - - n = strlen(buf); - - if (errnoflag) - snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); - strcat(buf, "\n"); - - if (logfp) { - fputs(buf, logfp); - fflush(logfp); - return; /* exit when logging completes */ - } - - if (fpout == stderr) { - /* perform line wrap when outputting to stderr */ - int word_len, post_len, chars; - char *buf_ptr; - const char *frmt = "%*s%n %n"; - - chars = 0; - buf_ptr = buf; - while (sscanf(buf_ptr, frmt, &word_len, &post_len) != EOF) { - int i; - char word[word_len + 1]; - char post[post_len + 1]; - - strncpy(word, buf_ptr, word_len); - word[word_len] = '\0'; - buf_ptr += word_len; - post_len -= word_len; - - if (chars + word_len > MAXWIDTH) { - fputc('\n', fpout); - chars = 0; - } - fputs(word, fpout); - chars += word_len; - - if (post_len > 0) { - strncpy(post, buf_ptr, post_len); - post[post_len] = '\0'; - buf_ptr += post_len; - } - for (i = 0; i < post_len; i++) { - int inc = 1, chars_new; - - if (post[i] == '\t') - inc = 8; - if (post[i] == '\n') { - inc = 0; - chars_new = 0; - } else - chars_new = chars + inc; - - if (chars_new > MAXWIDTH) { - fputc('\n', fpout); - chars_new = inc; - } - fputc(post[i], fpout); - chars = chars_new; - } - } - } - else - fputs(buf, fpout); - fflush(fpout); - if (fpout != stderr) - fclose(fpout); - - return; -} diff --git a/ubi-utils/src/error.h b/ubi-utils/src/error.h deleted file mode 100644 index 05d8078..0000000 --- a/ubi-utils/src/error.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef __ERROR_H__ -#define __ERROR_H__ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <stdio.h> - -void error_initlog(const char *logfile); -int read_procfile(FILE *fp_out, const char *procfile); - -void __err_ret(const char *fmt, ...); -void __err_sys(const char *fmt, ...); -void __err_msg(const char *fmt, ...); -void __err_quit(const char *fmt, ...); -void __err_dump(const char *fmt, ...); - -void info_msg(const char *fmt, ...); - -#ifdef DEBUG -#define __loc_msg(str) do { \ - __err_msg("[%s. FILE: %s FUNC: %s LINE: %d]\n", \ - str, __FILE__, __FUNCTION__, __LINE__); \ -} while (0) -#else -#define __loc_msg(str) -#endif - - -#define err_dump(fmt, ...) do { \ - __loc_msg("ErrDump"); \ - __err_dump(fmt, ##__VA_ARGS__); \ -} while (0) - -#define err_quit(fmt, ...) do { \ - __loc_msg("ErrQuit"); \ - __err_quit(fmt, ##__VA_ARGS__); \ -} while (0) - - -#define err_ret(fmt, ...) do { \ - __loc_msg("ErrRet"); \ - __err_ret(fmt, ##__VA_ARGS__); \ -} while (0) - -#define err_sys(fmt, ...) do { \ - __loc_msg("ErrSys"); \ - __err_sys(fmt, ##__VA_ARGS__); \ -} while (0) - -#define err_msg(fmt, ...) do { \ - __loc_msg("ErrMsg"); \ - __err_msg(fmt, ##__VA_ARGS__); \ -} while (0) - -#define log_msg(fmt, ...) do { \ - /* __loc_msg("LogMsg"); */ \ - __err_msg(fmt, ##__VA_ARGS__); \ -} while (0) - -#ifdef DEBUG -#define dbg_msg(fmt, ...) do { \ - __loc_msg("DbgMsg"); \ - __err_msg(fmt, ##__VA_ARGS__); \ -} while (0) -#else -#define dbg_msg(fmt, ...) do {} while (0) -#endif - -#endif /* __ERROR_H__ */ diff --git a/ubi-utils/src/libpfiflash.c b/ubi-utils/src/libpfiflash.c deleted file mode 100644 index 7e3d3b3..0000000 --- a/ubi-utils/src/libpfiflash.c +++ /dev/null @@ -1,1325 +0,0 @@ -/* - * Copyright International Business Machines Corp., 2006, 2007 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Authors: Oliver Lohmann <oliloh@de.ibm.com> - * Drake Dowsett <dowsett@de.ibm.com> - * Contact: Andreas Arnez <anrez@de.ibm.com> - */ - -/* TODO Compare data before writing it. This implies that the volume - * parameters are compared first: size, alignment, name, type, ..., - * this is the same, compare the data. Volume deletion is deffered - * until the difference has been found out. - */ - -#include <stdio.h> -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#define __USE_GNU -#include <string.h> -#include <stdlib.h> -#include <limits.h> -#include <sys/ioctl.h> - -#include <libubi.h> -#include <pfiflash.h> - -#include <mtd/ubi-user.h> /* FIXME Is this ok here? */ -#include <mtd/mtd-user.h> - -#include "pfiflash_error.h" -#include "ubimirror.h" -#include "error.h" -#include "reader.h" -#include "example_ubi.h" -#include "bootenv.h" - -/* ubi-header.h and crc32.h needed for CRC checking */ -#include <mtd/ubi-header.h> /* FIXME Is this ok here? */ -#include "crc32.h" - -#define ubi_unused __attribute__((unused)) - -#define COMPARE_BUFFER_SIZE 2048 - -#define DEFAULT_DEV_PATTERN "/dev/ubi%d" -#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d" - -static const char copyright [] ubi_unused = - "Copyright International Business Machines Corp., 2006, 2007"; - -/* simply clear buffer, then write into front of it */ -#define EBUF(fmt...) \ - snprintf(err_buf, err_buf_size, fmt); - -/* make a history of buffer and then prepend something in front */ -#define EBUF_PREPEND(fmt) \ - do { \ - int EBUF_HISTORY_LENGTH = strlen(err_buf); \ - char EBUF_HISTORY[EBUF_HISTORY_LENGTH + 1]; \ - strncpy(EBUF_HISTORY, err_buf, EBUF_HISTORY_LENGTH + 1);\ - EBUF(fmt ": %s", EBUF_HISTORY); \ - } while (0) - -/* An array of PDD function pointers indexed by the algorithm. */ -static pdd_func_t pdd_funcs[PDD_HANDLING_NUM] = - { - &bootenv_pdd_keep, - &bootenv_pdd_merge, - &bootenv_pdd_overwrite - }; - -typedef enum ubi_update_process_t { - UBI_REMOVE = 0, - UBI_WRITE, - UBI_COMPARE, -} ubi_update_process_t; - - -/** - * skip_raw_volumes - reads data from pfi to advance fp past raw block - * @pfi: fp to pfi data - * @pfi_raws: header information - * - * Error handling): - * when early EOF in pfi data - * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err - * when file I/O error - * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err - **/ -static int -skip_raw_volumes(FILE* pfi, list_t pfi_raws, - char* err_buf, size_t err_buf_size) -{ - int rc; - void *i; - list_t ptr; - - if (is_empty(pfi_raws)) - return 0; - - rc = 0; - foreach(i, ptr, pfi_raws) { - size_t j; - pfi_raw_t raw; - - raw = (pfi_raw_t)i; - for(j = 0; j < raw->data_size; j++) { - int c; - - c = fgetc(pfi); - if (c == EOF) - rc = -PFIFLASH_ERR_EOF; - else if (ferror(pfi)) - rc = -PFIFLASH_ERR_FIO; - - if (rc != 0) - goto err; - } - } - - err: - EBUF(PFIFLASH_ERRSTR[-rc]); - return rc; -} - - -/** - * my_ubi_mkvol - wraps the ubi_mkvol functions and impl. bootenv update hook - * @devno: UBI device number. - * @s: Current seqnum. - * @u: Information about the UBI volume from the PFI. - * - * Error handling: - * when UBI system couldn't be opened - * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err - * when UBI system couldn't create a volume - * - returns -PFIFLASH_ERR_UBI_MKVOL, err_buf matches text to err - **/ -static int -my_ubi_mkvol(int devno, int s, pfi_ubi_t u, - char *err_buf, size_t err_buf_size) -{ - int rc, type; - char path[PATH_MAX]; - libubi_t ulib; - struct ubi_mkvol_request req; - - rc = 0; - ulib = NULL; - - log_msg("[ ubimkvol id=%d, size=%d, data_size=%d, type=%d, " - "alig=%d, nlen=%d, name=%s", - u->ids[s], u->size, u->data_size, u->type, u->alignment, - strnlen(u->names[s], PFI_UBI_VOL_NAME_LEN), u->names[s]); - - ulib = libubi_open(); - if (ulib == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - switch (u->type) { - case pfi_ubi_static: - type = UBI_STATIC_VOLUME; break; - case pfi_ubi_dynamic: - default: - type = UBI_DYNAMIC_VOLUME; - } - - snprintf(path, PATH_MAX, DEFAULT_DEV_PATTERN, devno); - - req.vol_id = u->ids[s]; - req.alignment = u->alignment; - req.bytes = u->size; - req.vol_type = type; - req.name = u->names[s]; - - rc = ubi_mkvol(ulib, path, &req); - if (rc != 0) { - rc = -PFIFLASH_ERR_UBI_MKVOL; - EBUF(PFIFLASH_ERRSTR[-rc], u->ids[s]); - goto err; - } - - err: - if (ulib != NULL) - libubi_close(ulib); - - return rc; -} - - -/** - * my_ubi_rmvol - a wrapper around the UBI library function ubi_rmvol - * @devno UBI device number - * @id UBI volume id to remove - * - * If the volume does not exist, the function will return success. - * - * Error handling: - * when UBI system couldn't be opened - * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err - * when UBI system couldn't update (truncate) a volume - * - returns -PFIFLASH_ERR_UBI_VOL_UPDATE, err_buf matches text to err - * when UBI system couldn't remove a volume - * - returns -PFIFLASH_ERR_UBI_RMVOL, err_buf matches text to err - **/ -static int -my_ubi_rmvol(int devno, uint32_t id, - char *err_buf, size_t err_buf_size) -{ - int rc, fd; - char path[PATH_MAX]; - libubi_t ulib; - - rc = 0; - ulib = NULL; - - log_msg("[ ubirmvol id=%d", id); - - ulib = libubi_open(); - if (ulib == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); - - /* truncate whether it exist or not */ - fd = open(path, O_RDWR); - if (fd < 0) { - libubi_close(ulib); - return 0; /* not existent, return 0 */ - } - - rc = ubi_update_start(ulib, fd, 0); - close(fd); - if (rc < 0) { - rc = -PFIFLASH_ERR_UBI_VOL_UPDATE; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; /* if EBUSY than empty device, continue */ - } - - snprintf(path, PATH_MAX, DEFAULT_DEV_PATTERN, devno); - - rc = ubi_rmvol(ulib, path, id); - if (rc != 0) { -#ifdef DEBUG - int rc_old = rc; - dbg_msg("Remove UBI volume %d returned with error: %d " - "errno=%d", id, rc_old, errno); -#endif - - rc = -PFIFLASH_ERR_UBI_RMVOL; - EBUF(PFIFLASH_ERRSTR[-rc], id); - - /* TODO Define a ubi_rmvol return value which says - * sth like EUBI_NOSUCHDEV. In this case, a failed - * operation is acceptable. Everything else has to be - * classified as real error. But talk to Andreas Arnez - * before defining something odd... - */ - /* if ((errno == EINVAL) || (errno == ENODEV)) - return 0; */ /* currently it is EINVAL or ENODEV */ - - goto err; - } - - err: - if (ulib != NULL) - libubi_close(ulib); - - return rc; -} - - -/** - * read_bootenv_volume - reads the current bootenv data from id into be_old - * @devno UBI device number - * @id UBI volume id to remove - * @bootenv_old to hold old boot_env data - * - * Error handling: - * when UBI system couldn't be opened - * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err - * when UBI system couldn't open a volume to read - * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err - * when couldn't read bootenv data - * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err - **/ -static int -read_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, - char *err_buf, size_t err_buf_size) -{ - int rc; - FILE* fp_in; - char path[PATH_MAX]; - libubi_t ulib; - - rc = 0; - fp_in = NULL; - ulib = NULL; - - ulib = libubi_open(); - if (ulib == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); - - fp_in = fopen(path, "r"); - if (!fp_in) { - rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; - } - - log_msg("[ reading old bootenvs ..."); - - /* Save old bootenvs for reference */ - rc = bootenv_read(fp_in, bootenv_old, BOOTENV_MAXSIZE); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_READ; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - err: - if (fp_in) - fclose(fp_in); - if (ulib) - libubi_close(ulib); - - return rc; -} - - -/** - * write_bootenv_volume - writes data from PFI file int to bootenv UBI volume - * @devno UBI device number - * @id UBI volume id - * @bootend_old old PDD data from machine - * @pdd_f function to handle PDD with - * @fp_in new pdd data contained in PFI - * @fp_in_size data size of new pdd data in PFI - * @pfi_crc crc value from PFI header - * - * Error handling: - * when UBI system couldn't be opened - * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err - * when bootenv can't be created - * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err - * when bootenv can't be read - * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err - * when PDD handling function returns and error - * - passes rc and err_buf data - * when CRC check fails - * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err - * when bootenv can't be resized - * - returns -PFIFLASH_ERR_BOOTENV_SIZE, err_buf matches text to err - * when UBI system couldn't open a volume - * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err - * when couldn't write bootenv data - * - returns -PFIFLASH_ERR_BOOTENV_WRITE, err_buf matches text to err - **/ -static int -write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, - pdd_func_t pdd_f, FILE* fp_in, size_t fp_in_size, - uint32_t pfi_crc, - char *err_buf, size_t err_buf_size) -{ - int rc, warnings, fd_out; - uint32_t crc; - char path[PATH_MAX]; - size_t update_size; - FILE *fp_out; - bootenv_t bootenv_new, bootenv_res; - libubi_t ulib; - - rc = 0; - warnings = 0; - crc = 0; - update_size = 0; - fp_out = NULL; - bootenv_new = NULL; - bootenv_res = NULL; - ulib = NULL; - - log_msg("[ ubiupdatevol bootenv id=%d, fp_in=%p", id, fp_in); - - /* Workflow: - * 1. Apply PDD operation and get the size of the returning - * bootenv_res section. Without the correct size it wouldn't - * be possible to call UBI update vol. - * 2. Call UBI update vol - * 3. Get FILE* to vol dev - * 4. Write to FILE* - */ - - ulib = libubi_open(); - if (ulib == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - rc = bootenv_create(&bootenv_new); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_CREATE; - EBUF(PFIFLASH_ERRSTR[-rc], " 'new'"); - goto err; - } - - rc = bootenv_create(&bootenv_res); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_CREATE; - EBUF(PFIFLASH_ERRSTR[-rc], " 'res'"); - goto err; - } - - rc = bootenv_read_crc(fp_in, bootenv_new, fp_in_size, &crc); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_READ; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } else if (crc != pfi_crc) { - rc = -PFIFLASH_ERR_CRC_CHECK; - EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc); - goto err; - } - - rc = pdd_f(bootenv_old, bootenv_new, &bootenv_res, &warnings, - err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("handling PDD"); - goto err; - } - else if (warnings) - /* TODO do something with warnings */ - dbg_msg("A warning in the PDD operation occured: %d", - warnings); - - rc = bootenv_size(bootenv_res, &update_size); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_SIZE; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); - - fd_out = open(path, O_RDWR); - if (fd_out < 0) { - rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; - } - fp_out = fdopen(fd_out, "r+"); - if (!fp_out) { - rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; - } - rc = ubi_update_start(ulib, fd_out, update_size); - if (rc < 0) { - rc = -PFIFLASH_ERR_UBI_VOL_UPDATE; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; - } - - rc = bootenv_write(fp_out, bootenv_res); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_WRITE; - EBUF(PFIFLASH_ERRSTR[-rc], devno, id); - goto err; - } - - err: - if (ulib != NULL) - libubi_close(ulib); - if (bootenv_new != NULL) - bootenv_destroy(&bootenv_new); - if (bootenv_res != NULL) - bootenv_destroy(&bootenv_res); - if (fp_out) - fclose(fp_out); - - return rc; -} - - -/** - * write_normal_volume - writes data from PFI file int to regular UBI volume - * @devno UBI device number - * @id UBI volume id - * @update_size size of data stream - * @fp_in PFI data file pointer - * @pfi_crc CRC data from PFI header - * - * Error handling: - * when UBI system couldn't be opened - * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err - * when UBI system couldn't open a volume - * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err - * when unexpected EOF is encountered - * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err - * when file I/O error - * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err - * when CRC check fails - * - retruns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err - **/ -static int -write_normal_volume(int devno, uint32_t id, size_t update_size, FILE* fp_in, - uint32_t pfi_crc, - char *err_buf, size_t err_buf_size) -{ - int rc, fd_out; - uint32_t crc, crc32_table[256]; - char path[PATH_MAX]; - size_t bytes_left; - FILE* fp_out; - libubi_t ulib; - - rc = 0; - crc = UBI_CRC32_INIT; - bytes_left = update_size; - fp_out = NULL; - ulib = NULL; - - log_msg("[ ubiupdatevol id=%d, update_size=%d fp_in=%p", - id, update_size, fp_in); - - ulib = libubi_open(); - if (ulib == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); - - fd_out = open(path, O_RDWR); - if (fd_out < 0) { - rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; - } - fp_out = fdopen(fd_out, "r+"); - if (!fp_out) { - rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; - } - rc = ubi_update_start(ulib, fd_out, update_size); - if (rc < 0) { - rc = -PFIFLASH_ERR_UBI_VOL_UPDATE; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; - } - - init_crc32_table(crc32_table); - while (bytes_left) { - char buf[1024]; - size_t to_rw = sizeof buf > bytes_left ? - bytes_left : sizeof buf; - if (fread(buf, 1, to_rw, fp_in) != to_rw) { - rc = -PFIFLASH_ERR_EOF; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - crc = clc_crc32(crc32_table, crc, buf, to_rw); - if (fwrite(buf, 1, to_rw, fp_out) != to_rw) { - rc = -PFIFLASH_ERR_FIO; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - bytes_left -= to_rw; - } - - if (crc != pfi_crc) { - rc = -PFIFLASH_ERR_CRC_CHECK; - EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc); - goto err; - } - - err: - if (fp_out) - fclose(fp_out); - if (ulib) - libubi_close(ulib); - - return rc; -} - -static int compare_bootenv(FILE *fp_pfi, FILE **fp_flash, uint32_t ids_size, - uint32_t data_size, pdd_func_t pdd_f, char *err_buf, - size_t err_buf_size) -{ - int rc, warnings = 0; - unsigned int i; - bootenv_t bootenv_pfi, bootenv_res = NULL, bootenv_flash = NULL; - - rc = bootenv_create(&bootenv_pfi); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_CREATE; - goto err; - } - - rc = bootenv_create(&bootenv_res); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_CREATE; - goto err; - } - - rc = bootenv_read(fp_pfi, bootenv_pfi, data_size); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_READ; - goto err; - } - - for (i = 0; i < ids_size; i++) { - rc = bootenv_create(&bootenv_flash); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_CREATE; - goto err; - } - - rc = bootenv_read(fp_flash[i], bootenv_flash, BOOTENV_MAXSIZE); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_READ; - goto err; - } - - rc = pdd_f(bootenv_flash, bootenv_pfi, &bootenv_res, - &warnings, err_buf, err_buf_size); - if (rc != 0) { - rc = -PFIFLASH_ERR_PDD_UNKNOWN; - goto err; - } - - rc = bootenv_compare(bootenv_flash, bootenv_res); - if (rc > 0) { - rc = -PFIFLASH_CMP_DIFF; - goto err; - } else if (rc < 0) { - rc = -PFIFLASH_ERR_COMPARE; - goto err; - } - - bootenv_destroy(&bootenv_flash); - bootenv_flash = NULL; - } - -err: - if (bootenv_pfi) - bootenv_destroy(&bootenv_pfi); - if (bootenv_res) - bootenv_destroy(&bootenv_res); - if (bootenv_flash) - bootenv_destroy(&bootenv_flash); - - return rc; -} - -static int compare_data(FILE *fp_pfi, FILE **fp_flash, uint32_t ids_size, - uint32_t bytes_left) -{ - unsigned int i; - size_t read_bytes, rc = 0; - char buf_pfi[COMPARE_BUFFER_SIZE]; - char *buf_flash[ids_size]; - - for (i = 0; i < ids_size; i++) { - buf_flash[i] = malloc(COMPARE_BUFFER_SIZE); - if (!buf_flash[i]) - return -PFIFLASH_ERR_COMPARE; - } - - while (bytes_left) { - if (bytes_left > COMPARE_BUFFER_SIZE) - read_bytes = COMPARE_BUFFER_SIZE; - else - read_bytes = bytes_left; - - rc = fread(buf_pfi, 1, read_bytes, fp_pfi); - if (rc != read_bytes) { - rc = -PFIFLASH_ERR_COMPARE; - goto err; - } - - for (i = 0; i < ids_size; i++) { - rc = fread(buf_flash[i], 1, read_bytes, fp_flash[i]); - if (rc != read_bytes) { - rc = -PFIFLASH_CMP_DIFF; - goto err; - } - - rc = memcmp(buf_pfi, buf_flash[i], read_bytes); - if (rc != 0) { - rc = -PFIFLASH_CMP_DIFF; - goto err; - } - } - - bytes_left -= read_bytes; - } - -err: - for (i = 0; i < ids_size; i++) - free(buf_flash[i]); - - return rc; -} - -static int compare_volumes(int devno, pfi_ubi_t u, FILE *fp_pfi, - pdd_func_t pdd_f, char *err_buf, size_t err_buf_size) -{ - int rc, is_bootenv = 0; - unsigned int i; - char path[PATH_MAX]; - libubi_t ulib = NULL; - FILE *fp_flash[u->ids_size]; - - ulib = libubi_open(); - if (ulib == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - goto err; - } - - for (i = 0; i < u->ids_size; i++) { - if (u->ids[i] == EXAMPLE_BOOTENV_VOL_ID_1 || - u->ids[i] == EXAMPLE_BOOTENV_VOL_ID_2) - is_bootenv = 1; - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, u->ids[i]); - - fp_flash[i] = fopen(path, "r"); - if (fp_flash[i] == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - goto err; - } - } - - if (is_bootenv) - rc = compare_bootenv(fp_pfi, fp_flash, u->ids_size, - u->data_size, pdd_f, err_buf, err_buf_size); - else - rc = compare_data(fp_pfi, fp_flash, u->ids_size, u->data_size); - -err: - if (rc < 0) - EBUF(PFIFLASH_ERRSTR[-rc]); - - for (i = 0; i < u->ids_size; i++) - fclose(fp_flash[i]); - if (ulib) - libubi_close(ulib); - - return rc; -} - -static int -erase_mtd_region(FILE* file_p, int start, int length) -{ - int rc, fd; - erase_info_t erase; - mtd_info_t mtdinfo; - loff_t offset = start; - loff_t end = offset + length; - - fd = fileno(file_p); - if (fd < 0) - return -PFIFLASH_ERR_MTD_ERASE; - - rc = ioctl(fd, MEMGETINFO, &mtdinfo); - if (rc) - return -PFIFLASH_ERR_MTD_ERASE; - - /* check for bad blocks in case of NAND flash */ - if (mtdinfo.type == MTD_NANDFLASH) { - while (offset < end) { - rc = ioctl(fd, MEMGETBADBLOCK, &offset); - if (rc > 0) { - return -PFIFLASH_ERR_MTD_ERASE; - } - - offset += mtdinfo.erasesize; - } - } - - erase.start = start; - erase.length = length; - - rc = ioctl(fd, MEMERASE, &erase); - if (rc) { - return -PFIFLASH_ERR_MTD_ERASE; - } - - return rc; -} - -/** - * process_raw_volumes - writes the raw sections of the PFI data - * @pfi PFI data file pointer - * @pfi_raws list of PFI raw headers - * @rawdev device to use to write raw data - * - * Error handling: - * when early EOF in PFI data - * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err - * when file I/O error - * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err - * when CRC check fails - * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err - * when opening MTD device fails - * - reutrns -PFIFLASH_ERR_MTD_OPEN, err_buf matches text to err - * when closing MTD device fails - * - returns -PFIFLASH_ERR_MTD_CLOSE, err_buf matches text to err - **/ -static int -process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev, - char* err_buf, size_t err_buf_size) -{ - int rc; - char *pfi_data; - void *i; - uint32_t crc, crc32_table[256]; - size_t j, k; - FILE* mtd = NULL; - list_t ptr; - - if (is_empty(pfi_raws)) - return 0; - - if (rawdev == NULL) - return 0; - - rc = 0; - - pfi_data = NULL; - - log_msg("[ rawupdate dev=%s", rawdev); - - crc = UBI_CRC32_INIT; - init_crc32_table(crc32_table); - - /* most likely only one element in list, but just in case */ - foreach(i, ptr, pfi_raws) { - pfi_raw_t r = (pfi_raw_t)i; - - /* read in pfi data */ - if (pfi_data != NULL) - free(pfi_data); - pfi_data = malloc(r->data_size * sizeof(char)); - for (j = 0; j < r->data_size; j++) { - int c = fgetc(pfi); - if (c == EOF) { - rc = -PFIFLASH_ERR_EOF; - EBUF(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++) { - 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); - if (c == EOF) { - fclose(mtd); - rc = -PFIFLASH_ERR_EOF; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - if ((char)c != pfi_data[k]) { - fclose(mtd); - rc = -1; - goto err; - } - } - } - rc = fclose(mtd); - mtd = NULL; - if (rc != 0) { - rc = -PFIFLASH_ERR_MTD_CLOSE; - EBUF(PFIFLASH_ERRSTR[-rc], rawdev); - goto err; - } - } - - err: - if (mtd != NULL) - fclose(mtd); - if (pfi_data != NULL) - free(pfi_data); - return rc; -} - - -/** - * erase_unmapped_ubi_volumes - skip volumes provided by PFI file, clear rest - * @devno UBI device number - * @pfi_ubis list of UBI header data - * - * Error handling: - * when UBI id is out of bounds - * - returns -PFIFLASH_ERR_UBI_VID_OOB, err_buf matches text to err - * when UBI volume can't be removed - * - passes rc, prepends err_buf with contextual aid - **/ -static int -erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis, - char *err_buf, size_t err_buf_size) -{ - int rc; - uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES]; - size_t i; - list_t ptr; - pfi_ubi_t u; - - rc = 0; - - for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) - ubi_volumes[i] = 1; - - foreach(u, ptr, pfi_ubis) { - /* iterate over each vol_id */ - for(i = 0; i < u->ids_size; i++) { - if (u->ids[i] >= PFI_UBI_MAX_VOLUMES) { - rc = -PFIFLASH_ERR_UBI_VID_OOB; - EBUF(PFIFLASH_ERRSTR[-rc], u->ids[i]); - goto err; - } - /* remove from removal list */ - ubi_volumes[u->ids[i]] = 0; - } - } - - for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) { - if (ubi_volumes[i]) { - rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("remove volume failed"); - goto err; - } - } - } - - err: - return rc; -} - - -/** - * process_ubi_volumes - delegate tasks regarding UBI volumes - * @pfi PFI data file pointer - * @seqnum sequence number - * @pfi_ubis list of UBI header data - * @bootenv_old storage for current system PDD - * @pdd_f function to handle PDD - * @ubi_update_process whether reading or writing - * - * Error handling: - * when and unknown ubi_update_process is given - * - returns -PFIFLASH_ERR_UBI_UNKNOWN, err_buf matches text to err - * otherwise - * - passes rc and err_buf - **/ -static int -process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis, - bootenv_t bootenv_old, pdd_func_t pdd_f, - ubi_update_process_t ubi_update_process, - char *err_buf, size_t err_buf_size) -{ - int rc; - pfi_ubi_t u; - list_t ptr; - - rc = 0; - - foreach(u, ptr, pfi_ubis) { - int s = seqnum; - - if (s > ((int)u->ids_size - 1)) - s = 0; /* per default use the first */ - u->curr_seqnum = s; - - switch (ubi_update_process) { - case UBI_REMOVE: - /* TODO are all these "EXAMPLE" vars okay? */ - if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || - (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { - rc = read_bootenv_volume(EXAMPLE_UBI_DEVICE, - u->ids[s], bootenv_old, - err_buf, err_buf_size); - /* it's okay if there is no bootenv - * we're going to write one */ - if ((rc == -PFIFLASH_ERR_UBI_VOL_FOPEN) || - (rc == -PFIFLASH_ERR_BOOTENV_READ)) - rc = 0; - if (rc != 0) - goto err; - } - - rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE, u->ids[s], - err_buf, err_buf_size); - if (rc != 0) - goto err; - - break; - case UBI_WRITE: - rc = my_ubi_mkvol(EXAMPLE_UBI_DEVICE, s, u, - err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("creating volume"); - goto err; - } - - if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || - (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { - rc = write_bootenv_volume(EXAMPLE_UBI_DEVICE, - u->ids[s], - bootenv_old, pdd_f, - pfi, - u->data_size, - u->crc, - err_buf, - err_buf_size); - if (rc != 0) - EBUF_PREPEND("bootenv volume"); - } else { - rc = write_normal_volume(EXAMPLE_UBI_DEVICE, - u->ids[s], - u->data_size, pfi, - u->crc, - err_buf, - err_buf_size); - if (rc != 0) - EBUF_PREPEND("normal volume"); - } - if (rc != 0) - goto err; - - break; - case UBI_COMPARE: - rc = compare_volumes(EXAMPLE_UBI_DEVICE, u, pfi, pdd_f, - err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("compare volume"); - goto err; - } - - break; - default: - rc = -PFIFLASH_ERR_UBI_UNKNOWN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - } - - err: - return rc; -} - - -/** - * mirror_ubi_volumes - mirror redundant pairs of volumes - * @devno UBI device number - * @pfi_ubis list of PFI header data - * - * Error handling: - * when UBI system couldn't be opened - * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err - **/ -static int -mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis, - char *err_buf, size_t err_buf_size) -{ - int rc; - uint32_t j; - list_t ptr; - pfi_ubi_t i; - libubi_t ulib; - - rc = 0; - ulib = NULL; - - log_msg("[ mirror ..."); - - ulib = libubi_open(); - if (ulib == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - /** - * Execute all mirror operations on redundant groups. - * Create a volume within a redundant group if it does - * not exist already (this is a precondition of - * ubimirror). - */ - foreach(i, ptr, pfi_ubis) { - for (j = 0; j < i->ids_size; j++) { - /* skip self-match */ - if (i->ids[j] == i->ids[i->curr_seqnum]) - continue; - - rc = my_ubi_rmvol(devno, i->ids[j], - err_buf, err_buf_size); - if (rc != 0) - goto err; - - rc = my_ubi_mkvol(devno, j, i, - err_buf, err_buf_size); - if (rc != 0) - goto err; - } - } - - foreach(i, ptr, pfi_ubis) { - rc = ubimirror(devno, i->curr_seqnum, i->ids, i->ids_size, - err_buf, err_buf_size); - if (rc != 0) - goto err; - } - - - err: - if (ulib != NULL) - libubi_close(ulib); - - return rc; -} - - -/** - * pfiflash_with_options - exposed func to flash memory with a PFI file - * @pfi PFI data file pointer - * @complete flag to erase unmapped volumes - * @seqnum sequence number - * @compare flag to compare - * @pdd_handling method to handle pdd (keep, merge, overwrite...) - * - * Error handling: - * when bootenv can't be created - * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err - * when PFI headers can't be read, or - * when fail to skip raw sections, or - * when error occurs while processing raw volumes, or - * when fail to erase unmapped UBI vols, or - * when error occurs while processing UBI volumes, or - * when error occurs while mirroring UBI volumes - * - passes rc, prepends err_buf with contextual aid - **/ -int -pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare, - pdd_handling_t pdd_handling, const char* rawdev, - char *err_buf, size_t err_buf_size) -{ - int rc; - bootenv_t bootenv; - pdd_func_t pdd_f; - - if (pfi == NULL) - return -EINVAL; - - rc = 0; - pdd_f = NULL; - - /* If the user didnt specify a seqnum we start per default - * with the index 0 */ - int curr_seqnum = seqnum < 0 ? 0 : seqnum; - - list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */ - list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */ - - rc = bootenv_create(&bootenv); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_CREATE; - EBUF(PFIFLASH_ERRSTR[-rc], ""); - goto err; - } - - rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi, err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("reading PFI header"); - goto err; - } - - if (rawdev == NULL || compare) - rc = skip_raw_volumes(pfi, pfi_raws, err_buf, err_buf_size); - else - rc = process_raw_volumes(pfi, pfi_raws, rawdev, err_buf, - err_buf_size); - if (rc != 0) { - EBUF_PREPEND("handling raw section"); - goto err; - } - - if (complete && !compare) { - rc = erase_unmapped_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, - err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("deleting unmapped UBI volumes"); - goto err; - } - } - - if (((int)pdd_handling >= 0) && - (pdd_handling < PDD_HANDLING_NUM)) - pdd_f = pdd_funcs[pdd_handling]; - else { - rc = -PFIFLASH_ERR_PDD_UNKNOWN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - if (!compare) { - rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, - pdd_f, UBI_REMOVE, err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("removing UBI volumes"); - goto err; - } - - rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, - pdd_f, UBI_WRITE, err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("writing UBI volumes"); - goto err; - } - - if (seqnum < 0) { /* mirror redundant pairs */ - rc = mirror_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, - err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("mirroring UBI volumes"); - goto err; - } - } - } else { - /* only compare volumes, don't alter the content */ - rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, - pdd_f, UBI_COMPARE, err_buf, err_buf_size); - - if (rc == -PFIFLASH_CMP_DIFF) - /* update is necessary, return positive value */ - rc = 1; - - if (rc < 0) { - EBUF_PREPEND("comparing UBI volumes"); - goto err; - } - } - - err: - pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws); - pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, pfi_ubis); - bootenv_destroy(&bootenv); - return rc; -} - - -/** - * pfiflash - passes to pfiflash_with_options - * @pfi PFI data file pointer - * @complete flag to erase unmapped volumes - * @seqnum sequence number - * @pdd_handling method to handle pdd (keep, merge, overwrite...) - **/ -int -pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, - char *err_buf, size_t err_buf_size) -{ - return pfiflash_with_options(pfi, complete, seqnum, 0, pdd_handling, - NULL, err_buf, err_buf_size); -} diff --git a/ubi-utils/src/libubimirror.c b/ubi-utils/src/libubimirror.c deleted file mode 100644 index d06770e..0000000 --- a/ubi-utils/src/libubimirror.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <memory.h> -#include <limits.h> -#include <fcntl.h> - -#include <libubi.h> -#include "ubimirror.h" - -#define COMPARE_BUF_SIZE (128 * 1024) - -#define DEFAULT_DEV_PATTERN "/dev/ubi%d" -#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d" - -#define EBUF(fmt...) do { \ - snprintf(err_buf, err_buf_size, fmt); \ -} while (0) - -enum { - compare_error = -1, - seek_error = -2, - write_error = -3, - read_error = -4, - update_error = -5, - ubi_error = -6, - open_error = -7, - close_error = -8, - compare_equal = 0, - compare_different = 1 -}; - -/* - * Read len number of bytes from fd. - * Return 0 on EOF, -1 on error. - */ -static ssize_t fill_buffer(int fd, unsigned char *buf, ssize_t len) -{ - ssize_t got, have = 0; - - do { - got = read(fd, buf + have, len - have); - if (got == -1 && errno != EINTR) - return -1; - have += got; - } while (got > 0 && have < len); - return have; -} - -/* - * Write len number of bytes to fd. - * Return bytes written (>= 0), -1 on error. - */ -static ssize_t flush_buffer(int fd, unsigned char *buf, ssize_t len) -{ - ssize_t done, have = 0; - - do { - done = write(fd, buf + have, len - have); - if (done == -1 && errno != EINTR) - return -1; - have += done; - } while (done > 0 && have < len); - return have; -} - -/* - * Compare two files. Return 0, 1, or -1, depending on whether the - * files are equal, different, or an error occured. - * Return compare-different when target volume can not be read. Might be - * an interrupted volume update and then the target device returns -EIO but - * can be updated. - * - * fd_a is source - * fd_b is destination - */ -static int compare_files(int fd_a, int fd_b) -{ - unsigned char buf_a[COMPARE_BUF_SIZE], buf_b[COMPARE_BUF_SIZE]; - ssize_t len_a, len_b; - int rc; - - for (;;) { - len_a = fill_buffer(fd_a, buf_a, sizeof(buf_a)); - if (len_a == -1) { - rc = compare_error; - break; - } - len_b = fill_buffer(fd_b, buf_b, sizeof(buf_b)); - if (len_b == -1) { - rc = compare_different; - break; - } - if (len_a != len_b) { - rc = compare_different; - break; - } - if (len_a == 0) { /* Size on both files equal and EOF */ - rc = compare_equal; - break; - } - if (memcmp(buf_a, buf_b, len_a) != 0 ) { - rc = compare_different; - break; - } - } - /* Position both files at the beginning */ - if (lseek(fd_a, 0, SEEK_SET) == -1 || - lseek(fd_b, 0, SEEK_SET) == -1) - rc = seek_error; - return rc; -} - -int vol_get_used_bytes(int vol_fd, unsigned long long *bytes) -{ - off_t res; - - res = lseek(vol_fd, 0, SEEK_END); - if (res == (off_t)-1) - return -1; - *bytes = (unsigned long long) res; - res = lseek(vol_fd, 0, SEEK_SET); - return res == (off_t)-1 ? -1 : 0; -} - -static int copy_files(libubi_t ulib, int fd_in, int fd_out) -{ - unsigned char buf_a[COMPARE_BUF_SIZE]; - ssize_t len_a, len_b; - unsigned long long update_size, copied; - - if (vol_get_used_bytes(fd_in, &update_size) == -1 || - ubi_update_start(ulib, fd_out, update_size) == -1) - return update_error; - for (copied = 0; copied < update_size; copied += len_b ) { - len_a = fill_buffer(fd_in, buf_a, sizeof(buf_a)); - if (len_a == -1) - return read_error; - if (len_a == 0) /* Reach EOF */ - return 0; - len_b = flush_buffer(fd_out, buf_a, len_a); - if (len_b != len_a) - return write_error; - } - return 0; -} - -int ubimirror(uint32_t devno, int seqnum, uint32_t *ids, ssize_t ids_size, - char *err_buf, size_t err_buf_size) -{ - int rc = 0; - uint32_t src_id; - char path[PATH_MAX]; - libubi_t ulib; - int fd_in = -1, i = 0, fd_out = -1; - - if (ids_size == 0) - return 0; - else { - if ((seqnum < 0) || (seqnum > (ids_size - 1))) { - EBUF("volume id %d out of range", seqnum); - return EUBIMIRROR_NO_SRC; - } - src_id = ids[seqnum]; - } - - ulib = libubi_open(); - if (ulib == NULL) - return ubi_error; - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, src_id); - - fd_in = open(path, O_RDONLY); - if (fd_in == -1) { - EBUF("open error source volume %d", ids[i]); - rc = open_error; - goto err; - } - - for (i = 0; i < ids_size; i++) { - if (ids[i] == src_id) /* skip self-mirror */ - continue; - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, ids[i]); - - fd_out = open(path, O_RDWR); - if (fd_out < 0){ - EBUF("open error destination volume %d", ids[i]); - rc = open_error; - goto err; - } - rc = compare_files(fd_in, fd_out); - if (rc < 0) { - EBUF("compare error volume %d and %d", src_id, ids[i]); - goto err; - } else if (rc == compare_different) { - rc = copy_files(ulib, fd_in, fd_out); - if (rc != 0) { - EBUF("mirror error volume %d to %d", src_id, - ids[i]); - goto err; - } - } - if ((rc = close(fd_out)) == -1) { - EBUF("close error volume %d", ids[i]); - rc = close_error; - goto err; - } else - fd_out = -1; - } -err: - if (fd_out != -1) - close(fd_out); - if (fd_in != -1) - close(fd_in); - if (ulib != NULL) - libubi_close(ulib); - return rc; -} diff --git a/ubi-utils/src/pfi2bin.c b/ubi-utils/src/pfi2bin.c index 7f31938..1474482 100644 --- a/ubi-utils/src/pfi2bin.c +++ b/ubi-utils/src/pfi2bin.c @@ -37,15 +37,14 @@ #include <ubigen.h> #include <mtd/ubi-header.h> - -#include "config.h" +#include "common.h" #include "list.h" -#include "error.h" #include "reader.h" #include "peb.h" #include "crc32.h" -#define PROGRAM_VERSION "1.4" +#define PROGRAM_VERSION "1.5" +#define PROGRAM_NAME "pfi2bin" #define MAX_FNAME 255 #define DEFAULT_ERASE_COUNT 0 /* Hmmm.... Perhaps */ @@ -155,8 +154,6 @@ parse_opt(int argc, char **argv, myargs *args) printf("pfi2bin [OPTION...] pfifile\n"); printf("%s", doc); printf("%s", optionsstr); - printf("\nReport bugs to %s\n", - PACKAGE_BUGREPORT); exit(0); break; @@ -449,15 +446,15 @@ write_remaining_raw_ebs(pdd_data_t pdd, list_t raw_blocks, size_t *ebs_written, } if (peb->num < *ebs_written) { - err_msg("eb_num: %d\n", peb->num); - err_msg("Bug: This should never happen. %d %s", + errmsg("eb_num: %d\n", peb->num); + errmsg("Bug: This should never happen. %d %s", __LINE__, __FILE__); goto err; } delta = peb->num - *ebs_written; if (((delta + *ebs_written) * pdd->eb_size) > pdd->flash_size) { - err_msg("RAW block outside of flash_size."); + errmsg("RAW block outside of flash_size."); goto err; } for (j = 0; j < delta; j++) { @@ -518,23 +515,21 @@ create_raw(io_t io) rc = init_vol_tab (&vol_tab, &vol_tab_size); if (rc != 0) { - err_msg("Cannot initialize volume table."); + errmsg("cannot initialize volume table"); goto err; } rc = read_pdd_data(io->fp_pdd, &pdd, err_buf, ERR_BUF_SIZE); if (rc != 0) { - err_msg("Cannot read necessary pdd_data: %s rc: %d", - err_buf, rc); + errmsg("cannot read necessary pdd_data: %s rc: %d", err_buf, rc); goto err; } rc = read_pfi_headers(&pfi_raws, &pfi_ubis, io->fp_pfi, err_buf, ERR_BUF_SIZE); if (rc != 0) { - err_msg("Cannot read pfi header: %s rc: %d", - err_buf, rc); + errmsg("cannot read pfi header: %s rc: %d", err_buf, rc); goto err; } @@ -543,8 +538,7 @@ create_raw(io_t io) rc = memorize_raw_eb(pfi_raw, pdd, &raw_pebs, io); if (rc != 0) { - err_msg("Cannot create raw_block in mem. rc: %d\n", - rc); + errmsg("cannot create raw_block in mem. rc: %d\n", rc); goto err; } } @@ -554,7 +548,7 @@ create_raw(io_t io) rc = convert_ubi_volume(pfi_ubi, pdd, raw_pebs, vol_tab, &ebs_written, io); if (rc != 0) { - err_msg("Cannot convert UBI volume. rc: %d\n", rc); + errmsg("cannot convert UBI volume. rc: %d\n", rc); goto err; } } @@ -562,7 +556,7 @@ create_raw(io_t io) rc = write_ubi_volume_table(pdd, raw_pebs, vol_tab, vol_tab_size, &ebs_written, io); if (rc != 0) { - err_msg("Cannot write UBI volume table. rc: %d\n", rc); + errmsg("cannot write UBI volume table. rc: %d\n", rc); goto err; } @@ -571,7 +565,7 @@ create_raw(io_t io) goto err; if (io->fp_out != stdout) - info_msg("Physical eraseblocks written: %8d\n", ebs_written); + printf("Physical eraseblocks written: %8d\n", ebs_written); err: free(vol_tab); pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws); @@ -589,13 +583,13 @@ open_io_handle(myargs *args, io_t io) /* set PDD input */ io->fp_pdd = fopen(args->f_in_pdd, "r"); if (io->fp_pdd == NULL) { - err_sys("Cannot open: %s", args->f_in_pdd); + errmsg("cannot open: %s", args->f_in_pdd); } /* set PFI input */ io->fp_pfi = fopen(args->f_in_pfi, "r"); if (io->fp_pfi == NULL) { - err_sys("Cannot open PFI input file: %s", args->f_in_pfi); + errmsg("cannot open PFI input file: %s", args->f_in_pfi); } /* set output prefix */ @@ -604,7 +598,7 @@ open_io_handle(myargs *args, io_t io) else { io->fp_out = fopen(args->f_out, "wb"); if (io->fp_out == NULL) { - err_sys("Cannot open output file: %s", args->f_out); + errmsg("cannot open output file: %s", args->f_out); } } } @@ -613,14 +607,14 @@ static void close_io_handle(io_t io) { if (fclose(io->fp_pdd) != 0) { - err_sys("Cannot close PDD file."); + errmsg("cannot close PDD file"); } if (fclose(io->fp_pfi) != 0) { - err_sys("Cannot close PFI file."); + errmsg("cannot close PFI file"); } if (io->fp_out != stdout) { if (fclose(io->fp_out) != 0) { - err_sys("Cannot close output file."); + errmsg("cannot close output file"); } } @@ -629,8 +623,7 @@ close_io_handle(io_t io) io->fp_out = NULL; } -int -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { int rc = 0; @@ -655,19 +648,21 @@ main(int argc, char *argv[]) parse_opt(argc, argv, &args); if (strcmp(args.f_in_pfi, "") == 0) { - err_quit("No PFI input file specified!"); + errmsg("no PFI input file specified"); + exit(EXIT_FAILURE); } if (strcmp(args.f_in_pdd, "") == 0) { - err_quit("No PDD input file specified!"); + errmsg("no PDD input file specified"); + exit(EXIT_FAILURE); } open_io_handle(&args, &io); - info_msg("[ Creating RAW..."); + printf("Creating RAW..."); rc = create_raw(&io); if (rc != 0) { - err_msg("Creating RAW failed."); + errmsg("creating RAW failed"); goto err; } diff --git a/ubi-utils/src/ubimirror.c b/ubi-utils/src/ubimirror.c deleted file mode 100644 index 2cc4596..0000000 --- a/ubi-utils/src/ubimirror.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Oliver Lohmann - * - * 1.2 Removed argp because we want to use uClibc. - * 1.3 Minor cleanups - * 1.4 Migrated to new libubi - */ - -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <getopt.h> -#include <unistd.h> -#include <errno.h> -#include <mtd/ubi-header.h> - -#include "config.h" -#include "error.h" -#include "example_ubi.h" -#include "ubimirror.h" - -#define PROGRAM_VERSION "1.4" - -typedef enum action_t { - ACT_NORMAL = 0, - ACT_ARGP_ABORT, - ACT_ARGP_ERR, -} action_t; - -#define ABORT_ARGP do { \ - args->action = ACT_ARGP_ABORT; \ -} while (0) - -#define ERR_ARGP do { \ - args->action = ACT_ARGP_ERR; \ -} while (0) - -#define VOL_ARGS_MAX 2 - -static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" - "ubimirror - mirrors ubi volumes.\n"; - -static const char *optionsstr = -" -c, --copyright Print copyright information.\n" -" -s, --side=<seqnum> Use the side <seqnum> as source.\n" -" -?, --help Give this help list\n" -" --usage Give a short usage message\n" -" -V, --version Print program version\n"; - -static const char *usage = -"Usage: ubimirror [-c?V] [-s <seqnum>] [--copyright] [--side=<seqnum>]\n" -" [--help] [--usage] [--version] <source> <destination>\n"; - -static const char copyright [] __attribute__((unused)) = - "(C) IBM Coorporation 2007"; - -struct option long_options[] = { - { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, - { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' }, - { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, - { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, - { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, - { NULL, 0, NULL, 0} -}; - -typedef struct myargs { - action_t action; - int side; - int vol_no; /* index of current volume */ - /* @FIXME replace by bootenv_list, makes live easier */ - /* @FIXME remove the constraint of two entries in the array */ - const char* vol[VOL_ARGS_MAX]; /* comma separated list of src/dst - volumes */ - char *arg1; - char **options; /* [STRING...] */ -} myargs; - -static int -get_update_side(const char* str) -{ - uint32_t i = strtoul(str, NULL, 0); - - if ((i != 0) && (i != 1)) { - return -1; - } - return i; -} - - -static int -parse_opt(int argc, char **argv, myargs *args) -{ - while (1) { - int key; - - key = getopt_long(argc, argv, "cs:?V", long_options, NULL); - if (key == -1) - break; - - switch (key) { - case 'c': - err_msg("%s", copyright); - ABORT_ARGP; - break; - case 's': - args->side = get_update_side(optarg); - if (args->side < 0) { - err_msg("Unsupported seqnum: %s.\n" - "Supported seqnums are '0' " - "and '1'\n", optarg); - ERR_ARGP; - } - break; - case '?': /* help */ - err_msg("Usage: ubimirror [OPTION...] " - "<source> <destination>\n"); - err_msg("%s", doc); - err_msg("%s", optionsstr); - err_msg("\nReport bugs to %s\n", - PACKAGE_BUGREPORT); - exit(0); - break; - case 'V': - err_msg("%s", PROGRAM_VERSION); - exit(0); - break; - default: - err_msg("%s", usage); - exit(-1); - } - } - - while (optind < argc) { - /* only two entries allowed */ - if (args->vol_no >= VOL_ARGS_MAX) { - err_msg("%s", usage); - ERR_ARGP; - } - args->vol[(args->vol_no)++] = argv[optind++]; - } - - return 0; -} - - -int -main(int argc, char **argv) { - int rc = 0; - unsigned int ids[VOL_ARGS_MAX]; - char err_buf[1024]; - - myargs args = { - .action = ACT_NORMAL, - .side = -1, - .vol_no = 0, - .vol = {"", ""}, - .options = NULL, - }; - - parse_opt(argc, argv, &args); - if (args.action == ACT_ARGP_ERR) { - rc = 127; - goto err; - } - if (args.action == ACT_ARGP_ABORT) { - rc = 126; - goto out; - } - if (args.vol_no < VOL_ARGS_MAX) { - fprintf(stderr, "missing volume number for %s\n", - args.vol_no == 0 ? "source and target" : "target"); - rc = 125; - goto out; - } - for( rc = 0; rc < args.vol_no; ++rc){ - char *endp; - ids[rc] = strtoul(args.vol[rc], &endp, 0); - if( *endp != '\0' ){ - fprintf(stderr, "invalid volume number %s\n", - args.vol[rc]); - rc = 125; - goto out; - } - } - rc = ubimirror(EXAMPLE_UBI_DEVICE, args.side, ids, args.vol_no, - err_buf, sizeof(err_buf)); - if( rc ){ - err_buf[sizeof err_buf - 1] = '\0'; - fprintf(stderr, err_buf); - if( rc < 0 ) - rc = -rc; - } - out: - err: - return rc; -} diff --git a/ubi-utils/src/ubimirror.h b/ubi-utils/src/ubimirror.h deleted file mode 100644 index d7ae2ad..0000000 --- a/ubi-utils/src/ubimirror.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __UBIMIRROR_H__ -#define __UBIMIRROR_H__ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Oliver Lohmann - * - * An utility to mirror UBI volumes. - */ - -#include <stdint.h> - -/** - * @def EUBIMIRROR_SRC_EQ_DST - * @brief Given source volume is also in the set of destination volumes. - */ -#define EUBIMIRROR_SRC_EQ_DST 20 - -/** - * @def EUBIMIRROR_NO_SRC - * @brief The given source volume does not exist. - */ -#define EUBIMIRROR_NO_SRC 21 - -/** - * @def EUBIMIRROR_NO_DST - * @brief One of the given destination volumes does not exist. - */ -#define EUBIMIRROR_NO_DST 22 - -/** - * @brief Mirrors UBI devices from a source device (specified by seqnum) - * to n target devices. - * @param devno Device number used by the UBI operations. - * @param seqnum An index into ids (defines the src_id). - * @param ids An array of ids. - * @param ids_size The number of entries in the ids array. - * @param err_buf A buffer to store verbose error messages. - * @param err_buf_size The size of the error buffer. - * - * @note A seqnum of value < 0 defaults to a seqnum of 0. - * @note A seqnum exceeding the range of ids_size defaults to 0. - * @note An empty ids list results in a empty stmt. - * @pre The UBI volume which shall be used as source volume exists. - * @pre The UBI volumes which are defined as destination volumes exist. - * @post The content of the UBI volume which was defined as source volume - * equals the content of the volumes which were defined as destination. - */ -int ubimirror(uint32_t devno, int seqnum, uint32_t* ids, ssize_t ids_size, - char *err_buf, size_t err_buf_size); - -#endif /* __UBIMIRROR_H__ */ |