summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
Diffstat (limited to 'util')
-rw-r--r--util/nvmutil/nvmutil.c514
1 files changed, 333 insertions, 181 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c
index 91095c18..64ab6158 100644
--- a/util/nvmutil/nvmutil.c
+++ b/util/nvmutil/nvmutil.c
@@ -351,7 +351,7 @@ int good_checksum(unsigned long partnum);
* Execute user command on GbE data.
* These are stubs that call helpers.
*/
-void run_cmd(unsigned long c);
+void run_cmd(void);
void check_command_num(unsigned long c);
unsigned char valid_command(unsigned long c);
@@ -373,8 +373,7 @@ void set_mac_byte(unsigned long mac_byte_pos);
void set_mac_nib(unsigned long mac_str_pos,
unsigned long mac_byte_pos, unsigned long mac_nib_pos);
unsigned short hextonum(char ch_s);
-unsigned short rhex(void);
-unsigned short read_urandom(void);
+unsigned long rlong(void);
unsigned long entropy_jitter(void);
int x_i_gettimeofday(struct x_st_timeval *tv, void *tz);
void write_mac_part(unsigned long partnum);
@@ -419,7 +418,8 @@ unsigned short calculated_checksum(unsigned long p);
* the NVM area during operation.
*/
unsigned short nvm_word(unsigned long pos16, unsigned long part);
-void set_nvm_word(unsigned long pos16, unsigned long part, unsigned short val16);
+void set_nvm_word(unsigned long pos16,
+ unsigned long part, unsigned short val16);
void set_part_modified(unsigned long p);
void check_nvm_bound(unsigned long pos16, unsigned long part);
void check_bin(unsigned long a, const char *a_name);
@@ -472,7 +472,13 @@ const char *getnvmprogname(void);
char *new_tmpfile(int *fd, int local, const char *path);
int x_i_mkstemp(char *template);
char *x_c_strrchr(const char *s, int c);
+/* x_i_rename not suitable
+ * for atomic writes. kept
+ * commentted for use in a
+ * library in the future */
+/*
int x_i_rename(const char *src, const char *dst);
+*/
char *x_c_tmpdir(void);
int x_i_close(int fd);
void *x_v_memcpy(void *dst,
@@ -599,66 +605,6 @@ enum {
CHECKSUM_WRITE
};
-struct commands {
- unsigned long chk;
- const char *str;
- void (*run)(void);
- int argc;
- unsigned char arg_part;
- unsigned char chksum_read;
- unsigned char chksum_write;
- unsigned long rw_size; /* within the 4KB GbE part */
- int flags; /* e.g. O_RDWR or O_RDONLY */
-};
-
-/*
- * Command table, for nvmutil commands
- */
-const struct commands command[] = {
- { CMD_DUMP, "dump", cmd_helper_dump, ARGC_3,
- ARG_NOPART,
- SKIP_CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
- NVM_SIZE, O_RDONLY },
-
- { CMD_SETMAC, "setmac", cmd_helper_setmac, ARGC_3,
- ARG_NOPART,
- CHECKSUM_READ, CHECKSUM_WRITE,
- NVM_SIZE, O_RDWR },
-
- { CMD_SWAP, "swap", cmd_helper_swap, ARGC_3,
- ARG_NOPART,
- CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
- GBE_PART_SIZE, O_RDWR },
-
- { CMD_COPY, "copy", cmd_helper_copy, ARGC_4,
- ARG_PART,
- CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
- GBE_PART_SIZE, O_RDWR },
-
- { CMD_CAT, "cat", cmd_helper_cat, ARGC_3,
- ARG_NOPART,
- CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
- GBE_PART_SIZE, O_RDONLY },
-
- { CMD_CAT16, "cat16", cmd_helper_cat, ARGC_3,
- ARG_NOPART,
- CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
- GBE_PART_SIZE, O_RDONLY },
-
- { CMD_CAT128, "cat128", cmd_helper_cat, ARGC_3,
- ARG_NOPART,
- CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
- GBE_PART_SIZE, O_RDONLY },
-};
-
-#define MAX_CMD_LEN 50
-#define N_COMMANDS items(command)
-#define CMD_NULL N_COMMANDS
-
-/*
- * Index in command[], will be set later
- */
-unsigned long cmd_index = CMD_NULL;
/*
* asserts (variables/defines sanity check)
@@ -709,21 +655,139 @@ ino_t tmp_ino;
int tmp_fd = -1;
char *tname = NULL;
+/*
+ * Used for checking whether.
+ * a file is a file via stat().
+ *
+ * Portable macro for compatibility
+ * with older unix e.g. v7 unix (has S_IFREG),
+ * 4.2bsd (has S_IFMT) or POSIX (has S_ISREG)
+ *
+ * Fallback works where S_IFREG == 0100000
+ * (classic unix bitmask)
+ */
+
#ifndef S_ISREG
-#ifdef S_IFMT
-#define S_ISREG(m) (((m) & (S_IFMT)) == (S_IFREG))
+#if defined(S_IFMT) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#elif defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFREG) != 0)
#else
-#define S_ISREG(m) (((m) & (S_IFREG)) == (S_IFREG))
+#error "can't determine types with stat()"
#endif
#endif
-#ifndef S_ISREG
-#define S_ISREG(m) (((m) & (S_IFMT) == (S_IFREG))
-#endif
+struct commands {
+ unsigned long chk;
+ const char *str;
+ void (*run)(void);
+ int argc;
+ unsigned char arg_part;
+ unsigned char chksum_read;
+ unsigned char chksum_write;
+ unsigned long rw_size; /* within the 4KB GbE part */
+ int flags; /* e.g. O_RDWR or O_RDONLY */
+};
+
+#define MAX_CMD_LEN 50
+
+/*
+ * BE CAREFUL when editing this
+ * to ensure that you also update
+ * the tables in new_xstate()
+ */
+struct xstate {
+ struct commands cmd[7];
+ unsigned long i; /* index to cmd[] for current command */
+ int no_cmd;
+
+ /* store size of a struct here.
+ (can be used to copy old state) */
+ unsigned long xsize;
+};
+
+/*
+ * Program state/command table
+ * Default config stored here,
+ * and copied to a newly allocated
+ * buffer in memory, then the pointer
+ * is passed. The rest of the program
+ * will manipulate this data.
+ */
+struct xstate *
+new_xstate(void)
+{
+ static struct xstate us = {
+ /* .cmd (update cmd[] in the struct if adding to it) */
+ {
+ {
+ CMD_DUMP, "dump", cmd_helper_dump, ARGC_3,
+ ARG_NOPART,
+ SKIP_CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
+ NVM_SIZE, O_RDONLY
+ }, {
+ CMD_SETMAC, "setmac", cmd_helper_setmac, ARGC_3,
+ ARG_NOPART,
+ CHECKSUM_READ, CHECKSUM_WRITE,
+ NVM_SIZE, O_RDWR
+ }, {
+ CMD_SWAP, "swap", cmd_helper_swap, ARGC_3,
+ ARG_NOPART,
+ CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
+ GBE_PART_SIZE, O_RDWR
+ }, {
+ CMD_COPY, "copy", cmd_helper_copy, ARGC_4,
+ ARG_PART,
+ CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
+ GBE_PART_SIZE, O_RDWR
+ }, {
+ CMD_CAT, "cat", cmd_helper_cat, ARGC_3,
+ ARG_NOPART,
+ CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
+ GBE_PART_SIZE, O_RDONLY
+ }, {
+ CMD_CAT16, "cat16", cmd_helper_cat, ARGC_3,
+ ARG_NOPART,
+ CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
+ GBE_PART_SIZE, O_RDONLY
+ }, {
+ CMD_CAT128, "cat128", cmd_helper_cat, ARGC_3,
+ ARG_NOPART,
+ CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
+ GBE_PART_SIZE, O_RDONLY
+ }
+ },
+ /* .cmd_index */
+ 0,
+ /* .no_cmd (set 0 when a command is found) */
+ 1,
+ /* .xsize (size of the stuct will be stored here later) */
+ 0
+ };
+
+ struct xstate *xs_new;
+
+ us.xsize = sizeof(us);
+
+ if ((xs_new = malloc(us.xsize)) == NULL)
+ err(ECANCELED, "Could not initialise new state");
+
+ memcpy(xs_new, &us, us.xsize);
+
+ return xs_new;
+}
+
+struct xstate *nv = NULL;
int
main(int argc, char *argv[])
{
+ struct commands *cmd;
+
+ nv = new_xstate();
+ if (nv == NULL)
+ err(errno, NULL);
+
argv0 = argv[0];
if (argc < 3)
usage();
@@ -766,6 +830,8 @@ main(int argc, char *argv[])
set_cmd(argc, argv);
set_cmd_args(argc, argv);
+ cmd = &nv->cmd[nv->i];
+
#ifdef NVMUTIL_UNVEIL
if (command[cmd_index].flags == O_RDONLY) {
if (unveil(fname, "r") == -1)
@@ -796,9 +862,9 @@ main(int argc, char *argv[])
read_checksums();
- run_cmd(cmd_index);
+ run_cmd();
- if (command[cmd_index].flags == O_RDWR)
+ if (cmd->flags == O_RDWR)
write_to_gbe_bin();
if (exit_cleanup() == -1)
@@ -820,8 +886,9 @@ void
sanitize_command_list(void)
{
unsigned long c;
+ unsigned long num_commands = items(nv->cmd);
- for (c = 0; c < N_COMMANDS; c++)
+ for (c = 0; c < num_commands; c++)
sanitize_command_index(c);
}
@@ -833,34 +900,37 @@ sanitize_command_index(unsigned long c)
{
unsigned long gbe_rw_size;
+ struct commands *cmd = &nv->cmd[c];
+
check_command_num(c);
- if (command[c].argc < 3)
+ if (cmd->argc < 3)
err(EINVAL, "cmd index %lu: argc below 3, %d",
- (unsigned long)c, command[c].argc);
+ (unsigned long)c, cmd->argc);
- if (command[c].str == NULL)
+ if (cmd->str == NULL)
err(EINVAL, "cmd index %lu: NULL str",
(unsigned long)c);
- if (*command[c].str == '\0')
+
+ if (*cmd->str == '\0')
err(EINVAL, "cmd index %lu: empty str",
(unsigned long)c);
- if (xstrxlen(command[c].str, MAX_CMD_LEN + 1) >
+ if (xstrxlen(cmd->str, MAX_CMD_LEN + 1) >
MAX_CMD_LEN) {
err(EINVAL, "cmd index %lu: str too long: %s",
- (unsigned long)c, command[c].str);
+ (unsigned long)c, cmd->str);
}
- if (command[c].run == NULL)
+ if (cmd->run == NULL)
err(EINVAL, "cmd index %lu: cmd ptr null",
(unsigned long)c);
- check_bin(command[c].arg_part, "cmd.arg_part");
- check_bin(command[c].chksum_read, "cmd.chksum_read");
- check_bin(command[c].chksum_write, "cmd.chksum_write");
+ check_bin(cmd->arg_part, "cmd.arg_part");
+ check_bin(cmd->chksum_read, "cmd.chksum_read");
+ check_bin(cmd->chksum_write, "cmd.chksum_write");
- gbe_rw_size = command[c].rw_size;
+ gbe_rw_size = cmd->rw_size;
switch (gbe_rw_size) {
case GBE_PART_SIZE:
@@ -875,52 +945,75 @@ sanitize_command_index(unsigned long c)
err(EINVAL, "rw_size larger than GbE part: %lu",
(unsigned long)gbe_rw_size);
- if (command[c].flags != O_RDONLY &&
- command[c].flags != O_RDWR)
+ if (cmd->flags != O_RDONLY &&
+ cmd->flags != O_RDWR)
err(EINVAL, "invalid cmd.flags setting");
}
void
set_cmd(int argc, char *argv[])
{
- const char *cmd_str;
+ const char *cmd;
+
+ unsigned long i = 0;
+
+ for (i = 0; i < items(nv->cmd); i++) {
- for (cmd_index = 0; valid_command(cmd_index); cmd_index++) {
- cmd_str = command[cmd_index].str;
+ cmd = nv->cmd[i].str;
- if (xstrxcmp(argv[2], cmd_str, MAX_CMD_LEN) != 0)
+ /* not the right command */
+ if (xstrxcmp(argv[2], cmd, MAX_CMD_LEN) != 0)
continue;
- else if (argc >= command[cmd_index].argc)
+
+ /* valid command found */
+ if (argc >= nv->cmd[i].argc) {
+ nv->no_cmd = 0;
+ nv->i = i; /* set command */
+
return;
+ }
- err(EINVAL, "Too few args on command '%s'", cmd_str);
+ err(EINVAL,
+ "Too few args on command '%s'", cmd);
}
- cmd_index = CMD_NULL;
+ nv->no_cmd = 1;
}
void
set_cmd_args(int argc, char *argv[])
{
unsigned char arg_part;
+ unsigned long index;
- if (!valid_command(cmd_index) || argc < 3)
+ struct commands *cmd;
+
+ if (!valid_command(nv->i) || argc < 3)
usage();
- arg_part = command[cmd_index].arg_part;
+ index = nv->i;
+
+ cmd = &nv->cmd[index];
+
+ arg_part = cmd->arg_part;
/* Maintainer bugs */
if (arg_part && argc < 4)
err(EINVAL,
"arg_part set for command that needs argc4");
- if (arg_part && cmd_index == CMD_SETMAC)
+
+ if (arg_part && index == CMD_SETMAC)
err(EINVAL,
"arg_part set on CMD_SETMAC");
- if (cmd_index == CMD_SETMAC)
+ if (index == CMD_SETMAC) {
+
mac_str = argc >= 4 ? argv[3] : rmac;
- else if (arg_part)
+
+ } else if (arg_part) {
+
part = conv_argv_part_num(argv[3]);
+ }
}
unsigned long
@@ -986,8 +1079,10 @@ open_gbe_file(void)
struct stat gbe_st;
int flags;
+ struct commands *cmd = &nv->cmd[nv->i];
+
xopen(&gbe_fd, fname,
- command[cmd_index].flags | O_BINARY |
+ cmd->flags | O_BINARY |
O_NOFOLLOW | O_CLOEXEC, &gbe_st);
/* inode will be checked later on write */
@@ -995,8 +1090,8 @@ open_gbe_file(void)
gbe_ino = gbe_st.st_ino;
if (gbe_st.st_nlink > 1)
- fprintf(stderr,
- "%s: warning: file has %lu hard links\n",
+ err(EINVAL,
+ "%s: warning: file has multiple (%lu) hard links\n",
fname, (unsigned long)gbe_st.st_nlink);
if (gbe_st.st_nlink == 0)
@@ -1034,10 +1129,11 @@ int
lock_file(int fd)
{
struct flock fl;
+ struct commands *cmd = &nv->cmd[nv->i];
memset(&fl, 0, sizeof(fl));
- if (command[cmd_index].flags == O_RDONLY)
+ if (cmd->flags == O_RDONLY)
fl.l_type = F_RDLCK;
else
fl.l_type = F_WRLCK;
@@ -1158,16 +1254,18 @@ read_checksums(void)
unsigned char num_invalid;
unsigned char max_invalid;
+ struct commands *cmd = &nv->cmd[nv->i];
+
part_valid[0] = 0;
part_valid[1] = 0;
- if (!command[cmd_index].chksum_read)
+ if (!cmd->chksum_read)
return;
num_invalid = 0;
max_invalid = 2;
- arg_part = command[cmd_index].arg_part;
+ arg_part = cmd->arg_part;
if (arg_part)
max_invalid = 1;
@@ -1201,24 +1299,30 @@ read_checksums(void)
int
good_checksum(unsigned long partnum)
{
- unsigned short expected_checksum = calculated_checksum(partnum);
- unsigned short current_checksum = nvm_word(NVM_CHECKSUM_WORD, partnum);
+ unsigned short expected_checksum =
+ calculated_checksum(partnum);
- if (current_checksum == expected_checksum)
- return 1;
+ unsigned short current_checksum =
+ nvm_word(NVM_CHECKSUM_WORD, partnum);
- return 0;
+ return current_checksum == expected_checksum;
}
void
-run_cmd(unsigned long c)
+run_cmd(void)
{
- check_command_num(c);
+ unsigned long cmd_num;
+ struct commands *cmd;
+
+ cmd_num = nv->i;
+ cmd = &nv->cmd[cmd_num];
- if (command[c].run == NULL)
- err(EINVAL, "Command %lu: null ptr", (unsigned long)c);
+ check_command_num(cmd_num);
- command[c].run();
+ if (cmd->run == NULL)
+ err(EINVAL, "Command %lu: null ptr", cmd_num);
+
+ cmd->run();
}
void
@@ -1232,12 +1336,17 @@ check_command_num(unsigned long c)
unsigned char
valid_command(unsigned long c)
{
- if (c >= N_COMMANDS)
+ struct commands *cmd;
+
+ if (c >= items(nv->cmd))
return 0;
- if (c != command[c].chk)
- err(EINVAL, "Invalid cmd chk value (%lu) vs arg: %lu",
- (unsigned long)command[c].chk, (unsigned long)c);
+ cmd = &nv->cmd[c];
+
+ if (c != cmd->chk)
+ err(EINVAL,
+ "Invalid cmd chk value (%lu) vs arg: %lu",
+ cmd->chk, c);
return 1;
}
@@ -1362,30 +1471,25 @@ hextonum(char ch_s)
return ch - 'a' + 10;
if (ch == '?' || ch == 'x')
- return rhex(); /* random character */
+ return (unsigned short)rlong() & 0xf;
return 16; /* invalid character */
}
-unsigned short
-rhex(void)
+unsigned long
+rlong(void)
{
struct x_st_timeval tv;
- unsigned long mix;
+ static unsigned long mix = 0;
static unsigned long counter = 0;
- unsigned short r;
- /* Read /dev/urandom
- * if possible */
- r = read_urandom();
- if (r < 16)
- return r;
-
- /* Fallback */
+ static int fd = -1;
+ unsigned long rval = 0;
+ long nr = -1;
x_i_gettimeofday(&tv, NULL);
- mix = (unsigned long)tv.tv_sec
+ mix ^= (unsigned long)tv.tv_sec
^ (unsigned long)tv.tv_usec
^ (unsigned long)getpid()
^ (unsigned long)&mix
@@ -1400,45 +1504,45 @@ rhex(void)
mix ^= (unsigned long)&tv;
mix ^= (unsigned long)&counter;
- return (unsigned short)(mix & 0xf);
-}
-
-unsigned short
-read_urandom(void)
-{
- static int fd = -1;
- static long n = -1;
-
- static unsigned char r[256];
+ /*
+ * 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
+ */
- if (fd < 0) {
+ if (fd < 0)
+ fd = open("/dev/urandom", O_RDONLY | O_BINARY | O_NONBLOCK);
- fd = open("/dev/urandom", O_RDONLY | O_NONBLOCK);
-#ifndef NVMUTIL_UNVEIL
- if (fd < 0) /* older openbsd */
- fd = open("/dev/arandom", O_RDONLY | O_NONBLOCK);
+#if !(defined(__OpenBSD__) && defined(OpenBSD)) || \
+ (defined(__OpenBSD__) && defined(OpenBSD) && \
+ OpenBSD < 604)
+ if (fd < 0) /* old openbsd */
+ fd = open("/dev/arandom", O_RDONLY | O_BINARY | O_NONBLOCK);
#endif
- if (fd < 0) /* super old unix (could block) */
- fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
-
- if (fd < 0)
- return 16;
- }
- if (n < 0) {
+ if (fd < 0)
+ fd = open("/dev/random", O_RDONLY | O_BINARY | O_NONBLOCK);
- n = rw_file_exact(fd, r, 256, 0, IO_READ,
- LOOP_EAGAIN, LOOP_EINTR, 2, OFF_ERR);
+ 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 (n == 0)
- n = -1;
- if (n < 0)
- return 16;
+ if (nr == sizeof(unsigned long))
+ return rval;
- --n;
- }
-
- return r[n--] & 0xf;
+ return mix;
}
unsigned long
@@ -1449,8 +1553,9 @@ entropy_jitter(void)
long mix_diff;
int i;
- for (i = 0; i < 8; i++) {
- x_i_gettimeofday(&a, NULL);
+ x_i_gettimeofday(&a, NULL);
+
+ for (i = 0; i < 32; i++) {
getpid();
x_i_gettimeofday(&b, NULL);
@@ -1481,7 +1586,7 @@ x_i_gettimeofday(struct x_st_timeval *tv, void *tz)
t = time(NULL);
tv->tv_sec = t;
- tv->tv_usec = (long)clock() % 1000000;
+ tv->tv_usec = (long)((unsigned long)clock() % 1000000UL);
return 0;
}
@@ -1605,11 +1710,13 @@ cmd_helper_cat(void)
unsigned long ff = 0;
unsigned long nff = 0;
+ unsigned long cmd_num = nv->i;
+
fflush(NULL);
memset(pad, 0xff, GBE_PART_SIZE);
- switch (cmd_index) {
+ switch (cmd_num) {
case CMD_CAT:
nff = 0;
break;
@@ -1649,7 +1756,9 @@ write_gbe_file(void)
unsigned long p;
unsigned char update_checksum;
- if (command[cmd_index].flags == O_RDONLY)
+ struct commands *cmd = &nv->cmd[nv->i];
+
+ if (cmd->flags == O_RDONLY)
return;
if (fstat(gbe_fd, &gbe_st) == -1)
@@ -1670,7 +1779,7 @@ write_gbe_file(void)
if (!S_ISREG(tmp_st.st_mode))
err(errno, "%s: file type changed before write", tname);
- update_checksum = command[cmd_index].chksum_write;
+ update_checksum = cmd->chksum_write;
for (p = 0; p < 2; p++) {
if (!part_modified[p])
@@ -1772,11 +1881,15 @@ rw_gbe_file_part(unsigned long p, int rw_type,
const char *rw_type_str)
{
long r;
- unsigned long gbe_rw_size = command[cmd_index].rw_size;
+ unsigned long gbe_rw_size;
+ struct commands *cmd = &nv->cmd[nv->i];
unsigned char *mem_offset;
+
off_t file_offset;
+ gbe_rw_size = cmd->rw_size;
+
if (rw_type < IO_PREAD || rw_type > IO_PWRITE)
err(errno, "%s: %s: part %lu: invalid rw_type, %d",
fname, rw_type_str, (unsigned long)p, rw_type);
@@ -1802,7 +1915,9 @@ write_to_gbe_bin(void)
int saved_errno;
int mv;
- if (command[cmd_index].flags != O_RDWR)
+ struct commands *cmd = &nv->cmd[nv->i];
+
+ if (cmd->flags != O_RDWR)
return;
write_gbe_file();
@@ -1892,10 +2007,12 @@ check_written_part(unsigned long p)
unsigned char *buf_restore;
struct stat st;
+ struct commands *cmd = &nv->cmd[nv->i];
+
if (!part_modified[p])
return;
- gbe_rw_size = command[cmd_index].rw_size;
+ gbe_rw_size = cmd->rw_size;
/* invert not needed for pwrite */
mem_offset = gbe_mem_offset(p, "pwrite");
@@ -2003,7 +2120,7 @@ gbe_mv(void)
saved_errno = errno;
- r = x_i_rename(tname, fname);
+ r = rename(tname, fname);
if (r > -1) {
/*
@@ -2056,7 +2173,7 @@ gbe_mv(void)
if (x_i_close(dest_fd) == -1)
goto ret_gbe_mv;
- if (x_i_rename(dest_tmp, fname) == -1)
+ if (rename(dest_tmp, fname) == -1)
goto ret_gbe_mv;
if (fsync_dir(fname) < 0)
@@ -2109,7 +2226,7 @@ ret_gbe_mv:
}
/*
- * Ensure x_i_rename() is durable by syncing the
+ * Ensure rename() is durable by syncing the
* directory containing the target file.
*/
int
@@ -2138,6 +2255,12 @@ fsync_dir(const char *path)
goto err_fsync_dir;
}
+ if (pathlen == 0)
+ {
+ errno = EINVAL;
+ goto err_fsync_dir;
+ }
+
dirbuf = malloc(pathlen + 1);
if (dirbuf == NULL)
goto err_fsync_dir;
@@ -2147,13 +2270,23 @@ fsync_dir(const char *path)
if (slash != NULL) {
*slash = '\0';
- if (*dirbuf == '\0')
- strcpy(dirbuf, "/");
+ if (*dirbuf == '\0') {
+ dirbuf[0] = '/';
+ dirbuf[1] = '\0';
+ }
} else {
- strcpy(dirbuf, ".");
+ dirbuf[0] = '.';
+ dirbuf[1] = '\0';
}
- dfd = open(dirbuf, O_RDONLY);
+ dfd = open(dirbuf, O_RDONLY
+#ifdef O_DIRECTORY
+ | O_DIRECTORY
+#endif
+#ifdef O_NOFOLLOW
+ | O_NOFOLLOW
+#endif
+ );
if (dfd == -1)
goto err_fsync_dir;
@@ -3029,6 +3162,7 @@ x_i_mkstemp(char *template)
char *p;
char ch[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ unsigned long r = rlong();
len = xstrxlen(template, PATH_LEN);
@@ -3041,7 +3175,7 @@ x_i_mkstemp(char *template)
for (i = 0; i < 100; i++) {
for (j = 0; j < 6; j++)
- p[j] = ch[rhex() & 31];
+ p[j] = ch[r % (sizeof(ch) - 1)];
fd = open(template, O_RDWR | O_CREAT | O_EXCL, 0600);
@@ -3073,6 +3207,7 @@ x_c_strrchr(const char *s, int c)
return (char *)p;
}
+/*
int
x_i_rename(const char *src, const char *dst)
{
@@ -3115,6 +3250,7 @@ x_i_rename(const char *src, const char *dst)
return 0;
}
+*/
char *
x_c_tmpdir(void)
@@ -3177,6 +3313,12 @@ x_i_memcmp(const void *a, const void *b, unsigned long n)
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)
{
@@ -3198,16 +3340,26 @@ x_try_fdpath(const char *prefix, int fd, mode_t mode)
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);
- i += j;
+ if (i + j >= PATH_LEN)
+ return -1;
+
+ i += j;
path[i] = '\0';
+ if (stat(path, &st) < 0)
+ return -1;
+
return chmod(path, mode);
}