summaryrefslogtreecommitdiff
path: root/util/nvmutil
diff options
context:
space:
mode:
Diffstat (limited to 'util/nvmutil')
-rw-r--r--util/nvmutil/nvmutil.c379
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;
}