summaryrefslogtreecommitdiff
path: root/util/nvmutil
diff options
context:
space:
mode:
Diffstat (limited to 'util/nvmutil')
-rw-r--r--util/nvmutil/nvmutil.c197
1 files changed, 119 insertions, 78 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c
index 294f12f3..c9d9b4ca 100644
--- a/util/nvmutil/nvmutil.c
+++ b/util/nvmutil/nvmutil.c
@@ -40,11 +40,11 @@ static void read_gbe_file(void);
static void read_gbe_file_part(size_t part, uint8_t invert);
static void cmd_setmac(void);
static void parse_mac_string(void);
-static void set_mac_byte(size_t mac_str_pos);
-static void check_mac_separator(size_t mac_str_pos);
-static void set_mac_nib(size_t mac_str_pos, size_t mac_nib_pos);
-static uint8_t hextonum(char mac_ch);
-static uint8_t rhex(void);
+static void set_mac_byte(size_t mac_byte_pos);
+static void set_mac_nib(size_t mac_str_pos,
+ size_t mac_byte_pos, size_t mac_nib_pos);
+static uint16_t hextonum(char ch_s);
+static uint16_t rhex(void);
static void read_file_exact(int fd, void *buf, size_t len,
off_t off, const char *path, const char *op);
static int write_mac_part(size_t partnum);
@@ -108,18 +108,28 @@ static void set_err(int errval);
#define MAX_RETRY_READ 30
/*
- * Portably macro based on BSD nitems.
+ * Portable macro based on BSD nitems.
* Used to count the number of commands (see below).
*/
#define items(x) (sizeof((x)) / sizeof((x)[0]))
+#ifndef HAVE_ARC4RANDOM_BUF
static const char newrandom[] = "/dev/urandom";
static const char oldrandom[] = "/dev/random"; /* fallback on OLD unix */
-#ifndef HAVE_ARC4RANDOM_BUF
static const char *rname = NULL;
#endif
-static uint8_t buf[GBE_FILE_SIZE]; /* 8KB */
+/*
+ * GbE files can be 8KB, 16KB or 128KB,
+ * but we only need the two 4KB parts
+ * from offset zero and offset 64KB in
+ * a 128KB file, or zero and 8KB in a 16KB
+ * file, or zero and 4KB in an 8KB file.
+ *
+ * The code will handle this properly.
+ */
+static uint8_t buf[GBE_FILE_SIZE];
+
static uint16_t mac_buf[3];
static off_t gbe_file_size;
@@ -132,9 +142,9 @@ static size_t part;
static uint8_t invert;
static uint8_t part_modified[2];
-static const char *mac_str = NULL;
+static const char *mac_str;
static const char rmac[] = "xx:xx:xx:xx:xx:xx";
-static const char *fname = "";
+static const char *fname;
static const char *argv0;
struct commands {
@@ -226,6 +236,19 @@ main(int argc, char *argv[])
err(ECANCELED, "close '%s'", rname);
#endif
+ /*
+ * We still exit with non-zero status if
+ * errno is set, but we don't need to print
+ * the error on dump commands, because they
+ * already print errors.
+ *
+ * If both parts have bad checksums, then
+ * cmd_dump will cause non-zero exit. If at
+ * least one part is valid, it resets errno.
+ *
+ * However, if we're not using cmd_dump, then
+ * we have a bug somewhere in the code.
+ */
if (cmd != cmd_dump) {
if (errno)
err(ECANCELED, "Unhandled error on exit");
@@ -242,11 +265,19 @@ set_cmd(int argc, char *argv[])
{
size_t i;
+ /*
+ * No extra args: ./nvmutil gbe.bin
+ * Equivalent: ./nvmutil gbe.bin setmac xx:xx:xx:xx:xx:xx
+ */
if (argc == 2) {
cmd = cmd_setmac;
return;
}
+ /*
+ * Three or more args.
+ * Example: ./nvmutil gbe.bin copy 0
+ */
for (i = 0; i < items(command); i++) {
if (strcmp(argv[2], command[i].str) != 0)
continue;
@@ -262,14 +293,24 @@ set_cmd(int argc, char *argv[])
static void
check_cmd_args(int argc, char *argv[])
{
- if (cmd == NULL && argc > 2) { /* nvm gbe [MAC] */
+ if (cmd == NULL && argc > 2) {
+ /*
+ * Example: ./nvmutil gbe.bin xx:1f:16:xx:xx:xx
+ * Equivalent ./nvmutil gbe.bin setmac xx:1f:16:xx:xx:xx
+ */
mac_str = argv[2];
cmd = cmd_setmac;
- } else if (cmd == cmd_setmac) { /* nvm gbe setmac [MAC] */
+ } else if (cmd == cmd_setmac) {
+ /*
+ * Example: ./nvmutil gbe.bin setmac xx:1f:16:xx:xx:xx
+ */
mac_str = rmac; /* random MAC */
if (argc > 3)
mac_str = argv[3];
} else if (cmd != NULL && argc > 3) { /* user-supplied partnum */
+ /*
+ * Example: ./nvmutil gbe.bin copy 0
+ */
part = conv_argv_part_num(argv[3]);
}
@@ -284,16 +325,18 @@ conv_argv_part_num(const char *part_str)
/*
* Because char signedness is implementation-defined,
- * it is assumed to be signed, and handled accordingly.
+ * we cast to unsigned char before arithmetic.
*/
if (part_str[0] == '\0' || part_str[1] != '\0')
- err(EINVAL, "Partnum string '%s' wrong length.", part_str);
+ err(EINVAL, "Partnum string '%s' wrong length", part_str);
+
+ ch = (unsigned char)part_str[0];
- ch = (unsigned char)part_str[0] - '0';
+ if (ch < '0' || ch > '1')
+ err(EINVAL, "Bad part number (%c)", ch);
- check_part_num((size_t)ch);
- return (size_t)ch;
+ return (size_t)(ch - '0');
}
static void
@@ -314,21 +357,24 @@ open_dev_urandom(void)
{
struct stat st_urandom_fd;
+ /*
+ * Try /dev/urandom first
+ */
rname = newrandom;
+ if ((urandom_fd = open(rname, O_RDONLY)) != -1)
+ return;
- if ((urandom_fd = open(rname, O_RDONLY)) == -1) {
- /*
- * Fall back to /dev/random on old platforms
- * where /dev/urandom does not exist.
- *
- * We must reset the error condition first,
- * to prevent stale error status later.
- */
- errno = 0;
+ /*
+ * Fall back to /dev/random on old platforms
+ * where /dev/urandom does not exist.
+ *
+ * We must reset the error condition first,
+ * to prevent stale error status later.
+ */
+ errno = 0;
- rname = oldrandom;
- xopen(&urandom_fd, rname, O_RDONLY, &st_urandom_fd);
- }
+ rname = oldrandom;
+ xopen(&urandom_fd, rname, O_RDONLY, &st_urandom_fd);
}
#endif
@@ -364,7 +410,7 @@ static void
read_gbe_file(void)
{
size_t p;
- unsigned char do_read[2] = {1, 1};
+ uint8_t do_read[2] = {1, 1};
/*
* The copy, brick and setchecksum commands need
@@ -409,7 +455,7 @@ static void
cmd_setmac(void)
{
size_t partnum;
- unsigned char mac_updated = 0;
+ uint8_t mac_updated = 0;
parse_mac_string();
printf("MAC address to be written: %s\n", mac_str);
@@ -424,13 +470,15 @@ cmd_setmac(void)
static void
parse_mac_string(void)
{
- size_t mac_str_pos;
+ size_t mac_byte;
if (strlen(mac_str) != 17)
err(EINVAL, "MAC address is the wrong length");
- for (mac_str_pos = 0; mac_str_pos < 16; mac_str_pos += 3)
- set_mac_byte(mac_str_pos);
+ memset(mac_buf, 0, sizeof(mac_buf));
+
+ for (mac_byte = 0; mac_byte < 6; mac_byte++)
+ set_mac_byte(mac_byte);
if ((mac_buf[0] | mac_buf[1] | mac_buf[2]) == 0)
err(EINVAL, "Must not specify all-zeroes MAC address");
@@ -440,49 +488,40 @@ parse_mac_string(void)
}
static void
-set_mac_byte(size_t mac_str_pos)
+set_mac_byte(size_t mac_byte_pos)
{
+ size_t mac_str_pos = mac_byte_pos * 3;
size_t mac_nib_pos;
-
- check_mac_separator(mac_str_pos);
-
- for (mac_nib_pos = 0; mac_nib_pos < 2; mac_nib_pos++)
- set_mac_nib(mac_str_pos, mac_nib_pos);
-}
-
-static void
-check_mac_separator(size_t mac_str_pos)
-{
char separator;
- if (mac_str_pos == 15)
- return;
- if ((separator = mac_str[mac_str_pos + 2]) == ':')
- return;
+ if (mac_str_pos < 15) {
+ if ((separator = mac_str[mac_str_pos + 2]) != ':')
+ err(EINVAL, "Invalid MAC address separator '%c'",
+ separator);
+ }
- err(EINVAL, "Invalid MAC address separator '%c'", separator);
+ for (mac_nib_pos = 0; mac_nib_pos < 2; mac_nib_pos++)
+ set_mac_nib(mac_str_pos, mac_byte_pos, mac_nib_pos);
}
static void
-set_mac_nib(size_t mac_str_pos, size_t mac_nib_pos)
+set_mac_nib(size_t mac_str_pos,
+ size_t mac_byte_pos, size_t mac_nib_pos)
{
- uint8_t mac_ch;
+ char mac_ch;
+ uint16_t hex_num;
- size_t mac_byte_pos;
- size_t mac_word_left_shift;
+ mac_ch = mac_str[mac_str_pos + mac_nib_pos];
- if ((mac_ch = hextonum(mac_str[mac_str_pos + mac_nib_pos])) > 15)
+ if ((hex_num = hextonum(mac_ch)) > 15)
err(EINVAL, "Invalid character '%c'",
mac_str[mac_str_pos + mac_nib_pos]);
- mac_byte_pos = mac_str_pos / 3;
-
/* If random, ensure that local/unicast bits are set */
if ((mac_byte_pos == 0) && (mac_nib_pos == 1) &&
- ((mac_str[mac_str_pos + mac_nib_pos] == '?') ||
- (mac_str[mac_str_pos + mac_nib_pos] == 'x') ||
- (mac_str[mac_str_pos + mac_nib_pos] == 'X'))) /* random */
- mac_ch = (mac_ch & 0xE) | 2; /* local, unicast */
+ ((mac_ch | 0x20) == 'x' ||
+ (mac_ch == '?')))
+ hex_num = (hex_num & 0xE) | 2; /* local, unicast */
/*
* Words other than the MAC address are stored little
@@ -494,21 +533,20 @@ set_mac_nib(size_t mac_str_pos, size_t mac_nib_pos)
*
* Later code using the MAC string will handle this.
*/
- mac_word_left_shift =
- ((mac_byte_pos & 1) << 3) /* left or right byte? */
- | ((mac_nib_pos ^ 1) << 2); /* left or right nib? */
- /*
- * Now we can shift properly, OR'ing the result:
- */
- mac_buf[mac_byte_pos >> 1] |=
- (uint16_t)mac_ch << mac_word_left_shift;
+ mac_buf[mac_byte_pos >> 1] |= hex_num <<
+ (((mac_byte_pos & 1) << 3) /* left or right byte? */
+ | ((mac_nib_pos ^ 1) << 2)); /* left or right nib? */
}
-static uint8_t
-hextonum(char mac_ch)
+static uint16_t
+hextonum(char ch_s)
{
- unsigned char ch = (unsigned char)mac_ch;
+ /*
+ * We assume char is signed, hence ch_s.
+ * We explicitly cast to unsigned:
+ */
+ unsigned char ch = (unsigned char)ch_s;
if ((unsigned)(ch - '0') <= 9)
return ch - '0';
@@ -517,13 +555,14 @@ hextonum(char mac_ch)
if ((unsigned)(ch - 'a') <= 5)
return ch - 'a' + 10;
- else if (ch == '?' || ch == 'x')
+
+ if (ch == '?' || ch == 'x')
return rhex(); /* random character */
- else
- return 16; /* invalid character */
+
+ return 16; /* invalid character */
}
-static uint8_t
+static uint16_t
rhex(void)
{
static size_t n = 0;
@@ -538,7 +577,7 @@ rhex(void)
#endif
}
- return rnum[--n] & 0xf;
+ return (uint16_t)(rnum[--n] & 0xf);
}
static void
@@ -836,8 +875,10 @@ write_gbe_file_part(size_t p)
static off_t
gbe_file_offset(size_t p, const char *f_op)
{
+ off_t gbe_file_half_size = gbe_file_size >> 1;
+
return gbe_x_offset(p, f_op, "file",
- gbe_file_size >> 1, gbe_file_size);
+ gbe_file_half_size, gbe_file_size);
}
/*