aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrake Dowsett <dowsett@de.ibm.com>2006-11-06 16:54:10 +0100
committerFrank Haverkamp <haver@vnet.ibm.com>2006-11-06 16:54:10 +0100
commit31b015fc08a13a5b63245808f7d1a49eadd8193a (patch)
tree6ab4ce9a35f18e7b53c95c5cb8063cc55e54615d
parent6918e0320c89bc892a6c5d2c6792e5d058e40a6e (diff)
[MTD] UBI: pfiflash needs to flash raw sections and check CRC
Flashing of raw partitions should be possible now. CRC checking of pfi files before flashing the content was added. Signed-off-by: Frank Haverkamp <haver@vnet.ibm.com>
-rw-r--r--ubi-utils/Makefile8
-rw-r--r--ubi-utils/src/bootenv.c105
-rw-r--r--ubi-utils/src/bootenv.h9
-rw-r--r--ubi-utils/src/error.c67
-rw-r--r--ubi-utils/src/error.h2
-rw-r--r--ubi-utils/src/libpfiflash.c841
-rw-r--r--ubi-utils/src/pfiflash.c37
-rw-r--r--ubi-utils/src/pfiflash.h13
-rw-r--r--ubi-utils/src/pfiflash_error.h69
-rw-r--r--ubi-utils/src/reader.c15
-rw-r--r--ubi-utils/src/reader.h2
11 files changed, 890 insertions, 278 deletions
diff --git a/ubi-utils/Makefile b/ubi-utils/Makefile
index 6161f3d..2776c07 100644
--- a/ubi-utils/Makefile
+++ b/ubi-utils/Makefile
@@ -48,15 +48,15 @@ ubirmvol: ubirmvol.o error.o libubi.o libubi_sysfs.o
$(CC) $(LDFLAGS) -o $@ $^
pddcustomize: pddcustomize.o error.o libubimirror.o bootenv.o hashmap.o \
- libubi.o libubi_sysfs.o
+ libubi.o libubi_sysfs.o crc32.o
$(CC) $(LDFLAGS) -o $@ $^
pfiflash: pfiflash.o libpfiflash.o list.o reader.o error.o libubimirror.o \
- bootenv.o hashmap.o pfi.o libubi.o libubi_sysfs.o
+ bootenv.o hashmap.o pfi.o libubi.o libubi_sysfs.o crc32.o
$(CC) $(LDFLAGS) -o $@ $^
ubimirror: ubimirror.o error.o libubimirror.o bootenv.o hashmap.o \
- libubi.o libubi_sysfs.o
+ libubi.o libubi_sysfs.o crc32.o
$(CC) $(LDFLAGS) -o $@ $^
nand2bin: nand2bin.o nandecc.o nandcorr.o
@@ -68,7 +68,7 @@ bin2nand: bin2nand.o error.o nandecc.o
ubigen: ubigen.o libubigen.o crc32.o
$(CC) $(LDFLAGS) -o $@ $^
-mkbootenv: mkbootenv.o bootenv.o hashmap.o error.o
+mkbootenv: mkbootenv.o bootenv.o hashmap.o error.o crc32.o
$(CC) $(LDFLAGS) -o $@ $^
unubi: unubi.o crc32.o
diff --git a/ubi-utils/src/bootenv.c b/ubi-utils/src/bootenv.c
index 8871d90..ed15dc7 100644
--- a/ubi-utils/src/bootenv.c
+++ b/ubi-utils/src/bootenv.c
@@ -27,10 +27,14 @@
#include <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;
@@ -457,6 +474,12 @@ err:
}
int
+bootenv_write(FILE* fp, bootenv_t env)
+{
+ return bootenv_write_crc(fp, env, NULL);
+}
+
+int
bootenv_size(bootenv_t env, size_t *size)
{
int rc = 0;
diff --git a/ubi-utils/src/bootenv.h b/ubi-utils/src/bootenv.h
index 86743ed..9003d70 100644
--- a/ubi-utils/src/bootenv.h
+++ b/ubi-utils/src/bootenv.h
@@ -230,6 +230,10 @@ int bootenv_size(bootenv_t env, size_t *size);
*/
int bootenv_read(FILE* fp, bootenv_t env, size_t size);
+/**
+ * @param ret_crc return value of crc of read data
+ */
+int bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t *ret_crc);
/**
* @brief Read bootenv data from an text/ascii file.
@@ -250,6 +254,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.
* @param env Bootenv structure which shall be written.
diff --git a/ubi-utils/src/error.c b/ubi-utils/src/error.c
index c8c623c..4aaedad 100644
--- a/ubi-utils/src/error.c
+++ b/ubi-utils/src/error.c
@@ -25,6 +25,7 @@
#include "error.h"
#define MAXLINE 4096
+#define MAXWIDTH 80
static FILE *logfp = NULL;
@@ -35,6 +36,9 @@ read_procfile(FILE *fp_out, const char *procfile)
{
FILE *fp;
+ if (!fp_out)
+ return -ENXIO;
+
fp = fopen(procfile, "r");
if (!fp)
return -ENOENT;
@@ -57,6 +61,9 @@ read_procfile(FILE *fp_out, const char *procfile)
void
error_initlog(const char *logfile)
{
+ if (!logfile)
+ return;
+
logfp = fopen(logfile, "a+");
read_procfile(logfp, "/proc/cpuinfo");
}
@@ -143,7 +150,11 @@ __err_dump(const char *fmt, ...)
exit(EXIT_FAILURE); /* shouldn't get here */
}
-
+/**
+ * If a logfile is used we must not print on stderr and stdout
+ * anymore. Since pfilfash might be used in a server context, it is
+ * even dangerous to write to those descriptors.
+ */
static void
err_doit(int errnoflag, int level __attribute__((unused)),
const char *fmt, va_list ap)
@@ -166,9 +177,61 @@ err_doit(int errnoflag, int level __attribute__((unused)),
if (logfp) {
fputs(buf, logfp);
fflush(logfp);
+ return; /* exit when logging completes */
}
- fputs(buf, fpout);
+ if (fpout == stderr) {
+ /* perform line wrap when outputting to stderr */
+ int word_len, post_len, chars;
+ char *buf_ptr;
+ const char *frmt = "%*s%n %n";
+
+ chars = 0;
+ buf_ptr = buf;
+ while (sscanf(buf_ptr, frmt, &word_len, &post_len) != EOF) {
+ int i;
+ char word[word_len + 1];
+ char post[post_len + 1];
+
+ strncpy(word, buf_ptr, word_len);
+ word[word_len] = '\0';
+ buf_ptr += word_len;
+ post_len -= word_len;
+
+ if (chars + word_len > MAXWIDTH) {
+ fputc('\n', fpout);
+ chars = 0;
+ }
+ fputs(word, fpout);
+ chars += word_len;
+
+ if (post_len > 0) {
+ strncpy(post, buf_ptr, post_len);
+ post[post_len] = '\0';
+ buf_ptr += post_len;
+ }
+ for (i = 0; i < post_len; i++) {
+ int inc = 1, chars_new;
+
+ if (post[i] == '\t')
+ inc = 8;
+ if (post[i] == '\n') {
+ inc = 0;
+ chars_new = 0;
+ } else
+ chars_new = chars + inc;
+
+ if (chars_new > MAXWIDTH) {
+ fputc('\n', fpout);
+ chars_new = inc;
+ }
+ fputc(post[i], fpout);
+ chars = chars_new;
+ }
+ }
+ }
+ else
+ fputs(buf, fpout);
fflush(fpout);
if (fpout != stderr)
fclose(fpout);
diff --git a/ubi-utils/src/error.h b/ubi-utils/src/error.h
index e8d7137..05d8078 100644
--- a/ubi-utils/src/error.h
+++ b/ubi-utils/src/error.h
@@ -78,7 +78,7 @@ void info_msg(const char *fmt, ...);
__err_msg(fmt, ##__VA_ARGS__); \
} while (0)
#else
-#define dbg_msg(fmt, ...)
+#define dbg_msg(fmt, ...) do {} while (0)
#endif
#endif /* __ERROR_H__ */
diff --git a/ubi-utils/src/libpfiflash.c b/ubi-utils/src/libpfiflash.c
index ed2af3c..1dc9f10 100644
--- a/ubi-utils/src/libpfiflash.c
+++ b/ubi-utils/src/libpfiflash.c
@@ -16,16 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/**
- * @file pfiflash.c
- *
- * @author Oliver Lohmann <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.
@@ -40,89 +37,130 @@
#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 0 */
rc = ubi_vol_update(fd, 0);
+ ubi_vol_close(fd);
if (rc < 0) {
- fprintf(stderr, "update failed rc=%d errno=%d\n", rc, errno);
- ubi_vol_close(fd);
+ rc = -PFIFLASH_ERR_UBI_VOL_UPDATE;
+ EBUF(PFIFLASH_ERRSTR[-rc], id);
goto err; /* if EBUSY than empty device, continue */
}
- ubi_vol_close(fd);
rc = ubi_rmvol(ulib, devno, id);
if (rc != 0) {
- /* @TODO Define a ubi_rmvol return value which says
+#ifdef DEBUG
+ int rc_old = rc;
+ dbg_msg("Remove UBI volume %d returned with error: %d "
+ "errno=%d", id, rc_old, errno);
+#endif
+
+ rc = -PFIFLASH_ERR_UBI_RMVOL;
+ EBUF(PFIFLASH_ERRSTR[-rc], id);
+
+ /* TODO Define a ubi_rmvol return value which says
* sth like EUBI_NOSUCHDEV. In this case, a failed
* operation is acceptable. Everything else has to be
* classified as real error. But talk to Andreas Arnez
@@ -198,65 +255,128 @@ my_ubi_rmvol(int devno, uint32_t id,
/* if ((errno == EINVAL) || (errno == ENODEV))
return 0; */ /* currently it is EINVAL or ENODEV */
- dbg_msg("Remove UBI volume %d returned with error: %d "
- "errno=%d", id, rc, errno);
goto err;
}
+
err:
if (ulib != NULL)
ubi_close(&ulib);
+
return rc;
}
+
+/**
+ * read_bootenv_volume - reads the current bootenv data from id into be_old
+ * @devno UBI device number
+ * @id UBI volume id to remove
+ * @bootenv_old to hold old boot_env data
+ *
+ * Error handling:
+ * when UBI system couldn't be opened
+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ * when UBI system couldn't open a volume to read
+ * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err
+ * when couldn't read bootenv data
+ * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err
+ **/
static int
read_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old,
char *err_buf, size_t err_buf_size)
{
- int rc = 0;
- ubi_lib_t ulib = NULL;
- FILE* fp_in = NULL;
+ int rc;
+ FILE* fp_in;
+ ubi_lib_t ulib;
+
+ rc = 0;
+ fp_in = NULL;
+ ulib = NULL;
rc = ubi_open(&ulib);
- if (rc)
- return rc;
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_UBI_OPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
fp_in = ubi_vol_fopen_read(ulib, devno, id);
if (!fp_in) {
- EBUF("Cannot open bootenv volume");
- rc = -EIO;
+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc], id);
goto err;
}
- log_msg("%s reading old bootenvs", __func__);
+ log_msg("[ reading old bootenvs ...");
/* Save old bootenvs for reference */
rc = bootenv_read(fp_in, bootenv_old, BOOTENV_MAXSIZE);
- if (rc)
- EBUF("Cannot read bootenv_old");
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_READ;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+
err:
if (fp_in)
fclose(fp_in);
if (ulib)
ubi_close(&ulib);
+
return rc;
}
+
+/**
+ * write_bootenv_volume - writes data from PFI file int to bootenv UBI volume
+ * @devno UBI device number
+ * @id UBI volume id
+ * @bootend_old old PDD data from machine
+ * @pdd_f function to handle PDD with
+ * @fp_in new pdd data contained in PFI
+ * @fp_in_size data size of new pdd data in PFI
+ * @pfi_crc crc value from PFI header
+ *
+ * Error handling:
+ * when UBI system couldn't be opened
+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ * when bootenv can't be created
+ * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err
+ * when bootenv can't be read
+ * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err
+ * when PDD handling function returns and error
+ * - passes rc and err_buf data
+ * when CRC check fails
+ * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err
+ * when bootenv can't be resized
+ * - returns -PFIFLASH_ERR_BOOTENV_SIZE, err_buf matches text to err
+ * when UBI system couldn't open a volume
+ * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err
+ * when couldn't write bootenv data
+ * - returns -PFIFLASH_ERR_BOOTENV_WRITE, err_buf matches text to err
+ **/
static int
write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old,
- pdd_func_t pdd_f,
- FILE* fp_in, /* new pdd data contained in pfi */
- size_t fp_in_size, /* data size of new pdd data in pfi */
+ pdd_func_t pdd_f, FILE* fp_in, size_t fp_in_size,
+ uint32_t pfi_crc,
char *err_buf, size_t err_buf_size)
{
- int rc = 0;
- int warnings = 0;
- ubi_lib_t ulib = NULL;
- bootenv_t bootenv_new = NULL;
- bootenv_t bootenv_res = NULL;
- size_t update_size = 0;
- FILE *fp_out = NULL;
-
- log_msg("%s(id=%d, fp_in=%p)", __func__, id, fp_in);
+ int rc, warnings;
+ uint32_t crc;
+ size_t update_size;
+ FILE *fp_out;
+ bootenv_t bootenv_new, bootenv_res;
+ ubi_lib_t ulib;
+
+ rc = 0;
+ warnings = 0;
+ crc = 0;
+ update_size = 0;
+ fp_out = NULL;
+ bootenv_new = NULL;
+ bootenv_res = NULL;
+ ulib = NULL;
+
+ log_msg("[ ubiupdatevol bootenv id=%d, fp_in=%p", id, fp_in);
/* Workflow:
* 1. Apply PDD operation and get the size of the returning
@@ -269,43 +389,65 @@ write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old,
rc = ubi_open(&ulib);
if (rc != 0) {
+ rc = -PFIFLASH_ERR_UBI_OPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
goto err;
}
rc = bootenv_create(&bootenv_new);
- if (rc != 0)
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+ EBUF(PFIFLASH_ERRSTR[-rc], " 'new'");
goto err;
+ }
+
rc = bootenv_create(&bootenv_res);
- if (rc != 0)
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+ EBUF(PFIFLASH_ERRSTR[-rc], " 'res'");
goto err;
+ }
- rc = bootenv_read(fp_in, bootenv_new, fp_in_size);
- if (rc != 0)
+ rc = bootenv_read_crc(fp_in, bootenv_new, fp_in_size, &crc);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_READ;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ } else if (crc != pfi_crc) {
+ rc = -PFIFLASH_ERR_CRC_CHECK;
+ EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc);
goto err;
+ }
rc = pdd_f(bootenv_old, bootenv_new, &bootenv_res, &warnings,
err_buf, err_buf_size);
- if (rc != 0)
+ if (rc != 0) {
+ EBUF_PREPEND("handling PDD");
goto err;
- if (warnings) {
- /* @TODO Do sth with the warning */
+ }
+ else if (warnings)
+ /* TODO do something with warnings */
dbg_msg("A warning in the PDD operation occured: %d",
warnings);
- }
- log_msg("... (2)");
rc = bootenv_size(bootenv_res, &update_size);
- if (rc != 0)
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_SIZE;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
goto err;
+ }
fp_out = ubi_vol_fopen_update(ulib, devno, id, update_size);
- if (fp_out == NULL)
+ if (!fp_out) {
+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc], id);
goto err;
+ }
rc = bootenv_write(fp_out, bootenv_res);
if (rc != 0) {
- EBUF("Write operation on ubi%d_%d failed.", devno, id);
- rc = -EIO;
+ rc = -PFIFLASH_ERR_BOOTENV_WRITE;
+ EBUF(PFIFLASH_ERRSTR[-rc], devno, id);
goto err;
}
@@ -318,102 +460,327 @@ write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old,
bootenv_destroy(&bootenv_res);
if (fp_out)
fclose(fp_out);
+
return rc;
}
+
+/**
+ * write_normal_volume - writes data from PFI file int to regular UBI volume
+ * @devno UBI device number
+ * @id UBI volume id
+ * @update_size size of data stream
+ * @fp_in PFI data file pointer
+ * @pfi_crc CRC data from PFI header
+ *
+ * Error handling:
+ * when UBI system couldn't be opened
+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ * when UBI system couldn't open a volume
+ * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err
+ * when unexpected EOF is encountered
+ * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err
+ * when file I/O error
+ * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err
+ * when CRC check fails
+ * - retruns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err
+ **/
static int
write_normal_volume(int devno, uint32_t id, size_t update_size, FILE* fp_in,
- char *err_buf __unused, size_t err_buf_size __unused)
+ uint32_t pfi_crc,
+ char *err_buf, size_t err_buf_size)
{
- int rc = 0;
- ubi_lib_t ulib = NULL;
- FILE* fp_out = NULL;
- int c;
- size_t i;
+ int rc;
+ uint32_t crc, crc32_table[256];
+ size_t bytes_left;
+ FILE* fp_out;
+ ubi_lib_t ulib;
- log_msg("%s(id=%d, update_size=%d fp_in=%p)",
- __func__, id, update_size, fp_in);
+ rc = 0;
+ crc = UBI_CRC32_INIT;
+ bytes_left = update_size;
+ fp_out = NULL;
+ ulib = NULL;
+
+ log_msg("[ ubiupdatevol id=%d, update_size=%d fp_in=%p",
+ id, update_size, fp_in);
rc = ubi_open(&ulib);
- if (rc)
- return rc;
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_UBI_OPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
fp_out = ubi_vol_fopen_update(ulib, devno, id, update_size);
- if (fp_out == NULL) {
- rc = -1;
+ if (!fp_out) {
+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc], id);
goto err;
}
- log_msg("starting the update ... "); /* FIXME DBG */
- for (i = 0; i < update_size; i++) {
- c = getc(fp_in);
- if (c == EOF && ferror(fp_in)) {
- rc = -EIO;
+ init_crc32_table(crc32_table);
+ while (bytes_left) {
+ char buf[1024];
+ size_t to_rw = sizeof buf > bytes_left ?
+ bytes_left : sizeof buf;
+ if (fread(buf, 1, to_rw, fp_in) != to_rw) {
+ rc = -PFIFLASH_ERR_EOF;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
goto err;
}
- if (putc(c, fp_out) == EOF) {
- rc = -EIO;
+ crc = clc_crc32(crc32_table, crc, buf, to_rw);
+ if (fwrite(buf, 1, to_rw, fp_out) != to_rw) {
+ rc = -PFIFLASH_ERR_FIO;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
goto err;
}
- /* FIXME DBG */
- /* if ((i & 0xFFF) == 0xFFF) log_msg("."); */
+ bytes_left -= to_rw;
}
- /* log_msg("\n"); */ /* FIXME DBG */
+
+ if (crc != pfi_crc) {
+ rc = -PFIFLASH_ERR_CRC_CHECK;
+ EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc);
+ goto err;
+ }
+
err:
if (fp_out)
fclose(fp_out);
if (ulib)
ubi_close(&ulib);
+
return rc;
}
/**
- * @brief ...
- * @precondition The PFI file contains at least one ubi_id entry.
- * This is assured by the PFI read process.
- * @postcondition The used seqnum number is set in the UBI PFI
- * header list.
- * The UBI volumes specified by seqnum are processed.
- */
+ * process_raw_volumes - writes the raw sections of the PFI data
+ * @pfi PFI data file pointer
+ * @pfi_raws list of PFI raw headers
+ * @rawdev device to use to write raw data
+ *
+ * Error handling:
+ * when early EOF in PFI data
+ * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err
+ * when file I/O error
+ * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err
+ * when CRC check fails
+ * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err
+ * when opening MTD device fails
+ * - reutrns -PFIFLASH_ERR_MTD_OPEN, err_buf matches text to err
+ * when closing MTD device fails
+ * - returns -PFIFLASH_ERR_MTD_CLOSE, err_buf matches text to err
+ **/
+static int
+process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev,
+ char* err_buf, size_t err_buf_size)
+{
+ int rc;
+ char *pfi_data;
+ void *i;
+ uint32_t crc, crc32_table[256];
+ size_t j, k;
+ FILE* mtd;
+ list_t ptr;
+
+ if (is_empty(pfi_raws))
+ return 0;
+
+ if (rawdev == NULL)
+ return 0;
+
+ rc = 0;
+
+ log_msg("[ rawupdate dev=%s", rawdev);
+
+ crc = UBI_CRC32_INIT;
+ init_crc32_table(crc32_table);
+
+ /* most likely only one element in list, but just in case */
+ foreach(i, ptr, pfi_raws) {
+ pfi_raw_t r = (pfi_raw_t)i;
+
+ /* read in pfi data */
+ pfi_data = malloc(r->data_size * sizeof(char));
+ for (j = 0; j < r->data_size; j++) {
+ int c = fgetc(pfi);
+ if (c == EOF) {
+ rc = -PFIFLASH_ERR_EOF;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ } else if (ferror(pfi)) {
+ rc = -PFIFLASH_ERR_FIO;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+ pfi_data[j] = (char)c;
+ }
+ crc = clc_crc32(crc32_table, crc, pfi_data, r->data_size);
+
+ /* check crc */
+ if (crc != r->crc) {
+ rc = -PFIFLASH_ERR_CRC_CHECK;
+ EBUF(PFIFLASH_ERRSTR[-rc], r->crc, crc);
+ goto err;
+ }
+
+ /* open device */
+ mtd = fopen(rawdev, "r+");
+ if (mtd == NULL) {
+ rc = PFIFLASH_ERR_MTD_OPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc], rawdev);
+ goto err;
+ }
+
+ for (j = 0; j < r->starts_size; j++) {
+ fseek(mtd, r->starts[j], SEEK_SET);
+ for (k = 0; k < r->data_size; k++) {
+ int c = fputc((int)pfi_data[k], mtd);
+ if (c == EOF) {
+ fclose(mtd);
+ rc = -PFIFLASH_ERR_EOF;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ return rc;
+ }
+ if ((char)c != pfi_data[k]) {
+ fclose(mtd);
+ return -1;
+ }
+ }
+ }
+ rc = fclose(mtd);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_MTD_CLOSE;
+ EBUF(PFIFLASH_ERRSTR[-rc], rawdev);
+ goto err;
+ }
+ }
+
+ err:
+ return rc;
+}
+
+
+/**
+ * erase_unmapped_ubi_volumes - skip volumes provided by PFI file, clear rest
+ * @devno UBI device number
+ * @pfi_ubis list of UBI header data
+ *
+ * Error handling:
+ * when UBI id is out of bounds
+ * - returns -PFIFLASH_ERR_UBI_VID_OOB, err_buf matches text to err
+ * when UBI volume can't be removed
+ * - passes rc, prepends err_buf with contextual aid
+ **/
+static int
+erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis,
+ char *err_buf, size_t err_buf_size)
+{
+ int rc;
+ uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES];
+ size_t i;
+ list_t ptr;
+ pfi_ubi_t u;
+
+ rc = 0;
+
+ for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++)
+ ubi_volumes[i] = 1;
+
+ foreach(u, ptr, pfi_ubis) {
+ /* iterate over each vol_id */
+ for(i = 0; i < u->ids_size; i++) {
+ if (u->ids[i] > PFI_UBI_MAX_VOLUMES) {
+ rc = -PFIFLASH_ERR_UBI_VID_OOB;
+ EBUF(PFIFLASH_ERRSTR[-rc], u->ids[i]);
+ goto err;
+ }
+ /* remove from removal list */
+ ubi_volumes[u->ids[i]] = 0;
+ }
+ }
+
+ for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) {
+ if (ubi_volumes[i]) {
+ rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size);
+ if (rc != 0) {
+ EBUF_PREPEND("remove volume failed");
+ goto err;
+ }
+ }
+ }
+
+ err:
+ return rc;
+}
+
+
+/**
+ * process_ubi_volumes - delegate tasks regarding UBI volumes
+ * @pfi PFI data file pointer
+ * @seqnum sequence number
+ * @pfi_ubis list of UBI header data
+ * @bootenv_old storage for current system PDD
+ * @pdd_f function to handle PDD
+ * @ubi_update_process whether reading or writing
+ *
+ * Error handling:
+ * when and unknown ubi_update_process is given
+ * - returns -PFIFLASH_ERR_UBI_UNKNOWN, err_buf matches text to err
+ * otherwise
+ * - passes rc and err_buf
+ **/
static int
process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis,
bootenv_t bootenv_old, pdd_func_t pdd_f,
ubi_update_process_t ubi_update_process,
char *err_buf, size_t err_buf_size)
{
- int rc = 0;
+ int rc;
pfi_ubi_t u;
list_t ptr;
+ rc = 0;
+
foreach(u, ptr, pfi_ubis) {
int s = seqnum;
- if (seqnum > ((int)u->ids_size - 1)) {
+
+ if (s > ((int)u->ids_size - 1))
s = 0; /* per default use the first */
- }
u->curr_seqnum = s;
switch (ubi_update_process) {
case UBI_REMOVE:
+ /* TODO are all these "EXAMPLE" vars okay? */
if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) ||
(u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) {
- rc =read_bootenv_volume(EXAMPLE_UBI_DEVICE,
- u->ids[s],
- bootenv_old, err_buf,
- err_buf_size);
+ rc = read_bootenv_volume(EXAMPLE_UBI_DEVICE,
+ u->ids[s], bootenv_old,
+ err_buf, err_buf_size);
+ /* it's okay if there is no bootenv
+ * we're going to write one */
+ if ((rc == -PFIFLASH_ERR_UBI_VOL_FOPEN) ||
+ (rc == -PFIFLASH_ERR_BOOTENV_READ))
+ rc = 0;
if (rc != 0)
goto err;
- }
- rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE, u->ids[s],
+ }
+
+ rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE, u->ids[s],
err_buf, err_buf_size);
if (rc != 0)
goto err;
+
break;
case UBI_WRITE:
rc = my_ubi_mkvol(EXAMPLE_UBI_DEVICE, s, u,
err_buf, err_buf_size);
- if (rc != 0)
+ if (rc != 0) {
+ EBUF_PREPEND("creating volume");
goto err;
+ }
+
if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) ||
(u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) {
rc = write_bootenv_volume(EXAMPLE_UBI_DEVICE,
@@ -421,87 +788,67 @@ process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis,
bootenv_old, pdd_f,
pfi,
u->data_size,
+ u->crc,
err_buf,
err_buf_size);
- }
- else {
+ if (rc != 0)
+ EBUF_PREPEND("bootenv volume");
+ } else {
rc = write_normal_volume(EXAMPLE_UBI_DEVICE,
u->ids[s],
u->data_size, pfi,
+ u->crc,
err_buf,
err_buf_size);
+ if (rc != 0)
+ EBUF_PREPEND("normal volume");
}
if (rc != 0)
goto err;
+
break;
default:
- EBUF("Invoked unknown UBI operation.");
- rc = -1;
- goto err;
-
- }
- if (rc != 0) {
+ rc = -PFIFLASH_ERR_UBI_UNKNOWN;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
goto err;
}
}
- err:
- return rc;
-
-}
-
-static int
-erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis,
- char *err_buf, size_t err_buf_size)
-{
- int rc = 0;
- list_t ptr;
- pfi_ubi_t u;
- size_t i;
- uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES];
-
- for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) {
- ubi_volumes[i] = 1;
- }
-
- foreach(u, ptr, pfi_ubis) {
- /* iterate over each vol_id */
- for(i = 0; i < u->ids_size; i++) {
- if (u->ids[i] > PFI_UBI_MAX_VOLUMES) {
- EBUF("PFI file contains an invalid "
- "volume id: %d", u->ids[i]);
- goto err;
- }
- /* remove from removal list */
- ubi_volumes[u->ids[i]] = 0;
- }
- }
- for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) {
- if (ubi_volumes[i]) {
- rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size);
- if (rc != 0)
- goto err;
- }
- }
err:
return rc;
}
+
+/**
+ * mirror_ubi_volumes - mirror redundant pairs of volumes
+ * @devno UBI device number
+ * @pfi_ubis list of PFI header data
+ *
+ * Error handling:
+ * when UBI system couldn't be opened
+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ **/
static int
mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis,
char *err_buf, size_t err_buf_size)
{
- int rc = 0;
- list_t ptr;
+ int rc;
uint32_t j;
+ list_t ptr;
pfi_ubi_t i;
- ubi_lib_t ulib = NULL;
+ ubi_lib_t ulib;
- log_msg("%s(...)", __func__);
+ rc = 0;
+ ulib = NULL;
+
+ log_msg("[ mirror ...");
rc = ubi_open(&ulib);
- if (rc != 0)
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_UBI_OPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
goto err;
+ }
/**
* Execute all mirror operations on redundant groups.
@@ -510,25 +857,26 @@ mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis,
* ubimirror).
*/
foreach(i, ptr, pfi_ubis) {
- for(j = 0; j < i->ids_size; j++) {
+ for (j = 0; j < i->ids_size; j++) {
/* skip self-match */
if (i->ids[j] == i->ids[i->curr_seqnum])
continue;
- rc = my_ubi_rmvol(devno, i->ids[j], err_buf,
- err_buf_size);
+ rc = my_ubi_rmvol(devno, i->ids[j],
+ err_buf, err_buf_size);
if (rc != 0)
goto err;
- rc = my_ubi_mkvol(devno, j, i, err_buf, err_buf_size);
+ rc = my_ubi_mkvol(devno, j, i,
+ err_buf, err_buf_size);
if (rc != 0)
goto err;
}
}
foreach(i, ptr, pfi_ubis) {
- rc = ubimirror(devno, i->curr_seqnum, i->ids,
- i->ids_size, err_buf, err_buf_size);
+ rc = ubimirror(devno, i->curr_seqnum, i->ids, i->ids_size,
+ err_buf, err_buf_size);
if (rc != 0)
goto err;
}
@@ -537,44 +885,71 @@ mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis,
err:
if (ulib != NULL)
ubi_close(&ulib);
+
return rc;
}
+
+/**
+ * pfiflash_with_raw - exposed func to flash memory with a PFI file
+ * @pfi PFI data file pointer
+ * @complete flag to erase unmapped volumes
+ * @seqnum sequence number
+ * @pdd_handling method to handle pdd (keep, merge, overwrite...)
+ *
+ * Error handling:
+ * when bootenv can't be created
+ * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err
+ * when PFI headers can't be read, or
+ * when fail to skip raw sections, or
+ * when error occurs while processing raw volumes, or
+ * when fail to erase unmapped UBI vols, or
+ * when error occurs while processing UBI volumes, or
+ * when error occurs while mirroring UBI volumes
+ * - passes rc, prepends err_buf with contextual aid
+ **/
int
-pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling,
- char *err_buf, size_t err_buf_size)
+pfiflash_with_raw(FILE* pfi, int complete, int seqnum,
+ pdd_handling_t pdd_handling, const char* rawdev,
+ char *err_buf, size_t err_buf_size)
{
- int rc = 0;
- pdd_func_t pdd_f = NULL;
+ int rc;
+ bootenv_t bootenv;
+ pdd_func_t pdd_f;
if (pfi == NULL)
return -EINVAL;
- /**
- * If the user didnt specify a seqnum we start per default
- * with the index 0
- */
+ rc = 0;
+ pdd_f = NULL;
+
+ /* If the user didnt specify a seqnum we start per default
+ * with the index 0 */
int curr_seqnum = seqnum < 0 ? 0 : seqnum;
list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */
list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */
- bootenv_t bootenv;
rc = bootenv_create(&bootenv);
if (rc != 0) {
- EBUF("Cannot create bootenv variable");
+ rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+ EBUF(PFIFLASH_ERRSTR[-rc], "");
+ goto err;
}
- rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi,
- err_buf, err_buf_size);
+ rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi, err_buf, err_buf_size);
if (rc != 0) {
- EBUF("Cannot read PFI headers.");
+ EBUF_PREPEND("reading PFI header");
goto err;
}
- /* @TODO: If you want to implement an IPL update - start here. */
- rc = skip_raw_sections(pfi, pfi_raws, err_buf, err_buf_size);
+ if (rawdev == NULL)
+ rc = skip_raw_volumes(pfi, pfi_raws, err_buf, err_buf_size);
+ else
+ rc = process_raw_volumes(pfi, pfi_raws, rawdev, err_buf,
+ err_buf_size);
if (rc != 0) {
+ EBUF_PREPEND("handling raw section");
goto err;
}
@@ -582,33 +957,41 @@ pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling,
rc = erase_unmapped_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis,
err_buf, err_buf_size);
if (rc != 0) {
- EBUF("Cannot delete unmapped UBI volumes.");
+ EBUF_PREPEND("deleting unmapped UBI volumes");
goto err;
}
}
- if (((int)pdd_handling >= 0) && (pdd_handling < PDD_HANDLING_NUM)) {
+ if (((int)pdd_handling >= 0) &&
+ (pdd_handling < PDD_HANDLING_NUM))
pdd_f = pdd_funcs[pdd_handling];
- }
else {
- EBUF("Used unknown PDD handling algorithm (pdd_handling)");
+ rc = -PFIFLASH_ERR_PDD_UNKNOWN;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
}
rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, pdd_f,
UBI_REMOVE, err_buf, err_buf_size);
- if (rc != 0) {
+ if (rc != 0) {
+ EBUF_PREPEND("removing UBI volumes");
goto err;
}
+
rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, pdd_f,
UBI_WRITE, err_buf, err_buf_size);
if (rc != 0) {
+ EBUF_PREPEND("writing UBI volumes");
goto err;
}
+
if (seqnum < 0) { /* mirror redundant pairs */
rc = mirror_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis,
err_buf, err_buf_size);
- if (rc != 0)
+ if (rc != 0) {
+ EBUF_PREPEND("mirroring UBI volumes");
goto err;
+ }
}
err:
@@ -617,3 +1000,19 @@ pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling,
bootenv_destroy(&bootenv);
return rc;
}
+
+
+/**
+ * pfiflash - passes to pfiflash_with_raw
+ * @pfi PFI data file pointer
+ * @complete flag to erase unmapped volumes
+ * @seqnum sequence number
+ * @pdd_handling method to handle pdd (keep, merge, overwrite...)
+ **/
+int
+pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling,
+ char *err_buf, size_t err_buf_size)
+{
+ return pfiflash_with_raw(pfi, complete, seqnum, pdd_handling,
+ NULL, err_buf, err_buf_size);
+}
diff --git a/ubi-utils/src/pfiflash.c b/ubi-utils/src/pfiflash.c
index 04f62df..c49fb1e 100644
--- a/ubi-utils/src/pfiflash.c
+++ b/ubi-utils/src/pfiflash.c
@@ -21,6 +21,8 @@
* Process a PFI (partial flash image) and write the data to the
* specified UBI volumes. This tool is intended to be used for system
* update using PFI files.
+ *
+ * 1.1 fixed output to stderr and stdout in logfile mode.
*/
#include <unistd.h>
@@ -34,12 +36,15 @@
#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;
}
diff --git a/ubi-utils/src/pfiflash.h b/ubi-utils/src/pfiflash.h
index fc2eede..a063e7f 100644
--- a/ubi-utils/src/pfiflash.h
+++ b/ubi-utils/src/pfiflash.h
@@ -49,6 +49,19 @@ typedef enum pdd_handling_t
* @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.
+ * @param seqnum Index in a redundant group.
+ * @param pdd_handling The PDD handling algorithm.
* @param err_buf An error buffer.
* @param err_buf_size Size of the error buffer.
*/
diff --git a/ubi-utils/src/pfiflash_error.h b/ubi-utils/src/pfiflash_error.h
new file mode 100644
index 0000000..34b705e
--- /dev/null
+++ b/ubi-utils/src/pfiflash_error.h
@@ -0,0 +1,69 @@
+#ifndef __PFIFLASH_ERROR_H__
+#define __PFIFLASH_ERROR_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Author: Drake Dowsett <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__ */
diff --git a/ubi-utils/src/reader.c b/ubi-utils/src/reader.c
index 5de06d5..975caa1 100644
--- a/ubi-utils/src/reader.c
+++ b/ubi-utils/src/reader.c
@@ -29,10 +29,11 @@
#include <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.");
diff --git a/ubi-utils/src/reader.h b/ubi-utils/src/reader.h
index d00fa17..715e464 100644
--- a/ubi-utils/src/reader.h
+++ b/ubi-utils/src/reader.h
@@ -50,6 +50,7 @@ struct pfi_raw {
uint32_t data_size;
uint32_t *starts;
uint32_t starts_size;
+ uint32_t crc;
};
struct pfi_ubi {
@@ -63,6 +64,7 @@ struct pfi_ubi {
enum { pfi_ubi_dynamic, pfi_ubi_static } type;
int curr_seqnum; /* specifies the seqnum taken in an update,
default: 0 (used by pfiflash, ubimirror) */
+ uint32_t crc;
};
int read_pdd_data(FILE* fp_pdd, pdd_data_t *pdd_data,