diff options
author | Bjørn Mork <bjorn@mork.no> | 2015-04-16 00:33:16 +0200 |
---|---|---|
committer | Bjørn Mork <bjorn@mork.no> | 2015-04-16 00:33:16 +0200 |
commit | 67d1ed10ff85433b68f80dbd83874d90a0ce4cb4 (patch) | |
tree | b6bdf3362c1c1b430908e6a8a8f62cf502a34735 | |
parent | 7a6989e8d87a95921af9c9bcc5b7599c3d353fe2 (diff) |
covery: imitate options
Signed-off-by: Bjørn Mork <bjorn@mork.no>
-rw-r--r-- | covery/src/covery.c | 174 |
1 files changed, 137 insertions, 37 deletions
diff --git a/covery/src/covery.c b/covery/src/covery.c index af0bde6..a03a07c 100644 --- a/covery/src/covery.c +++ b/covery/src/covery.c @@ -12,10 +12,51 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <getopt.h> +#include <sysexits.h> #include <fcntl.h> #include <sys/ioctl.h> #include <mtd/mtd-user.h> +#define VERSION "0.00" + +#ifdef TEST +static const char s_env[] = "\"mtdram test device\""; +#else +static const char s_env[] = "\"s_env\""; +#endif + +static const struct option long_options[] = { + { "show", 0, NULL, 'i' }, + { "clear", 0, NULL, 'c' }, + { "dump", 0, NULL, 'd' }, + { "hex", 0, NULL, 'x' }, + { "ascii", 0, NULL, 'a' }, + { "verbose", 0, NULL, 'v' }, + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, + { 0, 0, 0, 0 } +}; + +const char *program; + +static void usage(int ex) { + fprintf(stderr, + "Usage: %s [options]\n" + " Updates recovery information\n" + "Options:\n" + " -i --show Show current boot count info\n" + " -c --clear Clear boot count info\n" + " -dx --dump --hex Dump hex of %s data\n" + " -da --dump --ascii Ascii of %s data\n" + " -v --verbose Verbose output\n" + " -h --help Display this text\n" + " -V --version Display version\n", + program, s_env, s_env); + exit(ex); +} + +/* FIXME: verify these magic constants - RECSZ seems to match writesize */ #define MAGIC 0x20110811 #define RECSZ 2048 @@ -33,25 +74,14 @@ struct s_env_rec { __le32 magic; __le32 count; __le32 check; - __u8 padding[RECSZ - 3 * sizeof(__le32)]; }; -static int nowrite = 1; - -#ifdef TEST -static const char s_env[] = "\"mtdram test device\""; -#else -static const char s_env[] = "\"s_env\""; -#endif - - /* use globals to reduce stack abuse */ struct mtd_info_user info; struct erase_info_user li; -struct s_env_rec rec; -char buf[256]; +char buf[RECSZ]; -int mtd_open(const char *mtd, struct mtd_info_user *info) +static int mtd_open(const char *mtd, struct mtd_info_user *info) { int fd; @@ -114,18 +144,17 @@ void dump_info(struct mtd_info_user *info) { fprintf(stderr, "erasesize:\t%#010x\n", info->erasesize); fprintf(stderr, "writesize:\t%#010x\n", info->writesize); fprintf(stderr, "oobsize:\t%#010x\n", info->oobsize); + fprintf(stderr, "records:\t%u\n", info->size / RECSZ); } int rec_ok(struct s_env_rec *rec) { return (rec->magic == cpu_to_le32(MAGIC) && cpu_to_le32(rec->magic) + cpu_to_le32(rec->count) == cpu_to_le32(rec->check)); } -int write_ok(int fd, struct s_env_rec *rec) { - memset(rec, 0xff, sizeof(*rec)); +void rec_zero(struct s_env_rec *rec) { rec->magic = cpu_to_le32(MAGIC); rec->count = 0; rec->check = rec->magic; - return write(fd, rec, sizeof(*rec)); } int find_mtd(const char *name) @@ -146,7 +175,44 @@ int find_mtd(const char *name) int main(int argc, char *argv[]) { - int i, fd, bootcount = 0; + int opt, i, fd, cmd = 0, verbose = 0; + struct s_env_rec rec; + char *p; + + program = argv[0]; + if (argc < 2 ) + usage(EX_USAGE); + optopt = 0; + while ((opt = getopt_long(argc, argv, "+icdxavhV?", long_options, NULL)) != EOF ) { + switch(opt) { + case 'i': + case 'c': + case 'd': + if (cmd) + usage(EX_USAGE); + cmd = opt; + break; + case 'x': + case 'a': + if (cmd != 'd') + usage(EX_USAGE); + cmd = opt; + break; + case 'v': + verbose = 1; + break; + case 'V': + fprintf(stderr, "%s (%s)\n", program, VERSION); + exit(0); + default: + /* optopt will be set if this was an unrecognized option, i.e. *not* 'h' or '?' */ + usage(optopt ? EX_USAGE : 0); + break; + } + } + /* dump requires type */ + if (cmd == 'd') + usage(EX_USAGE); i = find_mtd(s_env); if (i < 0) { @@ -154,34 +220,68 @@ int main(int argc, char *argv[]) return -1; } sprintf(buf, "/dev/mtd%d", i); - fprintf(stderr, "name:\t%s\n", s_env); - fprintf(stderr, "chrdev:\t%s\n", buf); + if (verbose) { + fprintf(stderr, "name:\t%s\n", s_env); + fprintf(stderr, "chrdev:\t%s\n", buf); + } fd = mtd_open(buf, &info); if (fd > 0) { - dump_info(&info); - fprintf(stderr, "rec magic count check\n"); + if (verbose) + dump_info(&info); +#ifndef TEST + if (info.writesize != RECSZ) { + fprintf(stderr, "ERROR: unexpected writesize != recordsize (%u)\n", RECSZ); + close(fd); + return -1; + } +#endif + if (verbose) + fprintf(stderr, "\nrec magic count check\n"); for (i = 1;; i++) { - if (read(fd, &rec, sizeof(rec)) != sizeof(rec)) + if (read(fd, buf, RECSZ) != RECSZ) break; - if (rec_ok(&rec)) { - fprintf(stderr, "%3u: %#010x %#010x %#010x\n", - i, le32_to_cpu(rec.magic), le32_to_cpu(rec.count), le32_to_cpu(rec.check)); - bootcount = le32_to_cpu(rec.count); + if (rec_ok((struct s_env_rec *)buf)) { + memcpy(&rec, buf, sizeof(rec)); + if (verbose) + /* avoid %#010x format for values being 0 */ + fprintf(stderr, "%3u: %#010x 0x%08x %#010x\n", + i, le32_to_cpu(rec.magic), le32_to_cpu(rec.count), + le32_to_cpu(rec.check)); } else break; } - /* bugger out if we never read anything sane */ if (i < 2) { - fprintf(stderr, "ERROR: failed to read any valid records\n"); - } else { - fprintf(stderr, "bootcount=%u\n", bootcount); - if (!nowrite) { - /* rewind after last failed read */ - lseek(fd, -RECSZ, SEEK_CUR); - fprintf(stderr, "adding record #%d\n", i); - if (write_ok(fd, &rec) != sizeof(rec)) - fprintf(stderr, "ERROR: failed to save a null record\n"); - } + /* bugger out if we never read anything sane */ + fprintf(stderr, "ERROR: failed to read any valid records from %s\n", buf); + close(fd); + return -1; + } + if (cmd == 'i') + fprintf(stderr, "boot_count:%u, next_record:%u\n", le32_to_cpu(rec.count), i); + if (cmd == 'c') { + /* rewind one record after last failed read */ + fprintf(stderr, "updating boot_count page[%d]:%x\n", i, lseek(fd, -RECSZ, SEEK_CUR)); + memset(buf, 0xff, RECSZ); + rec_zero((struct s_env_rec *)buf); + if (write(fd, buf, RECSZ) != RECSZ) + fprintf(stderr, "ERROR: failed to update boot_count\n"); + } + if (cmd == 'x' || cmd == 'a') { + p = (char *)&rec; + fprintf(stderr, "\nErase Size: %d, Write Size: %d\nRecords read: %d\n", + info.erasesize, info.writesize, i - 1); + } + if (cmd == 'x') { + fprintf(stderr, "Hex Dump of record:\n000000: "); + for (i = 0; i < sizeof(rec); i++) + fprintf(stderr, " %02x", p[i]); + fprintf(stderr, "\n"); + } + if (cmd == 'a') { + fprintf(stderr, "%s data:\n===============================\n", s_env); + for (i = 0; i < sizeof(rec); i++) + fprintf(stderr, "%c", p[i]); + fprintf(stderr, "\n===============================\n%d bytes\n", sizeof(rec)); } close(fd); } |