diff options
Diffstat (limited to 'util')
| -rw-r--r-- | util/nvmutil/nvmutil.c | 178 |
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; |
