]> www.infradead.org Git - mtd-utils.git/commitdiff
[MTD] UBI: pfiflash needs to flash raw sections and check CRC
authorDrake Dowsett <dowsett@de.ibm.com>
Mon, 6 Nov 2006 15:54:10 +0000 (16:54 +0100)
committerFrank Haverkamp <haver@vnet.ibm.com>
Mon, 6 Nov 2006 15:54:10 +0000 (16:54 +0100)
Flashing of raw partitions should be possible now.
CRC checking of pfi files before flashing the content was added.

Signed-off-by: Frank Haverkamp <haver@vnet.ibm.com>
ubi-utils/Makefile
ubi-utils/src/bootenv.c
ubi-utils/src/bootenv.h
ubi-utils/src/error.c
ubi-utils/src/error.h
ubi-utils/src/libpfiflash.c
ubi-utils/src/pfiflash.c
ubi-utils/src/pfiflash.h
ubi-utils/src/pfiflash_error.h [new file with mode: 0644]
ubi-utils/src/reader.c
ubi-utils/src/reader.h

index 6161f3dda3abf927ed6a36686996cfb5471f22f4..2776c07001a0b4b6f6959016e4d4786a26870f08 100644 (file)
@@ -48,15 +48,15 @@ ubirmvol: ubirmvol.o error.o libubi.o libubi_sysfs.o
        $(CC) $(LDFLAGS) -o $@ $^
 
 pddcustomize: pddcustomize.o error.o libubimirror.o bootenv.o hashmap.o \
-               libubi.o libubi_sysfs.o
+               libubi.o libubi_sysfs.o crc32.o
        $(CC) $(LDFLAGS) -o $@ $^
 
 pfiflash: pfiflash.o libpfiflash.o list.o reader.o error.o libubimirror.o \
-               bootenv.o hashmap.o pfi.o libubi.o libubi_sysfs.o
+               bootenv.o hashmap.o pfi.o libubi.o libubi_sysfs.o crc32.o
        $(CC) $(LDFLAGS) -o $@ $^
 
 ubimirror: ubimirror.o error.o libubimirror.o bootenv.o hashmap.o \
-               libubi.o libubi_sysfs.o
+               libubi.o libubi_sysfs.o crc32.o
        $(CC) $(LDFLAGS) -o $@ $^
 
 nand2bin: nand2bin.o nandecc.o nandcorr.o
@@ -68,7 +68,7 @@ bin2nand: bin2nand.o error.o nandecc.o
 ubigen: ubigen.o libubigen.o crc32.o
        $(CC) $(LDFLAGS) -o $@ $^
 
-mkbootenv: mkbootenv.o bootenv.o hashmap.o error.o
+mkbootenv: mkbootenv.o bootenv.o hashmap.o error.o crc32.o
        $(CC) $(LDFLAGS) -o $@ $^
 
 unubi: unubi.o crc32.o
index 8871d90685c27e85b146ea6271b21f2a3ddc507a..ed15dc771438cfc1183310323284e9bd1b340b04 100644 (file)
 #include <sys/stat.h>
 #include <bootenv.h>
 
-#include "config.h"
 #include "hashmap.h"
 #include "error.h"
 
+#include <mtd/ubi-header.h>
+#include "crc32.h"
+
+#define __unused __attribute__((unused))
+
 #define BOOTENV_MAXLINE 512 /* max line size of a bootenv.txt file */
 
 /* Structures */
@@ -189,9 +193,10 @@ extract_pair(const char *str, bootenv_t env)
 
        *val = '\0'; /* split strings */
        val++;
+
        rc = bootenv_set(env, key, val);
 
-err:
+ err:
        free(key);
        return rc;
 }
@@ -248,46 +253,36 @@ bootenv_create(bootenv_t* env)
 static int
 rd_buffer(bootenv_t env, const char *buf, size_t size)
 {
-       const char *curr = buf; /* ptr to current key/value pair */
-       uint32_t i = 0;         /* current length */
-       uint32_t j = 0;         /* processed chars */
-       uint32_t items = 0;     /* processed items */
-       int rc = 0;
+       const char *curr = buf;         /* ptr to current key/value pair */
+       uint32_t i, j;                  /* current length, chars processed */
 
-       if (buf[size-1] != '\0') {
+       if (buf[size - 1] != '\0')      /* must end in '\0' */
                return BOOTENV_EFMT;
-       }
 
-       while ((i = strlen(curr)) != 0) {
-               /* there is a key value pair remaining */
-               rc = extract_pair(curr, env);
-               if (rc != 0) {
-                       rc = BOOTENV_EINVAL;
-                       return rc;
-               }
-               items++;
+       for (j = 0; j < size; j += i, curr += i) {
+               /* strlen returns the size of the string upto
+                  but not including the null terminator;
+                  adding 1 to account for '\0' */
+               i = strlen(curr) + 1;
 
-               j += i;
-               if (j >= size)
-                       return 0; /* finished, end of buffer */
-               curr += i + 1;
+               if (i == 1)
+                       return 0;       /* no string found */
+
+               if (extract_pair(curr, env) != 0)
+                       return BOOTENV_EINVAL;
        }
 
        return 0;
 }
 
-/**
- * If we have a single file containing the boot-parameter size should
- * be specified either as the size of the file or as BOOTENV_MAXSIZE.
- * If the bootparameter are in the middle of a file we need the exact
- * length of the data.
- */
+
 int
-bootenv_read(FILE* fp, bootenv_t env, size_t size)
+bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t* ret_crc)
 {
        int rc;
        char *buf = NULL;
        size_t i = 0;
+       uint32_t crc32_table[256];
 
        if ((fp == NULL) || (env == NULL))
                return -EINVAL;
@@ -306,33 +301,47 @@ bootenv_read(FILE* fp, bootenv_t env, size_t size)
         */
        while((i < size) && (!feof(fp))) {
                int c = fgetc(fp);
-
                if (c == EOF) {
+                       /* FIXME isn't this dangerous, to update
+                          the boot envs with incomplete data? */
                        buf[i++] = '\0';
                        break;  /* we have enough */
                }
-
-               /* log_msg("%c", c); */ /* FIXME DBG */
-
-               buf[i++] = c;
                if (ferror(fp)) {
                        rc = -EIO;
                        goto err;
                }
+
+               buf[i++] = (char)c;
+       }
+
+       /* calculate crc to return */
+       if (ret_crc != NULL) {
+               init_crc32_table(crc32_table);
+               *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size);
        }
 
        /* transfer to hashmap */
        rc = rd_buffer(env, buf, size);
 
-       /* FIXME DBG */
-       /* log_msg("\n%s:%d rc=%d\n", __func__, __LINE__, rc); */
-
 err:
        free(buf);
        return rc;
 }
 
 
+/**
+ * If we have a single file containing the boot-parameter size should
+ * be specified either as the size of the file or as BOOTENV_MAXSIZE.
+ * If the bootparameter are in the middle of a file we need the exact
+ * length of the data.
+ */
+int
+bootenv_read(FILE* fp, bootenv_t env, size_t size)
+{
+       return bootenv_read_crc(fp, env, size, NULL);
+}
+
 
 int
 bootenv_read_txt(FILE* fp, bootenv_t env)
@@ -390,8 +399,8 @@ err:
 }
 
 static int
-fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max,
-                  size_t *written)
+fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max __unused,
+               size_t *written)
 {
        int rc = 0;
        size_t keys_size, i;
@@ -404,7 +413,7 @@ fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max,
                goto err;
 
        for (i = 0; i < keys_size; i++) {
-               if (wr > buf_size_max) {
+               if (wr > BOOTENV_MAXSIZE) {
                        rc = -ENOSPC;
                        goto err;
                }
@@ -413,7 +422,7 @@ fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max,
                if (rc != 0)
                        goto err;
 
-               wr += snprintf(buf + wr, buf_size_max - wr,
+               wr += snprintf(buf + wr, BOOTENV_MAXSIZE - wr,
                                "%s=%s", keys[i], val);
                wr++; /* for \0 */
        }
@@ -428,11 +437,12 @@ err:
 }
 
 int
-bootenv_write(FILE* fp, bootenv_t env)
+bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc)
 {
        int rc = 0;
        size_t size = 0;
        char *buf = NULL;
+       uint32_t crc32_table[256];
 
        if ((fp == NULL) || (env == NULL))
                return -EINVAL;
@@ -441,10 +451,17 @@ bootenv_write(FILE* fp, bootenv_t env)
        if (buf == NULL)
                return -ENOMEM;
 
+
        rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, &size);
        if (rc != 0)
                goto err;
 
+       /* calculate crc to return */
+       if (ret_crc != NULL) {
+               init_crc32_table(crc32_table);
+               *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size);
+       }
+
        if (fwrite(buf, size, 1, fp) != 1) {
                rc = -EIO;
                goto err;
@@ -456,6 +473,12 @@ err:
        return rc;
 }
 
+int
+bootenv_write(FILE* fp, bootenv_t env)
+{
+       return bootenv_write_crc(fp, env, NULL);
+}
+
 int
 bootenv_size(bootenv_t env, size_t *size)
 {
index 86743ed16a8b72e62ca857eebd7eca8469c7bcc0..9003d705e14476a21c0ef9b21bcf28d37b0d5353 100644 (file)
@@ -230,6 +230,10 @@ int bootenv_size(bootenv_t env, size_t *size);
  */
 int bootenv_read(FILE* fp, bootenv_t env, size_t size);
 
+/**
+ * @param ret_crc  return value of crc of read data
+ */
+int bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t *ret_crc);
 
 /**
  * @brief Read bootenv data from an text/ascii file.
@@ -249,6 +253,11 @@ int bootenv_read_txt(FILE* fp, bootenv_t env);
  */
 int bootenv_write(FILE* fp, bootenv_t env);
 
+/**
+ * @param ret_crc  return value of crc of read data
+ */
+int bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc);
+
 /**
  * @brief Write a bootenv structure to the given location (text).
  * @param fp   Filepointer to text file.
index c8c623c4729028863fccde0ce0a2b23de1ef37a4..4aaedadbbe34f295feb7022f8118f1271e220a29 100644 (file)
@@ -25,6 +25,7 @@
 #include "error.h"
 
 #define MAXLINE 4096
+#define MAXWIDTH 80
 
 static FILE *logfp = NULL;
 
@@ -35,6 +36,9 @@ read_procfile(FILE *fp_out, const char *procfile)
 {
        FILE *fp;
 
+       if (!fp_out)
+               return -ENXIO;
+
        fp = fopen(procfile, "r");
        if (!fp)
                return -ENOENT;
@@ -57,6 +61,9 @@ read_procfile(FILE *fp_out, const char *procfile)
 void
 error_initlog(const char *logfile)
 {
+       if (!logfile)
+               return;
+
        logfp = fopen(logfile, "a+");
        read_procfile(logfp, "/proc/cpuinfo");
 }
@@ -143,7 +150,11 @@ __err_dump(const char *fmt, ...)
        exit(EXIT_FAILURE);     /* shouldn't get here */
 }
 
-
+/**
+ * If a logfile is used we must not print on stderr and stdout
+ * anymore. Since pfilfash might be used in a server context, it is
+ * even dangerous to write to those descriptors.
+ */
 static void
 err_doit(int errnoflag, int level __attribute__((unused)),
         const char *fmt, va_list ap)
