From 2134e864c823b456d6de0a128bb6c55d1a04aba7 Mon Sep 17 00:00:00 2001 From: James Maki Date: Fri, 23 Apr 2010 14:27:29 -0500 Subject: initial commit --- src/u_boot.c | 363 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 363 insertions(+) create mode 100644 src/u_boot.c (limited to 'src/u_boot.c') diff --git a/src/u_boot.c b/src/u_boot.c new file mode 100644 index 0000000..e240475 --- /dev/null +++ b/src/u_boot.c @@ -0,0 +1,363 @@ +/* + * U-Boot utility program for Linux + * + * Copyright (C) 2010 by Multi-Tech Systems + * + * Author: James Maki + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "u_boot.h" + +static int tokcmp(const char *cmd, const char *pattern) { + int len = strlen(cmd); + if (len > strlen(pattern)) { + return -1; + } + + return memcmp(pattern, cmd, len); +} + +#define ENV_HEADER_SIZE (sizeof(uint32_t) + sizeof(uint8_t)) +#define ENV_DATA_SIZE (MTD_SIZE - ENV_HEADER_SIZE) + +struct environment { + uint32_t crc; + uint8_t flags; + char data[ENV_DATA_SIZE]; +}; + +static int write_uboot_env(const char *device, struct environment *env) +{ + int err; + int fd; + + err = mtd_erase_all(device, 0); + if (!err) { + error("mtd_erase_all %s failed", device); + return -1; + } + + fd = open(device, O_WRONLY); + if (fd < 0) { + error("open %s failed: %d", device, errno); + return -1; + } + + err = write(fd, env, sizeof(*env)); + if (err != sizeof(*env)) { + error("write to %s failed: %d", device, errno); + close(fd); + return -1; + } + + close(fd); + + return err; +} + +static int read_uboot_env(const char *device, struct environment *env) +{ + int fd; + int err; + + memset(env, 0, sizeof(*env)); + + fd = open(device, O_RDONLY); + if (fd < 0) { + error("open %s failed: %d", device, errno); + return -1; + } + + err = read(fd, env, sizeof(*env)); + if (err != sizeof(*env)) { + error("read from %s failed: %d", device, errno); + close(fd); + return -1; + } + + close(fd); + + return err; +} + +static char *next_var(const char *var) +{ + return (char *) (var + strlen(var) + 1); +} + +static int cmd_printenv(struct environment *env, int argc, char **argv) +{ + char *var; + char *name = NULL; + size_t name_len = 0; + + if (argc) { + name = *argv; + name_len = strlen(name); + } + + var = env->data; + while (*var) { + if (!name) { + printf("%s\n", var); + } else if (!strncmp(var, name, name_len) && var[name_len] == '=') { + printf("%s\n", var); + return true; + } + + var = next_var(var); + } + + if (name) { + fprintf(stderr, "environment variable not found\n"); + return false; + } + + return true; +} + +static int cmd_setenv(struct environment *env, int argc, char **argv) +{ + int tmp; + char *var; + char *cp; + char *end = env->data + sizeof(env->data); + char *name; + size_t name_len; + size_t value_len; + + if (!argc) { + fprintf(stderr, "name expected\n"); + return false; + } + name = *argv; + argc--; argv++; + + name_len = strlen(name); + + var = env->data; + while (*var) { + if (!strncmp(var, name, name_len) && var[name_len] == '=') { + dbg("found variable (%s) at %lld", var, (long long int) var); + + cp = next_var(var); + while (*cp) { + while (*cp) { + *var++ = *cp++; + } + *var++ = *cp++; + } + + break; + } + + var = next_var(var); + } + + value_len = 0; + for (tmp = 0; tmp < argc; tmp++) { + value_len += strlen(argv[tmp]); + if (tmp + 1 < argc) { + value_len += 1; + } + } + + if (value_len) { + if (var + strlen(name) + strlen("=") + value_len + 1 >= end) { + error("end of environment reached"); + return false; + } + *var = 0; + strcat(var, name); + strcat(var, "="); + for (tmp = 0; tmp < argc; tmp++) { + strcat(var, argv[tmp]); + if (tmp + 1 < argc) { + strcat(var, " "); + } + } + var += strlen(var) + 1; + } + + *var = 0; + if (var == env->data) { + *(var + 1) = 0; + } + + env->crc = crc32(0, (uint8_t *) env->data, sizeof(env->data)); + dbg("crc: 0x%08X", env->crc); + env->flags = 0; + + tmp = write_uboot_env(MTD_ENV1, env); + if (tmp < 0) { + dbg("write_uboot_env %s failed with %d", MTD_ENV1, tmp); + } + tmp = write_uboot_env(MTD_ENV2, env); + if (tmp < 0) { + dbg("write_uboot_env %s failed with %d", MTD_ENV1, tmp); + } + + return true; +} + +static void print_version(const char *name) { + printf("%s (" PACKAGE ") " VERSION " (" __DATE__ " " __TIME__ ")\n", name); + printf("Copyright (C) 2010 by Multi-Tech Systems\n"); + printf( +"This program is free software; you may redistribute it under the terms of\n" +"the GNU General Public License version 2 or (at your option) any later version.\n" +"This program has absolutely no warranty.\n"); +} + +static void usage(FILE *out) { + fprintf(out, "Usage: u-boot { printenv [ name ] | setenv name [ value ] }\n"); + fprintf(out, "\n"); +} + +int main(int argc, char *argv[]) { + int err; + char *cmd; + char *option; + struct environment *env = NULL; + + struct environment *env1; + struct environment *env2; + uint32_t crc1_ok; + uint32_t crc2_ok; + + if (argc <= 1) { + usage(stderr); + exit(1); + } + argc--; argv++; + + while (argc) { + option = *argv; + if (*option != '-') { + break; + } else if (!strcmp(option, "--")) { + break; + } else if (!strcmp(option, "--version")) { + print_version("u-boot"); + exit(0); + } else if (!strcmp(option, "--help")) { + usage(stdout); + exit(0); + } else { + usage(stderr); + exit(1); + } + + argc--; argv++; + } + + if (!argc) { + usage(stderr); + exit(1); + } + + env1 = malloc(sizeof(struct environment)); + if (!env1) { + error("out of memory"); + return 1; + } + + env2 = malloc(sizeof(struct environment)); + if (!env2) { + error("out of memory"); + return 1; + } + + err = read_uboot_env(MTD_ENV1, env1); + if (err < 0) { + error("read_uboot_env failed"); + return 1; + } + dbg("env1 crc: 0x%08X", env1->crc); + dbg("env1 flags: %d", env1->flags); + if (crc32(0, (uint8_t *) env1->data, sizeof(env1->data)) == env1->crc) { + crc1_ok = 1; + } else { + error("crc does not match on primary env"); + crc1_ok = 0; + } + + err = read_uboot_env(MTD_ENV2, env2); + if (err < 0) { + error("read_uboot_env failed"); + return 1; + } + dbg("env2 crc: 0x%08X", env2->crc); + dbg("env2 flags: %d", env2->flags); + if (crc32(0, (uint8_t *) env2->data, sizeof(env2->data)) == env2->crc) { + crc2_ok = 1; + } else { + error("crc does not match on redundant env"); + crc2_ok = 0; + } + + if (!crc1_ok && !crc2_ok) { + error("both environments are bad: loading DEFAULT_ENV"); + env = env1; + env->flags = 0; + memcpy(env->data, DEFAULT_ENV, sizeof(DEFAULT_ENV)); + } else if (crc1_ok && !crc2_ok) { + env = env1; + } else if (!crc1_ok && crc2_ok) { + env = env2; + } else { + if (env1->flags == 255 && env2->flags == 0) { + env = env2; + } else if (env2->flags == 255 && env1->flags == 0) { + env = env1; + } else if (env1->flags > env2->flags) { + env = env1; + } else if (env2->flags > env1->flags) { + env = env2; + } else { + env = env1; + } + } + + cmd = *argv; + argc--; argv++; + if (!tokcmp(cmd, "printenv")) { + err = cmd_printenv(env, argc, argv); + } else if (!tokcmp(cmd, "setenv")) { + err = cmd_setenv(env, argc, argv); + } else { + usage(stderr); + exit(1); + } + + return !err; +} + -- cgit v1.2.3