[U-Boot] [PATCHv5] new tool mkenvimage: generates an env image from an arbitrary config file

David Wagner david.wagner at free-electrons.com
Thu Sep 1 17:57:09 CEST 2011


This tool takes a key=value configuration file (same as would a `printenv' show)
and generates the corresponding environment image, ready to be flashed.

use case: flash the environment with an external tool

Signed-off-by: David Wagner <david.wagner at free-electrons.com>
---

	changes since v4
	~~~~~~~~~~~~~~~~

 - keep the Makefiles somewhat sorted (I'm not sure how it is sorted but since
   "mkenvimage" is alphabetically before "mkimage", I put the former just before
   the latter).

 - replace f{open, read, write, ...} with {open, read, write, ...} and remove
   the now unused stdlib.h include

 - tweak usage()

 - typos

 - properly handle embedded newlines, comments and empty lines at the beginning
   of the input file.  This introduced a second buffer ('filebuf') (see the
   big for loop): When we encouter a newline after a backslash, without this
   buffer, we would have needed to shift all envptr one byte backward to
   overwrite the preceeding backslash.  Introducing this second buffer looked
   like a simpler alternative.

 - correct the way how 2 \0 are put at the end of the environment (@Wolfgang:
   the second "ep >= envsize" check is there to handle the corner case where the
   env target partition would be, say, 32 bytes long and the input file is 31
   byte long but doesn't have an ending newline)

PS: as the input file is probably always pretty small and we read the file
sequentially, we don't go back in the stream, we didn't find much advantage over
read()

 tools/Makefile     |    5 +
 tools/mkenvimage.c |  263 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 268 insertions(+), 0 deletions(-)
 create mode 100644 tools/mkenvimage.c

diff --git a/tools/Makefile b/tools/Makefile
index fc741d3..da7caf0 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -66,6 +66,7 @@ BIN_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc$(SFX)
 BIN_FILES-$(CONFIG_CMD_NET) += gen_eth_addr$(SFX)
 BIN_FILES-$(CONFIG_CMD_LOADS) += img2srec$(SFX)
 BIN_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes$(SFX)
+BIN_FILES-y += mkenvimage$(SFX)
 BIN_FILES-y += mkimage$(SFX)
 BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX)
 BIN_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX)
@@ -89,6 +90,7 @@ OBJ_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes.o
 NOPED_OBJ_FILES-y += kwbimage.o
 NOPED_OBJ_FILES-y += imximage.o
 NOPED_OBJ_FILES-y += omapimage.o
+NOPED_OBJ_FILES-y += mkenvimage.o
 NOPED_OBJ_FILES-y += mkimage.o
 OBJ_FILES-$(CONFIG_NETCONSOLE) += ncb.o
 NOPED_OBJ_FILES-y += os_support.o
@@ -184,6 +186,9 @@ $(obj)xway-swap-bytes$(SFX):	$(obj)xway-swap-bytes.o
 	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
 	$(HOSTSTRIP) $@
 
+$(obj)mkenvimage$(SFX):	$(obj)crc32.o $(obj)mkenvimage.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+
 $(obj)mkimage$(SFX):	$(obj)crc32.o \
 			$(obj)default_image.o \
 			$(obj)fit_image.o \
diff --git a/tools/mkenvimage.c b/tools/mkenvimage.c
new file mode 100644
index 0000000..8aaa5ce
--- /dev/null
+++ b/tools/mkenvimage.c
@@ -0,0 +1,263 @@
+/*
+ * (C) Copyright 2011 Free Electrons
+ * David Wagner <david.wagner at free-electrons.com>
+ *
+ * Inspired from envcrc.c:
+ * (C) Copyright 2001
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio at tin.it
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <compiler.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <u-boot/crc.h>
+
+#define CRC_SIZE sizeof(uint32_t)
+
+static void usage(const char *exec_name)
+{
+	fprintf(stderr, "%s [-h] [-r] [-b] [-p <byte>] "
+	       "-s <envrionment partition size> -o <output> <input file>\n"
+	       "\n"
+	       "This tool takes a key=value input file (same as would a "
+	       "`printenv' show) and generates the corresponding environment "
+	       "image, ready to be flashed.\n"
+	       "\n"
+	       "\tThe input file is in format:\n"
+	       "\t\tkey1=value1\n"
+	       "\t\tkey2=value2\n"
+	       "\t\t...\n"
+	       "\t-r : the environment has multiple copies in flash\n"
+	       "\t-b : the target is big endian (default is little endian)\n"
+	       "\t-p <byte> : fill the image with <byte> bytes instead of "
+	       "0xff bytes\n"
+	       "\n"
+	       "If the input file is \"-\", data is read from standard input\n",
+	       exec_name);
+}
+
+int main(int argc, char **argv)
+{
+	uint32_t crc, targetendian_crc;
+	const char *txt_filename = NULL, *bin_filename = NULL;
+	int txt_fd, bin_fd;
+	unsigned char *dataptr, *envptr;
+	unsigned char *filebuf;
+	unsigned int envsize, datasize = 0;
+	int bigendian = 0;
+	int redundant = 0;
+	unsigned char padbyte = 0xff;
+
+	int option;
+	int ret = EXIT_SUCCESS;
+
+	struct stat txt_file_stat;
+
+	int fp, ep;
+
+	/* Parse the cmdline */
+	while ((option = getopt(argc, argv, "s:o:rbp:h")) != -1) {
+		switch (option) {
+		case 's':
+			datasize = strtol(optarg, NULL, 0);
+			break;
+		case 'o':
+			bin_filename = strdup(optarg);
+			if (!bin_filename) {
+				fprintf(stderr, "Can't strdup() the output "
+						"filename\n");
+				return EXIT_FAILURE;
+			}
+			break;
+		case 'r':
+			redundant = 1;
+			break;
+		case 'b':
+			bigendian = 1;
+			break;
+		case 'p':
+			padbyte = strtol(optarg, NULL, 0);
+			break;
+		case 'h':
+			usage(argv[0]);
+			return EXIT_SUCCESS;
+		default:
+			fprintf(stderr, "Wrong option -%c\n", option);
+			usage(argv[0]);
+			return EXIT_FAILURE;
+		}
+	}
+
+	/* Check datasize and allocate the data */
+	if (datasize == 0) {
+		fprintf(stderr,
+			"Please specify the size of the envrionnment "
+			"partition.\n");
+		usage(argv[0]);
+		return EXIT_FAILURE;
+	}
+
+	dataptr = malloc(datasize * sizeof(*dataptr));
+	if (!dataptr) {
+		fprintf(stderr, "Can't alloc dataptr.\n");
+		return EXIT_FAILURE;
+	}
+
+	/*
+	 * envptr points to the beginning of the actual environment (after the
+	 * crc and possible `redundant' bit
+	 */
+	envsize = datasize - (CRC_SIZE + redundant);
+	envptr = dataptr + CRC_SIZE + redundant;
+
+	/* Pad the environment with the padding byte */
+	memset(envptr, padbyte, envsize);
+
+	/* Open the input file ... */
+	if (optind >= argc) {
+		fprintf(stderr, "Please specify an input filename\n");
+		return EXIT_FAILURE;
+	}
+
+	txt_filename = argv[optind];
+	if (strcmp(txt_filename, "-") == 0) {
+		txt_fd = STDIN_FILENO;
+	} else {
+		txt_fd = open(txt_filename, O_RDONLY);
+		if (txt_fd == -1) {
+			fprintf(stderr, "Can't open \"%s\": %s\n",
+					txt_filename, strerror(errno));
+			return EXIT_FAILURE;
+		}
+	}
+	/* ... and check it */
+	ret = fstat(txt_fd, &txt_file_stat);
+	if (ret == -1) {
+		fprintf(stderr, "Can't stat() on \"%s\": "
+				"%s\n", txt_filename, strerror(errno));
+		return EXIT_FAILURE;
+	}
+	/*
+	 * The right test to do is "=>" (not ">") because of the additionnal
+	 * ending \0. See below.
+	 */
+	if (txt_file_stat.st_size >= envsize) {
+		fprintf(stderr, "The input file is larger than the "
+				"envrionnment partition size\n");
+		return EXIT_FAILURE;
+	}
+
+	/* Read the raw input file and transform it */
+	filebuf = malloc(sizeof(*envptr) * txt_file_stat.st_size);
+	ret = read(txt_fd, filebuf, sizeof(*envptr) * txt_file_stat.st_size);
+	if (ret != txt_file_stat.st_size) {
+		fprintf(stderr, "Can't read the whole input file\n");
+		return EXIT_FAILURE;
+	}
+	ret = close(txt_fd);
+
+	/* Replace newlines separating variables with \0 */
+	for (fp = 0, ep = 0 ; fp < txt_file_stat.st_size ; fp++) {
+		/* TODO: what happens if we find a \n at the beginning of the
+		 * file ?
+		 */
+		if (filebuf[fp] == '\n') {
+			if (fp == 0) {
+				/*
+				 * Newline at the beggining of the file ?
+				 * Ignore it.
+				 */
+				continue;
+			} else if (filebuf[fp-1] == '\\') {
+				/*
+				 * Embedded newline in a variable.
+				 *
+				 * The backslash was added to the envptr ;
+				 * rewind and replace it with a newline
+				 */
+				ep--;
+				envptr[ep++] = '\n';
+			} else {
+				/* End of a variable */
+				envptr[ep++] = '\0';
+			}
+		} else if (filebuf[fp] == '#') {
+			if (fp != 0 && filebuf[fp-1] == '\n') {
+				/* This line is a comment, let's skip it */
+				while (fp < txt_file_stat.st_size && fp++ &&
+				       filebuf[fp] != '\n');
+			} else {
+				envptr[ep++] = filebuf[fp];
+			}
+		} else {
+			envptr[ep++] = filebuf[fp];
+		}
+	}
+	/*
+	 * Make sure there is a final '\0'
+	 * And do it again on the next byte to mark the end of the environment.
+	 */
+	if (envptr[ep-1] != '\0') {
+		envptr[ep++] = '\0';
+		/*
+		 * The text file doesn't have an ending newline.  We need to
+		 * check the env size again to make sure we have room for two \0
+		 */
+		if (ep >= envsize) {
+			fprintf(stderr, "The environment file is too large for "
+					"the target environment storage\n");
+			return EXIT_FAILURE;
+		}
+		envptr[ep] = '\0';
+	} else {
+		envptr[ep] = '\0';
+	}
+
+	/* Computes the CRC and put it at the beginning of the data */
+	crc = crc32(0, envptr, envsize);
+	targetendian_crc = bigendian ? cpu_to_be32(crc) : cpu_to_le32(crc);
+
+	memcpy(dataptr, &targetendian_crc, sizeof(uint32_t));
+
+	bin_fd = creat(bin_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+	if (bin_fd == -1) {
+		fprintf(stderr, "Can't open output file \"%s\": %s\n",
+				bin_filename, strerror(errno));
+		return EXIT_FAILURE;
+	}
+
+	if (write(bin_fd, dataptr, sizeof(*dataptr) * datasize) !=
+			sizeof(*dataptr) * datasize) {
+		fprintf(stderr, "write() failed: %s\n", strerror(errno));
+		return EXIT_FAILURE;
+	}
+
+	ret = close(bin_fd);
+
+	return ret;
+}
-- 
1.7.0.4



More information about the U-Boot mailing list