summaryrefslogtreecommitdiff
path: root/ubi-utils/src/libpfiflash/pfiflash.c
diff options
context:
space:
mode:
Diffstat (limited to 'ubi-utils/src/libpfiflash/pfiflash.c')
-rw-r--r--ubi-utils/src/libpfiflash/pfiflash.c617
1 files changed, 0 insertions, 617 deletions
diff --git a/ubi-utils/src/libpfiflash/pfiflash.c b/ubi-utils/src/libpfiflash/pfiflash.c
deleted file mode 100644
index 0859a22..0000000
--- a/ubi-utils/src/libpfiflash/pfiflash.c
+++ /dev/null
@@ -1,617 +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.
- */
-
-/**
- * @file pfiflash.c
- *
- * @author Oliver Lohmann <oliloh@de.ibm.com>
- *
- * @brief This library is provides an interface to the pfiflash utility.
- *
- * <oliloh@de.ibm.com> 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 <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#define __USE_GNU
-#include <string.h>
-
-#include <libubi.h>
-#include <pfiflash.h>
-
-#include <mtd/ubi-user.h> /* FIXME Is this ok here!!?? */
-
-#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, size_t err_buf_size)
-{
- 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, size_t err_buf_size)
-{
- 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 > (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 ((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;
-}