/*
- * 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
#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...) \
typedef enum ubi_update_process_t {
UBI_REMOVE = 0,
UBI_WRITE,
+ UBI_COMPARE,
} ubi_update_process_t;
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)
{
if (rc != 0)
goto err;
+ break;
+ case UBI_COMPARE:
+ rc = compare_volumes(EXAMPLE_UBI_DEVICE, u, pfi, pdd_f,
+ err_buf, err_buf_size);
+ if (rc != 0) {
+ EBUF_PREPEND("compare volume");
+ goto err;
+ }
+
break;
default:
rc = -PFIFLASH_ERR_UBI_UNKNOWN;
/**
- * 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:
* - 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)
{
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,
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) {
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;
}
}
/**
- * 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
**/
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);
}
" '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"
"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";
{ .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' },
pdd_handling_t pdd_handling;
int seqnum;
+ int compare;
int complete;
FILE* fp_in;
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;
"and '1'\n", optarg);
}
break;
+ case 'x':
+ args->compare = 1;
+ break;
case 'r':
args->raw_dev = optarg;
break;
myargs args = {
.verbose = 0,
.seqnum = -1,
+ .compare = 0,
.complete = 0,
.logfile = NULL, /* "/tmp/pfiflash.log", */
.pdd_handling = PDD_KEEP,
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;
}