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