summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--util/nvmutil/.gitignore3
-rw-r--r--util/nvmutil/ChangeLog.md8
-rw-r--r--util/nvmutil/Makefile33
-rw-r--r--util/nvmutil/README.md4
-rw-r--r--util/nvmutil/nvmutil.c658
6 files changed, 348 insertions, 360 deletions
diff --git a/.gitignore b/.gitignore
index e5085ba5..43285fbc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,8 +30,6 @@
*me.bin
*sch5545ec.bin
/mrc/
-/util/nvmutil/nvm
-/util/nvmutil/nvmutil
/src/
/CHANGELOG
/todo.txt
diff --git a/util/nvmutil/.gitignore b/util/nvmutil/.gitignore
new file mode 100644
index 00000000..802202a4
--- /dev/null
+++ b/util/nvmutil/.gitignore
@@ -0,0 +1,3 @@
+/nvm
+/nvmutil
+*.bin
diff --git a/util/nvmutil/ChangeLog.md b/util/nvmutil/ChangeLog.md
deleted file mode 100644
index e1ed5754..00000000
--- a/util/nvmutil/ChangeLog.md
+++ /dev/null
@@ -1,8 +0,0 @@
-This change log has moved. Please refer here for historical pre-osboot-merge
-changes:
-
-<https://libreboot.org/docs/install/nvmutilimport.html>
-
-Osboot merged with Libreboot on November 17th, 2022. For nvmutil changes after
-this date, please check regular Libreboot release announcements which shall
-now specify any such changes.
diff --git a/util/nvmutil/Makefile b/util/nvmutil/Makefile
index 91b5ba1c..22376c70 100644
--- a/util/nvmutil/Makefile
+++ b/util/nvmutil/Makefile
@@ -3,33 +3,28 @@
# SPDX-FileCopyrightText: 2023 Riku Viitanen <riku.viitanen@protonmail.com>
CC?=cc
-CFLAGS?=-Os -Wall -Wextra -Werror -pedantic
+CFLAGS?=-Os -Wall -Wextra -Werror -pedantic -std=c99
DESTDIR?=
PREFIX?=/usr/local
INSTALL?=install
-# nvm is the old binary name,
-# but it was renamed to nvmutil
-# to avoid conflict with a certain
-# package manager by that name!
+PROG=nvmutil
-nvm: nvmutil.c
- rm -f nvm
- $(CC) $(CFLAGS) nvmutil.c -o nvmutil
+all: $(PROG)
-install:
- $(INSTALL) nvmutil $(DESTDIR)$(PREFIX)/bin/nvmutil
+$(PROG): nvmutil.c
+ $(CC) $(CFLAGS) nvmutil.c -o $(PROG)
-# do not delete *bin/nvm because
-# there is a package manager by
-# that name. this makefile now
-# treats nvmutil as the binary
+install: $(PROG)
+ mkdir -p $(DESTDIR)$(PREFIX)/bin/
+ install $(PROG) $(DESTDIR)$(PREFIX)/bin/
uninstall:
- rm -f $(DESTDIR)$(PREFIX)/bin/nvmutil
-
-distclean:
- rm -f nvm nvmutil
+ rm -f $(DESTDIR)$(PREFIX)/bin/$(PROG)
clean:
- rm -f nvm nvmutil
+ rm -f $(PROG)
+
+distclean: clean
+
+.PHONY: all install uninstall clean distclean
diff --git a/util/nvmutil/README.md b/util/nvmutil/README.md
deleted file mode 100644
index 03a25bc4..00000000
--- a/util/nvmutil/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-
-This documentation has become part of lbwww. See:
-
-<https://libreboot.org/docs/install/nvmutil.html>
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c
index 21fb8bdd..c763727d 100644
--- a/util/nvmutil/nvmutil.c
+++ b/util/nvmutil/nvmutil.c
@@ -1,6 +1,21 @@
-/* SPDX-License-Identifier: MIT */
-/* Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org> */
-/* Copyright (c) 2023 Riku Viitanen <riku.viitanen@protonmail.com> */
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org>
+ * Copyright (c) 2023 Riku Viitanen <riku.viitanen@protonmail.com>
+ *
+ * This tool lets you modify Intel GbE NVM (Gigabit Ethernet
+ * Non-Volatile Memory) images, e.g. change the MAC address.
+ * These images configure your Intel Gigabit Ethernet adapter.
+ *
+ * This code is designed to be portable, running on as many
+ * Unix and Unix-like systems as possible (mainly BSD/Linux).
+ *
+ * Recommended CFLAGS for Clang/GCC:
+ *
+ * -Os -Wall -Wextra -Werror -pedantic -std=c99
+ */
+
+#define _POSIX_C_SOURCE 200809L
#ifdef __OpenBSD__
#include <sys/param.h>
@@ -19,14 +34,17 @@
/*
* The BSD versions that could realistically build
* nvmutil almost certainly have arc4random (first
- * introduced in 1990s or early 2000s in most of
- * them - you can just patch as needed, on old BSD.
+ * introduced in 1990s to early 2000s).
+ *
+ * If you want it on another platform, e.g. Linux,
+ * just patch this accordingly. Or patch it to remove
+ * arc4random on old/weird Unix systems.
*/
#if defined(__OpenBSD__) || defined(__FreeBSD__) || \
defined(__NetBSD__) || defined(__APPLE__) || \
defined(__DragonFly__)
-#ifndef HAVE_ARC4RANDOM_BUF
-#define HAVE_ARC4RANDOM_BUF 1
+#ifndef NVMUTIL_ARC4RANDOM_BUF
+#define NVMUTIL_ARC4RANDOM_BUF 1
#endif
#endif
@@ -52,59 +70,58 @@
static void sanitize_command_list(void);
static void sanitize_command_index(size_t c);
-static void check_bin(size_t a, const char *a_name);
static void check_enum_bin(size_t a, const char *a_name,
size_t b, const char *b_name);
static void set_cmd(int argc, char *argv[]);
static void set_cmd_args(int argc, char *argv[]);
static size_t conv_argv_part_num(const char *part_str);
+static void set_io_flags(int argc, char *argv[]);
static void run_cmd(size_t c);
static void check_command_num(size_t c);
static uint8_t valid_command(size_t c);
-static void set_io_flags(int argc, char *argv[]);
-static void open_gbe_file(void);
-#ifndef HAVE_ARC4RANDOM_BUF
+static int xstrxcmp(const char *a, const char *b, size_t maxlen);
+#ifndef NVMUTIL_ARC4RANDOM_BUF
static void open_dev_urandom(void);
#endif
+static void open_gbe_file(void);
static void xopen(int *fd, const char *path, int flags, struct stat *st);
static void read_gbe_file(void);
static void read_gbe_file_part(size_t part);
static void read_checksums(void);
-static void cmd_setmac(void);
+static int good_checksum(size_t partnum);
+static void cmd_helper_setmac(void);
static void parse_mac_string(void);
+static size_t xstrxlen(const char *scmp, size_t maxlen);
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,
+static ssize_t read_gbe_file_exact(int fd, void *buf, size_t len,
off_t off, const char *path, const char *op);
static void write_mac_part(size_t partnum);
-static void cmd_dump(void);
+static void cmd_helper_dump(void);
static void print_mac_from_nvm(size_t partnum);
static void hexdump(size_t partnum);
-static void cmd_setchecksum(void);
+static void write_gbe_file(void);
+static void override_part_modified(void);
static void set_checksum(size_t part);
-static void cmd_brick(void);
-static int good_checksum(size_t partnum);
+static uint16_t calculated_checksum(size_t p);
static uint16_t nvm_word(size_t pos16, size_t part);
static void set_nvm_word(size_t pos16, size_t part, uint16_t val16);
+static void set_part_modified(size_t p);
static void check_nvm_bound(size_t pos16, size_t part);
-static void write_gbe_file(void);
-static void override_part_modified(void);
+static void check_bin(size_t a, const char *a_name);
static void write_gbe_file_part(size_t part);
static off_t gbe_file_offset(size_t part, const char *f_op);
static void *gbe_mem_offset(size_t part, const char *f_op);
static off_t gbe_x_offset(size_t part, const char *f_op,
const char *d_type, off_t nsize, off_t ncmp);
-static void set_part_modified(size_t p);
-static void usage(uint8_t usage_exit);
-static size_t xstrxlen(const char *scmp, size_t maxlen);
-static int xstrxcmp(const char *a, const char *b, size_t maxlen);
static void err(int nvm_errval, const char *msg, ...);
+static void close_files(void);
static const char *getnvmprogname(void);
static void set_err(int errval);
-static void close_files(void);
+static void usage(uint8_t usage_exit);
/*
* Sizes in bytes:
@@ -146,7 +163,7 @@ static void close_files(void);
*/
#define items(x) (sizeof((x)) / sizeof((x)[0]))
-#ifndef HAVE_ARC4RANDOM_BUF
+#ifndef NVMUTIL_ARC4RANDOM_BUF
static const char newrandom[] = "/dev/urandom";
static const char oldrandom[] = "/dev/random"; /* fallback on OLD unix */
static const char *rname = NULL;
@@ -167,7 +184,7 @@ static uint16_t mac_buf[3];
static off_t gbe_file_size;
static int gbe_flags;
-#ifndef HAVE_ARC4RANDOM_BUF
+#ifndef NVMUTIL_ARC4RANDOM_BUF
static int urandom_fd = -1;
#endif
static int gbe_fd = -1;
@@ -202,8 +219,6 @@ enum {
CMD_SETMAC,
CMD_SWAP,
CMD_COPY,
- CMD_BRICK,
- CMD_SETCHECKSUM
};
/*
@@ -250,13 +265,17 @@ struct commands {
* Command table, for nvmutil commands
*/
static const struct commands command[] = {
- { CMD_DUMP, "dump", cmd_dump, ARGC_3,
+ /*
+ * Unlike older versions, we now require
+ * both checksums to be valid for "dump".
+ */
+ { CMD_DUMP, "dump", cmd_helper_dump, ARGC_3,
NO_INVERT, SET_MOD_OFF,
ARG_NOPART,
- SKIP_CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
+ CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
NVM_SIZE },
- { CMD_SETMAC, "setmac", cmd_setmac, ARGC_3,
+ { CMD_SETMAC, "setmac", cmd_helper_setmac, ARGC_3,
NO_INVERT, SET_MOD_OFF,
ARG_NOPART,
CHECKSUM_READ, CHECKSUM_WRITE,
@@ -280,24 +299,6 @@ static const struct commands command[] = {
ARG_PART,
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
GBE_PART_SIZE },
-
- /*
- * The non-target part will not be read.
- */
- { CMD_BRICK, "brick", cmd_brick, ARGC_4,
- NO_INVERT, SET_MOD_OFF,
- ARG_PART,
- CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
- NVM_SIZE },
-
- /*
- * The non-target part will not be read.
- */
- { CMD_SETCHECKSUM, "setchecksum", cmd_setchecksum, ARGC_4,
- NO_INVERT, SET_MOD_OFF,
- ARG_PART,
- SKIP_CHECKSUM_READ, CHECKSUM_WRITE,
- NVM_SIZE },
};
#define MAX_CMD_LEN 50
@@ -313,7 +314,7 @@ int
main(int argc, char *argv[])
{
argv0 = argv[0];
- if (argc < 2)
+ if (argc < 3)
usage(1);
fname = argv[1];
@@ -340,14 +341,14 @@ main(int argc, char *argv[])
#ifdef NVMUTIL_UNVEIL
if (gbe_flags == O_RDONLY) {
if (unveil(fname, "r") == -1)
- err(ECANCELED, "unveil ro '%s'", fname);
+ err(ECANCELED, "%s: unveil ro", fname);
if (unveil(NULL, NULL) == -1)
err(ECANCELED, "unveil block (ro)");
if (pledge("stdio rpath", NULL) == -1)
err(ECANCELED, "pledge ro (kill unveil)");
} else {
if (unveil(fname, "rw") == -1)
- err(ECANCELED, "unveil rw '%s'", fname);
+ err(ECANCELED, "%s: unveil rw", fname);
if (unveil(NULL, NULL) == -1)
err(ECANCELED, "unveil block (rw)");
if (pledge("stdio rpath wpath", NULL) == -1)
@@ -361,7 +362,7 @@ main(int argc, char *argv[])
#endif
#endif
-#ifndef HAVE_ARC4RANDOM_BUF
+#ifndef NVMUTIL_ARC4RANDOM_BUF
#if defined(__OpenBSD__) || defined(__FreeBSD__) || \
defined(__NetBSD__) || defined(__APPLE__) || \
defined(__DragonFly__)
@@ -383,7 +384,7 @@ main(int argc, char *argv[])
run_cmd(cmd_index);
if (errno)
- err(errno, "Unhandled error: will not write file: %s", fname);
+ err(errno, "%s: Unhandled error (WRITE SKIPPED)", fname);
else if (gbe_flags != O_RDONLY)
write_gbe_file();
@@ -415,8 +416,13 @@ sanitize_command_index(size_t c)
check_command_num(c);
- if (command[c].argc < 2)
- err(ECANCELED, "cmd index %zu: argc below 2, %d",
+ if (ARGC_3 != 3)
+ err(ECANCELED, "ARGC_3 is not equal to 3");
+ if (ARGC_4 != 4)
+ err(ECANCELED, "ARGC_4 is not equal to 4");
+
+ if (command[c].argc < 3)
+ err(ECANCELED, "cmd index %zu: argc below 3, %d",
c, command[c].argc);
if (command[c].str == NULL)
@@ -482,19 +488,17 @@ check_enum_bin(size_t a, const char *a_name,
static void
set_cmd(int argc, char *argv[])
{
+ const char *cmd_str;
+
for (cmd_index = 0; valid_command(cmd_index); cmd_index++) {
- if (argc < 3)
- break;
+ cmd_str = command[cmd_index].str;
- if (xstrxcmp(argv[2], command[cmd_index].str,
- MAX_CMD_LEN) != 0)
+ if (xstrxcmp(argv[2], cmd_str, MAX_CMD_LEN) != 0)
continue;
-
- if (argc >= command[cmd_index].argc)
+ else if (argc >= command[cmd_index].argc)
return;
- err(EINVAL, "Too few args: command '%s'",
- command[cmd_index].str);
+ err(EINVAL, "Too few args on command '%s'", cmd_str);
}
cmd_index = CMD_NULL;
@@ -503,45 +507,25 @@ set_cmd(int argc, char *argv[])
static void
set_cmd_args(int argc, char *argv[])
{
- if (cmd_index == CMD_SETMAC && argc >= 4) {
- /*
- * 4th arg e.g.: ./nvmutil gbe.bin setmac 00:xx:11:22:xx:xx
- */
- mac_str = argv[3];
- } else if (!valid_command(cmd_index) && argc >= 3) {
- /*
- * 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_index = CMD_SETMAC;
- } else if (argc == 2) {
- /*
- * No extra args: ./nvmutil gbe.bin
- * Equivalent: ./nvmutil gbe.bin setmac xx:xx:xx:xx:xx:xx
- */
- mac_str = rmac;
- cmd_index = CMD_SETMAC;
- } else if (valid_command(cmd_index) && argc >= 4) {
- if (command[cmd_index].arg_part) {
- /*
- * User-supplied partnum.
- * Example: ./nvmutil gbe.bin copy 0
- */
- part = conv_argv_part_num(argv[3]);
- } else {
- err(ECANCELED, "Bad command: %s %s",
- argv[2], argv[3]);
- }
- } else if (valid_command(cmd_index) && argc >= 3) {
- if (cmd_index == CMD_SETMAC)
- mac_str = rmac;
- }
+ uint8_t arg_part;
- if (!valid_command(cmd_index)) {
- usage(0);
- err(EINVAL, "Unhandled command error");
- }
+ if (!valid_command(cmd_index) || argc < 3)
+ usage(1);
+
+ arg_part = command[cmd_index].arg_part;
+
+ /* Maintainer bugs */
+ if (arg_part && argc < 4)
+ err(ECANCELED,
+ "arg_part set for command that needs argc4");
+ if (arg_part && cmd_index == CMD_SETMAC)
+ err(ECANCELED,
+ "arg_part set on CMD_SETMAC");
+
+ if (cmd_index == CMD_SETMAC)
+ mac_str = argc >= 4 ? argv[3] : rmac;
+ else if (arg_part)
+ part = conv_argv_part_num(argv[3]);
}
static size_t
@@ -561,6 +545,18 @@ conv_argv_part_num(const char *part_str)
}
static void
+set_io_flags(int argc, char *argv[])
+{
+ gbe_flags = O_RDWR;
+
+ if (argc < 3)
+ return;
+
+ if (xstrxcmp(argv[2], "dump", MAX_CMD_LEN) == 0)
+ gbe_flags = O_RDONLY;
+}
+
+static void
run_cmd(size_t c)
{
check_command_num(c);
@@ -588,19 +584,42 @@ valid_command(size_t c)
return 1;
}
-static void
-set_io_flags(int argc, char *argv[])
+/*
+ * Portable strcmp() but blocks NULL/empty/unterminated
+ * strings. Even stricter than strncmp().
+ */
+static int
+xstrxcmp(const char *a, const char *b, size_t maxlen)
{
- gbe_flags = O_RDWR;
+ size_t i;
- if (argc < 3)
- return;
+ if (a == NULL || b == NULL)
+ err(EINVAL, "NULL input to xstrxcmp");
- if (xstrxcmp(argv[2], "dump", MAX_CMD_LEN) == 0)
- gbe_flags = O_RDONLY;
+ if (*a == '\0' || *b == '\0')
+ err(EINVAL, "Empty string in xstrxcmp");
+
+ for (i = 0; i < maxlen; i++) {
+ if (a[i] != b[i])
+ return (unsigned char)a[i] - (unsigned char)b[i];
+
+ if (a[i] == '\0')
+ return 0;
+ }
+
+ /*
+ * We reached maxlen, so assume unterminated string.
+ */
+ err(EINVAL, "Unterminated string in xstrxcmp");
+
+ /*
+ * Should never reach here. This keeps compilers happy.
+ */
+ errno = EINVAL;
+ return -1;
}
-#ifndef HAVE_ARC4RANDOM_BUF
+#ifndef NVMUTIL_ARC4RANDOM_BUF
static void
open_dev_urandom(void)
{
@@ -680,11 +699,13 @@ read_gbe_file_part(size_t p)
void *mem_offset =
gbe_mem_offset(p ^ command[cmd_index].invert, "pread");
- read_file_exact(gbe_fd, mem_offset,
- gbe_rw_size, gbe_file_offset(p, "pread"), fname, "pread");
+ if ((size_t)read_gbe_file_exact(gbe_fd, mem_offset,
+ gbe_rw_size, gbe_file_offset(p, "pread"), fname, "pread") !=
+ gbe_rw_size)
+ err(ECANCELED, "%s: Partial read from p%zu", fname, p);
- printf("Read %zu bytes from part %zu: %s\n",
- gbe_rw_size, p, fname);
+ printf("%s: Read %zu bytes from p%zu\n",
+ fname, gbe_rw_size, p);
}
static void
@@ -731,20 +752,45 @@ read_checksums(void)
errno = 0;
if (num_invalid >= max_invalid)
- err(ECANCELED, "No valid checksum found in file: %s",
+ err(ECANCELED, "%s: No valid checksum found in file",
fname);
}
+static int
+good_checksum(size_t partnum)
+{
+ uint16_t expected_checksum = calculated_checksum(partnum);
+ uint16_t current_checksum = nvm_word(NVM_CHECKSUM_WORD, partnum);
+
+ size_t real_partnum = partnum ^ command[cmd_index].invert;
+
+ if (current_checksum == expected_checksum)
+ return 1;
+
+ fprintf(stderr,
+ "WARNING: BAD checksum in part %zu\n"
+ "EXPECTED checksum in part %zu: %04x\n"
+ "CURRENT checksum in part %zu: %04x\n",
+ real_partnum,
+ real_partnum,
+ expected_checksum,
+ real_partnum,
+ current_checksum);
+
+ set_err(ECANCELED);
+ return 0;
+}
+
static void
-cmd_setmac(void)
+cmd_helper_setmac(void)
{
size_t partnum;
- #ifdef HAVE_ARC4RANDOM_BUF
- printf("Randomisation method: arc4random_buf\n");
- #else
- printf("Randomisation method: %s\n", rname);
- #endif
+#ifdef NVMUTIL_ARC4RANDOM_BUF
+ printf("Randomisation method: arc4random_buf\n");
+#else
+ printf("Randomisation method: %s\n", rname);
+#endif
printf("MAC address to be written: %s\n", mac_str);
parse_mac_string();
@@ -773,6 +819,33 @@ parse_mac_string(void)
err(EINVAL, "Must not specify multicast MAC address");
}
+/*
+ * strnlen() but aborts on NULL input, and empty strings.
+ * Our version also prohibits unterminated strings.
+ * strnlen() was standardized in POSIX.1-2008 and is not
+ * available on some older systems, so we provide our own.
+ */
+static size_t
+xstrxlen(const char *scmp, size_t maxlen)
+{
+ size_t xstr_index;
+
+ if (scmp == NULL)
+ err(EINVAL, "NULL input to xstrxlen");
+
+ if (*scmp == '\0')
+ err(EINVAL, "Empty string in xstrxlen");
+
+ for (xstr_index = 0;
+ xstr_index < maxlen && scmp[xstr_index] != '\0';
+ xstr_index++);
+
+ if (xstr_index == maxlen)
+ err(EINVAL, "Unterminated string in xstrxlen");
+
+ return xstr_index;
+}
+
static void
set_mac_byte(size_t mac_byte_pos)
{
@@ -847,18 +920,19 @@ rhex(void)
if (!n) {
n = sizeof(rnum);
-#ifdef HAVE_ARC4RANDOM_BUF
+#ifdef NVMUTIL_ARC4RANDOM_BUF
arc4random_buf(rnum, n);
#else
- read_file_exact(urandom_fd, rnum, n, 0, rname, NULL);
+ n = (size_t)read_gbe_file_exact(urandom_fd,
+ rnum, n, 0, rname, NULL);
#endif
}
return (uint16_t)(rnum[--n] & 0xf);
}
-static void
-read_file_exact(int fd, void *buf, size_t len,
+static ssize_t
+read_gbe_file_exact(int fd, void *buf, size_t len,
off_t off, const char *path, const char *op)
{
int retry;
@@ -875,13 +949,31 @@ read_file_exact(int fd, void *buf, size_t len,
if (rval == (ssize_t)len) {
errno = 0;
- return;
+ return rval;
}
- if (rval != -1)
+ if (rval != -1) {
+ if (fd == urandom_fd) {
+ /*
+ * /dev/[u]random reads can still return
+ * partial reads legally, on some weird
+ * Unix systems (especially older ones).
+ *
+ * We use a circular buffer for random
+ * bytes in rhex(), so we can just use
+ * the smaller amount of bytes and call
+ * read_gbe_file_exact again if necessary.
+ */
+ if (rval > 0) {
+ errno = 0;
+ return rval;
+ }
+ }
+
err(ECANCELED,
"Short %s, %zd bytes, on file: %s",
op ? op : "read", rval, path);
+ }
if (errno != EINTR)
err(ECANCELED,
@@ -891,6 +983,8 @@ read_file_exact(int fd, void *buf, size_t len,
err(EINTR, "%s: max retries exceeded on file: %s",
op ? op : "read", path);
+
+ return -1;
}
static void
@@ -907,27 +1001,19 @@ write_mac_part(size_t partnum)
printf("Wrote MAC address to part %zu: ", partnum);
print_mac_from_nvm(partnum);
-
- set_checksum(partnum);
}
static void
-cmd_dump(void)
+cmd_helper_dump(void)
{
size_t partnum;
- int num_invalid = 0;
for (partnum = 0; partnum < 2; partnum++) {
- if (!good_checksum(partnum))
- ++num_invalid;
printf("MAC (part %zu): ", partnum);
print_mac_from_nvm(partnum);
hexdump(partnum);
}
-
- if (num_invalid < 2)
- errno = 0;
}
static void
@@ -965,47 +1051,76 @@ hexdump(size_t partnum)
}
static void
-cmd_setchecksum(void)
+write_gbe_file(void)
{
- set_checksum(part);
+ size_t p;
+ size_t partnum;
+ uint8_t update_checksum;
+
+ if (gbe_flags == O_RDONLY)
+ return;
+
+ update_checksum = command[cmd_index].chksum_write;
+
+ override_part_modified();
+
+ for (p = 0; p < 2; p++) {
+ partnum = p ^ command[cmd_index].invert;
+
+ if (!part_modified[partnum])
+ continue;
+
+ if (update_checksum)
+ set_checksum(partnum);
+
+ write_gbe_file_part(partnum);
+ }
}
static void
-set_checksum(size_t p)
+override_part_modified(void)
{
- size_t c;
- uint16_t val16 = 0;
-
- for (c = 0; c < NVM_CHECKSUM_WORD; c++)
- val16 += nvm_word(c, p);
+ uint8_t mod_type = command[cmd_index].set_modified;
- set_nvm_word(NVM_CHECKSUM_WORD, p, NVM_CHECKSUM - val16);
+ switch (mod_type) {
+ case SET_MOD_0:
+ set_part_modified(0);
+ break;
+ case SET_MOD_1:
+ set_part_modified(1);
+ break;
+ case SET_MOD_N:
+ set_part_modified(part ^ command[cmd_index].invert);
+ break;
+ case SET_MOD_BOTH:
+ set_part_modified(0);
+ set_part_modified(1);
+ break;
+ case SET_MOD_OFF:
+ break;
+ default:
+ err(EINVAL, "Unsupported set_mod type: %u",
+ mod_type);
+ }
}
static void
-cmd_brick(void)
+set_checksum(size_t p)
{
- uint16_t checksum_word = nvm_word(NVM_CHECKSUM_WORD, part);
- set_nvm_word(NVM_CHECKSUM_WORD, part, checksum_word ^ 1);
+ check_bin(p, "part number");
+ set_nvm_word(NVM_CHECKSUM_WORD, p, calculated_checksum(p));
}
-static int
-good_checksum(size_t partnum)
+static uint16_t
+calculated_checksum(size_t p)
{
- size_t w;
- uint16_t total = 0;
-
- for (w = 0; w <= NVM_CHECKSUM_WORD; w++)
- total += nvm_word(w, partnum);
-
- if (total == NVM_CHECKSUM)
- return 1;
+ size_t c;
+ uint16_t val16 = 0;
- fprintf(stderr, "WARNING: BAD checksum in part %zu\n",
- partnum ^ command[cmd_index].invert);
+ for (c = 0; c < NVM_CHECKSUM_WORD; c++)
+ val16 += nvm_word(c, p);
- set_err(ECANCELED);
- return 0;
+ return NVM_CHECKSUM - val16;
}
/*
@@ -1024,7 +1139,7 @@ nvm_word(size_t pos16, size_t p)
check_nvm_bound(pos16, p);
pos = (pos16 << 1) + (p * GBE_PART_SIZE);
- return buf[pos] | (buf[pos + 1] << 8);
+ return (uint16_t)buf[pos] | (uint16_t)(buf[pos + 1] << 8);
}
static void
@@ -1042,6 +1157,13 @@ set_nvm_word(size_t pos16, size_t p, uint16_t val16)
}
static void
+set_part_modified(size_t p)
+{
+ check_bin(p, "part number");
+ part_modified[p] = 1;
+}
+
+static void
check_nvm_bound(size_t c, size_t p)
{
/*
@@ -1057,49 +1179,10 @@ check_nvm_bound(size_t c, size_t p)
}
static void
-write_gbe_file(void)
-{
- size_t p;
- size_t partnum;
-
- if (gbe_flags == O_RDONLY)
- return;
-
- override_part_modified();
-
- for (p = 0; p < 2; p++) {
- partnum = p ^ command[cmd_index].invert;
-
- if (part_modified[partnum])
- write_gbe_file_part(partnum);
- }
-}
-
-static void
-override_part_modified(void)
+check_bin(size_t a, const char *a_name)
{
- uint8_t mod_type = command[cmd_index].set_modified;
-
- switch (mod_type) {
- case SET_MOD_0:
- set_part_modified(0);
- break;
- case SET_MOD_1:
- set_part_modified(1);
- break;
- case SET_MOD_N:
- set_part_modified(part ^ command[cmd_index].invert);
- break;
- case SET_MOD_BOTH:
- set_part_modified(0);
- set_part_modified(1);
- break;
- case SET_MOD_OFF:
- break;
- default:
- err(EINVAL, "Unsupported set_mod type: %u",
- mod_type);
- }
+ if (a > 1)
+ err(ECANCELED, "%s must be 0 or 1, but is %zu", a_name, a);
}
static void
@@ -1110,7 +1193,7 @@ write_gbe_file_part(size_t p)
size_t gbe_rw_size;
if (gbe_fd == -1)
- err(ECANCELED, "Trying to write bad gbe_fd: %s", fname);
+ err(ECANCELED, "%s: Trying to write bad gbe_fd", fname);
gbe_rw_size = command[cmd_index].rw_size;
@@ -1120,22 +1203,22 @@ write_gbe_file_part(size_t p)
if (rval == (ssize_t)gbe_rw_size) {
errno = 0;
- printf("Wrote %zu bytes to part %zu: %s\n",
- gbe_rw_size, p, fname);
+ printf("%s: Wrote %zu bytes to part %zu\n",
+ fname, gbe_rw_size, p);
return;
}
if (rval != -1)
err(ECANCELED,
- "Short pwrite, %zd bytes, on file: %s",
- rval, fname);
+ "%s: Short pwrite, %zd bytes",
+ fname, rval);
if (errno != EINTR)
err(ECANCELED,
- "Could not pwrite file: '%s'", fname);
+ "%s: pwrite failed on p%zu", fname, p);
}
- err(EINTR, "pwrite: max retries exceeded on file: %s", fname);
+ err(EINTR, "%s: pwrite: max retries exceeded on p%zu", fname, p);
}
/*
@@ -1180,118 +1263,17 @@ gbe_x_offset(size_t p, const char *f_op, const char *d_type,
off = (off_t)p * nsize;
if (off + GBE_PART_SIZE > ncmp)
- err(ECANCELED, "GbE %s %s out of bounds: %s",
- d_type, f_op, fname);
+ err(ECANCELED, "%s: GbE %s %s out of bounds",
+ fname, d_type, f_op);
if (off != 0 && off != ncmp >> 1)
- err(ECANCELED, "GbE %s %s at bad offset: %s",
- d_type, f_op, fname);
+ err(ECANCELED, "%s: GbE %s %s at bad offset",
+ fname, d_type, f_op);
return off;
}
static void
-set_part_modified(size_t p)
-{
- check_bin(p, "part number");
- part_modified[p] = 1;
-}
-
-static void
-check_bin(size_t a, const char *a_name)
-{
- if (a > 1)
- err(ECANCELED, "%s must be 0 or 1, but is %zu", a_name, a);
-}
-
-static void
-usage(uint8_t usage_exit)
-{
- const char *util = getnvmprogname();
-
-#ifdef NVMUTIL_PLEDGE
- if (pledge("stdio", NULL) == -1)
- err(ECANCELED, "pledge");
-#endif
- fprintf(stderr,
- "Modify Intel GbE NVM images e.g. set MAC\n"
- "USAGE:\n"
- "\t%s FILE dump\n"
- "\t%s FILE # same as setmac without [MAC]\n"
- "\t%s FILE setmac [MAC]\n"
- "\t%s FILE swap\n"
- "\t%s FILE copy 0|1\n"
- "\t%s FILE brick 0|1\n"
- "\t%s FILE setchecksum 0|1\n",
- util, util, util, util, util, util, util);
-
- if (usage_exit)
- err(ECANCELED, "Too few arguments");
-}
-
-/*
- * strnlen() but aborts on NULL input, and empty strings.
- * Our version also prohibits unterminated strings.
- * strnlen() was standardized in POSIX.1-2008 and is not
- * available on some older systems, so we provide our own.
- */
-static size_t
-xstrxlen(const char *scmp, size_t maxlen)
-{
- size_t xstr_index;
-
- if (scmp == NULL)
- err(EINVAL, "NULL input to xstrxlen");
-
- if (*scmp == '\0')
- err(EINVAL, "Empty string in xstrxlen");
-
- for (xstr_index = 0;
- xstr_index < maxlen && scmp[xstr_index] != '\0';
- xstr_index++);
-
- if (xstr_index == maxlen)
- err(EINVAL, "Unterminated string in xstrxlen");
-
- return xstr_index;
-}
-
-/*
- * Portable, secure strcmp() with the same mentality
- * as our xstrxlen
- */
-static int
-xstrxcmp(const char *a, const char *b, size_t maxlen)
-{
- size_t i;
-
- if (a == NULL || b == NULL)
- err(EINVAL, "NULL input to xstrxcmp");
-
- if (*a == '\0' || *b == '\0')
- err(EINVAL, "Empty string in xstrxcmp");
-
- for (i = 0; i < maxlen; i++) {
- if (a[i] != b[i])
- return (unsigned char)a[i] - (unsigned char)b[i];
-
- if (a[i] == '\0')
- return 0;
- }
-
- /*
- * We reached maxlen, so assume unterminated string.
- */
- err(EINVAL, "Unterminated string in xstrxcmp");
-
- /*
- * Should never reach here. This keeps compilers happy.
- */
- errno = EINVAL;
- return -1;
-}
-
-static void
err(int nvm_errval, const char *msg, ...)
{
if (nvm_errval != -1)
@@ -1312,6 +1294,22 @@ err(int nvm_errval, const char *msg, ...)
exit(EXIT_FAILURE);
}
+static void
+close_files(void)
+{
+ if (gbe_fd > -1) {
+ if (close(gbe_fd) == -1)
+ err(-1, "%s: close failed", fname);
+ }
+
+#ifndef NVMUTIL_ARC4RANDOM_BUF
+ if (urandom_fd > -1) {
+ if (close(urandom_fd) == -1)
+ err(-1, "%s: close failed", rname);
+ }
+#endif
+}
+
static const char *
getnvmprogname(void)
{
@@ -1340,17 +1338,23 @@ set_err(int x)
}
static void
-close_files(void)
+usage(uint8_t usage_exit)
{
- if (gbe_fd > -1) {
- if (close(gbe_fd) == -1)
- err(-1, "close '%s'", fname);
- }
+ const char *util = getnvmprogname();
-#ifndef HAVE_ARC4RANDOM_BUF
- if (urandom_fd > -1) {
- if (close(urandom_fd) == -1)
- err(-1, "close '%s'", rname);
- }
+#ifdef NVMUTIL_PLEDGE
+ if (pledge("stdio", NULL) == -1)
+ err(ECANCELED, "pledge");
#endif
+ fprintf(stderr,
+ "Modify Intel GbE NVM images e.g. set MAC\n"
+ "USAGE:\n"
+ "\t%s FILE dump\n"
+ "\t%s FILE setmac [MAC]\n"
+ "\t%s FILE swap\n"
+ "\t%s FILE copy 0|1\n",
+ util, util, util, util);
+
+ if (usage_exit)
+ err(EINVAL, "Too few arguments");
}