@@ -166,9 +177,61 @@ err_doit(int errnoflag, int level __attribute__((unused)),
        if (logfp) {
                fputs(buf, logfp);
                fflush(logfp);
+               return;         /* exit when logging completes */
        }
 
-       fputs(buf, fpout);
+       if (fpout == stderr) {
+               /* perform line wrap when outputting to stderr */
+               int word_len, post_len, chars;
+               char *buf_ptr;
+               const char *frmt = "%*s%n %n";
+
+               chars = 0;
+               buf_ptr = buf;
+               while (sscanf(buf_ptr, frmt, &word_len, &post_len) != EOF) {
+                       int i;
+                       char word[word_len + 1];
+                       char post[post_len + 1];
+
+                       strncpy(word, buf_ptr, word_len);
+                       word[word_len] = '\0';
+                       buf_ptr += word_len;
+                       post_len -= word_len;
+
+                       if (chars + word_len > MAXWIDTH) {
+                               fputc('\n', fpout);
+                               chars = 0;
+                       }
+                       fputs(word, fpout);
+                       chars += word_len;
+
+                       if (post_len > 0) {
+                               strncpy(post, buf_ptr, post_len);
+                               post[post_len] = '\0';
+                               buf_ptr += post_len;
+                       }
+                       for (i = 0; i < post_len; i++) {
+                               int inc = 1, chars_new;
+
+                               if (post[i] == '\t')
+                                       inc = 8;
+                               if (post[i] == '\n') {
+                                       inc = 0;
+                                       chars_new = 0;
+                               } else
+                                       chars_new = chars + inc;
+
+                               if (chars_new > MAXWIDTH) {
+                                       fputc('\n', fpout);
+                                       chars_new = inc;
+                               }
+                               fputc(post[i], fpout);
+                               chars = chars_new;
+                       }
+               }
+       }
+       else
+               fputs(buf, fpout);
        fflush(fpout);
        if (fpout != stderr)
                fclose(fpout);
index e8d7137e710c354ea973d9d3279a8ac4c885b818..05d807878e98b9397cfbdc4e0a2032e8c28d976a 100644 (file)
@@ -78,7 +78,7 @@ void info_msg(const char *fmt, ...);
        __err_msg(fmt, ##__VA_ARGS__);                          \
 } while (0)
 #else
-#define dbg_msg(fmt, ...)
+#define dbg_msg(fmt, ...) do {} while (0)
 #endif
 
 #endif /* __ERROR_H__ */
index ed2af3c885d5539b07a29b4958af24dbe3962cf4..1dc9f10f26d78468e2144ebae8c5d2caf2b757cc 100644 (file)
  * 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
+/*
+ * 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 <libubi.h>
 #include <pfiflash.h>
 
-//#include <mtd/ubi-user.h>    /* FIXME Is this ok here!!?? */
+#include <mtd/ubi-user.h>      /* FIXME Is this ok here? */
 
-#include "config.h"
+#include "pfiflash_error.h"
 #include "ubimirror.h"
 #include "error.h"
 #include "reader.h"
 #include "example_ubi.h"
 #include "bootenv.h"
 
-static const char copyright [] __attribute__((unused)) =
+/* ubi-header.h and crc32.h needed for CRC checking */
+#include <mtd/ubi-header.h>    /* FIXME Is this ok here? */
+#include "crc32.h"
+
+#define __unused __attribute__((unused))
+
+static const char copyright [] __unused =
        "Copyright (c) International Business Machines Corp., 2006";
 
-#define EBUF(fmt...) do {                      \
-               snprintf(err_buf, err_buf_size, fmt);   \
+/* simply clear buffer, then write into front of it */
+#define EBUF(fmt...)                                                   \
+               snprintf(err_buf, err_buf_size, fmt);
+
+/* make a history of buffer and then prepend something in front */
+#define EBUF_PREPEND(fmt)                                              \
+       do {                                                            \
+               int EBUF_HISTORY_LENGTH = strlen(err_buf);              \
+               char EBUF_HISTORY[EBUF_HISTORY_LENGTH + 1];             \
+               strncpy(EBUF_HISTORY, err_buf, EBUF_HISTORY_LENGTH + 1);\
+               EBUF(fmt ": %s", EBUF_HISTORY);                         \
        } while (0)
 
+/* An array of PDD function pointers indexed by the algorithm. */
 static pdd_func_t pdd_funcs[PDD_HANDLING_NUM]  =
        {
                &bootenv_pdd_keep,
                &bootenv_pdd_merge,
                &bootenv_pdd_overwrite
        };
-/**< An array of PDD function pointers indexed by the algorithm. */
-
 
 typedef enum ubi_update_process_t {
        UBI_REMOVE = 0,
        UBI_WRITE,
 } ubi_update_process_t;
 
+
+/**
+ * skip_raw_volumes - reads data from pfi to advance fp past raw block
+ * @pfi:       fp to pfi data
+ * @pfi_raws:  header information
+ *
+ * Error handling):
+ *     when early EOF in pfi data
+ *     - returns -PFIFLASH_ERR_EOF, err_buf matches text to err
+ *     when file I/O error
+ *     - returns -PFIFLASH_ERR_FIO, err_buf matches text to err
+ **/
 static int
-skip_raw_sections(FILE* pfi, list_t pfi_raws,
+skip_raw_volumes(FILE* pfi, list_t pfi_raws,
                  char* err_buf, size_t err_buf_size)
 {
-       int rc = 0;
-
+       int rc;
        void *i;
        list_t ptr;
-       size_t j, skip_size;
 
        if (is_empty(pfi_raws))
                return 0;
 
+       rc = 0;
        foreach(i, ptr, pfi_raws) {
-               skip_size = ((pfi_raw_t)i)->data_size;
-               for(j = 0;  j < skip_size; j++) {
-                       fgetc(pfi);
-                       if (ferror(pfi)) {
-                               EBUF("Cannot skip raw section in PFI.");
-                               rc = -EIO;
+               size_t j;
+               pfi_raw_t raw;
+
+               raw = (pfi_raw_t)i;
+               for(j = 0; j < raw->data_size; j++) {
+                       int c;
+
+                       c = fgetc(pfi);
+                       if (c == EOF)
+                               rc = -PFIFLASH_ERR_EOF;
+                       else if (ferror(pfi))
+                               rc = -PFIFLASH_ERR_FIO;
+
+                       if (rc != 0)
                                goto err;
-                       }
                }
        }
+
  err:
+       EBUF(PFIFLASH_ERRSTR[-rc]);
        return rc;
 }
 
+
 /**
- * @brief Wraps the ubi_mkvol functions and implements a hook for the bootenv
- *       update.
- * @param devno UBI device number.
- * @param s Current seqnum.
- * @param u Information about the UBI volume from the PFI.
- * @param err_buf An error buffer.
- * @param err_buf_size The size of the error buffer.
- * @return 0 On Sucess.
- * @return else Error.
- */
+ * my_ubi_mkvol - wraps the ubi_mkvol functions and impl. bootenv update hook
+ * @devno:     UBI device number.
+ * @s:         Current seqnum.
+ * @u:         Information about the UBI volume from the PFI.
+ *
+ * Error handling:
+ *     when UBI system couldn't be opened
+ *     - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ *     when UBI system couldn't create a volume
+ *     - returns -PFIFLASH_ERR_UBI_MKVOL, err_buf matches text to err
+ **/
 static int
-my_ubi_mkvol(int devno, int s, pfi_ubi_t u, char *err_buf, size_t err_buf_size)
+my_ubi_mkvol(int devno, int s, pfi_ubi_t u,
+            char *err_buf, size_t err_buf_size)
 {
-       int rc = 0;
-       int type;
-       ubi_lib_t ulib = NULL;
+       int rc, type;
+       ubi_lib_t ulib;
+
+       rc = 0;
+       ulib = NULL;
 
-       log_msg("%s(vol_id=%d, size=%d, data_size=%d, type=%d, "
-               "alig=%d, nlen=%d, name=%s)", __func__,
+       log_msg("[ ubimkvol id=%d, size=%d, data_size=%d, type=%d, "
+               "alig=%d, nlen=%d, name=%s",
                u->ids[s], u->size, u->data_size, u->type, u->alignment,
                strnlen(u->names[s], PFI_UBI_VOL_NAME_LEN), u->names[s]);
 
        rc = ubi_open(&ulib);
        if (rc != 0) {
+               rc = -PFIFLASH_ERR_UBI_OPEN;
+               EBUF(PFIFLASH_ERRSTR[-rc]);
                goto err;
        }
 
@@ -130,7 +168,6 @@ my_ubi_mkvol(int devno, int s, pfi_ubi_t u, char *err_buf, size_t err_buf_size)
        case pfi_ubi_static:
                type = UBI_STATIC_VOLUME; break;
        case pfi_ubi_dynamic:
-               type = UBI_DYNAMIC_VOLUME; break;
        default:
                type = UBI_DYNAMIC_VOLUME;
        }
@@ -138,58 +175,78 @@ my_ubi_mkvol(int devno, int s, pfi_ubi_t u, char *err_buf, size_t err_buf_size)
        rc = ubi_mkvol(ulib, devno, u->ids[s], type, u->size, u->alignment,
                       u->names[s]);
        if (rc != 0) {
-               EBUF("Cannot create volume: %d", u->ids[s]);
+               rc = -PFIFLASH_ERR_UBI_MKVOL;
+               EBUF(PFIFLASH_ERRSTR[-rc], u->ids[s]);
                goto err;
        }
 
  err:
        if (ulib != NULL)
                ubi_close(&ulib);
+
        return rc;
 }
 
+
 /**
- * @brief A wrapper around the UBI library function ubi_rmvol.
- * @param devno UBI device number.
- * @param s Current seqnum.
- * @param u Information about the UBI volume from the PFI.
- * @param err_buf An error buffer.
- * @param err_buf_size The size of the error buffer.
+ * my_ubi_rmvol - a wrapper around the UBI library function ubi_rmvol
+ * @devno      UBI device number
+ * @id         UBI volume id to remove
  *
  * If the volume does not exist, the function will return success.
- */
+ *
+ * Error handling:
+ *     when UBI system couldn't be opened
+ *     - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ *     when UBI system couldn't update (truncate) a volume
+ *     - returns -PFIFLASH_ERR_UBI_VOL_UPDATE, err_buf matches text to err
+ *     when UBI system couldn't remove a volume
+ *     - returns -PFIFLASH_ERR_UBI_RMVOL, err_buf matches text to err
+ **/
 static int
 my_ubi_rmvol(int devno, uint32_t id,
-            char *err_buf __unused, size_t err_buf_size __unused)
+            char *err_buf, size_t err_buf_size)
 {
-       int rc = 0;
-       ubi_lib_t ulib = NULL;
-       int fd;
+       int rc, fd;
+       ubi_lib_t ulib;
 
-       log_msg("%s(id=%d)", __func__, id);
+       rc = 0;
+       ulib = NULL;
+
+       log_msg("[ ubirmvol id=%d", id);
 
        rc = ubi_open(&ulib);
-       if (rc != 0)
+       if (rc != 0) {
+               rc = -PFIFLASH_ERR_UBI_OPEN;
+               EBUF(PFIFLASH_ERRSTR[-rc]);
                goto err;
+       }
 
-       /**
-        * Truncate if it exist or not.
-        */
+       /* truncate whether it exist or not */
        fd = ubi_vol_open(ulib, devno, id, O_RDWR);
        if (fd == -1)
-               return 0;       /* not existent, return */
+               return 0;       /* not existent, return */
 
        rc = ubi_vol_update(fd, 0);
+       ubi_vol_close(fd);
        if (rc < 0) {
-               fprintf(stderr, "update failed rc=%d errno=%d\n", rc, errno);
-               ubi_vol_close(fd);
+               rc = -PFIFLASH_ERR_UBI_VOL_UPDATE;
+               EBUF(PFIFLASH_ERRSTR[-rc], id);
                goto err;       /* if EBUSY than empty device, continue */
        }
-       ubi_vol_close(fd);
 
        rc = ubi_rmvol(ulib, devno, id);
        if (rc != 0) {
-               /* @TODO Define a ubi_rmvol return value which says
+#ifdef DEBUG
+               int rc_old = rc;
+               dbg_msg("Remove UBI volume %d returned with error: %d "
+                       "errno=%d", id, rc_old, errno);
+#endif
+
+               rc = -PFIFLASH_ERR_UBI_RMVOL;
+               EBUF(PFIFLASH_ERRSTR[-rc], id);
+
+               /* TODO Define a ubi_rmvol return value which says
                 * sth like EUBI_NOSUCHDEV. In this case, a failed
                 * operation is acceptable. Everything else has to be
                 * classified as real error. But talk to Andreas Arnez
@@ -198,65 +255,128 @@ my_ubi_rmvol(int devno, uint32_t id,
                /* if ((errno == EINVAL) || (errno == ENODEV))
                   return 0; */ /* currently it is EINVAL or ENODEV */
 
-               dbg_msg("Remove UBI volume %d returned with error: %d "
-                       "errno=%d", id, rc, errno);
                goto err;
        }
+
  err:
        if (ulib != NULL)
                ubi_close(&ulib);
+
        return rc;
 }
 
+
+/**
+ * read_bootenv_volume - reads the current bootenv data from id into be_old
+ * @devno      UBI device number
+ * @id         UBI volume id to remove
+ * @bootenv_old        to hold old boot_env data
+ *
+ * Error handling:
+ *     when UBI system couldn't be opened
+ *     - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ *     when UBI system couldn't open a volume to read
+ *     - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err
+ *     when couldn't read bootenv data
+ *     - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err
+ **/
 static int
 read_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old,
                    char *err_buf, size_t err_buf_size)
 {
-       int rc = 0;
-       ubi_lib_t ulib = NULL;
-       FILE* fp_in = NULL;
+       int rc;
+       FILE* fp_in;
+       ubi_lib_t ulib;
+
+       rc = 0;
+       fp_in = NULL;
+       ulib = NULL;
 
        rc = ubi_open(&ulib);
-       if (rc)
-               return rc;
+       if (rc != 0) {
+               rc = -PFIFLASH_ERR_UBI_OPEN;
+               EBUF(PFIFLASH_ERRSTR[-rc]);
+               goto err;
+       }
 
        fp_in = ubi_vol_fopen_read(ulib, devno, id);
        if (!fp_in) {
-               EBUF("Cannot open bootenv volume");
-               rc = -EIO;
+               rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
+               EBUF(PFIFLASH_ERRSTR[-rc], id);
                goto err;
        }
 
-       log_msg("%s reading old bootenvs", __func__);
+       log_msg("[ reading old bootenvs ...");
 
        /* Save old bootenvs for reference */
        rc = bootenv_read(fp_in, bootenv_old, BOOTENV_MAXSIZE);
-       if (rc)
-               EBUF("Cannot read bootenv_old");
+       if (rc != 0) {
+               rc = -PFIFLASH_ERR_BOOTENV_READ;
+               EBUF(PFIFLASH_ERRSTR[-rc]);
+               goto err;
+       }
+
  err:
        if (fp_in)
                fclose(fp_in);
        if (ulib)
                ubi_close(&ulib);
+
        return rc;
 }
 
+
+/**
+ * write_bootenv_volume - writes data from PFI file int to bootenv UBI volume
+ * @devno      UBI device number
+ * @id         UBI volume id
+ * @bootend_old        old PDD data from machine
+ * @pdd_f      function to handle PDD with
+ * @fp_in      new pdd data contained in PFI
+ * @fp_in_size data size of new pdd data in PFI
+ * @pfi_crc    crc value from PFI header
+ *
+ * Error handling:
+ *     when UBI system couldn't be opened
+ *     - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ *     when bootenv can't be created
+ *     - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err
+ *     when bootenv can't be read
+ *     - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err
+ *     when PDD handling function returns and error
+ *     - passes rc and err_buf data
+ *     when CRC check fails
+ *     - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err
+ *     when bootenv can't be resized
+ *     - returns -PFIFLASH_ERR_BOOTENV_SIZE, err_buf matches text to err
+ *     when UBI system couldn't open a volume
+ *     - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err
+ *     when couldn't write bootenv data
+ *     - returns -PFIFLASH_ERR_BOOTENV_WRITE, err_buf matches text to err
+ **/
 static int
 write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old,
-                    pdd_func_t pdd_f,
-                    FILE* fp_in, /* new pdd data contained in pfi */
-                    size_t fp_in_size, /* data size of new pdd data in pfi */
+                    pdd_func_t pdd_f, FILE* fp_in, size_t fp_in_size,
+                    uint32_t pfi_crc,
                     char *err_buf, size_t err_buf_size)
 {
-       int rc = 0;
-       int warnings = 0;
-       ubi_lib_t ulib = NULL;
-       bootenv_t bootenv_new = NULL;
-       bootenv_t bootenv_res = NULL;
-       size_t update_size = 0;
-       FILE *fp_out = NULL;
-
-       log_msg("%s(id=%d, fp_in=%p)", __func__, id, fp_in);
+       int rc, warnings;
+       uint32_t crc;
+       size_t update_size;
+       FILE *fp_out;
+       bootenv_t bootenv_new, bootenv_res;
+       ubi_lib_t ulib;
+
+       rc = 0;
+       warnings = 0;
+       crc = 0;
+       update_size = 0;
+       fp_out = NULL;
+       bootenv_new = NULL;
+       bootenv_res = NULL;
+       ulib = NULL;
+
+       log_msg("[ ubiupdatevol bootenv id=%d, fp_in=%p", id, fp_in);
 
        /* Workflow:
         * 1. Apply PDD operation and get the size of the returning
@@ -269,43 +389,65 @@ write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old,
 
        rc = ubi_open(&ulib);
        if (rc != 0) {
+               rc = -PFIFLASH_ERR_UBI_OPEN;
+               EBUF(PFIFLASH_ERRSTR[-rc]);
                goto err;
        }
 
        rc = bootenv_create(&bootenv_new);
-       if (rc != 0)
+       if (rc != 0) {
+               rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+               EBUF(PFIFLASH_ERRSTR[-rc], " 'new'");
                goto err;
+       }
+
        rc = bootenv_create(&bootenv_res);
-       if (rc != 0)
+       if (rc != 0) {
+               rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+               EBUF(PFIFLASH_ERRSTR[-rc], " 'res'");
                goto err;
+       }
 
-       rc = bootenv_read(fp_in, bootenv_new, fp_in_size);
-       if (rc != 0)
+       rc = bootenv_read_crc(fp_in, bootenv_new, fp_in_size, &crc);
+       if (rc != 0) {
+               rc = -PFIFLASH_ERR_BOOTENV_READ;
+               EBUF(PFIFLASH_ERRSTR[-rc]);
+               goto err;
+       } else if (crc != pfi_crc) {
+               rc = -PFIFLASH_ERR_CRC_CHECK;
+               EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc);
                goto err;
+       }
 
        rc = pdd_f(bootenv_old, bootenv_new, &bootenv_res, &warnings,
                   err_buf, err_buf_size);
-       if (rc != 0)
+       if (rc != 0) {
+               EBUF_PREPEND("handling PDD");
                goto err;
-       if (warnings) {
-               /* @TODO Do sth with the warning */
+       }
+       else if (warnings)
+               /* TODO do something with warnings */
                dbg_msg("A warning in the PDD operation occured: %d",
                        warnings);
