/*
  Encode/decode u-Boot environment dump.
 
  Copyright (C) 2010 Federico Heinz <fheinz@vialibre.org.ar>

  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 3 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, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <endian.h>
#include "crc32.h"
#include "do_write.h"

#define ENVSIZE        (128*1024)

static const char *progname = NULL;
static const char *usage = NULL;
static const char *usage_env_decode =
	"usage: %s <env_block >text_file\n"
	"typical usage: nanddump -n -s 0xa0000 -l 0x20000 /dev/mtd0 | sheeva-nandrs-check | %s >env_as_text\n"
	"Takes a 128Kb dump of u-boot's environment area, and\n"
	"convert it into a textual representation that can be\n"
	"processed with standard Unix tools.\n";
static const char *usage_env_encode =
	"usage: %s <text_file >env_block\n"
	"typical usage: %s <text_file | sheeva-nandrs-add | nandwrite -o -s 0xa0000 /dev/mtd0\n"
	"Converts a text file into a 128KB block suitable for use as\n"
	"u-boot's environment, including CRC.\n"
	"WARNING: Performs only very little sanity checks on its input!\n"
	"         This program is perfectly happy producing syntactically\n"
	"         unsound environments, use with care!\n";
static const char *copyright =
	"This is %s %s\n"
	"Copyright (C) 2010 Federico Heinz <fheinz@vialibre.org.ar>\n"
	"This program comes with ABSOLUTELY NO WARRANTY;\n"
	"This is free software, and you are welcome to redistribute it\n"
	"under certain conditions (see the file COPYING).\n";

static int env_decode() {
	unsigned char env[ENVSIZE];
	unsigned char *envp;

	if (fread(env, sizeof(env), 1, stdin) != 1) {
		fprintf(stderr, "%s: environment must be 128Kb.\n", progname);
		return 2;
	}
	if (env[ENVSIZE-1] != '\0') {
		fprintf(stderr, "%s: environment must be terminated with '\\0'.\n", progname);
		return 3;
	}
	if (crc32(0, env+sizeof(uint32_t), ENVSIZE-sizeof(uint32_t)) != 
	    le32toh(*(uint32_t *)env)) {
		fprintf(stderr, "%s: environment checksum mismatch.\n", progname);
		return 4;
	}
	envp = env+sizeof(uint32_t);
	while (envp < env+ENVSIZE && *envp != '\0') {
		printf("%s\n", envp);
		envp += strlen((char *)envp)+1;
	}
	return 0;
}

static int env_encode() {
	unsigned char env[ENVSIZE];
	unsigned char line[ENVSIZE];
	unsigned char *envp = env+sizeof(uint32_t);

	bzero(env, sizeof(env));
	while (fgets((char *)line, sizeof(line), stdin) != NULL) {
		unsigned int line_storage = strlen((char *)line); /* Line includes \n */

		if (envp+line_storage >= env+sizeof(env)) {
			fprintf(stderr, "%s: environment too large\n", progname);
			return 1;
		}
		strncpy((char *)envp, (char *)line, line_storage-1); /* copy without \n */
		envp += line_storage; /* there's already a \0 in place (see bcopy) */
	}
	*(uint32_t *)env = htole32(crc32(0, env+sizeof(uint32_t),
					 sizeof(env)-sizeof(uint32_t)));
	if (do_write(env, sizeof(env)) != 0) {
		perror(progname);
		return -errno;
	}
	return 0;
}

int main(int argc, const char *argv[]) {
	int (*mode)();
	progname = strrchr(argv[0], '/');

	if (progname != NULL)
		progname++;
	else
		progname = argv[0];
	if (!strcmp(progname, "sheeva-ubootenv-decode")){
		mode = env_decode;
		usage = usage_env_decode;
	} else if (!strcmp(progname, "sheeva-ubootenv-encode")){
		mode = env_encode;
		usage = usage_env_encode;
	} else {
		fprintf(stderr, "%s: unknown operation mode\n", progname); 
		return 1;
	}
	if (argc != 1) {
		fprintf(stderr, usage, progname, progname);
		fprintf(stderr, copyright, progname, HGVERSION);
		return 1;
	}
	return (*mode)();
}

