summaryrefslogtreecommitdiff
path: root/ubi-utils/src/libpfiflash.c
diff options
context:
space:
mode:
Diffstat (limited to 'ubi-utils/src/libpfiflash.c')
-rw-r--r--ubi-utils/src/libpfiflash.c1325
1 files changed, 0 insertions, 1325 deletions
diff --git a/ubi-utils/src/libpfiflash.c b/ubi-utils/src/libpfiflash.c
deleted file mode 100644
index b0d454a..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-media.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("%s", 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("%s", 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("%s", 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("%s", 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("%s", 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("%s", 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("%s", 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("%s", 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("%s", 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("%s", 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("%s", 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("%s", 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("%s", PFIFLASH_ERRSTR[-rc]);
- goto err;
- } else if (ferror(pfi)) {
- rc = -PFIFLASH_ERR_FIO;
- EBUF("%s", 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("%s", 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("%s", 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("%s", 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("%s", 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("%s", 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);
-}