-       }
-       log_msg("... (2)");
 
        rc = bootenv_size(bootenv_res, &update_size);
-       if (rc != 0)
+       if (rc != 0) {
+               rc = -PFIFLASH_ERR_BOOTENV_SIZE;
+               EBUF(PFIFLASH_ERRSTR[-rc]);
                goto err;
+       }
 
        fp_out = ubi_vol_fopen_update(ulib, devno, id, update_size);
-       if (fp_out == NULL)
+       if (!fp_out) {
+               rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
+               EBUF(PFIFLASH_ERRSTR[-rc], id);
                goto err;
+       }
 
        rc = bootenv_write(fp_out, bootenv_res);
        if (rc != 0) {
-               EBUF("Write operation on ubi%d_%d failed.", devno, id);
-               rc = -EIO;
+               rc = -PFIFLASH_ERR_BOOTENV_WRITE;
+               EBUF(PFIFLASH_ERRSTR[-rc], devno, id);
                goto err;
        }
 
@@ -318,102 +460,327 @@ write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old,
                bootenv_destroy(&bootenv_res);
        if (fp_out)
                fclose(fp_out);
+
        return rc;
 }
 
+
+/**
+ * write_normal_volume - writes data from PFI file int to regular UBI volume
+ * @devno      UBI device number
+ * @id         UBI volume id
+ * @update_size        size of data stream
+ * @fp_in      PFI data file pointer
+ * @pfi_crc    CRC data from PFI header
+ *
+ * Error handling:
+ *     when UBI system couldn't be opened
+ *     - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ *     when UBI system couldn't open a volume
+ *     - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err
+ *     when unexpected EOF is encountered
+ *     - returns -PFIFLASH_ERR_EOF, err_buf matches text to err
+ *     when file I/O error
+ *     - returns -PFIFLASH_ERR_FIO, err_buf matches text to err
+ *     when CRC check fails
+ *     - retruns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err
+ **/
 static int
 write_normal_volume(int devno, uint32_t id, size_t update_size, FILE* fp_in,
-                   char *err_buf __unused, size_t err_buf_size __unused)
+                   uint32_t pfi_crc,
+                   char *err_buf, size_t err_buf_size)
 {
-       int rc = 0;
-       ubi_lib_t ulib = NULL;
-       FILE* fp_out = NULL;
-       int c;
-       size_t i;
+       int rc;
+       uint32_t crc, crc32_table[256];
+       size_t bytes_left;
+       FILE* fp_out;
+       ubi_lib_t ulib;
 
-       log_msg("%s(id=%d, update_size=%d fp_in=%p)",
-               __func__, id, update_size, fp_in);
+       rc = 0;
+       crc = UBI_CRC32_INIT;
+       bytes_left = update_size;
+       fp_out = NULL;
+       ulib = NULL;
+
+       log_msg("[ ubiupdatevol id=%d, update_size=%d fp_in=%p",
+               id, update_size, fp_in);
 
        rc = ubi_open(&ulib);
-       if (rc)
-               return rc;
+       if (rc != 0) {
+               rc = -PFIFLASH_ERR_UBI_OPEN;
+               EBUF(PFIFLASH_ERRSTR[-rc]);
+               goto err;
+       }
 
        fp_out = ubi_vol_fopen_update(ulib, devno, id, update_size);
-       if (fp_out == NULL) {
-               rc = -1;
+       if (!fp_out) {
+               rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
+               EBUF(PFIFLASH_ERRSTR[-rc], id);
                goto err;
        }
 
-       log_msg("starting the update ... "); /* FIXME DBG */
-       for (i = 0; i < update_size; i++) {
-               c = getc(fp_in);
-               if (c == EOF && ferror(fp_in)) {
-                       rc = -EIO;
+       init_crc32_table(crc32_table);
+       while (bytes_left) {
+               char buf[1024];
+               size_t to_rw = sizeof buf > bytes_left ?
+                       bytes_left : sizeof buf;
+               if (fread(buf, 1, to_rw, fp_in) != to_rw) {
+                       rc = -PFIFLASH_ERR_EOF;
+                       EBUF(PFIFLASH_ERRSTR[-rc]);
                        goto err;
                }
-               if (putc(c, fp_out) == EOF) {
-                       rc = -EIO;
+               crc = clc_crc32(crc32_table, crc, buf, to_rw);
+               if (fwrite(buf, 1, to_rw, fp_out) != to_rw) {
+                       rc = -PFIFLASH_ERR_FIO;
+                       EBUF(PFIFLASH_ERRSTR[-rc]);
                        goto err;
                }
-               /*  FIXME DBG */
-               /* if ((i & 0xFFF) == 0xFFF) log_msg("."); */
+               bytes_left -= to_rw;
        }
-       /* log_msg("\n"); */            /*  FIXME DBG */
+
+       if (crc != pfi_crc) {
+               rc = -PFIFLASH_ERR_CRC_CHECK;
+               EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc);
+               goto err;
+       }
+
  err:
        if (fp_out)
                fclose(fp_out);
        if (ulib)
                ubi_close(&ulib);
+
        return rc;
 }
 
 
 /**
- * @brief ...
- * @precondition       The PFI file contains at least one ubi_id entry.
- *                     This is assured by the PFI read process.
- * @postcondition      The used seqnum number is set in the UBI PFI
- *                     header list.
- *                     The UBI volumes specified by seqnum are processed.
- */
+ * process_raw_volumes - writes the raw sections of the PFI data
+ * @pfi                PFI data file pointer
+ * @pfi_raws   list of PFI raw headers
+ * @rawdev     device to use to write raw data
+ *
+ * Error handling:
+ *     when early EOF in PFI data
+ *     - returns -PFIFLASH_ERR_EOF, err_buf matches text to err
+ *     when file I/O error
+ *     - returns -PFIFLASH_ERR_FIO, err_buf matches text to err
+ *     when CRC check fails
+ *     - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err
+ *     when opening MTD device fails
+ *     - reutrns -PFIFLASH_ERR_MTD_OPEN, err_buf matches text to err
+ *     when closing MTD device fails
+ *     - returns -PFIFLASH_ERR_MTD_CLOSE, err_buf matches text to err
+ **/
+static int
+process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev,
+                   char* err_buf, size_t err_buf_size)
+{
+       int rc;
+       char *pfi_data;
+       void *i;
+       uint32_t crc, crc32_table[256];
+       size_t j, k;
+       FILE* mtd;
+       list_t ptr;
+
+       if (is_empty(pfi_raws))
+               return 0;
+
+       if (rawdev == NULL)
+               return 0;
+
+       rc = 0;
+
+       log_msg("[ rawupdate dev=%s", rawdev);
+
+       crc = UBI_CRC32_INIT;
+       init_crc32_table(crc32_table);
+
+       /* most likely only one element in list, but just in case */
+       foreach(i, ptr, pfi_raws) {
+               pfi_raw_t r = (pfi_raw_t)i;
+
+               /* read in pfi data */
+               pfi_data = malloc(r->data_size * sizeof(char));
+               for (j = 0; j < r->data_size; j++) {
+                       int c = fgetc(pfi);
+                       if (c == EOF) {
+                               rc = -PFIFLASH_ERR_EOF;
+                               EBUF(PFIFLASH_ERRSTR[-rc]);
+                               goto err;
+                       } else if (ferror(pfi)) {
+                               rc = -PFIFLASH_ERR_FIO;
+                               EBUF(PFIFLASH_ERRSTR[-rc]);
+                               goto err;
+                       }
+                       pfi_data[j] = (char)c;
+               }
+               crc = clc_crc32(crc32_table, crc, pfi_data, r->data_size);
+
+               /* check crc */
+               if (crc != r->crc) {
+                       rc = -PFIFLASH_ERR_CRC_CHECK;
+                       EBUF(PFIFLASH_ERRSTR[-rc], r->crc, crc);
+                       goto err;
+               }
+
+               /* open device */
+               mtd = fopen(rawdev, "r+");
+               if (mtd == NULL) {
+                       rc = PFIFLASH_ERR_MTD_OPEN;
+                       EBUF(PFIFLASH_ERRSTR[-rc], rawdev);
+                       goto err;
+               }
+
+               for (j = 0; j < r->starts_size; j++) {
+                       fseek(mtd, r->starts[j], SEEK_SET);
+                       for (k = 0; k < r->data_size; k++) {
+                               int c = fputc((int)pfi_data[k], mtd);
+                               if (c == EOF) {
+                                       fclose(mtd);
+                                       rc = -PFIFLASH_ERR_EOF;
+                                       EBUF(PFIFLASH_ERRSTR[-rc]);
+                                       return rc;
+                               }
+                               if ((char)c != pfi_data[k]) {
+                                       fclose(mtd);
+                                       return -1;
+                               }
+                       }
+               }
+               rc = fclose(mtd);
+               if (rc != 0) {
+                       rc = -PFIFLASH_ERR_MTD_CLOSE;
+                       EBUF(PFIFLASH_ERRSTR[-rc], rawdev);
+                       goto err;
+               }
+       }
+
+ err:
+       return rc;
+}
+
+
+/**
+ * erase_unmapped_ubi_volumes - skip volumes provided by PFI file, clear rest
+ * @devno      UBI device number
+ * @pfi_ubis   list of UBI header data
+ *
+ * Error handling:
+ *     when UBI id is out of bounds
+ *     - returns -PFIFLASH_ERR_UBI_VID_OOB, err_buf matches text to err
+ *     when UBI volume can't be removed
+ *     - passes rc, prepends err_buf with contextual aid
+ **/
+static int
+erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis,
+                          char *err_buf, size_t err_buf_size)
+{
+       int rc;
+       uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES];
+       size_t i;
+       list_t ptr;
+       pfi_ubi_t u;
+
+       rc = 0;
+
+       for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++)
+               ubi_volumes[i] = 1;
+
+       foreach(u, ptr, pfi_ubis) {
+               /* iterate over each vol_id */
+               for(i = 0; i < u->ids_size; i++) {
+                       if (u->ids[i] > PFI_UBI_MAX_VOLUMES) {
+                               rc = -PFIFLASH_ERR_UBI_VID_OOB;
+                               EBUF(PFIFLASH_ERRSTR[-rc], u->ids[i]);
+                               goto err;
+                       }
+                       /* remove from removal list */
+                       ubi_volumes[u->ids[i]] = 0;
+               }
+       }
+
+       for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) {
+               if (ubi_volumes[i]) {
+                       rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size);
+                       if (rc != 0) {
+                               EBUF_PREPEND("remove volume failed");
+                               goto err;
+                       }
+               }
+       }
+
+ err:
+       return rc;
+}
+
+
+/**
+ * process_ubi_volumes - delegate tasks regarding UBI volumes
+ * @pfi                        PFI data file pointer
+ * @seqnum             sequence number
+ * @pfi_ubis           list of UBI header data
+ * @bootenv_old                storage for current system PDD
+ * @pdd_f              function to handle PDD
+ * @ubi_update_process whether reading or writing
+ *
+ * Error handling:
+ *     when and unknown ubi_update_process is given
+ *     - returns -PFIFLASH_ERR_UBI_UNKNOWN, err_buf matches text to err
+ *     otherwise
+ *     - passes rc and err_buf
+ **/
 static int
 process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis,
                    bootenv_t bootenv_old, pdd_func_t pdd_f,
                    ubi_update_process_t ubi_update_process,
                    char *err_buf, size_t err_buf_size)
 {
-       int rc = 0;
+       int rc;
        pfi_ubi_t u;
        list_t ptr;
 
+       rc = 0;
+
        foreach(u, ptr, pfi_ubis) {
                int s = seqnum;
-               if (seqnum > ((int)u->ids_size - 1)) {
+
+               if (s > ((int)u->ids_size - 1))
                        s = 0; /* per default use the first */
-               }
                u->curr_seqnum = s;
 
                switch (ubi_update_process) {
                case UBI_REMOVE:
+                       /* TODO are all these "EXAMPLE" vars okay? */
                        if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) ||
                            (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) {
-                               rc =read_bootenv_volume(EXAMPLE_UBI_DEVICE,
-                                                       u->ids[s],
-                                                       bootenv_old, err_buf,
-                                                       err_buf_size);
+                               rc = read_bootenv_volume(EXAMPLE_UBI_DEVICE,
+                                                        u->ids[s], bootenv_old,
+                                                        err_buf, err_buf_size);
+                               /* it's okay if there is no bootenv
+                                * we're going to write one */
+                               if ((rc == -PFIFLASH_ERR_UBI_VOL_FOPEN) ||
+                                   (rc == -PFIFLASH_ERR_BOOTENV_READ))
+                                       rc = 0;
                                if (rc != 0)
                                        goto err;
-                               }
-                       rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE,  u->ids[s],
+                       }
+
+                       rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE, u->ids[s],
                                          err_buf, err_buf_size);
                        if (rc != 0)
                                goto err;
