int read_pdd_data(FILE* fp_pdd, pdd_data_t* pdd_data, char* err_buf, size_t err_buf_size) { int rc = 0; bootenv_t pdd = NULL; pdd_data_t res = NULL; const char* value; res = (pdd_data_t) malloc(sizeof(struct pdd_data)); if (!res) { rc = -ENOMEM; goto err; } rc = bootenv_create(&pdd); if (rc != 0) { goto err; } rc = bootenv_read_txt(fp_pdd, pdd); if (rc != 0) { goto err; } rc = bootenv_get(pdd, "flash_type", &value); if (rc != 0) { goto err; } if (strcmp(value, "NAND") == 0) { rc = bootenv_get_num(pdd, "flash_page_size", &(res->flash_page_size)); if (rc != 0) { EBUF("Cannot read 'flash_page_size' from pdd."); goto err; } res->flash_type = NAND_FLASH; switch (res->flash_page_size) { case 512: res->vid_hdr_offset = NAND512_DEFAULT_VID_HDR_OFF; break; case 2048: res->vid_hdr_offset = NAND2048_DEFAULT_VID_HDR_OFF; break; default: EBUF("Unsupported 'flash_page_size' %d.", res->flash_page_size); goto err; } } else if (strcmp(value, "NOR") == 0){ res->flash_type = NOR_FLASH; res->vid_hdr_offset = NOR_DEFAULT_VID_HDR_OFF; } else { snprintf(err_buf, err_buf_size, "Unkown flash type: %s", value); goto err; } rc = bootenv_get_num(pdd, "flash_eraseblock_size", &(res->eb_size)); if (rc != 0) { EBUF("Cannot read 'flash_eraseblock_size' from pdd."); goto err; } rc = bootenv_get_num(pdd, "flash_size", &(res->flash_size)); if (rc != 0) { EBUF("Cannot read 'flash_size' from pdd."); goto err; } goto out; err: if (res) { free(res); res = NULL; } out: bootenv_destroy(&pdd); *pdd_data = res; return rc; }
int main(int argc, char **argv) { int rc = 0; bootenv_t env = NULL; uint32_t boot_volno; myargs args = { .action = ACT_NORMAL, .file_in = NULL, .file_out = NULL, .side = -1, .x86 = 0, .both = 0, .env_in = NULL, .arg1 = NULL, .options = NULL, }; rc = bootenv_create(&env); if (rc != 0) { err_msg("Cannot create bootenv handle. rc: %d", rc); goto err; } rc = bootenv_create(&(args.env_in)); if (rc != 0) { err_msg("Cannot create bootenv handle. rc: %d", rc); goto err; } parse_opt(argc, argv, &args); if (args.action == ACT_ARGP_ERR) { rc = -1; goto err; } if (args.action == ACT_ARGP_ABORT) { rc = 0; goto out; } if ((args.side == 0) || (args.side == -1)) boot_volno = EXAMPLE_BOOTENV_VOL_ID_1; else boot_volno = EXAMPLE_BOOTENV_VOL_ID_2; if( args.x86 ) rc = read_bootenv(args.file_in, env); else rc = ubi_read_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env); if (rc != 0) { goto err; } if (args.action == ACT_LIST) { rc = list_bootenv(env); if (rc != 0) { goto err; } goto out; } rc = process_key_value(args.env_in, env); if (rc != 0) { goto err; } if( args.x86 ) rc = write_bootenv(args.file_in, env); else rc = ubi_write_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env); if (rc != 0) goto err; if( args.both ) /* No side specified, update both */ rc = do_mirror(boot_volno); out: err: bootenv_destroy(&env); bootenv_destroy(&(args.env_in)); 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, size_t fp_in_size, uint32_t pfi_crc, char *err_buf, size_t err_buf_size) { 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 * bootenv_res section. Without the correct size it wouldn't * be possible to call UBI update vol. * 2. Call UBI update vol * 3. Get FILE* to vol dev * 4. Write to FILE* */ rc = ubi_open(&ulib); if (rc != 0) { rc = -PFIFLASH_ERR_UBI_OPEN; EBUF(PFIFLASH_ERRSTR[-rc]); goto err; } rc = bootenv_create(&bootenv_new); if (rc != 0) { rc = -PFIFLASH_ERR_BOOTENV_CREATE; EBUF(PFIFLASH_ERRSTR[-rc], " 'new'"); goto err; } rc = bootenv_create(&bootenv_res); if (rc != 0) { rc = -PFIFLASH_ERR_BOOTENV_CREATE; EBUF(PFIFLASH_ERRSTR[-rc], " 'res'"); goto err; } 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) { EBUF_PREPEND("handling PDD"); goto err; } else if (warnings) /* TODO do something with warnings */ dbg_msg("A warning in the PDD operation occured: %d", warnings); rc = bootenv_size(bootenv_res, &update_size); 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) { rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; EBUF(PFIFLASH_ERRSTR[-rc], id); goto err; } rc = bootenv_write(fp_out, bootenv_res); if (rc != 0) { rc = -PFIFLASH_ERR_BOOTENV_WRITE; EBUF(PFIFLASH_ERRSTR[-rc], devno, id); goto err; } err: if (ulib != NULL) ubi_close(&ulib); if (bootenv_new != NULL) bootenv_destroy(&bootenv_new); if (bootenv_res != NULL) bootenv_destroy(&bootenv_res); if (fp_out) fclose(fp_out); return rc; }
static int 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; }
/** * 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: * 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_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) { int rc; bootenv_t bootenv; pdd_func_t pdd_f; if (pfi == NULL) return -EINVAL; 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 */ rc = bootenv_create(&bootenv); if (rc != 0) { 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); if (rc != 0) { EBUF_PREPEND("reading PFI header"); goto err; } 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, err_buf_size); if (rc != 0) { EBUF_PREPEND("handling raw section"); goto err; } if (complete && !compare) { rc = erase_unmapped_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, err_buf, err_buf_size); if (rc != 0) { EBUF_PREPEND("deleting unmapped UBI volumes"); goto err; } } if (((int)pdd_handling >= 0) && (pdd_handling < PDD_HANDLING_NUM)) pdd_f = pdd_funcs[pdd_handling]; else { rc = -PFIFLASH_ERR_PDD_UNKNOWN; EBUF(PFIFLASH_ERRSTR[-rc]); 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; } 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"); 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; } } err: pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws); pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, pfi_ubis); bootenv_destroy(&bootenv); return rc; }