summaryrefslogtreecommitdiff
path: root/util/nvmutil/nvmutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/nvmutil/nvmutil.c')
-rw-r--r--util/nvmutil/nvmutil.c1179
1 files changed, 637 insertions, 542 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c
index f6374a7a..ecc003ac 100644
--- a/util/nvmutil/nvmutil.c
+++ b/util/nvmutil/nvmutil.c
@@ -42,9 +42,26 @@
* is passed. The rest of the program
* will manipulate this data.
*/
+/*
+TODO:
+eventually, i will not have this return
+a pointer at all. instead, a similar key
+mechanism will be used for other access
+functions e.g. word/set_word, err(needs
+to clean up), and so on. then those
+would return values if already initialised,
+but would not permit additional init - will
+decide exactly how to implement this at a
+later state.
+
+this is part of an ongoing effort to introduce
+extreme memory safety into this program.
+ */
struct xstate *
-new_xstate(void)
+xstatus(void)
{
+ static int first_run = 1;
+
static struct xstate us = {
/* .cmd (update cmd[] in the struct if adding to it)
DO NOT FORGET. or C will init zeroes/NULLs */
@@ -79,12 +96,12 @@ new_xstate(void)
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
GBE_PART_SIZE, O_RDONLY
}, {
- CMD_CAT16, "cat16", cmd_helper_cat, ARGC_3,
+ CMD_CAT16, "cat16", cmd_helper_cat16, ARGC_3,
ARG_NOPART,
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
GBE_PART_SIZE, O_RDONLY
}, {
- CMD_CAT128, "cat128", cmd_helper_cat, ARGC_3,
+ CMD_CAT128, "cat128", cmd_helper_cat128, ARGC_3,
ARG_NOPART,
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
GBE_PART_SIZE, O_RDONLY
@@ -94,7 +111,7 @@ new_xstate(void)
/* ->mac */
{NULL, "xx:xx:xx:xx:xx:xx", {0, 0, 0}}, /* .str, .rmac, .mac_buf */
- /* .buf */
+ /* .f */
{0},
/* .argv0 (for our getprogname implementation) */
@@ -107,67 +124,58 @@ new_xstate(void)
1,
/* .xsize (size of the stuct will be stored here later) */
- 0
-
- };
-
- struct xstate *xs_new;
+ 0,
- us.xsize = sizeof(us);
+ /* .cat (cat helpers set this) */
+ -1
- xs_new = malloc(us.xsize);
- if (xs_new == NULL)
- err(ECANCELED, "Could not initialise new state");
+ };
- memcpy(xs_new, &us, us.xsize);
+ if (first_run) {
+ us.xsize = sizeof(us);
- /*
- * Some pointers should be set
- * in the copy, not the template,
- * if they point to other items
- * in the struct, because if they
- * were set before copy, then copied,
- * the copied pointer would be invalid,
- * referring to the reference struct
- *
- * e.g. ->f.buf (gbe tmp file work memory):
- */
+ us.f.buf = us.f.real_buf;
- xs_new->f.buf = xs_new->f.real_buf;
+ us.f.gbe_fd = -1;
+ us.f.tmp_fd = -1;
- xs_new->f.gbe_fd = -1;
- xs_new->f.tmp_fd = -1;
+ us.f.tname = NULL;
+ us.f.fname = NULL;
+ }
- xs_new->f.tname = NULL;
- xs_new->f.fname = NULL;
+ first_run = 0;
- return xs_new;
+ return &us;
}
-static struct xstate *nv = NULL;
-
int
main(int argc, char *argv[])
{
+ struct xstate *x;
struct commands *cmd;
struct xfile *f;
+ unsigned long i;
- unsigned long *i;
+ char *tmp_path;
- nv = new_xstate();
- if (nv == NULL)
- err(errno, NULL);
+ struct stat st;
+ int fd;
- nv->argv0 = argv[0];
- if (argc < 3)
- usage();
+ tmp_path = NULL;
+#ifndef S_ISREG
+ err(ECANCELED, "Can't determine file types (S_ISREG undefined)");
+#endif
+
+#ifndef CHAR_BIT
+ err(ECANCELED, "Unknown char size");
+#else
if (CHAR_BIT != 8)
err(EINVAL, "Unsupported char size");
+#endif
- f = &nv->f;
-
- f->fname = argv[1];
+ if (argc < 3)
+ usage();
#ifdef NVMUTIL_UNVEIL
/*
@@ -175,47 +183,65 @@ main(int argc, char *argv[])
* unveil would trap on final file rename
* and we can't know the path in advance
*/
- f->tname = new_tmpfile(&f->tmp_fd, 1, NULL);
+ tmp_path = new_tmpfile(&fd, 1, NULL);
#else
- f->tname = new_tmpfile(&f->tmp_fd, 0, NULL);
+ tmp_path = new_tmpfile(&fd, 0, NULL);
#endif
- if (f->tname == NULL)
+ if (tmp_path == NULL)
err(errno, "Can't create tmpfile");
#ifdef NVMUTIL_PLEDGE
#ifdef NVMUTIL_UNVEIL
if (pledge("stdio flock rpath wpath cpath unveil", NULL) == -1)
err(errno, "pledge, unveil");
- if (unveil("/dev/urandom", "r") == -1)
- err(errno, "unveil: /dev/urandom");
- if (unveil("/dev/random", "r") == -1)
- err(errno, "unveil: /dev/random");
+ if (unveil("/dev/null", "r") == -1)
+ err(errno, "unveil: /dev/null");
#else
if (pledge("stdio flock rpath wpath cpath", NULL) == -1)
err(errno, "pledge");
#endif
#endif
+ x = xstatus();
+
+ if (x == NULL)
+ err(errno, NULL);
+ if (x->f.buf == NULL)
+ err(EINVAL, "Work buffer not initialised");
+
+ x->argv0 = argv[0];
+ f = &x->f;
+
+ f->fname = argv[1];
+ f->tname = tmp_path;
+ f->tmp_fd = fd;
+
+ if(fstat(fd, &st) < 0)
+ err(errno, "can't stat tmpfile");
+
+ f->tmp_dev = st.st_dev;
+ f->tmp_ino = st.st_ino;
+
sanitize_command_list();
set_cmd(argc, argv);
set_cmd_args(argc, argv);
- i = &nv->i;
- cmd = &nv->cmd[*i];
+ i = x->i;
+ cmd = &x->cmd[i];
#ifdef NVMUTIL_UNVEIL
- if (cmd->flags == O_RDONLY) {
- if (unveil(fname, "r") == -1)
- err(errno, "%s: unveil r", fname);
+ if ((cmd->flags & O_ACCMODE) == O_RDONLY) {
+ if (unveil(f->fname, "r") == -1)
+ err(errno, "%s: unveil r", f->fname);
} else {
- if (unveil(fname, "rwc") == -1)
- err(errno, "%s: unveil rw", fname);
+ if (unveil(f->tname, "rwc") == -1)
+ err(errno, "%s: unveil rw", f->tname);
}
- if (unveil(tname, "rwc") == -1)
- err(errno, "%s: unveil rwc", tname);
+ if (unveil(f->tname, "rwc") == -1)
+ err(errno, "%s: unveil rwc", f->tname);
if (unveil(NULL, NULL) == -1)
err(errno, "unveil block (rw)");
@@ -224,8 +250,6 @@ main(int argc, char *argv[])
err(errno, "pledge (kill unveil)");
#endif
- srand((unsigned int)(time(NULL) ^ getpid()));
-
open_gbe_file();
memset(f->buf, 0, GBE_BUF_SIZE);
@@ -237,7 +261,7 @@ main(int argc, char *argv[])
run_cmd();
- if (cmd->flags == O_RDWR)
+ if ((cmd->flags & O_ACCMODE) == O_RDWR)
write_to_gbe_bin();
if (exit_cleanup() == -1)
@@ -258,8 +282,12 @@ main(int argc, char *argv[])
void
sanitize_command_list(void)
{
+ struct xstate *x = xstatus();
+
unsigned long c;
- unsigned long num_commands = items(nv->cmd);
+ unsigned long num_commands;
+
+ num_commands = items(x->cmd);
for (c = 0; c < num_commands; c++)
sanitize_command_index(c);
@@ -271,9 +299,13 @@ sanitize_command_list(void)
void
sanitize_command_index(unsigned long c)
{
+ struct xstate *x = xstatus();
+ struct commands *cmd;
+
+ int _flag;
unsigned long gbe_rw_size;
- struct commands *cmd = &nv->cmd[c];
+ cmd = &x->cmd[c];
check_command_num(c);
@@ -318,30 +350,33 @@ sanitize_command_index(unsigned long c)
err(EINVAL, "rw_size larger than GbE part: %lu",
(unsigned long)gbe_rw_size);
- if (cmd->flags != O_RDONLY &&
- cmd->flags != O_RDWR)
+ _flag = (cmd->flags & O_ACCMODE);
+
+ if (_flag != O_RDONLY &&
+ _flag != O_RDWR)
err(EINVAL, "invalid cmd.flags setting");
}
void
set_cmd(int argc, char *argv[])
{
+ struct xstate *x = xstatus();
const char *cmd;
- unsigned long i = 0;
+ unsigned long c;
- for (i = 0; i < items(nv->cmd); i++) {
+ for (c = 0; c < items(x->cmd); c++) {
- cmd = nv->cmd[i].str;
+ cmd = x->cmd[c].str;
/* not the right command */
if (xstrxcmp(argv[2], cmd, MAX_CMD_LEN) != 0)
continue;
/* valid command found */
- if (argc >= nv->cmd[i].argc) {
- nv->no_cmd = 0;
- nv->i = i; /* set command */
+ if (argc >= x->cmd[c].argc) {
+ x->no_cmd = 0;
+ x->i = c; /* set command */
return;
}
@@ -350,48 +385,44 @@ set_cmd(int argc, char *argv[])
"Too few args on command '%s'", cmd);
}
- nv->no_cmd = 1;
+ x->no_cmd = 1;
}
void
set_cmd_args(int argc, char *argv[])
{
- unsigned char arg_part;
+ struct xstate *x = xstatus();
+ struct commands *cmd;
+ struct xfile *f;
unsigned long i;
- struct xfile *f;
- struct commands *cmd;
+ i = x->i;
+ cmd = &x->cmd[i];
+ f = &x->f;
- if (!valid_command(nv->i) || argc < 3)
+ if (!valid_command(i) || argc < 3)
usage();
- if (nv->no_cmd)
+ if (x->no_cmd)
usage();
- i = nv->i;
- f = &nv->f;
-
- cmd = &nv->cmd[i];
-
- arg_part = cmd->arg_part;
-
/* Maintainer bugs */
- if (arg_part && argc < 4)
+ if (cmd->arg_part && argc < 4)
err(EINVAL,
"arg_part set for command that needs argc4");
- if (arg_part && i == CMD_SETMAC)
+ if (cmd->arg_part && i == CMD_SETMAC)
err(EINVAL,
"arg_part set on CMD_SETMAC");
if (i == CMD_SETMAC) {
if (argc >= 4)
- nv->mac.str = argv[3];
+ x->mac.str = argv[3];
else
- nv->mac.str = nv->mac.rmac;
+ x->mac.str = x->mac.rmac;
- } else if (arg_part) {
+ } else if (cmd->arg_part) {
f->part = conv_argv_part_num(argv[3]);
}
@@ -429,6 +460,7 @@ xstrxcmp(const char *a, const char *b, unsigned long maxlen)
err(EINVAL, "Empty string in xstrxcmp");
for (i = 0; i < maxlen; i++) {
+
unsigned char ac = (unsigned char)a[i];
unsigned char bc = (unsigned char)b[i];
@@ -457,14 +489,15 @@ xstrxcmp(const char *a, const char *b, unsigned long maxlen)
void
open_gbe_file(void)
{
+ struct xstate *x = xstatus();
+ struct commands *cmd;
+ struct xfile *f;
+
struct stat _st;
int _flags;
- unsigned long *i = &nv->i;
-
- struct commands *cmd = &nv->cmd[*i];
-
- struct xfile *f = &nv->f;
+ cmd = &x->cmd[x->i];
+ f = &x->f;
xopen(&f->gbe_fd, f->fname,
cmd->flags | O_BINARY |
@@ -506,19 +539,18 @@ open_gbe_file(void)
err(EINVAL, "File size must be 8KB, 16KB or 128KB");
}
- if (lock_file(f->gbe_fd) == -1)
+ if (lock_file(f->gbe_fd, cmd->flags) == -1)
err(errno, "%s: can't lock", f->fname);
}
int
-lock_file(int fd)
+lock_file(int fd, int flags)
{
struct flock fl;
- struct commands *cmd = &nv->cmd[nv->i];
memset(&fl, 0, sizeof(fl));
- if (cmd->flags == O_RDONLY)
+ if ((flags & O_ACCMODE) == O_RDONLY)
fl.l_type = F_RDLCK;
else
fl.l_type = F_WRLCK;
@@ -531,6 +563,21 @@ lock_file(int fd)
return 0;
}
+/*
+ * TODO: make generic. S_ISREG: check every other
+ * type, erring only if it doesn't match what was
+ * passed as type requested.
+ * also:
+ * have variable need_seek, only err on seek if
+ * need_seek is set.
+ * also consider the stat check in this generic
+ * context
+ * make tthe return type an int, not a void.
+ * return -1 with errno set to indicate error,
+ * though the syscalls mostly handle that.
+ * save errno before lseek, resetting it after
+ * the check if return >-1
+ */
void
xopen(int *fd_ptr, const char *path, int flags, struct stat *st)
{
@@ -561,7 +608,10 @@ xopen(int *fd_ptr, const char *path, int flags, struct stat *st)
void
copy_gbe(void)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct xfile *f;
+
+ f = &x->f;
read_file();
@@ -586,10 +636,13 @@ copy_gbe(void)
void
read_file(void)
{
- long _r;
+ struct xstate *x = xstatus();
+ struct xfile *f;
+
struct stat _st;
+ long _r;
- struct xfile *f = &nv->f;
+ f = &x->f;
/* read main file */
_r = rw_file_exact(f->gbe_fd, f->buf, f->gbe_file_size,
@@ -644,13 +697,18 @@ read_file(void)
void
read_checksums(void)
{
+ struct xstate *x = xstatus();
+ struct commands *cmd;
+ struct xfile *f;
+
unsigned long _p;
unsigned long _skip_part;
+
unsigned char _num_invalid;
unsigned char _max_invalid;
- struct xfile *f = &nv->f;
- struct commands *cmd = &nv->cmd[nv->i];
+ cmd = &x->cmd[x->i];
+ f = &x->f;
f->part_valid[0] = 0;
f->part_valid[1] = 0;
@@ -694,30 +752,41 @@ read_checksums(void)
int
good_checksum(unsigned long partnum)
{
- unsigned short expected_checksum =
+ unsigned short expected_checksum;
+ unsigned short actual_checksum;
+
+ expected_checksum =
calculated_checksum(partnum);
- unsigned short current_checksum =
+ actual_checksum =
nvm_word(NVM_CHECKSUM_WORD, partnum);
- return current_checksum == expected_checksum;
+ if (expected_checksum == actual_checksum) {
+ return 1;
+ } else {
+ return 0;
+ }
}
void
run_cmd(void)
{
- unsigned long cmd_num;
- struct commands *cmd;
+ struct xstate *x = xstatus();
+ unsigned long i;
+ void (*run)(void);
- cmd_num = nv->i;
- cmd = &nv->cmd[cmd_num];
+ i = x->i;
+ run = x->cmd[i].run;
- check_command_num(cmd_num);
+ check_command_num(i);
- if (cmd->run == NULL)
- err(EINVAL, "Command %lu: null ptr", cmd_num);
+ if (run == NULL)
+ err(EINVAL, "Command %lu: null ptr", i);
- cmd->run();
+ run();
+
+ for (i = 0; i < items(x->cmd); i++)
+ x->cmd[i].run = cmd_helper_err;
}
void
@@ -731,12 +800,13 @@ check_command_num(unsigned long c)
unsigned char
valid_command(unsigned long c)
{
+ struct xstate *x = xstatus();
struct commands *cmd;
- if (c >= items(nv->cmd))
+ if (c >= items(x->cmd))
return 0;
- cmd = &nv->cmd[c];
+ cmd = &x->cmd[c];
if (c != cmd->chk)
err(EINVAL,
@@ -749,8 +819,13 @@ valid_command(unsigned long c)
void
cmd_helper_setmac(void)
{
+ struct xstate *x = xstatus();
unsigned long partnum;
- struct macaddr *mac = &nv->mac;
+ struct macaddr *mac;
+
+ mac = &x->mac;
+
+ check_cmd(cmd_helper_setmac, "setmac");
printf("MAC address to be written: %s\n", mac->str);
parse_mac_string();
@@ -762,11 +837,14 @@ cmd_helper_setmac(void)
void
parse_mac_string(void)
{
+ struct xstate *x = xstatus();
+ struct macaddr *mac;
+
unsigned long mac_byte;
- struct macaddr *mac = &nv->mac;
+ mac = &x->mac;
- if (xstrxlen(nv->mac.str, 18) != 17)
+ if (xstrxlen(x->mac.str, 18) != 17)
err(EINVAL, "MAC address is the wrong length");
memset(mac->mac_buf, 0, sizeof(mac->mac_buf));
@@ -811,11 +889,17 @@ xstrxlen(const char *scmp, unsigned long maxlen)
void
set_mac_byte(unsigned long mac_byte_pos)
{
- unsigned long mac_str_pos = mac_byte_pos * 3;
- unsigned long mac_nib_pos;
+ struct xstate *x = xstatus();
+ struct macaddr *mac;
+
char separator;
- struct macaddr *mac = &nv->mac;
+ unsigned long mac_str_pos;
+ unsigned long mac_nib_pos;
+
+ mac = &x->mac;
+
+ mac_str_pos = mac_byte_pos * 3;
if (mac_str_pos < 15) {
if ((separator = mac->str[mac_str_pos + 2]) != ':')
@@ -831,10 +915,13 @@ void
set_mac_nib(unsigned long mac_str_pos,
unsigned long mac_byte_pos, unsigned long mac_nib_pos)
{
+ struct xstate *x = xstatus();
+ struct macaddr *mac;
+
char mac_ch;
unsigned short hex_num;
- struct macaddr *mac = &nv->mac;
+ mac = &x->mac;
mac_ch = mac->str[mac_str_pos + mac_nib_pos];
@@ -862,7 +949,9 @@ set_mac_nib(unsigned long mac_str_pos,
unsigned short
hextonum(char ch_s)
{
- unsigned char ch = (unsigned char)ch_s;
+ unsigned char ch;
+
+ ch = (unsigned char)ch_s;
if ((unsigned int)(ch - '0') <= 9)
return ch - '0';
@@ -881,125 +970,59 @@ hextonum(char ch_s)
unsigned long
rlong(void)
{
- struct x_st_timeval tv;
- static unsigned long mix = 0;
- static unsigned long counter = 0;
-
- static int fd = -1;
- unsigned long rval = 0;
- long nr = -1;
+#if (defined(__OpenBSD__) && (OpenBSD) >= 201) || \
+ defined(__FreeBSD__) || \
+ defined(__NetBSD__) || defined(__APPLE__)
- x_i_gettimeofday(&tv, NULL);
+ unsigned long rval;
+ arc4random_buf(&rval, sizeof(unsigned long));
- mix ^= (unsigned long)tv.tv_sec
- ^ (unsigned long)tv.tv_usec
- ^ (unsigned long)getpid()
- ^ (unsigned long)&mix
- ^ counter++
- ^ entropy_jitter();
+ return rval;
+#else
+ int fd;
- /*
- * Stack addresses can vary between
- * calls, thus increasing entropy.
- */
- mix ^= (unsigned long)&mix;
- mix ^= (unsigned long)&tv;
- mix ^= (unsigned long)&counter;
+ long nr;
- /*
- * Now, we won't use this mix
- * immediately. We'll try to
- * read urandom first, which is
- * likely safer, and pass that,
- * falling back to the mixture
- * if urandom fails.
- *
- * Since urandom is likely
- * reliable, the number of
- * times it will fail is
- * likely extremely random,
- * thus, building more than
- * sufficient entropy by the
- * time we do eventually use
- * the fallback code
- */
+ unsigned long rval;
- if (fd < 0)
- fd = open("/dev/urandom", O_RDONLY | O_BINARY | O_NONBLOCK);
+ fd = open("/dev/urandom", O_RDONLY | O_BINARY);
-#if !(defined(__OpenBSD__) && defined(OpenBSD)) || \
- (defined(__OpenBSD__) && defined(OpenBSD) && \
- OpenBSD < 604)
+#ifdef __OpenBSD__
if (fd < 0) /* old openbsd */
- fd = open("/dev/arandom", O_RDONLY | O_BINARY | O_NONBLOCK);
+ fd = open("/dev/arandom", O_RDONLY | O_BINARY);
#endif
if (fd < 0)
- fd = open("/dev/random", O_RDONLY | O_BINARY | O_NONBLOCK);
+ fd = open("/dev/random", O_RDONLY | O_BINARY);
+
+ if (fd < 0)
+ err(errno, "can't open random device");
nr = rw_file_exact(fd, (unsigned char *)&rval,
sizeof(unsigned long), 0, IO_READ, LOOP_EAGAIN,
LOOP_EINTR, MAX_ZERO_RW_RETRY, OFF_ERR);
- if (nr == sizeof(unsigned long))
- return rval;
+ if (x_i_close(fd) < 0)
+ err(errno, "Can't close randomness fd");
- return mix;
-}
-
-unsigned long
-entropy_jitter(void)
-{
- struct x_st_timeval a, b;
- unsigned long mix = 0;
- long mix_diff;
- int i;
-
- x_i_gettimeofday(&a, NULL);
-
- for (i = 0; i < 32; i++) {
- getpid();
- x_i_gettimeofday(&b, NULL);
-
- /*
- * prevent negative numbers to prevent overflow,
- * which would bias rand to large numbers
- */
- mix_diff = (long)(b.tv_usec - a.tv_usec);
- if (mix_diff < 0)
- mix_diff = -mix_diff;
-
- mix ^= (unsigned long)(mix_diff);
- mix ^= (unsigned long)&mix;
- }
-
- return mix;
-}
+ if (nr != sizeof(unsigned long))
+ err(errno, "Incomplete read from random device");
-
-
-int
-x_i_gettimeofday(struct x_st_timeval *tv, void *tz)
-{
- time_t t;
-
- (void)tz;
-
- t = time(NULL);
-
- tv->tv_sec = t;
- tv->tv_usec = (long)((unsigned long)clock() % 1000000UL);
-
- return 0;
+ return rval;
+#endif
}
void
write_mac_part(unsigned long partnum)
{
+ struct xstate *x = xstatus();
+ struct xfile *f;
+ struct macaddr *mac;
+
unsigned long w;
- struct xfile *f = &nv->f;
- struct macaddr *mac = &nv->mac;
+ f = &x->f;
+ mac = &x->mac;
check_bin(partnum, "part number");
if (!f->part_valid[partnum])
@@ -1016,25 +1039,35 @@ write_mac_part(unsigned long partnum)
void
cmd_helper_dump(void)
{
- unsigned long partnum;
+ struct xstate *x = xstatus();
+ struct xfile *f;
+
+ unsigned long p;
+
+ f = &x->f;
- struct xfile *f = &nv->f;
+ check_cmd(cmd_helper_dump, "dump");
f->part_valid[0] = good_checksum(0);
f->part_valid[1] = good_checksum(1);
- for (partnum = 0; partnum < 2; partnum++) {
- if (!f->part_valid[partnum])
+ for (p = 0; p < 2; p++) {
+
+ if (!f->part_valid[p]) {
+
fprintf(stderr,
"BAD checksum %04x in part %lu (expected %04x)\n",
- nvm_word(NVM_CHECKSUM_WORD, partnum),
- (unsigned long)partnum,
- calculated_checksum(partnum));
+ nvm_word(NVM_CHECKSUM_WORD, p),
+ (unsigned long)p,
+ calculated_checksum(p));
+ }
printf("MAC (part %lu): ",
- (unsigned long)partnum);
- print_mac_from_nvm(partnum);
- hexdump(partnum);
+ (unsigned long)p);
+
+ print_mac_from_nvm(p);
+
+ hexdump(p);
}
}
@@ -1064,15 +1097,23 @@ hexdump(unsigned long partnum)
unsigned short val16;
for (row = 0; row < 8; row++) {
- printf("%08lx ", (unsigned long)((unsigned long)row << 4));
+
+ printf("%08lx ",
+ (unsigned long)((unsigned long)row << 4));
+
for (c = 0; c < 8; c++) {
+
val16 = nvm_word((row << 3) + c, partnum);
+
if (c == 4)
printf(" ");
+
printf(" %02x %02x",
(unsigned int)(val16 & 0xff),
(unsigned int)(val16 >> 8));
+
}
+
printf("\n");
}
}
@@ -1080,7 +1121,12 @@ hexdump(unsigned long partnum)
void
cmd_helper_swap(void)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct xfile *f;
+
+ check_cmd(cmd_helper_swap, "swap");
+
+ f = &x->f;
x_v_memcpy(
f->buf + (unsigned long)GBE_WORK_SIZE,
@@ -1104,7 +1150,12 @@ cmd_helper_swap(void)
void
cmd_helper_copy(void)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct xfile *f;
+
+ check_cmd(cmd_helper_copy, "copy");
+
+ f = &x->f;
x_v_memcpy(
f->buf + (unsigned long)((f->part ^ 1) * GBE_PART_SIZE),
@@ -1117,44 +1168,105 @@ cmd_helper_copy(void)
void
cmd_helper_cat(void)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ check_cmd(cmd_helper_cat, "cat");
- unsigned long p = 0;
- unsigned long ff = 0;
- unsigned long nff = 0;
+ x->cat = 0;
+ cat(0);
+}
- unsigned long cmd_num = nv->i;
+void
+cmd_helper_cat16(void)
+{
+ struct xstate *x = xstatus();
+ check_cmd(cmd_helper_cat16, "cat16");
- fflush(NULL);
+ x->cat = 1;
+ cat(1);
+}
- memset(f->pad, 0xff, GBE_PART_SIZE);
+void
+cmd_helper_cat128(void)
+{
+ struct xstate *x = xstatus();
+ check_cmd(cmd_helper_cat128, "cat128");
- switch (cmd_num) {
- case CMD_CAT:
- nff = 0;
- break;
- case CMD_CAT16:
- nff = 1;
- break;
- case CMD_CAT128:
- nff = 15;
- break;
- default:
- err(EINVAL, "erroneous call to cat");
+ x->cat = 15;
+ cat(15);
+}
+
+void
+check_cmd(void (*fn)(void),
+ const char *name)
+{
+ struct xstate *x = xstatus();
+ unsigned long i;
+
+ if (x->cmd[x->i].run != fn)
+ err(ECANCELED, "Running %s, but cmd %s is set",
+ name, x->cmd[x->i].str);
+
+ /*
+ * In addition to making sure we ran
+ * the right command, we now disable
+ * all commands from running again
+ *
+ * the _nop function will just call
+ * err() immediately
+ */
+
+ for (i = 0; i < items(x->cmd); i++)
+ x->cmd[i].run = cmd_helper_err;
+}
+
+void
+cmd_helper_err(void)
+{
+ err(ECANCELED,
+ "Erroneously running command twice");
+}
+
+void
+cat(unsigned long nff)
+{
+ struct xstate *x = xstatus();
+ struct xfile *f;
+
+ unsigned long p;
+ unsigned long ff;
+
+ f = &x->f;
+
+ p = 0;
+ ff = 0;
+
+ if ((unsigned long)x->cat != nff) {
+
+ err(ECANCELED, "erroneous call to cat");
}
+ fflush(NULL);
+
+ memset(f->pad, 0xff, GBE_PART_SIZE);
+
for (p = 0; p < 2; p++) {
+
cat_buf(f->bufcmp +
(unsigned long)(p * (f->gbe_file_size >> 1)));
- for (ff = 0; ff < nff; ff++)
+ for (ff = 0; ff < nff; ff++) {
+
cat_buf(f->pad);
+ }
}
}
void
cat_buf(unsigned char *b)
{
+ if (b == NULL)
+ err(errno, "null pointer in cat command");
+
if (rw_file_exact(STDOUT_FILENO, b,
GBE_PART_SIZE, 0, IO_WRITE, LOOP_EAGAIN, LOOP_EINTR,
MAX_ZERO_RW_RETRY, OFF_ERR) < 0)
@@ -1164,16 +1276,20 @@ cat_buf(unsigned char *b)
void
write_gbe_file(void)
{
+ struct xstate *x = xstatus();
+ struct commands *cmd;
+ struct xfile *f;
+
struct stat _gbe_st;
struct stat _tmp_st;
unsigned long p;
unsigned char update_checksum;
- struct commands *cmd = &nv->cmd[nv->i];
- struct xfile *f = &nv->f;
+ cmd = &x->cmd[x->i];
+ f = &x->f;
- if (cmd->flags == O_RDONLY)
+ if ((cmd->flags & O_ACCMODE) == O_RDONLY)
return;
if (fstat(f->gbe_fd, &_gbe_st) == -1)
@@ -1218,7 +1334,9 @@ unsigned short
calculated_checksum(unsigned long p)
{
unsigned long c;
- unsigned int val16 = 0;
+ unsigned int val16;
+
+ val16 = 0;
for (c = 0; c < NVM_CHECKSUM_WORD; c++)
val16 += (unsigned int)nvm_word(c, p);
@@ -1237,10 +1355,13 @@ calculated_checksum(unsigned long p)
unsigned short
nvm_word(unsigned long pos16, unsigned long p)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct xfile *f;
unsigned long pos;
+ f = &x->f;
+
check_nvm_bound(pos16, p);
pos = (pos16 << 1) + (p * GBE_PART_SIZE);
@@ -1251,9 +1372,13 @@ nvm_word(unsigned long pos16, unsigned long p)
void
set_nvm_word(unsigned long pos16, unsigned long p, unsigned short val16)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct xfile *f;
+
unsigned long pos;
+ f = &x->f;
+
check_nvm_bound(pos16, p);
pos = (pos16 << 1) + (p * GBE_PART_SIZE);
@@ -1266,7 +1391,10 @@ set_nvm_word(unsigned long pos16, unsigned long p, unsigned short val16)
void
set_part_modified(unsigned long p)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct xfile *f;
+
+ f = &x->f;
check_bin(p, "part number");
f->part_modified[p] = 1;
@@ -1300,15 +1428,19 @@ void
rw_gbe_file_part(unsigned long p, int rw_type,
const char *rw_type_str)
{
- struct xfile *f = &nv->f;
- struct commands *cmd = &nv->cmd[nv->i];
+ struct xstate *x = xstatus();
+ struct commands *cmd;
+ struct xfile *f;
- long r;
- unsigned long gbe_rw_size;
+ long rval;
+ off_t file_offset;
+
+ unsigned long gbe_rw_size;
unsigned char *mem_offset;
- off_t file_offset;
+ cmd = &x->cmd[x->i];
+ f = &x->f;
gbe_rw_size = cmd->rw_size;
@@ -1319,14 +1451,14 @@ rw_gbe_file_part(unsigned long p, int rw_type,
mem_offset = gbe_mem_offset(p, rw_type_str);
file_offset = (off_t)gbe_file_offset(p, rw_type_str);
- r = rw_gbe_file_exact(f->tmp_fd, mem_offset,
+ rval = rw_gbe_file_exact(f->tmp_fd, mem_offset,
gbe_rw_size, file_offset, rw_type);
- if (r == -1)
+ if (rval == -1)
err(errno, "%s: %s: part %lu",
f->fname, rw_type_str, (unsigned long)p);
- if ((unsigned long)r != gbe_rw_size)
+ if ((unsigned long)rval != gbe_rw_size)
err(EIO, "%s: partial %s: part %lu",
f->fname, rw_type_str, (unsigned long)p);
}
@@ -1334,14 +1466,17 @@ rw_gbe_file_part(unsigned long p, int rw_type,
void
write_to_gbe_bin(void)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct commands *cmd;
+ struct xfile *f;
int saved_errno;
int mv;
- struct commands *cmd = &nv->cmd[nv->i];
+ cmd = &x->cmd[x->i];
+ f = &x->f;
- if (cmd->flags != O_RDWR)
+ if ((cmd->flags & O_ACCMODE) != O_RDWR)
return;
write_gbe_file();
@@ -1426,23 +1561,28 @@ write_to_gbe_bin(void)
void
check_written_part(unsigned long p)
{
- struct commands *cmd = &nv->cmd[nv->i];
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct commands *cmd;
+ struct xfile *f;
+
+ long rval;
unsigned long gbe_rw_size;
- unsigned char *mem_offset;
+
off_t file_offset;
- unsigned char *buf_restore;
+ unsigned char *mem_offset;
+
struct stat st;
+ unsigned char *buf_restore;
- long r;
+ cmd = &x->cmd[x->i];
+ f = &x->f;
if (!f->part_modified[p])
return;
gbe_rw_size = cmd->rw_size;
- /* invert not needed for pwrite */
mem_offset = gbe_mem_offset(p, "pwrite");
file_offset = (off_t)gbe_file_offset(p, "pwrite");
@@ -1458,12 +1598,12 @@ check_written_part(unsigned long p)
if (st.st_dev != f->tmp_dev || st.st_ino != f->tmp_ino)
err(EIO, "%s: file changed during write", f->tname);
- r = rw_gbe_file_exact(f->tmp_fd, f->pad,
+ rval = rw_gbe_file_exact(f->tmp_fd, f->pad,
gbe_rw_size, file_offset, IO_PREAD);
- if (r == -1)
+ if (rval == -1)
f->rw_check_err_read[p] = f->io_err_gbe = 1;
- else if ((unsigned long)r != gbe_rw_size)
+ else if ((unsigned long)rval != gbe_rw_size)
f->rw_check_partial_read[p] = f->io_err_gbe = 1;
else if (x_i_memcmp(mem_offset, f->pad, gbe_rw_size) != 0)
f->rw_check_bad_part[p] = f->io_err_gbe = 1;
@@ -1478,18 +1618,29 @@ check_written_part(unsigned long p)
* That's why we hardcode good_checksum(0).
*/
buf_restore = f->buf;
+
+ /*
+ * good_checksum works on f->buf
+ * so let's change f->buf for now
+ */
f->buf = f->pad;
- f->post_rw_checksum[p] = good_checksum(0);
+
+ if (good_checksum(0))
+ f->post_rw_checksum[p] = 1;
+
f->buf = buf_restore;
}
void
report_io_err_rw(void)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct xfile *f;
unsigned long p;
+ f = &x->f;
+
if (!f->io_err_gbe)
return;
@@ -1541,20 +1692,30 @@ report_io_err_rw(void)
int
gbe_mv(void)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct xfile *f;
+
+ int rval;
- int r;
int saved_errno;
- int tmp_gbe_bin_exists = 1;
+ int tmp_gbe_bin_exists;
+
+ char *dest_tmp;
+ int dest_fd;
- char *dest_tmp = NULL;
- int dest_fd = -1;
+ f = &x->f;
+
+ /* will be set 0 if it doesn't */
+ tmp_gbe_bin_exists = 1;
+
+ dest_tmp = NULL;
+ dest_fd = -1;
saved_errno = errno;
- r = rename(f->tname, f->fname);
+ rval = rename(f->tname, f->fname);
- if (r > -1) {
+ if (rval > -1) {
/*
* same filesystem
*/
@@ -1563,7 +1724,7 @@ gbe_mv(void)
if (fsync_dir(f->fname) < 0) {
f->io_err_gbe_bin = 1;
- r = -1;
+ rval = -1;
}
goto ret_gbe_mv;
@@ -1574,7 +1735,7 @@ gbe_mv(void)
/* cross-filesystem rename */
- if ((r = f->tmp_fd = open(f->tname,
+ if ((rval = f->tmp_fd = open(f->tname,
O_RDONLY | O_BINARY)) == -1)
goto ret_gbe_mv;
@@ -1585,20 +1746,20 @@ gbe_mv(void)
/* copy data */
- r = rw_file_exact(f->tmp_fd, f->bufcmp,
+ rval = rw_file_exact(f->tmp_fd, f->bufcmp,
f->gbe_file_size, 0, IO_PREAD,
NO_LOOP_EAGAIN, LOOP_EINTR,
MAX_ZERO_RW_RETRY, OFF_ERR);
- if (r < 0)
+ if (rval < 0)
goto ret_gbe_mv;
- r = rw_file_exact(dest_fd, f->bufcmp,
+ rval = rw_file_exact(dest_fd, f->bufcmp,
f->gbe_file_size, 0, IO_PWRITE,
NO_LOOP_EAGAIN, LOOP_EINTR,
MAX_ZERO_RW_RETRY, OFF_ERR);
- if (r < 0)
+ if (rval < 0)
goto ret_gbe_mv;
if (x_i_fsync(dest_fd) == -1)
@@ -1622,17 +1783,17 @@ ret_gbe_mv:
if (f->gbe_fd > -1) {
if (x_i_close(f->gbe_fd) < 0)
- r = -1;
+ rval = -1;
if (fsync_dir(f->fname) < 0) {
f->io_err_gbe_bin = 1;
- r = -1;
+ rval = -1;
}
f->gbe_fd = -1;
}
if (f->tmp_fd > -1) {
if (x_i_close(f->tmp_fd) < 0)
- r = -1;
+ rval = -1;
f->tmp_fd = -1;
}
@@ -1643,12 +1804,12 @@ ret_gbe_mv:
*/
if (tmp_gbe_bin_exists) {
if (unlink(f->tname) < 0)
- r = -1;
+ rval = -1;
else
tmp_gbe_bin_exists = 0;
}
- if (r < 0) {
+ if (rval < 0) {
/*
* if nothing set errno,
* we assume EIO, or we
@@ -1660,7 +1821,7 @@ ret_gbe_mv:
errno = saved_errno;
}
- return r;
+ return rval;
}
/*
@@ -1670,21 +1831,27 @@ ret_gbe_mv:
int
fsync_dir(const char *path)
{
-#if defined(PATH_LEN) && \
- (PATH_LEN) >= 256
- unsigned long maxlen = PATH_LEN;
-#else
- unsigned long maxlen = 1024;
-#endif
+ int saved_errno = errno;
+
unsigned long pathlen;
-/* char dirbuf[maxlen]; */
- char *dirbuf = NULL;
+ unsigned long maxlen;
+
+ char *dirbuf;
+ int dirfd;
+
char *slash;
- int dfd = -1;
struct stat st;
- int saved_errno = errno;
+#if defined(PATH_LEN) && \
+ (PATH_LEN) >= 256
+ maxlen = PATH_LEN;
+#else
+ maxlen = 1024;
+#endif
+
+ dirbuf = NULL;
+ dirfd = -1;
pathlen = xstrxlen(path, maxlen);
@@ -1717,7 +1884,7 @@ fsync_dir(const char *path)
dirbuf[1] = '\0';
}
- dfd = open(dirbuf, O_RDONLY
+ dirfd = open(dirbuf, O_RDONLY
#ifdef O_DIRECTORY
| O_DIRECTORY
#endif
@@ -1725,10 +1892,10 @@ fsync_dir(const char *path)
| O_NOFOLLOW
#endif
);
- if (dfd == -1)
+ if (dirfd == -1)
goto err_fsync_dir;
- if (fstat(dfd, &st) < 0)
+ if (fstat(dirfd, &st) < 0)
goto err_fsync_dir;
if (!S_ISDIR(st.st_mode)) {
@@ -1737,10 +1904,10 @@ fsync_dir(const char *path)
}
/* sync file on disk */
- if (x_i_fsync(dfd) == -1)
+ if (x_i_fsync(dirfd) == -1)
goto err_fsync_dir;
- if (x_i_close(dfd) == -1)
+ if (x_i_close(dirfd) == -1)
goto err_fsync_dir;
if (dirbuf != NULL)
@@ -1759,8 +1926,8 @@ err_fsync_dir:
if (dirbuf != NULL)
free(dirbuf);
- if (dfd > -1)
- x_i_close(dfd);
+ if (dirfd > -1)
+ x_i_close(dirfd);
errno = saved_errno;
@@ -1775,12 +1942,18 @@ err_fsync_dir:
unsigned char *
gbe_mem_offset(unsigned long p, const char *f_op)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct xfile *f;
+
+ off_t gbe_off;
+
+ f = &x->f;
- off_t gbe_off = gbe_x_offset(p, f_op, "mem",
+ gbe_off = gbe_x_offset(p, f_op, "mem",
GBE_PART_SIZE, GBE_WORK_SIZE);
- return (unsigned char *)(f->buf + (unsigned long)gbe_off);
+ return (unsigned char *)
+ (f->buf + (unsigned long)gbe_off);
}
/*
@@ -1793,9 +1966,14 @@ gbe_mem_offset(unsigned long p, const char *f_op)
off_t
gbe_file_offset(unsigned long p, const char *f_op)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct xfile *f;
+
+ off_t gbe_file_half_size;
+
+ f = &x->f;
- off_t gbe_file_half_size = f->gbe_file_size >> 1;
+ gbe_file_half_size = f->gbe_file_size >> 1;
return gbe_x_offset(p, f_op, "file",
gbe_file_half_size, f->gbe_file_size);
@@ -1805,12 +1983,15 @@ off_t
gbe_x_offset(unsigned long p, const char *f_op, const char *d_type,
off_t nsize, off_t ncmp)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct xfile *f;
off_t off;
check_bin(p, "part number");
+ f = &x->f;
+
off = ((off_t)p) * (off_t)nsize;
if (off > ncmp - GBE_PART_SIZE)
@@ -1828,10 +2009,13 @@ long
rw_gbe_file_exact(int fd, unsigned char *mem, unsigned long nrw,
off_t off, int rw_type)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct xfile *f;
long r;
+ f = &x->f;
+
if (io_args(fd, mem, nrw, off, rw_type) == -1)
return -1;
@@ -1899,23 +2083,31 @@ rw_file_exact(int fd, unsigned char *mem, unsigned long nrw,
int loop_eintr, unsigned long max_retries,
int off_reset)
{
- long rv = 0;
- long rc = 0;
- unsigned long retries_on_zero = 0;
- off_t off_cur;
+ long rval;
+ long rc;
+
unsigned long nrw_cur;
+
+ off_t off_cur;
void *mem_cur;
+ unsigned long retries_on_zero;
+
+ rval = 0;
+
+ rc = 0;
+ retries_on_zero = 0;
+
if (io_args(fd, mem, nrw, off, rw_type) == -1)
return -1;
while (1) {
/* Prevent theoretical overflow */
- if (rv >= 0 && (unsigned long)rv > (nrw - rc))
+ if (rval >= 0 && (unsigned long)rval > (nrw - rc))
goto err_rw_file_exact;
- rc += rv;
+ rc += rval;
if ((unsigned long)rc >= nrw)
break;
@@ -1925,14 +2117,14 @@ rw_file_exact(int fd, unsigned char *mem, unsigned long nrw,
goto err_rw_file_exact;
off_cur = off + (off_t)rc;
- rv = prw(fd, mem_cur, nrw_cur, off_cur,
+ rval = prw(fd, mem_cur, nrw_cur, off_cur,
rw_type, loop_eagain, loop_eintr,
off_reset);
- if (rv < 0)
+ if (rval < 0)
return -1;
- if (rv == 0) {
+ if (rval == 0) {
if (retries_on_zero++ < max_retries)
continue;
goto err_rw_file_exact;
@@ -1999,6 +2191,12 @@ prw(int fd, void *mem, unsigned long nrw,
int loop_eagain, int loop_eintr,
int off_reset)
{
+#ifndef MAX_EAGAIN_RETRIES
+ unsigned long retries = 100000;
+#else
+ unsigned long retries = MAX_EAGAIN_RETRIES;
+#endif
+
long r;
int positional_rw;
struct stat st;
@@ -2010,8 +2208,10 @@ prw(int fd, void *mem, unsigned long nrw,
off_t off_last;
#endif
- if (io_args(fd, mem, nrw, off, rw_type) == -1)
+ if (io_args(fd, mem, nrw, off, rw_type)
+ == -1) {
return -1;
+ }
r = -1;
@@ -2124,8 +2324,9 @@ real_pread_pwrite:
}
} while (r == -1 &&
- (errno == try_err(loop_eintr, EINTR)
- || errno == try_err(loop_eagain, EAGAIN)));
+ (errno == try_err(loop_eintr, EINTR) ||
+ errno == try_err(loop_eagain, EAGAIN)) &&
+ retries++ < MAX_EAGAIN_RETRIES);
}
saved_errno = errno;
@@ -2222,7 +2423,9 @@ rw_over_nrw(long r, unsigned long nrw)
if (r == -1)
return r;
- if ((unsigned long)r > X_LONG_MAX) {
+ if ((unsigned long)
+ r > X_LONG_MAX) {
+
/*
* Theoretical buggy libc
* check. Extremely academic.
@@ -2265,7 +2468,9 @@ off_t
lseek_loop(int fd, off_t off, int whence,
int loop_eagain, int loop_eintr)
{
- off_t old = -1;
+ off_t old;
+
+ old = -1;
do {
old = lseek(fd, off, whence);
@@ -2298,7 +2503,9 @@ try_err(int loop_err, int errval)
void
usage(void)
{
- const char *util = getnvmprogname();
+ const char *util;
+
+ util = getnvmprogname();
fprintf(stderr,
"Modify Intel GbE NVM images e.g. set MAC\n"
@@ -2319,7 +2526,7 @@ usage(void)
void
err(int nvm_errval, const char *msg, ...)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
va_list args;
@@ -2330,18 +2537,14 @@ err(int nvm_errval, const char *msg, ...)
(void)exit_cleanup();
- fprintf(stderr, "%s: ", getnvmprogname());
+ if (x != NULL)
+ fprintf(stderr, "%s: ", getnvmprogname());
va_start(args, msg);
vfprintf(stderr, msg, args);
va_end(args);
- fprintf(stderr, ": %s", strerror(errno));
-
- fprintf(stderr, "\n");
-
- if (f->tname != NULL)
- free(f->tname);
+ fprintf(stderr, ": %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
@@ -2349,28 +2552,36 @@ err(int nvm_errval, const char *msg, ...)
int
exit_cleanup(void)
{
- struct xfile *f = &nv->f;
+ struct xstate *x = xstatus();
+ struct xfile *f;
- int close_err = 0;
- int saved_errno = errno;
+ int close_err;
+ int saved_errno;
- if (f->gbe_fd > -1) {
- if (x_i_close(f->gbe_fd) == -1)
- close_err = 1;
- f->gbe_fd = -1;
- }
+ close_err = 0;
+ saved_errno = errno;
- if (f->tmp_fd > -1) {
- if (x_i_close(f->tmp_fd) == -1)
- close_err = 1;
- }
+ if (x != NULL) {
+ f = &x->f;
- if (f->tname != NULL) {
- if (unlink(f->tname) == -1)
- close_err = 1;
- }
+ if (f->gbe_fd > -1) {
+ if (x_i_close(f->gbe_fd) == -1)
+ close_err = 1;
+ f->gbe_fd = -1;
+ }
- f->tmp_fd = -1;
+ if (f->tmp_fd > -1) {
+ if (x_i_close(f->tmp_fd) == -1)
+ close_err = 1;
+ }
+
+ if (f->tname != NULL) {
+ if (unlink(f->tname) == -1)
+ close_err = 1;
+ }
+
+ f->tmp_fd = -1;
+ }
if (saved_errno)
errno = saved_errno;
@@ -2384,17 +2595,25 @@ exit_cleanup(void)
const char *
getnvmprogname(void)
{
+ struct xstate *x = xstatus();
const char *p;
+ static char fallback[] = "nvmutil";
- if (nv->argv0 == NULL || *nv->argv0 == '\0')
- return "";
+ char *rval = fallback;
- p = x_c_strrchr(nv->argv0, '/');
+ if (x != NULL) {
+ if (x->argv0 == NULL || *x->argv0 == '\0')
+ return "";
+
+ rval = x->argv0;
+ }
+
+ p = x_c_strrchr(rval, '/');
if (p)
return p + 1;
else
- return nv->argv0;
+ return rval;
}
/*
@@ -2424,8 +2643,6 @@ getnvmprogname(void)
char *
new_tmpfile(int *fd, int local, const char *path)
{
- struct xfile *f = &nv->f;
-
unsigned long maxlen;
struct stat st;
@@ -2487,7 +2704,7 @@ new_tmpfile(int *fd, int local, const char *path)
/*
* appended to filename for tmp:
*/
- tmpdir_len = sizeof(default_tmpname);
+ tmpdir_len = xstrxlen(default_tmpname, maxlen);
} else {
base = x_c_tmpdir();
@@ -2539,10 +2756,23 @@ new_tmpfile(int *fd, int local, const char *path)
if (fd_tmp == -1)
goto err_new_tmpfile;
- if (x_i_fchmod(fd_tmp, 0600) == -1)
+ if (fchmod(fd_tmp, 0600) == -1)
+ goto err_new_tmpfile;
+
+ flags = fcntl(fd_tmp, F_GETFL);
+
+ if (flags == -1)
goto err_new_tmpfile;
- if (lock_file(fd_tmp) == -1)
+ /*
+ * O_APPEND would permit offsets
+ * to be ignored, which breaks
+ * positional read/write
+ */
+ if (flags & O_APPEND)
+ goto err_new_tmpfile;
+
+ if (lock_file(fd_tmp, flags) == -1)
goto err_new_tmpfile;
if (fstat(fd_tmp, &st) == -1)
@@ -2561,10 +2791,6 @@ new_tmpfile(int *fd, int local, const char *path)
if (lseek(fd_tmp, 0, SEEK_CUR) == (off_t)-1)
goto err_new_tmpfile;
- /* inode will be checked later on write */
- f->tmp_dev = st.st_dev;
- f->tmp_ino = st.st_ino;
-
/* tmpfile has >1 hardlinks */
if (st.st_nlink > 1)
goto err_new_tmpfile;
@@ -2573,19 +2799,6 @@ new_tmpfile(int *fd, int local, const char *path)
if (st.st_nlink == 0)
goto err_new_tmpfile;
- flags = fcntl(fd_tmp, F_GETFL);
-
- if (flags == -1)
- goto err_new_tmpfile;
-
- /*
- * O_APPEND would permit offsets
- * to be ignored, which breaks
- * positional read/write
- */
- if (flags & O_APPEND)
- goto err_new_tmpfile;
-
*fd = fd_tmp;
return dest;
@@ -2612,8 +2825,10 @@ x_i_mkstemp(char *template)
unsigned long len;
char *p;
- char ch[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- unsigned long r = rlong();
+ char ch[] =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+ unsigned long r;
len = xstrxlen(template, PATH_LEN);
@@ -2625,8 +2840,10 @@ x_i_mkstemp(char *template)
for (i = 0; i < 100; i++) {
- for (j = 0; j < 6; j++)
- p[j] = ch[r % (sizeof(ch) - 1)];
+ for (j = 0; j < 6; j++) {
+ r = rlong();
+ p[j] = ch[(unsigned long)(r >> 1) % (sizeof(ch) - 1)];
+ }
fd = open(template, O_RDWR | O_CREAT | O_EXCL, 0600);
@@ -2659,10 +2876,17 @@ x_c_strrchr(const char *s, int c)
}
/*
+ * non-atomic rename
+ *
+ * commented because i can't sacrifice
+ * exactly this property. nvmutil tries
+ * to protect files against e.g. power loss
+ */
+/*
int
x_i_rename(const char *src, const char *dst)
{
- int sfd, dfd;
+ int sfd, dirfd;
ssize_t r;
char buf[8192];
@@ -2670,31 +2894,31 @@ x_i_rename(const char *src, const char *dst)
if (sfd < 0)
return -1;
- dfd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0600);
- if (dfd < 0) {
+ dirfd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (dirfd < 0) {
x_i_close(sfd);
return -1;
}
while ((r = read(sfd, buf, sizeof(buf))) > 0) {
- ssize_t w = write(dfd, buf, r);
+ ssize_t w = write(dirfd, buf, r);
if (w != r) {
x_i_close(sfd);
- x_i_close(dfd);
+ x_i_close(dirfd);
return -1;
}
}
if (r < 0) {
x_i_close(sfd);
- x_i_close(dfd);
+ x_i_close(dirfd);
return -1;
}
- x_i_fsync(dfd);
+ x_i_fsync(dirfd);
x_i_close(sfd);
- x_i_close(dfd);
+ x_i_close(dirfd);
if (unlink(src) < 0)
return -1;
@@ -2710,9 +2934,13 @@ x_c_tmpdir(void)
struct stat st;
t = getenv("TMPDIR");
+ t = getenv("TMPDIR");
if (t && *t) {
- if (stat(t, &st) == 0 && S_ISDIR(st.st_mode))
+ if (stat(t, &st) == 0 && S_ISDIR(st.st_mode)) {
+ if ((st.st_mode & S_IWOTH) && !(st.st_mode & S_ISVTX))
+ return NULL;
return t;
+ }
}
if (stat("/tmp", &st) == 0 && S_ISDIR(st.st_mode))
@@ -2728,11 +2956,15 @@ int
x_i_close(int fd)
{
int r;
+ int saved_errno = errno;
do {
r = close(fd);
} while (r == -1 && errno == EINTR);
+ if (r > -1)
+ errno = saved_errno;
+
return r;
}
@@ -2754,90 +2986,13 @@ x_i_memcmp(const void *a, const void *b, unsigned long n)
const unsigned char *pa = (const unsigned char *)a;
const unsigned char *pb = (const unsigned char *)b;
- while (n--) {
+ for ( ; n--; ++pa, ++pb)
if (*pa != *pb)
return *pa - *pb;
- pa++;
- pb++;
- }
return 0;
}
-/*
- * emulate fchmod() using file descriptor
- * paths, for old unix portability. should
- * work on e.g. BSD/MacOS (/dev/fd/N),
- * Linux (/proc/self/fd/N) and others
- */
-int
-x_i_fchmod(int fd, mode_t mode)
-{
- if (x_try_fdpath("/dev/fd/", fd, mode) == 0)
- return 0;
-
- if (x_try_fdpath("/proc/self/fd/", fd, mode) == 0)
- return 0;
-
- errno = ENOSYS;
- return -1;
-}
-
-int
-x_try_fdpath(const char *prefix, int fd, mode_t mode)
-{
- char path[PATH_LEN];
-
- unsigned long i = 0;
- unsigned long j;
-
- struct stat st;
-
- while (prefix[i]) {
- if (i >= PATH_LEN - 1)
- return -1;
- path[i] = prefix[i];
- i++;
- }
-
- j = x_conv_fd(path + i, (unsigned long)fd);
-
- if (i + j >= PATH_LEN)
- return -1;
-
- i += j;
- path[i] = '\0';
-
- if (stat(path, &st) < 0)
- return -1;
-
- return chmod(path, mode);
-}
-
-unsigned long
-x_conv_fd(char *buf, unsigned long n)
-{
- char tmp[256];
-
- unsigned long i = 0;
- unsigned long j = 0;
-
- if (n == 0) {
- buf[0] = '0';
- return 1;
- }
-
- while (n > 0) {
- tmp[i++] = (char)('0' + (n % 10));
- n /= 10;
- }
-
- while (i > 0)
- buf[j++] = tmp[--i];
-
- return j;
-}
-
int
x_i_fsync(int fd)
{
@@ -2849,63 +3004,3 @@ x_i_fsync(int fd)
return r;
}
-
-/* type asserts */
-typedef char static_assert_char_is_8_bits[(CHAR_BIT == 8) ? 1 : -1];
-typedef char static_assert_char_is_1[(sizeof(char) == 1) ? 1 : -1];
-typedef char static_assert_unsigned_char_is_1[
- (sizeof(unsigned char) == 1) ? 1 : -1];
-typedef char static_assert_unsigned_short_is_2[
- (sizeof(unsigned short) >= 2) ? 1 : -1];
-typedef char static_assert_short_is_2[(sizeof(short) >= 2) ? 1 : -1];
-typedef char static_assert_unsigned_int_is_4[
- (sizeof(unsigned int) >= 4) ? 1 : -1];
-typedef char static_assert_unsigned_long_is_4[
- (sizeof(unsigned long) >= 4) ? 1 : -1];
-typedef char static_assert_int_ge_32[(sizeof(int) >= 4) ? 1 : -1];
-typedef char static_assert_twos_complement[
- ((-1 & 3) == 3) ? 1 : -1
-];
-typedef char assert_unsigned_long_ptr[
- (sizeof(unsigned long) >= sizeof(void *)) ? 1 : -1
-];
-
-/*
- * We set _FILE_OFFSET_BITS 64, but we only handle
- * but we only need smaller files, so require 4-bytes.
- * Some operating systems ignore the define, hence assert:
- */
-typedef char static_assert_off_t_is_32[(sizeof(off_t) >= 4) ? 1 : -1];
-
-/*
- * asserts (variables/defines sanity check)
- */
-typedef char assert_argc3[(ARGC_3==3)?1:-1];
-typedef char assert_argc4[(ARGC_4==4)?1:-1];
-typedef char assert_read[(IO_READ==0)?1:-1];
-typedef char assert_write[(IO_WRITE==1)?1:-1];
-typedef char assert_pread[(IO_PREAD==2)?1:-1];
-typedef char assert_pwrite[(IO_PWRITE==3)?1:-1];
-typedef char assert_pathlen[(PATH_LEN>=256)?1:-1];
-/* commands */
-typedef char assert_cmd_dump[(CMD_DUMP==0)?1:-1];
-typedef char assert_cmd_setmac[(CMD_SETMAC==1)?1:-1];
-typedef char assert_cmd_swap[(CMD_SWAP==2)?1:-1];
-typedef char assert_cmd_copy[(CMD_COPY==3)?1:-1];
-typedef char assert_cmd_cat[(CMD_CAT==4)?1:-1];
-typedef char assert_cmd_cat16[(CMD_CAT16==5)?1:-1];
-typedef char assert_cmd_cat128[(CMD_CAT128==6)?1:-1];
-/* bool */
-typedef char bool_arg_nopart[(ARG_NOPART==0)?1:-1];
-typedef char bool_arg_part[(ARG_PART==1)?1:-1];
-typedef char bool_skip_checksum_read[(SKIP_CHECKSUM_READ==0)?1:-1];
-typedef char bool_checksum_read[(CHECKSUM_READ==1)?1:-1];
-typedef char bool_skip_checksum_write[(SKIP_CHECKSUM_WRITE==0)?1:-1];
-typedef char bool_checksum_write[(CHECKSUM_WRITE==1)?1:-1];
-typedef char bool_loop_eintr[(LOOP_EINTR==1||LOOP_EINTR==0)?1:-1];
-typedef char bool_loop_eagain[(LOOP_EAGAIN==1||LOOP_EAGAIN==0)?1:-1];
-typedef char bool_no_loop_eintr[(NO_LOOP_EINTR==0)?1:-1];
-typedef char bool_no_loop_eagain[(NO_LOOP_EAGAIN==0)?1:-1];
-typedef char bool_off_err[(OFF_ERR==0)?1:-1];
-typedef char bool_off_reset[(OFF_RESET==0||OFF_RESET==1)?1:-1];
-