+
                        break;
                case UBI_WRITE:
                        rc = my_ubi_mkvol(EXAMPLE_UBI_DEVICE, s, u,
                                          err_buf, err_buf_size);
-                       if (rc != 0)
+                       if (rc != 0) {
+                               EBUF_PREPEND("creating volume");
                                goto err;
+                       }
+
                        if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) ||
                            (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) {
                                rc = write_bootenv_volume(EXAMPLE_UBI_DEVICE,
@@ -421,87 +788,67 @@ process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis,
                                                          bootenv_old, pdd_f,
                                                          pfi,
                                                          u->data_size,
+                                                         u->crc,
                                                          err_buf,
                                                          err_buf_size);
-                       }
-                       else {
+                               if (rc != 0)
+                                       EBUF_PREPEND("bootenv volume");
+                       } else {
                                rc = write_normal_volume(EXAMPLE_UBI_DEVICE,
                                                         u->ids[s],
                                                         u->data_size, pfi,
+                                                        u->crc,
                                                         err_buf,
                                                         err_buf_size);
+                               if (rc != 0)
+                                       EBUF_PREPEND("normal volume");
                        }
                        if (rc != 0)
                                goto err;
+
                        break;
                default:
-                       EBUF("Invoked unknown UBI operation.");
-                       rc = -1;
-                       goto err;
-
-               }
-               if (rc != 0) {
+                       rc = -PFIFLASH_ERR_UBI_UNKNOWN;
+                       EBUF(PFIFLASH_ERRSTR[-rc]);
                        goto err;
                }
        }
