summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/nvmutil/nvmutil.c178
1 files changed, 90 insertions, 88 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c
index 3cf06338..68e041a3 100644
--- a/util/nvmutil/nvmutil.c
+++ b/util/nvmutil/nvmutil.c
@@ -211,6 +211,8 @@ static off_t gbe_x_offset(size_t part, const char *f_op,
const char *d_type, off_t nsize, off_t ncmp);
static ssize_t rw_file_exact(int fd, uint8_t *mem, size_t len,
off_t off, int rw_type);
+static ssize_t do_rw(int fd,
+ uint8_t *mem, size_t len, off_t off, int rw_type);
static ssize_t prw(int fd, void *mem, size_t nrw,
off_t off, int rw_type);
static off_t lseek_eintr(int fd, off_t off, int whence);
@@ -221,7 +223,7 @@ static off_t lseek_eintr(int fd, off_t off, int whence);
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 set_err_if_unset(int errval);
static void usage(uint8_t usage_exit);
/*
@@ -430,6 +432,9 @@ static const struct commands command[] = {
*/
static size_t cmd_index = CMD_NULL;
+typedef char assert_argc3[(ARGC_3==3)?1:-1];
+typedef char assert_argc4[(ARGC_4==4)?1:-1];
+
int
main(int argc, char *argv[])
{
@@ -501,9 +506,10 @@ main(int argc, char *argv[])
errno = 0;
run_cmd(cmd_index);
- if (errno)
+ if (errno && (!(part_valid[0] || part_valid[1])))
err(errno, "%s: Unhandled error (WRITE SKIPPED)", fname);
- else if (command[cmd_index].flags == O_RDWR)
+
+ if (command[cmd_index].flags == O_RDWR)
write_gbe_file();
close_files();
@@ -522,7 +528,7 @@ sanitize_command_list(void)
{
size_t c;
- for (c = 0; valid_command(c); c++)
+ for (c = 0; c < N_COMMANDS; c++)
sanitize_command_index(c);
}
@@ -534,11 +540,6 @@ sanitize_command_index(size_t c)
check_command_num(c);
- if (ARGC_3 != 3)
- err(EINVAL, "ARGC_3 is not equal to 3");
- if (ARGC_4 != 4)
- err(EINVAL, "ARGC_4 is not equal to 4");
-
if (command[c].argc < 3)
err(EINVAL, "cmd index %lu: argc below 3, %d",
(unsigned long)c, command[c].argc);
@@ -556,6 +557,15 @@ sanitize_command_index(size_t c)
(unsigned long)c, command[c].str);
}
+ if (!((CMD_SETMAC > CMD_DUMP) && (CMD_SWAP > CMD_SETMAC) &&
+ (CMD_COPY > CMD_SWAP) && (CMD_CAT > CMD_COPY) &&
+ (CMD_CAT16 > CMD_CAT) && (CMD_CAT128 > CMD_CAT16)))
+ err(EINVAL, "Some command integers are the same");
+
+ if (!((SET_MOD_0 > SET_MOD_OFF) && (SET_MOD_1 > SET_MOD_0) &&
+ (SET_MOD_N > SET_MOD_1) && (SET_MOD_BOTH > SET_MOD_N)))
+ err(EINVAL, "Some modtype integers are the same");
+
mod_type = command[c].set_modified;
switch (mod_type) {
case SET_MOD_0:
@@ -578,6 +588,7 @@ sanitize_command_index(size_t c)
CHECKSUM_READ, "CHECKSUM_READ");
check_enum_bin(SKIP_CHECKSUM_WRITE, "SKIP_CHECKSUM_WRITE",
CHECKSUM_WRITE, "CHECKSUM_WRITE");
+ check_enum_bin(NO_INVERT, "NO_INVERT", PART_INVERT, "PART_INVERT");
gbe_rw_size = command[c].rw_size;
@@ -598,8 +609,8 @@ sanitize_command_index(size_t c)
command[c].flags != O_RDWR)
err(EINVAL, "invalid cmd.flags setting");
- if (!((PLESEN > LESEN) && (SCHREIB > PLESEN) && (PSCHREIB > SCHREIB)))
- err(EINVAL, "some rw type integers are the same");
+ if (!((!LESEN) && (PLESEN == 1) && (SCHREIB == 2) && (PSCHREIB == 3)))
+ err(EINVAL, "rw type integers are the wrong values");
}
static void
@@ -703,7 +714,7 @@ xstrxcmp(const char *a, const char *b, size_t maxlen)
/*
* Should never reach here. This keeps compilers happy.
*/
- set_err(EINVAL);
+ set_err_if_unset(EINVAL);
return -1;
}
@@ -847,7 +858,7 @@ good_checksum(size_t partnum)
if (current_checksum == expected_checksum)
return 1;
- set_err(EINVAL);
+ set_err_if_unset(EINVAL);
return 0;
}
@@ -1015,6 +1026,7 @@ rhex(void)
n = sizeof(rnum);
if (rw_file_exact(urandom_fd, rnum, n, 0, LESEN) == -1)
err(errno, "Randomisation failed");
+ errno = 0;
}
return (uint16_t)(rnum[--n] & 0xf);
@@ -1130,30 +1142,32 @@ gbe_cat_buf(uint8_t *b)
rval = rw_file_exact(STDOUT_FILENO, b,
GBE_PART_SIZE, 0, SCHREIB);
- if (rval == -1) {
- if (errno == EAGAIN) {
- /*
- * We assume that no
- * data was written
- * to stdout.
- */
- errno = 0;
- continue;
- }
+ if (rval >= 0) {
+ /*
+ * A partial write is especially
+ * fatal, as it should already be
+ * prevented in rw_file_exact().
+ */
+ if ((size_t)rval != GBE_PART_SIZE)
+ err(EIO, "stdout: cat: Partial write");
+ break;
+ }
+ if (errno != EAGAIN)
err(errno, "stdout: cat");
- }
/*
- * A partial write is especially
- * fatal, as it should already be
- * prevented in rw_file_exact().
+ * We assume that no data
+ * was written to stdout.
*/
- if ((size_t)rval != GBE_PART_SIZE)
- err(EIO, "stdout: cat: Partial write");
-
- break;
+ errno = 0;
}
+
+ /*
+ * No errors here.
+ * Avoid the warning in main()
+ */
+ errno = 0;
}
static void
@@ -1317,6 +1331,8 @@ rw_gbe_file_part(size_t p, int rw_type,
rw_type) == -1)
err(errno, "%s: %s: part %lu",
fname, rw_type_str, (unsigned long)p);
+
+ errno = 0;
}
/*
@@ -1334,8 +1350,7 @@ gbe_mem_offset(size_t p, const char *f_op)
}
/*
- * Reads to GbE from write_gbe_file_part and read_gbe_file_part
- * are filtered through here. These operations must
+ * I/O operations filtered here. These operations must
* only write from the 0th position or the half position
* within the GbE file, and write 4KB of data.
*
@@ -1395,64 +1410,49 @@ rw_file_exact(int fd, uint8_t *mem, size_t len,
ssize_t rval = 0;
size_t rc = 0;
- if (fd < 0) {
- set_err(EIO);
- return -1;
- }
- if (!len) {
- set_err(EIO);
- return -1;
- }
- if (len > (size_t)SSIZE_MAX) {
- set_err(EIO);
+ if (fd < 0 || !len || len > (size_t)SSIZE_MAX) {
+ set_err_if_unset(EIO);
return -1;
}
while (rc < len) {
- if (rw_type == PSCHREIB) {
- rval = prw(fd, mem + rc, len - rc,
- off + rc, rw_type);
- } else if (rw_type == SCHREIB) {
- rval = write(fd, mem + rc, len - rc);
- } else if (rw_type == PLESEN) {
- rval = prw(fd, mem + rc, len - rc,
- off + rc, rw_type);
- } else if (rw_type == LESEN) {
- rval = read(fd, mem + rc, len - rc);
- } else {
- set_err(EIO);
- return -1;
- }
+ rval = do_rw(fd, mem + rc, len - rc, off + rc, rw_type);
- if (rval >= 0) {
- if ((size_t)rval > (len - rc) /* Prevent overflow */
- || rval == 0) { /* Prevent infinite 0-byte loop */
- set_err(EIO);
- return -1;
- }
-
- rc += (size_t)rval;
+ if (rval < 0 && errno == EINTR) {
continue;
+ } else if (rval < 0) {
+ set_err_if_unset(EIO);
+ return -1;
}
- if (errno == EINTR) {
- /*
- * EINTR is not fatal, because we
- * eventually return. We rely on
- * errno for general error state
- * after return from rw_file_exact,
- * so we don't want a false error.
- */
- errno = 0;
- continue;
+ if ((size_t)rval > (len - rc) /* Prevent overflow */
+ || rval == 0) { /* Prevent infinite 0-byte loop */
+ set_err_if_unset(EIO);
+ return -1;
}
- set_err(EIO);
- return -1;
+ rc += (size_t)rval;
}
return rc;
}
+static ssize_t
+do_rw(int fd, uint8_t *mem,
+ size_t len, off_t off, int rw_type)
+{
+ if (rw_type == LESEN || rw_type == PLESEN << 2)
+ return read(fd, mem, len);
+
+ if (rw_type == SCHREIB || rw_type == PSCHREIB << 2)
+ return write(fd, mem, len);
+
+ if (rw_type == PLESEN || rw_type == PSCHREIB)
+ return prw(fd, mem, len, off, rw_type);
+
+ set_err_if_unset(EINVAL);
+ return -1;
+}
+
/*
* This implements a portable analog of pwrite()
* and pread() - note that this version is not
@@ -1476,14 +1476,7 @@ prw(int fd, void *mem, size_t nrw,
return -1;
do {
- if (rw_type == PLESEN)
- r = read(fd, mem, nrw);
- else if (rw_type == PSCHREIB)
- r = write(fd, mem, nrw);
- else {
- set_err(EINVAL);
- return -1;
- }
+ r = do_rw(fd, mem, nrw, off, rw_type << 2);
} while (r < 0 && errno == EINTR);
saved_errno = errno;
@@ -1523,7 +1516,7 @@ err(int nvm_errval, const char *msg, ...)
* one that does this.
*
* Since the errval is for setting errno, -1
- * would be incorrect. Therefore, set_err()
+ * would be incorrect. Therefore, set_err_if_unset()
* avoids overriding errno if the given value
* is negative.
*
@@ -1538,7 +1531,7 @@ err(int nvm_errval, const char *msg, ...)
vfprintf(stderr, msg, args);
va_end(args);
- set_err(nvm_errval);
+ set_err_if_unset(nvm_errval);
fprintf(stderr, ": %s", strerror(errno));
fprintf(stderr, "\n");
@@ -1577,8 +1570,17 @@ getnvmprogname(void)
return argv0;
}
+/*
+ * Set errno only if it hasn't already been set.
+ * This prevents overriding real libc errors.
+ *
+ * We use errno for regular program state, while
+ * being careful not to clobber what was set by
+ * real libc function, or a minority of our stub
+ * functions such as prw()
+ */
static void
-set_err(int x)
+set_err_if_unset(int x)
{
if (errno)
return;