diff options
Diffstat (limited to 'util/nvmutil')
| -rw-r--r-- | util/nvmutil/nvmutil.c | 379 |
1 files changed, 200 insertions, 179 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c index 4188c0dc..e60501ab 100644 --- a/util/nvmutil/nvmutil.c +++ b/util/nvmutil/nvmutil.c @@ -15,17 +15,17 @@ #include <unistd.h> void cmd_setchecksum(void), cmd_brick(void), swap(int partnum), writeGbe(void), - cmd_dump(void), cmd_setmac(void), nvmalloc(void), readGbe(void), - checkdir(const char *path), macf(int partnum), hexdump(int partnum), + cmd_dump(void), cmd_setmac(void), readGbe(void), print_mac_address(int), + hexdump(int), set_mac_nib(int, int, uint8_t *), checkdir(const char *), parseMacString(const char *strMac, uint16_t *mac), cmd_swap(void), - openFiles(const char *path), cmd_copy(void), writeGbe_part(int), - readGbe_part(int), usage(char*); -int goodChecksum(int partnum); + openFiles(void), cmd_copy(void), writeGbe_part(int), readGbe_part(int), + set_cmd(int, char **), setWord(int, int, uint16_t), check_bounds(int, int), + xopen(int *, const char *, int p, struct stat *), checkMacSeparator(int), + set_mac_byte(int, uint64_t *), usage(char*), set_io_flags(int, char **), + err_if(int); +int goodChecksum(int partnum), write_mac_part(int), set_err(int); uint8_t hextonum(char chs), rhex(void); - -#ifdef __OpenBSD__ -void block_unveil(void); -#endif +uint16_t word(int, int); #define COMMAND argv[2] #define MAC_ADDRESS argv[3] @@ -39,13 +39,12 @@ void block_unveil(void); #define SIZE_16KB 0x4000 #define SIZE_128KB 0x20000 +uint8_t buf[SIZE_8KB]; uint16_t mac[3] = {0, 0, 0}; -ssize_t nf; -size_t partsize, gbe[2]; -uint8_t nvmPartChanged[2] = {0, 0}, do_read[2] = {1, 1}; +size_t partsize; int flags, rfd, fd, part, e = 1; -const char *strMac = NULL, *strRMac = "xx:xx:xx:xx:xx:xx", *fname = NULL; +const char *strMac = NULL, *strRMac = "xx:xx:xx:xx:xx:xx", *fname = ""; typedef struct op { char *str; @@ -53,60 +52,55 @@ typedef struct op { int args; } op_t; op_t op[] = { -{ .str = "dump", .cmd = cmd_dump, .args = 3}, -{ .str = "setmac", .cmd = cmd_setmac, .args = 3}, -{ .str = "swap", .cmd = cmd_swap, .args = 3}, -{ .str = "copy", .cmd = cmd_copy, .args = 4}, -{ .str = "brick", .cmd = cmd_brick, .args = 4}, -{ .str = "setchecksum", .cmd = cmd_setchecksum, .args = 4}, +{ .str = "dump", .cmd = cmd_dump, .args = 3 }, +{ .str = "setmac", .cmd = cmd_setmac, .args = 3 }, +{ .str = "swap", .cmd = cmd_swap, .args = 3 }, +{ .str = "copy", .cmd = cmd_copy, .args = 4 }, +{ .str = "brick", .cmd = cmd_brick, .args = 4 }, +{ .str = "setchecksum", .cmd = cmd_setchecksum, .args = 4 }, }; void (*cmd)(void) = NULL; -#define SET_ERR(x) errno = errno ? errno : x -#define err_if(x) if (x) err(SET_ERR(ECANCELED), "%s", fname) - -#define xopen(f,l,p) \ - if ((f = open(l, p)) == -1) \ - err(SET_ERR(ECANCELED), "%s", l); \ - if (fstat(f, &st) == -1) err(SET_ERR(ECANCELED), "%s", l) - -#define word(pos16, partnum) ((uint16_t *) gbe[partnum])[pos16] -#define setWord(pos16, p, val16) if (word(pos16, p) != val16) \ - nvmPartChanged[p] = 1 | (word(pos16, p) = val16) - int main(int argc, char *argv[]) { #ifdef __OpenBSD__ err_if(pledge("stdio rpath wpath unveil", NULL) == -1); + err_if(unveil("/dev/urandom", "r") == -1); #endif - if (argc < 2) - usage(argv[0]); + set_cmd(argc, argv); fname = argv[1]; - flags = O_RDWR; - if (argc > 2) - if (strcmp(COMMAND, "dump") == 0) - flags = O_RDONLY; - -#ifdef __OpenBSD__ - if (flags == O_RDONLY) - err_if(pledge("stdio rpath unveil", NULL) == -1); -#endif - - checkdir("/dev/urandom"); - checkdir(fname); - + set_io_flags(argc, argv); #ifdef __OpenBSD__ - block_unveil(); + if (flags == O_RDONLY) { + err_if(unveil(fname, "r") == -1); + err_if(unveil(NULL, NULL) == -1); + err_if(pledge("stdio rpath", NULL) == -1); + } else { + err_if(unveil(fname, "rw") == -1); + err_if(unveil(NULL, NULL) == -1); + err_if(pledge("stdio rpath wpath", NULL) == -1); + } #endif - - openFiles(fname); + openFiles(); #ifdef __OpenBSD__ err_if(pledge("stdio", NULL) == -1); #endif + readGbe(); + (*cmd)(); + writeGbe(); + + err_if((errno != 0) && (cmd != cmd_dump)); + return errno ? EXIT_FAILURE : EXIT_SUCCESS; +} - if (argc > 2) { +void +set_cmd(int argc, char *argv[]) +{ + if (argc < 2) { + usage(argv[0]); + } else if (argc > 2) { for (int i = 0; (i < 6) && (cmd == NULL); i++) { if (strcmp(COMMAND, op[i].str) != 0) continue; @@ -114,10 +108,10 @@ main(int argc, char *argv[]) cmd = op[i].cmd; break; } - err(SET_ERR(EINVAL), "Too few args on command '%s'", + err(set_err(EINVAL), "Too few args on command '%s'", op[i].str); } - } else { + } else { /* argc == 2 */ cmd = cmd_setmac; } @@ -133,32 +127,28 @@ main(int argc, char *argv[]) || PARTN[1] ? EINVAL : errno)); /* only allow '0' or '1' */ } err_if((errno = (cmd == NULL) ? EINVAL : errno)); - - nvmalloc(); - readGbe(); - (*cmd)(); - writeGbe(); - - err_if((errno != 0) && (cmd != cmd_dump)); - return errno; } void -checkdir(const char *path) +set_io_flags(int argc, char *argv[]) { - if (opendir(path) != NULL) - err(SET_ERR(EISDIR), "%s", path); - if (errno == ENOTDIR) - errno = 0; - err_if(errno); + flags = O_RDWR; + if (argc > 2) + if (strcmp(COMMAND, "dump") == 0) + flags = O_RDONLY; } void -openFiles(const char *path) +openFiles(void) { struct stat st; + struct stat st_rfd; - xopen(fd, path, flags); + checkdir("/dev/urandom"); + checkdir(fname); + + xopen(&rfd, "/dev/urandom", O_RDONLY, &st_rfd); + xopen(&fd, fname, flags, &st); switch(st.st_size) { case SIZE_8KB: @@ -167,50 +157,43 @@ openFiles(const char *path) partsize = st.st_size >> 1; break; default: - err(SET_ERR(ECANCELED), "Invalid file size (not 8/16/128KiB)"); + err(set_err(ECANCELED), "Invalid file size (not 8/16/128KiB)"); break; } - - xopen(rfd, "/dev/urandom", O_RDONLY); } void -nvmalloc(void) +checkdir(const char *path) { - /* same operations need the full block, others only 128 bytes */ - nf = NVM_SIZE; - if ((cmd == cmd_swap) || (cmd == cmd_copy)) - nf = SIZE_4KB; - - /* only read the part specified, for copy/setchecksum/brick */ - if ((cmd == cmd_copy) || (cmd == cmd_setchecksum) || (cmd == cmd_brick)) - do_read[part ^ 1] = 0; - - /* only allocate one block if only one part being read */ - char *buf = malloc(nf << (do_read[0] & do_read[1])); - if (buf == NULL) - err(errno, NULL); - - gbe[0] = (size_t) buf; + struct stat st; + if (stat(path, &st) == -1) + err(set_err(ECANCELED), "%s", path); + if (S_ISDIR(st.st_mode)) + err(set_err(EISDIR), "%s", path); +} - /* speedhack: for cmd copy, both pointers are set the same */ - gbe[1] = gbe[0] + (nf * (do_read[0] & do_read[1])); +void +xopen(int *f, const char *l, int p, struct stat *st) +{ + if ((*f = open(l, p)) == -1) + err(set_err(ECANCELED), "%s", l); + if (fstat(*f, st) == -1) + err(set_err(ECANCELED), "%s", l); } void readGbe(void) { for (int p = 0; p < 2; p++) - if (do_read[p]) - readGbe_part(p); + readGbe_part(p); } void readGbe_part(int p) { - if (pread(fd, (uint8_t *) gbe[p], nf, p * partsize) != nf) - err(SET_ERR(ECANCELED), - "Can't read %ld b from '%s' p%d", nf, fname, p); + if (pread(fd, buf + (SIZE_4KB * p), SIZE_4KB, p * partsize) != SIZE_4KB) + err(set_err(ECANCELED), + "Can't read %d b from '%s' p%d", SIZE_4KB, fname, p); swap(p); /* handle big-endian host CPU */ } @@ -222,20 +205,8 @@ cmd_setmac(void) printf("MAC address to be written: %s\n", strMac); - for (int partnum = 0; partnum < 2; partnum++) { - if (!goodChecksum(part = partnum)) - continue; - - for (int w = 0; w < 3; w++) - setWord(w, partnum, mac[w]); - - printf("Wrote MAC address to part %d: ", partnum); - macf(partnum); - - cmd_setchecksum(); - mac_updated = 1; - } - + for (int partnum = 0; partnum < 2; partnum++) + mac_updated |= write_mac_part(partnum); if (mac_updated) errno = 0; } @@ -245,38 +216,56 @@ parseMacString(const char *strMac, uint16_t *mac) { uint64_t total = 0; if (strnlen(strMac, 20) != 17) - err(SET_ERR(EINVAL), "Invalid MAC address string length"); - - for (uint8_t h, i = 0; i < 16; i += 3) { - if (i != 15) - if (strMac[i + 2] != ':') - err(SET_ERR(EINVAL), - "Invalid MAC address separator '%c'", - strMac[i + 2]); - - int byte = i / 3; - - for (int nib = 0; nib < 2; nib++, total += h) { - if ((h = hextonum(strMac[i + nib])) > 15) - err(SET_ERR(EINVAL), "Invalid character '%c'", - strMac[i + nib]); - - /* If random, ensure that local/unicast bits are set */ - if ((byte == 0) && (nib == 1)) - if ((strMac[i + nib] == '?') || - (strMac[i + nib] == 'x') || - (strMac[i + nib] == 'X')) /* random */ - h = (h & 0xE) | 2; /* local, unicast */ - - mac[byte >> 1] |= ((uint16_t ) h) - << ((8 * (byte % 2)) + (4 * (nib ^ 1))); - } - } + err(set_err(EINVAL), "Invalid MAC address string length"); + + for (int strMacPos = 0; strMacPos < 16; strMacPos += 3) + set_mac_byte(strMacPos, &total); if (total == 0) - err(SET_ERR(EINVAL), "Invalid MAC (all-zero MAC address)"); + err(set_err(EINVAL), "Invalid MAC (all-zero MAC address)"); if (mac[0] & 1) - err(SET_ERR(EINVAL), "Invalid MAC (multicast bit set)"); + err(set_err(EINVAL), "Invalid MAC (multicast bit set)"); +} + +void +set_mac_byte(int strMacPos, uint64_t *total) +{ + uint8_t h = 0; + checkMacSeparator(strMacPos); + + for (int nib = 0; nib < 2; nib++, *total += h) + set_mac_nib(strMacPos, nib, &h); +} + +void +checkMacSeparator(int strMacPos) +{ + if (strMacPos == 15) + return; + char separator = strMac[strMacPos + 2]; + if (separator == ':') + return; + err(set_err(EINVAL), "Invalid MAC address separator '%c'", separator); +} + +void +set_mac_nib(int strMacPos, int nib, uint8_t *h) +{ + int byte = strMacPos / 3; + + if ((*h = hextonum(strMac[strMacPos + nib])) > 15) + err(set_err(EINVAL), "Invalid character '%c'", + strMac[strMacPos + nib]); + + /* If random, ensure that local/unicast bits are set */ + if ((byte == 0) && (nib == 1)) + if ((strMac[strMacPos + nib] == '?') || + (strMac[strMacPos + nib] == 'x') || + (strMac[strMacPos + nib] == 'X')) /* random */ + *h = (*h & 0xE) | 2; /* local, unicast */ + + mac[byte >> 1] |= ((uint16_t ) *h) << ((8 * (byte % 2)) + + (4 * (nib ^ 1))); } uint8_t @@ -302,19 +291,31 @@ rhex(void) return rnum[n--] & 0xf; } +int +write_mac_part(int partnum) +{ + if (!goodChecksum(part = partnum)) + return 0; + + for (int w = 0; w < 3; w++) + setWord(w, partnum, mac[w]); + + printf("Wrote MAC address to part %d: ", partnum); + print_mac_address(partnum); + + cmd_setchecksum(); + return 1; +} + void cmd_dump(void) { for (int partnum = 0, numInvalid = 0; partnum < 2; partnum++) { - if ((cmd != cmd_dump) && (flags != O_RDONLY) && - (!nvmPartChanged[partnum])) - continue; - if (!goodChecksum(partnum)) ++numInvalid; printf("MAC (part %d): ", partnum); - macf(partnum); + print_mac_address(partnum); hexdump(partnum); if ((numInvalid < 2) && (partnum)) @@ -323,7 +324,7 @@ cmd_dump(void) } void -macf(int partnum) +print_mac_address(int partnum) { for (int c = 0; c < 3; c++) { uint16_t val16 = word(c, partnum); @@ -371,7 +372,9 @@ cmd_brick(void) void cmd_copy(void) { - nvmPartChanged[part ^ 1] = goodChecksum(part); + err_if(!goodChecksum(part)); + for (int c = 0; c < (SIZE_4KB >> 1); c++) + setWord(c, part ^ 1, word(c, part)); } void @@ -379,11 +382,11 @@ cmd_swap(void) { err_if(!(goodChecksum(0) || goodChecksum(1))); errno = 0; - gbe[0] ^= gbe[1]; - gbe[1] ^= gbe[0]; - gbe[0] ^= gbe[1]; - - nvmPartChanged[0] = nvmPartChanged[1] = 1; + for (int c = 0; c < (SIZE_4KB >> 1); c++) { + uint16_t chg = word(c, 0); + setWord(c, 0, word(c, 1)); + setWord(c, 1, chg); + } } int @@ -397,15 +400,38 @@ goodChecksum(int partnum) return 1; fprintf(stderr, "WARNING: BAD checksum in part %d\n", partnum); - SET_ERR(ECANCELED); + (void) set_err(ECANCELED); return 0; } +uint16_t +word(int pos16, int p) +{ + check_bounds(pos16, p); + return ((uint16_t *) (buf + (SIZE_4KB * p)))[pos16]; +} + +void +setWord(int pos16, int p, uint16_t val16) +{ + check_bounds(pos16, p); + ((uint16_t *) (buf + (SIZE_4KB * p)))[pos16] = val16; +} + +void +check_bounds(int c, int p) +{ + if ((p != 0) && (p != 1)) + err(set_err(EINVAL), "check_bounds: invalid partnum %d", p); + if ((c < 0) || (c >= (SIZE_4KB >> 1))) + err(set_err(EINVAL), "check_bounds: out of bounds %d", c); +} + void writeGbe(void) { - for (int p = 0; p < 2; p++) - if ((nvmPartChanged[p]) && (flags != O_RDONLY)) + if (flags != O_RDONLY) + for (int p = 0; p < 2; p++) writeGbe_part(p); err_if(close(fd) == -1); } @@ -414,43 +440,24 @@ void writeGbe_part(int p) { swap(p); /* swap bytes on big-endian host CPUs */ - if(pwrite(fd, (uint8_t *) gbe[p], nf, p * partsize) != nf) - err(SET_ERR(ECANCELED), - "Can't write %ld b to '%s' p%d", nf, fname, p); - + if(pwrite(fd, buf + (SIZE_4KB * p), SIZE_4KB, p * partsize) != SIZE_4KB) + err(set_err(ECANCELED), + "Can't write %d b to '%s' p%d", SIZE_4KB, fname, p); } void swap(int partnum) { - uint8_t *n = (uint8_t *) gbe[partnum]; + uint8_t *n = buf + (SIZE_4KB * partnum); for (size_t w = NVM_SIZE * ((uint8_t *) &e)[0], x = 1; w < NVM_SIZE; w += 2, x += 2) { - n[w] ^= n[x]; - n[x] ^= n[w]; - n[w] ^= n[x]; + uint8_t chg = n[w]; + n[w] = n[x]; + n[x] = chg; } } -#ifdef __OpenBSD__ -void -block_unveil(void) -{ - err_if(unveil("/dev/urandom", "r") == -1); - - if (flags == O_RDONLY) { - err_if(unveil(fname, "r") == -1); - err_if(unveil(NULL, NULL) == -1); - err_if(pledge("stdio rpath", NULL) == -1); - } else { - err_if(unveil(fname, "rw") == -1); - err_if(unveil(NULL, NULL) == -1); - err_if(pledge("stdio rpath wpath", NULL) == -1); - } -} -#endif - void usage(char *util) { @@ -468,5 +475,19 @@ usage(char *util) " %s FILE brick 0|1\n" " %s FILE setchecksum 0|1\n", util, util, util, util, util, util, util); - err(SET_ERR(ECANCELED), "Too few arguments"); + err(set_err(ECANCELED), "Too few arguments"); +} + +void +err_if(int x) +{ + if (x) + err(set_err(ECANCELED), "%s", fname); +} + +int +set_err(int x) +{ + errno = errno ? errno : x; + return EXIT_FAILURE; } |