- err:
-       return rc;
-
-}
-
-static int
-erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis,
-                          char *err_buf, size_t err_buf_size)
-{
-       int rc = 0;
-       list_t ptr;
-       pfi_ubi_t u;
-       size_t i;
-       uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES];
-
-       for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) {
-               ubi_volumes[i] = 1;
-       }
-
-       foreach(u, ptr, pfi_ubis) {
-               /* iterate over each vol_id */
-               for(i = 0; i < u->ids_size; i++) {
-                       if (u->ids[i] > PFI_UBI_MAX_VOLUMES) {
-                               EBUF("PFI file contains an invalid "
-                                    "volume id: %d", u->ids[i]);
-                               goto err;
-                       }
-                       /* remove from removal list */
-                       ubi_volumes[u->ids[i]] = 0;
-               }
-       }
 
-       for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) {
-               if (ubi_volumes[i]) {
-                       rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size);
-                       if (rc != 0)
-                               goto err;
-               }
-       }
  err:
        return rc;
 }
 
+
+/**
+ * mirror_ubi_volumes - mirror redundant pairs of volumes
+ * @devno      UBI device number
+ * @pfi_ubis   list of PFI header data
+ *
+ * Error handling:
+ *     when UBI system couldn't be opened
+ *     - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ **/
 static int
 mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis,
                   char *err_buf, size_t err_buf_size)
 {
-       int rc = 0;
-       list_t ptr;
+       int rc;
        uint32_t j;
+       list_t ptr;
        pfi_ubi_t i;
-       ubi_lib_t  ulib = NULL;
+       ubi_lib_t ulib;
 
-       log_msg("%s(...)", __func__);
+       rc = 0;
+       ulib = NULL;
+
+       log_msg("[ mirror ...");
 
        rc = ubi_open(&ulib);
-       if (rc != 0)
+       if (rc != 0) {
+               rc = -PFIFLASH_ERR_UBI_OPEN;
+               EBUF(PFIFLASH_ERRSTR[-rc]);
                goto err;
+       }
 
        /**
         * Execute all mirror operations on redundant groups.
@@ -510,25 +857,26 @@ mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis,
         * ubimirror).
         */
        foreach(i, ptr, pfi_ubis) {
-               for(j = 0; j < i->ids_size; j++) {
+               for (j = 0; j < i->ids_size; j++) {
                        /* skip self-match */
                        if (i->ids[j] == i->ids[i->curr_seqnum])
                                continue;
 
-                       rc = my_ubi_rmvol(devno, i->ids[j], err_buf,
-                                         err_buf_size);
+                       rc = my_ubi_rmvol(devno, i->ids[j],
+                                         err_buf, err_buf_size);
                        if (rc != 0)
                                goto err;
 
-                       rc = my_ubi_mkvol(devno, j, i, err_buf, err_buf_size);
+                       rc = my_ubi_mkvol(devno, j, i,
+                                         err_buf, err_buf_size);
                        if (rc != 0)
                                goto err;
                }
        }
 
        foreach(i, ptr, pfi_ubis) {
-               rc = ubimirror(devno, i->curr_seqnum, i->ids,
-                              i->ids_size, err_buf, err_buf_size);
+               rc = ubimirror(devno, i->curr_seqnum, i->ids, i->ids_size,
+                              err_buf, err_buf_size);
                if (rc != 0)
                        goto err;
        }
@@ -537,44 +885,71 @@ mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis,
  err:
        if (ulib != NULL)
                ubi_close(&ulib);
+
        return rc;
 }
 
+
+/**
+ * pfiflash_with_raw - exposed func to flash memory with a PFI file
+ * @pfi                        PFI data file pointer
+ * @complete           flag to erase unmapped volumes
+ * @seqnum             sequence number
+ * @pdd_handling       method to handle pdd (keep, merge, overwrite...)
+ *
+ * Error handling:
+ *     when bootenv can't be created
+ *     - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err
+ *     when PFI headers can't be read, or
+ *     when fail to skip raw sections, or
+ *     when error occurs while processing raw volumes, or
+ *     when fail to erase unmapped UBI vols, or
+ *     when error occurs while processing UBI volumes, or
+ *     when error occurs while mirroring UBI volumes
+ *     - passes rc, prepends err_buf with contextual aid
+ **/
 int
-pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling,
-        char *err_buf, size_t err_buf_size)
+pfiflash_with_raw(FILE* pfi, int complete, int seqnum,
+                 pdd_handling_t pdd_handling, const char* rawdev,
+                 char *err_buf, size_t err_buf_size)
 {
-       int rc = 0;
-       pdd_func_t pdd_f = NULL;
+       int rc;
+       bootenv_t bootenv;
+       pdd_func_t pdd_f;
 
        if (pfi == NULL)
                return -EINVAL;
 
-       /**
-        * If the user didnt specify a seqnum we start per default
-        * with the index 0
-        */
+       rc = 0;
+       pdd_f = NULL;
+
+       /* If the user didnt specify a seqnum we start per default
+        * with the index 0 */
        int curr_seqnum = seqnum < 0 ? 0 : seqnum;
 
        list_t pfi_raws   = mk_empty(); /* list of raw sections from a pfi */
        list_t pfi_ubis   = mk_empty(); /* list of ubi sections from a pfi */
 
-       bootenv_t bootenv;
        rc = bootenv_create(&bootenv);
        if (rc != 0) {
-               EBUF("Cannot create bootenv variable");
+               rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+               EBUF(PFIFLASH_ERRSTR[-rc], "");
+               goto err;
        }
 
-       rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi,
-                             err_buf, err_buf_size);
+       rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi, err_buf, err_buf_size);
        if (rc != 0) {
-               EBUF("Cannot read PFI headers.");
+               EBUF_PREPEND("reading PFI header");
                goto err;
        }
 
