summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Schmidt <alexs@linux.vnet.ibm.com>2007-07-10 17:53:54 +0200
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2007-07-10 21:00:43 +0300
commit0d62e6a7338d8f25727f56ca14236954fc8f2cef (patch)
tree767442d91fe044f6671cf618b3f08165f171fef0
parent8496f75b4897056a1423e30a41649dbc11b421d4 (diff)
UBI-utils: add compare feature
This is a new feature for pfiflash, called "--compare". It allows the user to simulate a pfiflash session without actually changing the flash content. If the flash content is equal to the data in the pfif file, pfiflash returns zero. A positive value is returned when the flash content differs from the pfi file, which indicates that an update is necessary. This feature is useful when a controller mounts an NFS share during boot and has to determine if a pfi file stored on this share contains a code update. Modified PDD values are also registered by the compare feature. Signed-off-by: Alexander Schmidt <alexs@linux.vnet.ibm.com>
-rw-r--r--ubi-utils/src/bootenv.c48
-rw-r--r--ubi-utils/src/bootenv.h10
-rw-r--r--ubi-utils/src/libpfiflash.c242
-rw-r--r--ubi-utils/src/pfiflash.c28
-rw-r--r--ubi-utils/src/pfiflash.h3
-rw-r--r--ubi-utils/src/pfiflash_error.h8
6 files changed, 298 insertions, 41 deletions
diff --git a/ubi-utils/src/bootenv.c b/ubi-utils/src/bootenv.c
index ed15dc7..561d473 100644
--- a/ubi-utils/src/bootenv.c
+++ b/ubi-utils/src/bootenv.c
@@ -480,6 +480,54 @@ bootenv_write(FILE* fp, bootenv_t env)
}
int
+bootenv_compare(bootenv_t first, bootenv_t second)
+{
+ int rc;
+ size_t written_first, written_second;
+ char *buf_first, *buf_second;
+
+ if (first == NULL || second == NULL)
+ return -EINVAL;
+
+ buf_first = malloc(BOOTENV_MAXSIZE);
+ if (!buf_first)
+ return -ENOMEM;
+ buf_second = malloc(BOOTENV_MAXSIZE);
+ if (!buf_second) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ rc = fill_output_buffer(first, buf_first, BOOTENV_MAXSIZE,
+ &written_first);
+ if (rc < 0)
+ goto err;
+ rc = fill_output_buffer(second, buf_second, BOOTENV_MAXSIZE,
+ &written_second);
+ if (rc < 0)
+ goto err;
+
+ if (written_first != written_second) {
+ rc = 1;
+ goto err;
+ }
+
+ rc = memcmp(buf_first, buf_second, written_first);
+ if (rc != 0) {
+ rc = 2;
+ goto err;
+ }
+
+err:
+ if (buf_first)
+ free(buf_first);
+ if (buf_second)
+ free(buf_second);
+
+ return rc;
+}
+
+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 9003d70..8fecdbf 100644
--- a/ubi-utils/src/bootenv.h
+++ b/ubi-utils/src/bootenv.h
@@ -268,6 +268,16 @@ int bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc);
int bootenv_write_txt(FILE* fp, bootenv_t env);
/**
+ * @brief Compare bootenvs using memcmp().
+ * @param first First bootenv.
+ * @param second Second bootenv.
+ * @return 0 if bootenvs are equal
+ * @return < 0 if error
+ * @return > 0 if unequal
+ */
+int bootenv_compare(bootenv_t first, bootenv_t second);
+
+/**
* @brief Prototype for a PDD handling funtion
*/
diff --git a/ubi-utils/src/libpfiflash.c b/ubi-utils/src/libpfiflash.c
index 4f1f5cd..e60290a 100644
--- a/ubi-utils/src/libpfiflash.c
+++ b/ubi-utils/src/libpfiflash.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) International Business Machines Corp., 2006
+ * Copyright International Business Machines Corp., 2006, 2007
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -55,8 +55,10 @@
#define __unused __attribute__((unused))
+#define COMPARE_BUFFER_SIZE 2048
+
static const char copyright [] __unused =
- "Copyright (c) International Business Machines Corp., 2006";
+ "Copyright International Business Machines Corp., 2006, 2007";
/* simply clear buffer, then write into front of it */
#define EBUF(fmt...) \
@@ -82,6 +84,7 @@ static pdd_func_t pdd_funcs[PDD_HANDLING_NUM] =
typedef enum ubi_update_process_t {
UBI_REMOVE = 0,
UBI_WRITE,
+ UBI_COMPARE,
} ubi_update_process_t;
@@ -556,6 +559,170 @@ write_normal_volume(int devno, uint32_t id, size_t update_size, FILE* fp_in,
return rc;
}
+static int compare_bootenv(FILE *fp_pfi, FILE **fp_flash, uint32_t ids_size,
+ uint32_t data_size, pdd_func_t pdd_f, char *err_buf,
+ size_t err_buf_size)
+{
+ int rc, warnings = 0;
+ unsigned int i;
+ bootenv_t bootenv_pfi, bootenv_res = NULL, bootenv_flash = NULL;
+
+ rc = bootenv_create(&bootenv_pfi);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+ goto err;
+ }
+
+ rc = bootenv_create(&bootenv_res);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+ goto err;
+ }
+
+ rc = bootenv_read(fp_pfi, bootenv_pfi, data_size);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_READ;
+ goto err;
+ }
+
+ for (i = 0; i < ids_size; i++) {
+ rc = bootenv_create(&bootenv_flash);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+ goto err;
+ }
+
+ rc = bootenv_read(fp_flash[i], bootenv_flash, BOOTENV_MAXSIZE);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_READ;
+ goto err;
+ }
+
+ rc = pdd_f(bootenv_flash, bootenv_pfi, &bootenv_res,
+ &warnings, err_buf, err_buf_size);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_PDD_UNKNOWN;
+ goto err;
+ }
+
+ rc = bootenv_compare(bootenv_flash, bootenv_res);
+ if (rc > 0) {
+ rc = -PFIFLASH_CMP_DIFF;
+ goto err;
+ } else if (rc < 0) {
+ rc = -PFIFLASH_ERR_COMPARE;
+ goto err;
+ }
+
+ bootenv_destroy(&bootenv_flash);
+ bootenv_flash = NULL;
+ }
+
+err:
+ if (bootenv_pfi)
+ bootenv_destroy(&bootenv_pfi);
+ if (bootenv_res)
+ bootenv_destroy(&bootenv_res);
+ if (bootenv_flash)
+ bootenv_destroy(&bootenv_flash);
+
+ return rc;
+}
+
+static int compare_data(FILE *fp_pfi, FILE **fp_flash, uint32_t ids_size,
+ uint32_t bytes_left)
+{
+ unsigned int i;
+ size_t read_bytes, rc = 0;
+ char buf_pfi[COMPARE_BUFFER_SIZE];
+ char *buf_flash[ids_size];
+
+ for (i = 0; i < ids_size; i++) {
+ buf_flash[i] = malloc(COMPARE_BUFFER_SIZE);
+ if (!buf_flash[i])
+ return -PFIFLASH_ERR_COMPARE;
+ }
+
+ while (bytes_left) {
+ if (bytes_left > COMPARE_BUFFER_SIZE)
+ read_bytes = COMPARE_BUFFER_SIZE;
+ else
+ read_bytes = bytes_left;
+
+ rc = fread(buf_pfi, 1, read_bytes, fp_pfi);
+ if (rc != read_bytes) {
+ rc = -PFIFLASH_ERR_COMPARE;
+ goto err;
+ }
+
+ for (i = 0; i < ids_size; i++) {
+ rc = fread(buf_flash[i], 1, read_bytes, fp_flash[i]);
+ if (rc != read_bytes) {
+ rc = -PFIFLASH_CMP_DIFF;
+ goto err;
+ }
+
+ rc = memcmp(buf_pfi, buf_flash[i], read_bytes);
+ if (rc != 0) {
+ rc = -PFIFLASH_CMP_DIFF;
+ goto err;
+ }
+ }
+
+ bytes_left -= read_bytes;
+ }
+
+err:
+ for (i = 0; i < ids_size; i++)
+ free(buf_flash[i]);
+
+ return rc;
+}
+
+static int compare_volumes(int devno, pfi_ubi_t u, FILE *fp_pfi,
+ pdd_func_t pdd_f, char *err_buf, size_t err_buf_size)
+{
+ int rc, is_bootenv = 0;
+ unsigned int i;
+ ubi_lib_t ulib = NULL;
+ FILE *fp_flash[u->ids_size];
+
+ rc = ubi_open(&ulib);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_UBI_OPEN;
+ goto err;
+ }
+
+ for (i = 0; i < u->ids_size; i++) {
+ if (u->ids[i] == EXAMPLE_BOOTENV_VOL_ID_1 ||
+ u->ids[i] == EXAMPLE_BOOTENV_VOL_ID_2)
+ is_bootenv = 1;
+
+ fp_flash[i] = ubi_vol_fopen_read(ulib, devno, u->ids[i]);
+ if (fp_flash[i] == NULL) {
+ rc = -PFIFLASH_ERR_UBI_OPEN;
+ goto err;
+ }
+ }
+
+ if (is_bootenv)
+ rc = compare_bootenv(fp_pfi, fp_flash, u->ids_size,
+ u->data_size, pdd_f, err_buf, err_buf_size);
+ else
+ rc = compare_data(fp_pfi, fp_flash, u->ids_size, u->data_size);
+
+err:
+ if (rc < 0)
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+
+ for (i = 0; i < u->ids_size; i++)
+ fclose(fp_flash[i]);
+ if (ulib)
+ ubi_close(&ulib);
+
+ return rc;
+}
+
static int
erase_mtd_region(FILE* file_p, int start, int length)
{
@@ -865,6 +1032,15 @@ process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis,
goto err;
break;
+ case UBI_COMPARE:
+ rc = compare_volumes(EXAMPLE_UBI_DEVICE, u, pfi, pdd_f,
+ err_buf, err_buf_size);
+ if (rc != 0) {
+ EBUF_PREPEND("compare volume");
+ goto err;
+ }
+
+ break;
default:
rc = -PFIFLASH_ERR_UBI_UNKNOWN;
EBUF(PFIFLASH_ERRSTR[-rc]);
@@ -949,10 +1125,11 @@ mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis,
/**
- * pfiflash_with_raw - exposed func to flash memory with a PFI file
+ * pfiflash_with_options - exposed func to flash memory with a PFI file
* @pfi PFI data file pointer
* @complete flag to erase unmapped volumes
* @seqnum sequence number
+ * @compare flag to compare
* @pdd_handling method to handle pdd (keep, merge, overwrite...)
*
* Error handling:
@@ -967,7 +1144,7 @@ mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis,
* - passes rc, prepends err_buf with contextual aid
**/
int
-pfiflash_with_raw(FILE* pfi, int complete, int seqnum,
+pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare,
pdd_handling_t pdd_handling, const char* rawdev,
char *err_buf, size_t err_buf_size)
{
@@ -1001,7 +1178,7 @@ pfiflash_with_raw(FILE* pfi, int complete, int seqnum,
goto err;
}
- if (rawdev == NULL)
+ if (rawdev == NULL || compare)
rc = skip_raw_volumes(pfi, pfi_raws, err_buf, err_buf_size);
else
rc = process_raw_volumes(pfi, pfi_raws, rawdev, err_buf,
@@ -1011,7 +1188,7 @@ pfiflash_with_raw(FILE* pfi, int complete, int seqnum,
goto err;
}
- if (complete) {
+ if (complete && !compare) {
rc = erase_unmapped_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis,
err_buf, err_buf_size);
if (rc != 0) {
@@ -1029,25 +1206,40 @@ pfiflash_with_raw(FILE* pfi, int complete, int seqnum,
goto err;
}
- rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, pdd_f,
- UBI_REMOVE, err_buf, err_buf_size);
- if (rc != 0) {
- EBUF_PREPEND("removing UBI volumes");
- goto err;
- }
+ if (!compare) {
+ rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv,
+ pdd_f, UBI_REMOVE, err_buf, err_buf_size);
+ if (rc != 0) {
+ EBUF_PREPEND("removing UBI volumes");
+ goto err;
+ }
- rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, pdd_f,
- UBI_WRITE, err_buf, err_buf_size);
- if (rc != 0) {
- EBUF_PREPEND("writing UBI volumes");
- goto err;
- }
+ 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,
+ if (seqnum < 0) { /* mirror redundant pairs */
+ rc = mirror_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis,
err_buf, err_buf_size);
- if (rc != 0) {
- EBUF_PREPEND("mirroring UBI volumes");
+ if (rc != 0) {
+ EBUF_PREPEND("mirroring UBI volumes");
+ goto err;
+ }
+ }
+ } else {
+ /* only compare volumes, don't alter the content */
+ rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv,
+ pdd_f, UBI_COMPARE, err_buf, err_buf_size);
+
+ if (rc == -PFIFLASH_CMP_DIFF)
+ /* update is necessary, return positive value */
+ rc = 1;
+
+ if (rc < 0) {
+ EBUF_PREPEND("comparing UBI volumes");
goto err;
}
}
@@ -1061,7 +1253,7 @@ pfiflash_with_raw(FILE* pfi, int complete, int seqnum,
/**
- * pfiflash - passes to pfiflash_with_raw
+ * pfiflash - passes to pfiflash_with_options
* @pfi PFI data file pointer
* @complete flag to erase unmapped volumes
* @seqnum sequence number
@@ -1069,8 +1261,8 @@ pfiflash_with_raw(FILE* pfi, int complete, int seqnum,
**/
int
pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling,
- char *err_buf, size_t err_buf_size)
+ char *err_buf, size_t err_buf_size)
{
- return pfiflash_with_raw(pfi, complete, seqnum, pdd_handling,
+ return pfiflash_with_options(pfi, complete, seqnum, 0, pdd_handling,
NULL, err_buf, err_buf_size);
}
diff --git a/ubi-utils/src/pfiflash.c b/ubi-utils/src/pfiflash.c
index d5b5406..bac62e6 100644
--- a/ubi-utils/src/pfiflash.c
+++ b/ubi-utils/src/pfiflash.c
@@ -63,6 +63,9 @@ static const char *optionsstr =
" 'keep', 'merge' or 'overwrite'.\n"
" -r, --raw-flash=<dev> Flash the raw data. Use the specified mtd device.\n"
" -s, --side=<seqnum> Select the side which shall be updated.\n"
+" -x, --compare Only compare on-flash and pfi data, print info if\n"
+" an update is neccessary and return appropriate\n"
+" error code.\n"
"\n"
" -?, --help Give this help list\n"
" --usage Give a short usage message\n"
@@ -72,7 +75,7 @@ static const char *usage =
"Usage: pfiflash [-cvC?V] [-l <file>] [-p <type>] [-r <dev>] [-s <seqnum>]\n"
" [--copyright] [--logfile=<file>] [--verbose] [--complete]\n"
" [--pdd-update=<type>] [--raw-flash=<dev>] [--side=<seqnum>]\n"
-" [--help] [--usage] [--version] [pfifile]\n";
+" [--compare] [--help] [--usage] [--version] [pfifile]\n";
static const char copyright [] __attribute__((unused)) =
"Copyright IBM Corp 2006";
@@ -85,6 +88,7 @@ struct option long_options[] = {
{ .name = "pdd-update", .has_arg = 1, .flag = NULL, .val = 'p' },
{ .name = "raw-flash", .has_arg = 1, .flag = NULL, .val = 'r' },
{ .name = "side", .has_arg = 1, .flag = NULL, .val = 's' },
+ { .name = "compare", .has_arg = 0, .flag = NULL, .val = 'x' },
{ .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
{ .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
{ .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
@@ -98,6 +102,7 @@ typedef struct myargs {
pdd_handling_t pdd_handling;
int seqnum;
+ int compare;
int complete;
FILE* fp_in;
@@ -142,7 +147,7 @@ parse_opt(int argc, char **argv, myargs *args)
while (1) {
int key;
- key = getopt_long(argc, argv, "cl:vCp:r:s:?V",
+ key = getopt_long(argc, argv, "cl:vCp:r:s:x?V",
long_options, NULL);
if (key == -1)
break;
@@ -180,6 +185,9 @@ parse_opt(int argc, char **argv, myargs *args)
"and '1'\n", optarg);
}
break;
+ case 'x':
+ args->compare = 1;
+ break;
case 'r':
args->raw_dev = optarg;
break;
@@ -222,6 +230,7 @@ int main (int argc, char** argv)
myargs args = {
.verbose = 0,
.seqnum = -1,
+ .compare = 0,
.complete = 0,
.logfile = NULL, /* "/tmp/pfiflash.log", */
.pdd_handling = PDD_KEEP,
@@ -239,17 +248,10 @@ int main (int argc, char** argv)
goto err;
}
- 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) {
+ rc = pfiflash_with_options(args.fp_in, args.complete, args.seqnum,
+ args.compare, args.pdd_handling, args.raw_dev, err_buf,
+ PFIFLASH_MAX_ERR_BUF_SIZE);
+ if (rc < 0) {
goto err_fp;
}
diff --git a/ubi-utils/src/pfiflash.h b/ubi-utils/src/pfiflash.h
index a063e7f..039705d 100644
--- a/ubi-utils/src/pfiflash.h
+++ b/ubi-utils/src/pfiflash.h
@@ -48,12 +48,13 @@ typedef enum pdd_handling_t
* @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 compare [0|1] Compare contents.
* @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,
+int pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare,
pdd_handling_t pdd_handling, const char* rawdev,
char *err_buf, size_t err_buf_size);
diff --git a/ubi-utils/src/pfiflash_error.h b/ubi-utils/src/pfiflash_error.h
index c06232a..0f27f4a 100644
--- a/ubi-utils/src/pfiflash_error.h
+++ b/ubi-utils/src/pfiflash_error.h
@@ -42,7 +42,9 @@ enum pfiflash_err {
PFIFLASH_ERR_MTD_OPEN,
PFIFLASH_ERR_MTD_CLOSE,
PFIFLASH_ERR_CRC_CHECK,
- PFIFLASH_ERR_MTD_ERASE
+ PFIFLASH_ERR_MTD_ERASE,
+ PFIFLASH_ERR_COMPARE,
+ PFIFLASH_CMP_DIFF
};
const char *const PFIFLASH_ERRSTR[] = {
@@ -65,7 +67,9 @@ const char *const PFIFLASH_ERRSTR[] = {
"couldn't open MTD device %s",
"couldn't close MTD device %s",
"CRC check failed: given=0x%08x, calculated=0x%08x",
- "couldn't erase raw mtd region"
+ "couldn't erase raw mtd region",
+ "couldn't compare volumes",
+ "on-flash data differ from pfi data, update is neccessary"
};
#endif /* __PFIFLASH_ERROR_H__ */