diff options
Diffstat (limited to 'ubi-utils/src/pddcustomize')
| -rw-r--r-- | ubi-utils/src/pddcustomize/pddcustomize.c | 496 | 
1 files changed, 496 insertions, 0 deletions
| diff --git a/ubi-utils/src/pddcustomize/pddcustomize.c b/ubi-utils/src/pddcustomize/pddcustomize.c new file mode 100644 index 0000000..f71d916 --- /dev/null +++ b/ubi-utils/src/pddcustomize/pddcustomize.c @@ -0,0 +1,496 @@ +/* + * 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: Oliver Lohmann + * + * PDD (platform description data) contains a set of system specific + * boot-parameters. Some of those parameters need to be handled + * special on updates, e.g. the MAC addresses. They must also be kept + * if the system is updated and one must be able to modify them when + * the system has booted the first time. This tool is intended to do + * PDD modification. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <argp.h> +#include <unistd.h> +#include <errno.h> +#include <mtd/ubi-header.h> + +#include "config.h" +#include "bootenv.h" +#include "error.h" +#include "example_ubi.h" +#include "libubi.h" +#include "ubimirror.h" + +typedef enum action_t { +	ACT_NORMAL   = 0, +	ACT_LIST, +	ACT_ARGP_ABORT, +	ACT_ARGP_ERR, +} action_t; + +#define ABORT_ARGP do {			\ +	state->next = state->argc;	\ +	args->action = ACT_ARGP_ABORT;	\ +} while (0) + +#define ERR_ARGP do {			\ +	state->next = state->argc;	\ +	args->action = ACT_ARGP_ERR;	\ +} while (0) + +const char *argp_program_version = PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " +	BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" +	"\n" +	"pddcustomize - customize bootenv and pdd values.\n"; + +static const char copyright [] __attribute__((unused)) = +	"FIXME: insert license type"; /* FIXME */ + +static struct argp_option options[] = { +	{ name: "copyright", key: 'c', arg: NULL,    flags: 0, +	  doc: "Print copyright information.", +	  group: 1 }, + +	{ name: "input", key: 'i', arg: "<input>",    flags: 0, +	  doc: "Binary input file. For debug purposes.", +	  group: 1 }, + +	{ name: "output", key: 'o', arg: "<output>",	flags: 0, +	  doc: "Binary output file. For debug purposes.", +	  group: 1 }, + +	{ name: "list", key: 'l', arg: NULL,	flags: 0, +	  doc: "List card bootenv/pdd values.", +	  group: 1 }, + +	{ name: "both", key: 'b', arg: NULL,	flags: 0, +	  doc: "Mirror updated PDD to redundand copy.", +	  group: 1 }, + +	{ name: "side", key: 's', arg: "<seqnum>",    flags: 0, +	  doc: "The side/seqnum to update.", +	  group: 1 }, + +	{ name: "host", key: 'x', arg: NULL,	flags: 0, +	  doc: "use x86 platform for debugging.", +	  group: 1 }, + +	{ name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 }, +}; + +typedef struct myargs { +	action_t action; +	const char* file_in; +	const char* file_out; +	int both; +	int side; +	int x86;		/* X86 host, use files for testing */ +	bootenv_t env_in; + +	char *arg1; +	char **options;		/* [STRING...] */ +} myargs; + +static int +get_update_side(const char* str) +{ +	uint32_t i = strtoul(str, NULL, 0); + +	if ((i != 0) && (i != 1)) { +		return -1; +	} + +	return i; +} + +static int +extract_pair(bootenv_t env, const char* str) +{ +	int rc = 0; +	char* key; +	char* val; + +	key = strdup(str); +	if (key == NULL) +		return -ENOMEM; + +	val = strstr(key, "="); +	if (val == NULL) { +		err_msg("Wrong argument: %s\n" +			"Expecting key=value pair.\n", str); +		rc = -1; +		goto err; +	} + +	*val = '\0'; /* split strings */ +	val++; +	rc = bootenv_set(env, key, val); + +err: +	free(key); +	return rc; +} + +static error_t +parse_opt(int key, char *arg, struct argp_state *state) +{ +	int rc = 0; +	int err = 0; + +	myargs *args = state->input; + +	switch (key) { +	case 'c': +		err_msg("%s\n", copyright); +		ABORT_ARGP; +		break; +	case 'l': +		args->action = ACT_LIST; +		break; +	case 'b': +		args->both = 1; +		break; +	case 'x': +		args->x86 = 1; +		break; +	case 's': +		args->side = get_update_side(arg); +		if (args->side < 0) { +			err_msg("Unsupported seqnum: %d.\n" +				"Supported seqnums are '0' and '1'\n", +				args->side, arg); +			ERR_ARGP; +		} +		break; +	case 'i': +		args->file_in = arg; +		break; +	case 'o': +		args->file_out = arg; +		break; +	case ARGP_KEY_ARG: +		rc = extract_pair(args->env_in, arg); +		if (rc != 0) +			ERR_ARGP; +		break; +	case ARGP_KEY_END: +		if (err) { +			err_msg("\n"); +			argp_usage(state); +			ERR_ARGP; +		} +		break; +	default: +		return(ARGP_ERR_UNKNOWN); +	} + +	return 0; +} + +static struct argp argp = { +	options:     options, +	parser:	     parse_opt, +	args_doc:    "[key=value] [...]", +	doc:	     doc, +	children:    NULL, +	help_filter: NULL, +	argp_domain: NULL, +}; + + +static int +list_bootenv(bootenv_t env) +{ +	int rc = 0; +	rc = bootenv_write_txt(stdout, env); +	if (rc != 0) { +		err_msg("Cannot list bootenv/pdd. rc: %d\n", rc); +		goto err; +	} +err: +	return rc; +} + +static int +process_key_value(bootenv_t env_in, bootenv_t env) +{ +	int rc = 0; +	size_t size, i; +	const char* tmp; +	const char** key_vec = NULL; + +	rc = bootenv_get_key_vector(env_in, &size, 0, &key_vec); +	if (rc != 0) +		goto err; + +	for (i = 0; i < size; i++) { +		rc = bootenv_get(env_in, key_vec[i], &tmp); +		if (rc != 0) { +			err_msg("Cannot read value to input key: %s. rc: %d\n", +					key_vec[i], rc); +			goto err; +		} +		rc = bootenv_set(env, key_vec[i], tmp); +		if (rc != 0) { +			err_msg("Cannot set value key: %s. rc: %d\n", +					key_vec[i], rc); +			goto err; +		} +	} + +err: +	if (key_vec != NULL) +		free(key_vec); +	return rc; +} + +static int +read_bootenv(const char* file, bootenv_t env) +{ +	int rc = 0; +	FILE* fp_in = NULL; + +	fp_in = fopen(file, "rb"); +	if (fp_in == NULL) { +		err_msg("Cannot open file: %s\n", file); +		return -EIO; +	} + +	rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE); +	if (rc != 0) { +		err_msg("Cannot read bootenv from file %s. rc: %d\n", +			file, rc); +		goto err; +	} + +err: +	fclose(fp_in); +	return rc; +} + +/* + * Read bootenv from ubi volume + */ +static int +ubi_read_bootenv(uint32_t devno, uint32_t id, bootenv_t env) +{ +	ubi_lib_t ulib = NULL; +	int rc = 0; +	FILE* fp_in = NULL; + +	rc = ubi_open(&ulib); +	if( rc ){ +		err_msg("Cannot allocate ubi structure\n"); +		return rc; +	} + +	fp_in = ubi_vol_fopen_read(ulib, devno, id); +	if (fp_in == NULL) { +		err_msg("Cannot open volume:%d number:%d\n", devno, id); +		goto err; +	} + +	rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE); +	if (rc != 0) { +		err_msg("Cannot read volume:%d number:%d\n", devno, id); +		goto err; +	} + +err: +	if( fp_in ) +		fclose(fp_in); +	ubi_close(&ulib); +	return rc; +} + +static int +write_bootenv(const char* file, bootenv_t env) +{ +	int rc = 0; +	FILE* fp_out; + +	fp_out = fopen(file, "wb"); +	if (fp_out == NULL) { +		err_msg("Cannot open file: %s\n", file); +		return -EIO; +	} + +	rc = bootenv_write(fp_out, env); +	if (rc != 0) { +		err_msg("Cannot write bootenv to file %s. rc: %d\n", file, rc); +		goto err; +	} + +err: +	fclose(fp_out); +	return rc; +} + +/* + * Read bootenv from ubi volume + */ +static int +ubi_write_bootenv(uint32_t devno, uint32_t id, bootenv_t env) +{ +	ubi_lib_t ulib = NULL; +	int rc = 0; +	FILE* fp_out; +	size_t nbytes ; + +	rc = bootenv_size(env, &nbytes); +	if( rc ){ +		err_msg("Cannot determine size of bootenv structure\n"); +		return rc; +	} +	rc = ubi_open(&ulib); +	if( rc ){ +		err_msg("Cannot allocate ubi structure\n"); +		return rc; +	} +	fp_out = ubi_vol_fopen_update(ulib, devno, id, +			(unsigned long long)nbytes); +	if (fp_out == NULL) { +		err_msg("Cannot open volume:%d number:%d\n", devno, id); +		goto err; +	} + +	rc = bootenv_write(fp_out, env); +	if (rc != 0) { +		err_msg("Cannot write bootenv to volume %d number:%d\n", +			devno, id); +		goto err; +	} + +err: +	if( fp_out ) +		fclose(fp_out); +	ubi_close(&ulib); +	return rc; +} + +static int +do_mirror(int volno) +{ +	char errbuf[1024]; +	uint32_t ids[2]; +	int rc; +	int src_volno_idx = 0; + +	ids[0] = EXAMPLE_BOOTENV_VOL_ID_1; +	ids[1] = EXAMPLE_BOOTENV_VOL_ID_2; + +	if (volno == EXAMPLE_BOOTENV_VOL_ID_2) +		src_volno_idx = 1; + +	rc = ubimirror(EXAMPLE_UBI_DEVICE, src_volno_idx, ids, 2, errbuf, +		       sizeof errbuf); +	if( rc ) +		err_msg(errbuf); +	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; +	} + +	argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &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; +} | 