-       /* @TODO: If you want to implement an IPL update - start here. */
-       rc = skip_raw_sections(pfi, pfi_raws, err_buf, err_buf_size);
+       if (rawdev == NULL)
+               rc = skip_raw_volumes(pfi, pfi_raws, err_buf, err_buf_size);
+       else
+               rc = process_raw_volumes(pfi, pfi_raws, rawdev, err_buf,
+                                        err_buf_size);
        if (rc != 0) {
+               EBUF_PREPEND("handling raw section");
                goto err;
        }
 
@@ -582,33 +957,41 @@ pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling,
                rc = erase_unmapped_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis,
                                                err_buf, err_buf_size);
                if (rc != 0) {
-                       EBUF("Cannot delete unmapped UBI volumes.");
+                       EBUF_PREPEND("deleting unmapped UBI volumes");
                        goto err;
                }
        }
 
-       if (((int)pdd_handling >= 0) && (pdd_handling < PDD_HANDLING_NUM)) {
+       if (((int)pdd_handling >= 0) &&
+           (pdd_handling < PDD_HANDLING_NUM))
                pdd_f = pdd_funcs[pdd_handling];
-       }
        else {
-               EBUF("Used unknown PDD handling algorithm (pdd_handling)");
+               rc = -PFIFLASH_ERR_PDD_UNKNOWN;
+               EBUF(PFIFLASH_ERRSTR[-rc]);
+               goto err;
        }
 
        rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, pdd_f,
                                 UBI_REMOVE, err_buf, err_buf_size);
-       if  (rc != 0) {
+       if (rc != 0) {
+               EBUF_PREPEND("removing UBI volumes");
                goto err;
        }
+
        rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, pdd_f,
                                 UBI_WRITE, err_buf, err_buf_size);
        if  (rc != 0) {
+               EBUF_PREPEND("writing UBI volumes");
                goto err;
        }
+
        if (seqnum < 0) { /* mirror redundant pairs */
                rc = mirror_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis,
                                        err_buf, err_buf_size);
-               if (rc != 0)
+               if (rc != 0) {
+                       EBUF_PREPEND("mirroring UBI volumes");
                        goto err;
+               }
        }
 
  err:
@@ -617,3 +1000,19 @@ pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling,
        bootenv_destroy(&bootenv);
        return rc;
 }
+
+
+/**
+ * pfiflash - passes to pfiflash_with_raw
+ * @pfi                        PFI data file pointer
+ * @complete           flag to erase unmapped volumes
+ * @seqnum             sequence number
+ * @pdd_handling       method to handle pdd (keep, merge, overwrite...)
+ **/
+int
+pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling,
+        char *err_buf, size_t err_buf_size)
+{
+       return pfiflash_with_raw(pfi, complete, seqnum, pdd_handling,
+                                NULL, err_buf, err_buf_size);
+}
index 04f62dffefe367ff1f00b2123c00ae3a689cc830..c49fb1ea27c5e1367ba71e611ce005519fb7e664 100644 (file)
@@ -21,6 +21,8 @@
  * Process a PFI (partial flash image) and write the data to the
  * specified UBI volumes. This tool is intended to be used for system
  * update using PFI files.
+ *
+ * 1.1 fixed output to stderr and stdout in logfile mode.
  */
 
 #include <unistd.h>
 #include <errno.h>
 
 #include <pfiflash.h>
+#undef DEBUG
 #include "error.h"
 #include "config.h"
 
-const char *argp_program_version = PACKAGE_VERSION;
+#define PROGRAM_VERSION  "1.2"
+
+const char *argp_program_version = PROGRAM_VERSION;
 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
-static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on "
+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\tBuilt on "
        BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n"
        "\n"
        "pfiflash - a tool for updating a controller with PFI files.\n";
@@ -83,12 +88,17 @@ static struct argp_option options[] = {
          "'keep', 'merge' or 'overwrite'.",
          group: 2 },
 
+       { name: "raw-flash", key: 'r', arg: "<dev>", flags: 0,
+         doc: "Flash the raw data. Use the specified mtd device.",
+         group: 2 },
+
        { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 },
 };
 
 typedef struct myargs {
        int verbose;
        const char *logfile;
+       const char *raw_dev;
 
        pdd_handling_t pdd_handling;
        int seqnum;
@@ -168,7 +178,9 @@ parse_opt(int key, char *arg, struct argp_state *state)
                                 "Supported sides are '0' and '1'\n", arg);
                }
                break;
-
+       case 'r':
+               args->raw_dev = arg;
+               break;
        case ARGP_KEY_ARG: /* input file */
                args->fp_in = fopen(arg, "r");
                if ((args->fp_in) == NULL) {
@@ -212,9 +224,10 @@ int main (int argc, char** argv)
                .verbose    = 0,
                .seqnum     = -1,
                .complete   = 0,
-               .logfile    = "/tmp/pfiflash.log",
+               .logfile    = NULL, /* "/tmp/pfiflash.log", */
                .pdd_handling = PDD_KEEP,
-               .fp_in    = stdin,
+               .fp_in      = stdin,
+               .raw_dev    = NULL,
        };
 
        argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args);
@@ -227,8 +240,16 @@ int main (int argc, char** argv)
                goto err;
        }
 
-       rc = pfiflash(args.fp_in, args.complete, args.seqnum,
-                     args.pdd_handling, err_buf, PFIFLASH_MAX_ERR_BUF_SIZE);
+       if (!args.raw_dev) {
+               rc = pfiflash(args.fp_in, args.complete, args.seqnum,
+                             args.pdd_handling, err_buf,
+                             PFIFLASH_MAX_ERR_BUF_SIZE);
+       } else {
+               rc = pfiflash_with_raw(args.fp_in, args.complete, args.seqnum,
+                             args.pdd_handling, args.raw_dev, err_buf,
+                             PFIFLASH_MAX_ERR_BUF_SIZE);
+       }
+
        if (rc != 0) {
                goto err_fp;
        }
@@ -238,6 +259,6 @@ int main (int argc, char** argv)
                fclose(args.fp_in);
  err:
        if (rc != 0)
-               err_msg("Error: %s\nrc: %d\n", err_buf, rc);
+               err_msg("pfiflash: %s\nrc: %d\n", err_buf, rc);
        return rc;
 }
index fc2eedefb92b3d0bd97afeb8ba60f0a82e50706d..a063e7f7fd16e2ad73c3c23007bfb23ddaf0f035 100644 (file)
@@ -44,6 +44,19 @@ typedef enum pdd_handling_t
        PDD_HANDLING_NUM, /* always the last item */
 } pdd_handling_t; /**< Possible PDD handle algorithms. */
 
+/**
+ * @brief Flashes a PFI file to UBI Device 0.
+ * @param complete     [0|1] Do a complete system update.
+ * @param seqnum       Index in a redundant group.
+ * @param pdd_handling The PDD handling algorithm.
+ * @param rawdev       Device to use for raw flashing
+ * @param err_buf      An error buffer.
+ * @param err_buf_size Size of the error buffer.
+ */
+int pfiflash_with_raw(FILE* pfi, int complete, int seqnum,
+               pdd_handling_t pdd_handling, const char* rawdev,
+               char *err_buf, size_t err_buf_size);
+
 /**
  * @brief Flashes a PFI file to UBI Device 0.
  * @param complete     [0|1] Do a complete system update.
diff --git a/ubi-utils/src/pfiflash_error.h b/ubi-utils/src/pfiflash_error.h
new file mode 100644 (file)
index 0000000..34b705e
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef __PFIFLASH_ERROR_H__
+#define __PFIFLASH_ERROR_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Author: Drake Dowsett <dowsett@de.ibm.com>
+ * Contact: Andreas Arnez <arnez@de.ibm.com>
+ */
+
+enum pfiflash_err {
+       PFIFLASH_ERR_EOF = 1,
+       PFIFLASH_ERR_FIO,
+       PFIFLASH_ERR_UBI_OPEN,
+       PFIFLASH_ERR_UBI_CLOSE,
+       PFIFLASH_ERR_UBI_MKVOL,
+       PFIFLASH_ERR_UBI_RMVOL,
+       PFIFLASH_ERR_UBI_VOL_UPDATE,
+       PFIFLASH_ERR_UBI_VOL_FOPEN,
+       PFIFLASH_ERR_UBI_UNKNOWN,
+       PFIFLASH_ERR_UBI_VID_OOB,
+       PFIFLASH_ERR_BOOTENV_CREATE,
+       PFIFLASH_ERR_BOOTENV_READ,
+       PFIFLASH_ERR_BOOTENV_SIZE,
+       PFIFLASH_ERR_BOOTENV_WRITE,
+       PFIFLASH_ERR_PDD_UNKNOWN,
+       PFIFLASH_ERR_MTD_OPEN,
+       PFIFLASH_ERR_MTD_CLOSE,
+       PFIFLASH_ERR_CRC_CHECK
+};
+
+const char *const PFIFLASH_ERRSTR[] = {
+       "",
+       "unexpected EOF",
+       "file I/O error",
+       "couldn't open UBI",
+       "couldn't close UBI",
+       "couldn't make UBI volume %d",
+       "couldn't remove UBI volume %d",
+       "couldn't update UBI volume %d",
+       "couldn't open UBI volume %d",
+       "unknown UBI operation",
+       "PFI data contains out of bounds UBI id %d",
+       "couldn't create bootenv%s",
+       "couldn't read bootenv",
+       "couldn't resize bootenv",
+       "couldn't write bootenv on ubi%d_%d",
+       "unknown PDD handling algorithm",
+       "couldn't open MTD device %s",
+       "couldn't close MTD device %s",
+       "CRC check failed: given=0x%08x, calculated=0x%08x"
+};
+
+#endif /* __PFIFLASH_ERROR_H__ */
index 5de06d549e49dbb811add7c36d0aaeab8bb618ff..975caa18e8c53541d5351a85fcd9183ed298ebb8 100644 (file)
 #include <stdlib.h>
 #include <errno.h>
 
-#include "config.h"
 #include "bootenv.h"
 #include "reader.h"
 
+#define __unused __attribute__((unused))
+
 /* @FIXME hard coded offsets right now - get them from Artem? */
 #define NAND2048_DEFAULT_VID_HDR_OFF 1984
 #define NAND512_DEFAULT_VID_HDR_OFF  448
@@ -152,6 +153,12 @@ read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_raw_t* pfi_raw,
                goto err;
        }
 
+       rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc));
+       if (rc != 0) {
+               EBUF_PFI("Cannot read 'crc' from PFI.");
+               goto err;
+       }
+
        rc = pfi_header_getstring(pfi_hd, "raw_starts",
                                  tmp_str, PFI_KEYWORD_LEN);
        if (rc != 0) {
@@ -212,6 +219,12 @@ read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_ubi_t* pfi_ubi,
                goto err;
        }
 
+       rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc));
+       if (rc != 0) {
+               EBUF_PFI("Cannot read 'crc' from PFI.");
+               goto err;
+       }
+
        rc = pfi_header_getstring(pfi_hd, "ubi_ids", tmp_str, PFI_KEYWORD_LEN);
        if (rc != 0) {
                EBUF_PFI("Cannot read 'ubi_ids' from PFI.");
index d00fa171a23ec963a836176e872bf2a2f230bcfd..715e4641c836affaed9046cd169f4a1112794a12 100644 (file)
@@ -50,6 +50,7 @@ struct pfi_raw {
        uint32_t data_size;
        uint32_t *starts;
        uint32_t starts_size;
+       uint32_t crc;
 };
 
 struct pfi_ubi {
@@ -63,6 +64,7 @@ struct pfi_ubi {
        enum { pfi_ubi_dynamic, pfi_ubi_static } type;
        int curr_seqnum; /* specifies the seqnum taken in an update,
                            default: 0 (used by pfiflash, ubimirror) */
+       uint32_t crc;
 };
 
 int read_pdd_data(FILE* fp_pdd, pdd_data_t *pdd_data,