mirror of
https://codeberg.org/libreboot/lbmk.git
synced 2026-07-18 23:01:33 +02:00
util/nvmutil: major cleanup
handle init in xstatus() it's now a singleton design also tidied up some other code also removed todo.c. bloat. will do all those anyway. too much change. i just kept touching the code until it looked good Signed-off-by: Leah Rowe <leah@libreboot.org>
This commit is contained in:
+87
-145
@@ -4,26 +4,33 @@
|
|||||||
* Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org>
|
* Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: split this per .c file
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Use this shorthand in cmd helpers. e.g.
|
|
||||||
in cmd_setmac function:
|
|
||||||
check_cmd(cmd_helper_cat);
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef COMMON_H
|
#ifndef COMMON_H
|
||||||
#define COMMON_H
|
#define COMMON_H
|
||||||
|
|
||||||
/*
|
/* keep SYS_RENAME 1 to
|
||||||
* system prototypes
|
* use libc rename()
|
||||||
|
* recommended
|
||||||
|
*/
|
||||||
|
#ifndef SYS_RENAME
|
||||||
|
#define SYS_RENAME 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define items(x) (sizeof((x)) / sizeof((x)[0]))
|
||||||
|
|
||||||
|
/* system prototypes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int fchmod(int fd, mode_t mode);
|
int fchmod(int fd, mode_t mode);
|
||||||
|
|
||||||
/*
|
/* analog of SSIZE_MAX
|
||||||
* build config
|
*/
|
||||||
|
|
||||||
|
#ifndef X_LONG_MAX
|
||||||
|
#define X_LONG_MAX ((long)(~((long)1 << (sizeof(long)*CHAR_BIT-1))))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* build config
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef NVMUTIL_H
|
#ifndef NVMUTIL_H
|
||||||
@@ -71,27 +78,6 @@ int fchmod(int fd, mode_t mode);
|
|||||||
#define _FILE_OFFSET_BITS 64
|
#define _FILE_OFFSET_BITS 64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Older versions of BSD to the early 2000s
|
|
||||||
* could compile nvmutil, but pledge was
|
|
||||||
* added in the 2010s. Therefore, for extra
|
|
||||||
* portability, we will only pledge/unveil
|
|
||||||
* on OpenBSD versions that have it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(__OpenBSD__) && defined(OpenBSD)
|
|
||||||
#if OpenBSD >= 604
|
|
||||||
#ifndef NVMUTIL_UNVEIL
|
|
||||||
#define NVMUTIL_UNVEIL 1
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#if OpenBSD >= 509
|
|
||||||
#ifndef NVMUTIL_PLEDGE
|
|
||||||
#define NVMUTIL_PLEDGE 1
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EXIT_FAILURE
|
#ifndef EXIT_FAILURE
|
||||||
#define EXIT_FAILURE 1
|
#define EXIT_FAILURE 1
|
||||||
#endif
|
#endif
|
||||||
@@ -132,8 +118,7 @@ int fchmod(int fd, mode_t mode);
|
|||||||
#define FD_CLOEXEC 0
|
#define FD_CLOEXEC 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/* Sizes in bytes:
|
||||||
* Sizes in bytes:
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SIZE_1KB 1024
|
#define SIZE_1KB 1024
|
||||||
@@ -144,17 +129,12 @@ int fchmod(int fd, mode_t mode);
|
|||||||
|
|
||||||
#define GBE_BUF_SIZE (SIZE_128KB)
|
#define GBE_BUF_SIZE (SIZE_128KB)
|
||||||
|
|
||||||
/*
|
/* First 128 bytes of gbe.bin is NVM.
|
||||||
* First 128 bytes of a GbE part contains
|
* Then extended area. All of NVM must
|
||||||
* the regular NVM (Non-Volatile-Memory)
|
* add up to BABA, truncated (LE)
|
||||||
* area. All of these bytes must add up,
|
|
||||||
* truncated to 0xBABA.
|
|
||||||
*
|
*
|
||||||
* The full GbE region is 4KB, but only
|
* First 4KB of each half of the file
|
||||||
* the first 128 bytes are used here.
|
* contains NVM+extended.
|
||||||
*
|
|
||||||
* There is a second 4KB part with the same
|
|
||||||
* rules, and it *should* be identical.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define GBE_WORK_SIZE (SIZE_8KB)
|
#define GBE_WORK_SIZE (SIZE_8KB)
|
||||||
@@ -164,29 +144,7 @@ int fchmod(int fd, mode_t mode);
|
|||||||
#define NVM_WORDS (NVM_SIZE >> 1)
|
#define NVM_WORDS (NVM_SIZE >> 1)
|
||||||
#define NVM_CHECKSUM_WORD (NVM_WORDS - 1)
|
#define NVM_CHECKSUM_WORD (NVM_WORDS - 1)
|
||||||
|
|
||||||
/*
|
/* argc minimum (dispatch)
|
||||||
* Portable macro based on BSD nitems.
|
|
||||||
* Used to count the number of commands (see below).
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define items(x) (sizeof((x)) / sizeof((x)[0]))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* GbE files can be 8KB, 16KB or 128KB,
|
|
||||||
* but we only need the two 4KB parts
|
|
||||||
* from offset zero and offset 64KB in
|
|
||||||
* a 128KB file, or zero and 8KB in a 16KB
|
|
||||||
* file, or zero and 4KB in an 8KB file.
|
|
||||||
*
|
|
||||||
* The code will handle this properly.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef X_LONG_MAX
|
|
||||||
#define X_LONG_MAX ((long)(~((long)1 << (sizeof(long)*CHAR_BIT-1))))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use these for .argc in command[]:
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ARGC_3 3
|
#define ARGC_3 3
|
||||||
@@ -195,16 +153,11 @@ int fchmod(int fd, mode_t mode);
|
|||||||
#define NO_LOOP_EAGAIN 0
|
#define NO_LOOP_EAGAIN 0
|
||||||
#define NO_LOOP_EINTR 0
|
#define NO_LOOP_EINTR 0
|
||||||
|
|
||||||
/*
|
/* For checking if an fd is a normal file.
|
||||||
* Used for checking whether.
|
* Portable for old Unix e.g. v7 (S_IFREG),
|
||||||
* a file is a file via stat().
|
* 4.2BSD (S_IFMT), POSIX (S_ISREG).
|
||||||
*
|
*
|
||||||
* Portable macro for compatibility
|
* IFREG: assumed 0100000 (classic bitmask)
|
||||||
* 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
|
#ifndef S_ISREG
|
||||||
@@ -222,9 +175,7 @@ int fchmod(int fd, mode_t mode);
|
|||||||
#define IO_PREAD 2
|
#define IO_PREAD 2
|
||||||
#define IO_PWRITE 3
|
#define IO_PWRITE 3
|
||||||
|
|
||||||
/*
|
/* for nvmutil commands
|
||||||
* Used as indices for command[]
|
|
||||||
* MUST be in the same order as entries in command[]
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CMD_DUMP 0
|
#define CMD_DUMP 0
|
||||||
@@ -244,6 +195,9 @@ int fchmod(int fd, mode_t mode);
|
|||||||
#define SKIP_CHECKSUM_WRITE 0
|
#define SKIP_CHECKSUM_WRITE 0
|
||||||
#define CHECKSUM_WRITE 1
|
#define CHECKSUM_WRITE 1
|
||||||
|
|
||||||
|
/* command table
|
||||||
|
*/
|
||||||
|
|
||||||
struct commands {
|
struct commands {
|
||||||
unsigned long chk;
|
unsigned long chk;
|
||||||
char *str;
|
char *str;
|
||||||
@@ -256,15 +210,24 @@ struct commands {
|
|||||||
int flags; /* e.g. O_RDWR or O_RDONLY */
|
int flags; /* e.g. O_RDWR or O_RDONLY */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* mac address
|
||||||
|
*/
|
||||||
|
|
||||||
struct macaddr {
|
struct macaddr {
|
||||||
char *str; /* set to rmac, or argv string */
|
char *str; /* set to rmac, or argv string */
|
||||||
char rmac[18]; /* xx:xx:xx:xx:xx:xx */
|
char rmac[18]; /* xx:xx:xx:xx:xx:xx */
|
||||||
unsigned short mac_buf[3];
|
unsigned short mac_buf[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* gbe.bin and tmpfile
|
||||||
|
*/
|
||||||
|
|
||||||
struct xfile {
|
struct xfile {
|
||||||
int gbe_fd;
|
int gbe_fd;
|
||||||
|
struct stat gbe_st;
|
||||||
|
|
||||||
int tmp_fd;
|
int tmp_fd;
|
||||||
|
struct stat tmp_st;
|
||||||
|
|
||||||
char *tname; /* path of tmp file */
|
char *tname; /* path of tmp file */
|
||||||
char *fname; /* path of gbe file */
|
char *fname; /* path of gbe file */
|
||||||
@@ -279,12 +242,6 @@ struct xfile {
|
|||||||
|
|
||||||
int post_rw_checksum[2];
|
int post_rw_checksum[2];
|
||||||
|
|
||||||
dev_t gbe_dev;
|
|
||||||
ino_t gbe_ino;
|
|
||||||
|
|
||||||
dev_t tmp_dev;
|
|
||||||
ino_t tmp_ino;
|
|
||||||
|
|
||||||
off_t gbe_file_size;
|
off_t gbe_file_size;
|
||||||
off_t gbe_tmp_size;
|
off_t gbe_tmp_size;
|
||||||
|
|
||||||
@@ -298,11 +255,13 @@ struct xfile {
|
|||||||
unsigned char pad[GBE_WORK_SIZE]; /* the file that wouldn't die */
|
unsigned char pad[GBE_WORK_SIZE]; /* the file that wouldn't die */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/* Command table, MAC address, files
|
||||||
|
*
|
||||||
* BE CAREFUL when editing this
|
* BE CAREFUL when editing this
|
||||||
* to ensure that you also update
|
* to ensure that you also update
|
||||||
* the tables in xstatus()
|
* the tables in xstatus()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct xstate {
|
struct xstate {
|
||||||
struct commands cmd[7];
|
struct commands cmd[7];
|
||||||
struct macaddr mac;
|
struct macaddr mac;
|
||||||
@@ -313,10 +272,6 @@ struct xstate {
|
|||||||
unsigned long i; /* index to cmd[] for current command */
|
unsigned long i; /* index to cmd[] for current command */
|
||||||
int no_cmd;
|
int no_cmd;
|
||||||
|
|
||||||
/* store size of a struct here.
|
|
||||||
(can be used to copy old state) */
|
|
||||||
unsigned long xsize;
|
|
||||||
|
|
||||||
/* Cat commands set this.
|
/* Cat commands set this.
|
||||||
the cat cmd helpers check it */
|
the cat cmd helpers check it */
|
||||||
int cat;
|
int cat;
|
||||||
@@ -324,52 +279,47 @@ struct xstate {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct xstate *xstatus(int argc, char *argv[]);
|
||||||
|
|
||||||
struct xstate *xstatus(void);
|
/* Sanitize command tables.
|
||||||
|
|
||||||
/*
|
|
||||||
* Sanitize command tables.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void sanitize_command_list(void);
|
void sanitize_command_list(void);
|
||||||
void sanitize_command_index(unsigned long c);
|
void sanitize_command_index(unsigned long c);
|
||||||
|
|
||||||
/*
|
/* Argument handling (user input)
|
||||||
* Argument handling (user input)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void set_cmd(int argc, char *argv[]);
|
void set_cmd(int argc, char *argv[]);
|
||||||
void set_cmd_args(int argc, char *argv[]);
|
void set_cmd_args(int argc, char *argv[]);
|
||||||
unsigned long conv_argv_part_num(const char *part_str);
|
unsigned long conv_argv_part_num(const char *part_str);
|
||||||
int xstrxcmp(const char *a, const char *b, unsigned long maxlen);
|
int xstrxcmp(const char *a, const char *b, unsigned long maxlen);
|
||||||
|
|
||||||
/*
|
/* Prep files for reading
|
||||||
* Prep files for reading
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void open_gbe_file(void);
|
void open_gbe_file(void);
|
||||||
int lock_file(int fd, int flags);
|
int lock_file(int fd, int flags);
|
||||||
|
int same_file(int fd, struct stat *st_old, int check_size);
|
||||||
void xopen(int *fd, const char *path, int flags, struct stat *st);
|
void xopen(int *fd, const char *path, int flags, struct stat *st);
|
||||||
|
|
||||||
/*
|
/* Read GbE file and verify checksums
|
||||||
* Read GbE file and verify
|
|
||||||
* checksums.
|
|
||||||
*
|
|
||||||
* After this, we can run commands.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void copy_gbe(void);
|
void copy_gbe(void);
|
||||||
void read_file(void);
|
void read_file(void);
|
||||||
void read_checksums(void);
|
void read_checksums(void);
|
||||||
int good_checksum(unsigned long partnum);
|
int good_checksum(unsigned long partnum);
|
||||||
|
|
||||||
/*
|
/* validate commands
|
||||||
* Execute user command on GbE data.
|
|
||||||
* These are stubs that call helpers.
|
|
||||||
*/
|
*/
|
||||||
void run_cmd(void);
|
|
||||||
void check_command_num(unsigned long c);
|
void check_command_num(unsigned long c);
|
||||||
unsigned char valid_command(unsigned long c);
|
unsigned char valid_command(unsigned long c);
|
||||||
|
|
||||||
/*
|
/* Helper functions for command: setmac
|
||||||
* Helper functions for command: setmac
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void cmd_helper_setmac(void);
|
void cmd_helper_setmac(void);
|
||||||
void parse_mac_string(void);
|
void parse_mac_string(void);
|
||||||
unsigned long xstrxlen(const char *scmp, unsigned long maxlen);
|
unsigned long xstrxlen(const char *scmp, unsigned long maxlen);
|
||||||
@@ -380,51 +330,49 @@ unsigned short hextonum(char ch_s);
|
|||||||
unsigned long rlong(void);
|
unsigned long rlong(void);
|
||||||
void write_mac_part(unsigned long partnum);
|
void write_mac_part(unsigned long partnum);
|
||||||
|
|
||||||
/*
|
/* Helper functions for command: dump
|
||||||
* Helper functions for command: dump
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void cmd_helper_dump(void);
|
void cmd_helper_dump(void);
|
||||||
void print_mac_from_nvm(unsigned long partnum);
|
void print_mac_from_nvm(unsigned long partnum);
|
||||||
void hexdump(unsigned long partnum);
|
void hexdump(unsigned long partnum);
|
||||||
|
|
||||||
/*
|
/* Helper functions for command: swap
|
||||||
* Helper functions for command: swap
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void cmd_helper_swap(void);
|
void cmd_helper_swap(void);
|
||||||
|
|
||||||
/*
|
/* Helper functions for command: copy
|
||||||
* Helper functions for command: copy
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void cmd_helper_copy(void);
|
void cmd_helper_copy(void);
|
||||||
|
|
||||||
/*
|
/* Helper functions for commands:
|
||||||
* Helper functions for commands:
|
|
||||||
* cat, cat16 and cat128
|
* cat, cat16 and cat128
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void cmd_helper_cat(void);
|
void cmd_helper_cat(void);
|
||||||
void cmd_helper_cat16(void);
|
void cmd_helper_cat16(void);
|
||||||
void cmd_helper_cat128(void);
|
void cmd_helper_cat128(void);
|
||||||
void cat(unsigned long nff);
|
void cat(unsigned long nff);
|
||||||
void cat_buf(unsigned char *b);
|
void cat_buf(unsigned char *b);
|
||||||
|
|
||||||
|
/* Command verification/control
|
||||||
|
*/
|
||||||
|
|
||||||
void check_cmd(void (*fn)(void), const char *name);
|
void check_cmd(void (*fn)(void), const char *name);
|
||||||
void cmd_helper_err(void);
|
void cmd_helper_err(void);
|
||||||
|
|
||||||
/*
|
/* Write GbE files to disk
|
||||||
* After command processing, write
|
|
||||||
* the modified GbE file back.
|
|
||||||
*
|
|
||||||
* These are stub functions: check
|
|
||||||
* below for the actual functions.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void write_gbe_file(void);
|
void write_gbe_file(void);
|
||||||
void set_checksum(unsigned long part);
|
void set_checksum(unsigned long part);
|
||||||
unsigned short calculated_checksum(unsigned long p);
|
unsigned short calculated_checksum(unsigned long p);
|
||||||
|
|
||||||
/*
|
/* NVM read/write
|
||||||
* Helper functions for accessing
|
|
||||||
* the NVM area during operation.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned short nvm_word(unsigned long pos16, unsigned long part);
|
unsigned short nvm_word(unsigned long pos16, unsigned long part);
|
||||||
void set_nvm_word(unsigned long pos16,
|
void set_nvm_word(unsigned long pos16,
|
||||||
unsigned long part, unsigned short val16);
|
unsigned long part, unsigned short val16);
|
||||||
@@ -432,23 +380,26 @@ void set_part_modified(unsigned long p);
|
|||||||
void check_nvm_bound(unsigned long pos16, unsigned long part);
|
void check_nvm_bound(unsigned long pos16, unsigned long part);
|
||||||
void check_bin(unsigned long a, const char *a_name);
|
void check_bin(unsigned long a, const char *a_name);
|
||||||
|
|
||||||
/*
|
/* GbE file read/write
|
||||||
* Helper functions for stub functions
|
|
||||||
* that handle GbE file reads/writes.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void rw_gbe_file_part(unsigned long p, int rw_type,
|
void rw_gbe_file_part(unsigned long p, int rw_type,
|
||||||
const char *rw_type_str);
|
const char *rw_type_str);
|
||||||
void write_to_gbe_bin(void);
|
void write_to_gbe_bin(void);
|
||||||
int gbe_mv(void);
|
int gbe_mv(void);
|
||||||
void check_written_part(unsigned long p);
|
void check_written_part(unsigned long p);
|
||||||
void report_io_err_rw(void);
|
void report_io_err_rw(void);
|
||||||
int fsync_dir(const char *path);
|
|
||||||
unsigned char *gbe_mem_offset(unsigned long part, const char *f_op);
|
unsigned char *gbe_mem_offset(unsigned long part, const char *f_op);
|
||||||
off_t gbe_file_offset(unsigned long part, const char *f_op);
|
off_t gbe_file_offset(unsigned long part, const char *f_op);
|
||||||
off_t gbe_x_offset(unsigned long part, const char *f_op,
|
off_t gbe_x_offset(unsigned long part, const char *f_op,
|
||||||
const char *d_type, off_t nsize, off_t ncmp);
|
const char *d_type, off_t nsize, off_t ncmp);
|
||||||
long rw_gbe_file_exact(int fd, unsigned char *mem, unsigned long nrw,
|
long rw_gbe_file_exact(int fd, unsigned char *mem, unsigned long nrw,
|
||||||
off_t off, int rw_type);
|
off_t off, int rw_type);
|
||||||
|
|
||||||
|
/* Generic read/write
|
||||||
|
*/
|
||||||
|
|
||||||
|
int fsync_dir(const char *path);
|
||||||
long rw_file_exact(int fd, unsigned char *mem, unsigned long len,
|
long rw_file_exact(int fd, unsigned char *mem, unsigned long len,
|
||||||
off_t off, int rw_type, int loop_eagain, int loop_eintr,
|
off_t off, int rw_type, int loop_eagain, int loop_eintr,
|
||||||
unsigned long max_retries, int off_reset);
|
unsigned long max_retries, int off_reset);
|
||||||
@@ -466,27 +417,21 @@ off_t lseek_loop(int fd, off_t off,
|
|||||||
#endif
|
#endif
|
||||||
int try_err(int loop_err, int errval);
|
int try_err(int loop_err, int errval);
|
||||||
|
|
||||||
/*
|
/* Error handling and cleanup
|
||||||
* Error handling and cleanup
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void usage(void);
|
void usage(void);
|
||||||
void err(int nvm_errval, const char *msg, ...);
|
void err(int nvm_errval, const char *msg, ...);
|
||||||
int exit_cleanup(void);
|
int exit_cleanup(void);
|
||||||
const char *getnvmprogname(void);
|
const char *getnvmprogname(void);
|
||||||
|
|
||||||
/*
|
/* Portable libc functions
|
||||||
* a special kind of hell
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char *new_tmpfile(int *fd, int local, const char *path);
|
char *new_tmpfile(int *fd, int local, const char *path);
|
||||||
int x_i_mkstemp(char *template);
|
int x_i_mkstemp(char *template);
|
||||||
char *x_c_strrchr(const char *s, int c);
|
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);
|
int x_i_rename(const char *src, const char *dst);
|
||||||
*/
|
|
||||||
char *x_c_tmpdir(void);
|
char *x_c_tmpdir(void);
|
||||||
int x_i_close(int fd);
|
int x_i_close(int fd);
|
||||||
void *x_v_memcpy(void *dst,
|
void *x_v_memcpy(void *dst,
|
||||||
@@ -495,9 +440,6 @@ int x_i_memcmp(const void *a,
|
|||||||
const void *b, unsigned long n);
|
const void *b, unsigned long n);
|
||||||
int x_i_fsync(int fd);
|
int x_i_fsync(int fd);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* asserts */
|
/* asserts */
|
||||||
|
|
||||||
/* type asserts */
|
/* type asserts */
|
||||||
|
|||||||
@@ -29,9 +29,9 @@
|
|||||||
void
|
void
|
||||||
read_checksums(void)
|
read_checksums(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct commands *cmd;
|
struct commands *cmd = &x->cmd[x->i];
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
unsigned long _p;
|
unsigned long _p;
|
||||||
unsigned long _skip_part;
|
unsigned long _skip_part;
|
||||||
@@ -39,9 +39,6 @@ read_checksums(void)
|
|||||||
unsigned char _num_invalid;
|
unsigned char _num_invalid;
|
||||||
unsigned char _max_invalid;
|
unsigned char _max_invalid;
|
||||||
|
|
||||||
cmd = &x->cmd[x->i];
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
f->part_valid[0] = 0;
|
f->part_valid[0] = 0;
|
||||||
f->part_valid[1] = 0;
|
f->part_valid[1] = 0;
|
||||||
|
|
||||||
|
|||||||
+47
-92
@@ -24,13 +24,13 @@
|
|||||||
|
|
||||||
#include "../include/common.h"
|
#include "../include/common.h"
|
||||||
|
|
||||||
/*
|
/* Guard against regressions by maintainers (command table)
|
||||||
* Guard against regressions by maintainers (command table)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
sanitize_command_list(void)
|
sanitize_command_list(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
|
|
||||||
unsigned long c;
|
unsigned long c;
|
||||||
unsigned long num_commands;
|
unsigned long num_commands;
|
||||||
@@ -41,20 +41,18 @@ sanitize_command_list(void)
|
|||||||
sanitize_command_index(c);
|
sanitize_command_index(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* TODO: specific config checks per command
|
||||||
* TODO: specific config checks per command
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
sanitize_command_index(unsigned long c)
|
sanitize_command_index(unsigned long c)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct commands *cmd;
|
struct commands *cmd = &x->cmd[c];
|
||||||
|
|
||||||
int _flag;
|
int _flag;
|
||||||
unsigned long gbe_rw_size;
|
unsigned long gbe_rw_size;
|
||||||
|
|
||||||
cmd = &x->cmd[c];
|
|
||||||
|
|
||||||
check_command_num(c);
|
check_command_num(c);
|
||||||
|
|
||||||
if (cmd->argc < 3)
|
if (cmd->argc < 3)
|
||||||
@@ -108,7 +106,7 @@ sanitize_command_index(unsigned long c)
|
|||||||
void
|
void
|
||||||
set_cmd(int argc, char *argv[])
|
set_cmd(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
const char *cmd;
|
const char *cmd;
|
||||||
|
|
||||||
unsigned long c;
|
unsigned long c;
|
||||||
@@ -139,14 +137,10 @@ set_cmd(int argc, char *argv[])
|
|||||||
void
|
void
|
||||||
set_cmd_args(int argc, char *argv[])
|
set_cmd_args(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct commands *cmd;
|
unsigned long i = x->i;
|
||||||
struct xfile *f;
|
struct commands *cmd = &x->cmd[i];
|
||||||
unsigned long i;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
i = x->i;
|
|
||||||
cmd = &x->cmd[i];
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
if (!valid_command(i) || argc < 3)
|
if (!valid_command(i) || argc < 3)
|
||||||
usage();
|
usage();
|
||||||
@@ -191,26 +185,6 @@ conv_argv_part_num(const char *part_str)
|
|||||||
|
|
||||||
return (unsigned long)(ch - '0');
|
return (unsigned long)(ch - '0');
|
||||||
}
|
}
|
||||||
void
|
|
||||||
run_cmd(void)
|
|
||||||
{
|
|
||||||
struct xstate *x = xstatus();
|
|
||||||
unsigned long i;
|
|
||||||
void (*run)(void);
|
|
||||||
|
|
||||||
i = x->i;
|
|
||||||
run = x->cmd[i].run;
|
|
||||||
|
|
||||||
check_command_num(i);
|
|
||||||
|
|
||||||
if (run == NULL)
|
|
||||||
err(EINVAL, "Command %lu: null ptr", i);
|
|
||||||
|
|
||||||
run();
|
|
||||||
|
|
||||||
for (i = 0; i < items(x->cmd); i++)
|
|
||||||
x->cmd[i].run = cmd_helper_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
check_command_num(unsigned long c)
|
check_command_num(unsigned long c)
|
||||||
@@ -223,7 +197,7 @@ check_command_num(unsigned long c)
|
|||||||
unsigned char
|
unsigned char
|
||||||
valid_command(unsigned long c)
|
valid_command(unsigned long c)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct commands *cmd;
|
struct commands *cmd;
|
||||||
|
|
||||||
if (c >= items(x->cmd))
|
if (c >= items(x->cmd))
|
||||||
@@ -242,11 +216,10 @@ valid_command(unsigned long c)
|
|||||||
void
|
void
|
||||||
cmd_helper_setmac(void)
|
cmd_helper_setmac(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
unsigned long partnum;
|
struct macaddr *mac = &x->mac;
|
||||||
struct macaddr *mac;
|
|
||||||
|
|
||||||
mac = &x->mac;
|
unsigned long partnum;
|
||||||
|
|
||||||
check_cmd(cmd_helper_setmac, "setmac");
|
check_cmd(cmd_helper_setmac, "setmac");
|
||||||
|
|
||||||
@@ -260,13 +233,11 @@ cmd_helper_setmac(void)
|
|||||||
void
|
void
|
||||||
parse_mac_string(void)
|
parse_mac_string(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct macaddr *mac;
|
struct macaddr *mac = &x->mac;
|
||||||
|
|
||||||
unsigned long mac_byte;
|
unsigned long mac_byte;
|
||||||
|
|
||||||
mac = &x->mac;
|
|
||||||
|
|
||||||
if (xstrxlen(x->mac.str, 18) != 17)
|
if (xstrxlen(x->mac.str, 18) != 17)
|
||||||
err(EINVAL, "MAC address is the wrong length");
|
err(EINVAL, "MAC address is the wrong length");
|
||||||
|
|
||||||
@@ -285,16 +256,14 @@ parse_mac_string(void)
|
|||||||
void
|
void
|
||||||
set_mac_byte(unsigned long mac_byte_pos)
|
set_mac_byte(unsigned long mac_byte_pos)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct macaddr *mac;
|
struct macaddr *mac = &x->mac;
|
||||||
|
|
||||||
char separator;
|
char separator;
|
||||||
|
|
||||||
unsigned long mac_str_pos;
|
unsigned long mac_str_pos;
|
||||||
unsigned long mac_nib_pos;
|
unsigned long mac_nib_pos;
|
||||||
|
|
||||||
mac = &x->mac;
|
|
||||||
|
|
||||||
mac_str_pos = mac_byte_pos * 3;
|
mac_str_pos = mac_byte_pos * 3;
|
||||||
|
|
||||||
if (mac_str_pos < 15) {
|
if (mac_str_pos < 15) {
|
||||||
@@ -311,14 +280,12 @@ void
|
|||||||
set_mac_nib(unsigned long mac_str_pos,
|
set_mac_nib(unsigned long mac_str_pos,
|
||||||
unsigned long mac_byte_pos, unsigned long mac_nib_pos)
|
unsigned long mac_byte_pos, unsigned long mac_nib_pos)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct macaddr *mac;
|
struct macaddr *mac = &x->mac;
|
||||||
|
|
||||||
char mac_ch;
|
char mac_ch;
|
||||||
unsigned short hex_num;
|
unsigned short hex_num;
|
||||||
|
|
||||||
mac = &x->mac;
|
|
||||||
|
|
||||||
mac_ch = mac->str[mac_str_pos + mac_nib_pos];
|
mac_ch = mac->str[mac_str_pos + mac_nib_pos];
|
||||||
|
|
||||||
if ((hex_num = hextonum(mac_ch)) > 15)
|
if ((hex_num = hextonum(mac_ch)) > 15)
|
||||||
@@ -345,15 +312,12 @@ set_mac_nib(unsigned long mac_str_pos,
|
|||||||
void
|
void
|
||||||
write_mac_part(unsigned long partnum)
|
write_mac_part(unsigned long partnum)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
struct macaddr *mac;
|
struct macaddr *mac = &x->mac;
|
||||||
|
|
||||||
unsigned long w;
|
unsigned long w;
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
mac = &x->mac;
|
|
||||||
|
|
||||||
check_bin(partnum, "part number");
|
check_bin(partnum, "part number");
|
||||||
if (!f->part_valid[partnum])
|
if (!f->part_valid[partnum])
|
||||||
return;
|
return;
|
||||||
@@ -369,13 +333,11 @@ write_mac_part(unsigned long partnum)
|
|||||||
void
|
void
|
||||||
cmd_helper_dump(void)
|
cmd_helper_dump(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
unsigned long p;
|
unsigned long p;
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
check_cmd(cmd_helper_dump, "dump");
|
check_cmd(cmd_helper_dump, "dump");
|
||||||
|
|
||||||
f->part_valid[0] = good_checksum(0);
|
f->part_valid[0] = good_checksum(0);
|
||||||
@@ -408,10 +370,13 @@ print_mac_from_nvm(unsigned long partnum)
|
|||||||
unsigned short val16;
|
unsigned short val16;
|
||||||
|
|
||||||
for (c = 0; c < 3; c++) {
|
for (c = 0; c < 3; c++) {
|
||||||
|
|
||||||
val16 = nvm_word(c, partnum);
|
val16 = nvm_word(c, partnum);
|
||||||
|
|
||||||
printf("%02x:%02x",
|
printf("%02x:%02x",
|
||||||
(unsigned int)(val16 & 0xff),
|
(unsigned int)(val16 & 0xff),
|
||||||
(unsigned int)(val16 >> 8));
|
(unsigned int)(val16 >> 8));
|
||||||
|
|
||||||
if (c == 2)
|
if (c == 2)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
else
|
else
|
||||||
@@ -451,13 +416,11 @@ hexdump(unsigned long partnum)
|
|||||||
void
|
void
|
||||||
cmd_helper_swap(void)
|
cmd_helper_swap(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
check_cmd(cmd_helper_swap, "swap");
|
check_cmd(cmd_helper_swap, "swap");
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
x_v_memcpy(
|
x_v_memcpy(
|
||||||
f->buf + (unsigned long)GBE_WORK_SIZE,
|
f->buf + (unsigned long)GBE_WORK_SIZE,
|
||||||
f->buf,
|
f->buf,
|
||||||
@@ -480,13 +443,11 @@ cmd_helper_swap(void)
|
|||||||
void
|
void
|
||||||
cmd_helper_copy(void)
|
cmd_helper_copy(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
check_cmd(cmd_helper_copy, "copy");
|
check_cmd(cmd_helper_copy, "copy");
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
x_v_memcpy(
|
x_v_memcpy(
|
||||||
f->buf + (unsigned long)((f->part ^ 1) * GBE_PART_SIZE),
|
f->buf + (unsigned long)((f->part ^ 1) * GBE_PART_SIZE),
|
||||||
f->buf + (unsigned long)(f->part * GBE_PART_SIZE),
|
f->buf + (unsigned long)(f->part * GBE_PART_SIZE),
|
||||||
@@ -498,7 +459,8 @@ cmd_helper_copy(void)
|
|||||||
void
|
void
|
||||||
cmd_helper_cat(void)
|
cmd_helper_cat(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
|
|
||||||
check_cmd(cmd_helper_cat, "cat");
|
check_cmd(cmd_helper_cat, "cat");
|
||||||
|
|
||||||
x->cat = 0;
|
x->cat = 0;
|
||||||
@@ -508,7 +470,8 @@ cmd_helper_cat(void)
|
|||||||
void
|
void
|
||||||
cmd_helper_cat16(void)
|
cmd_helper_cat16(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
|
|
||||||
check_cmd(cmd_helper_cat16, "cat16");
|
check_cmd(cmd_helper_cat16, "cat16");
|
||||||
|
|
||||||
x->cat = 1;
|
x->cat = 1;
|
||||||
@@ -518,7 +481,8 @@ cmd_helper_cat16(void)
|
|||||||
void
|
void
|
||||||
cmd_helper_cat128(void)
|
cmd_helper_cat128(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
|
|
||||||
check_cmd(cmd_helper_cat128, "cat128");
|
check_cmd(cmd_helper_cat128, "cat128");
|
||||||
|
|
||||||
x->cat = 15;
|
x->cat = 15;
|
||||||
@@ -528,14 +492,12 @@ cmd_helper_cat128(void)
|
|||||||
void
|
void
|
||||||
cat(unsigned long nff)
|
cat(unsigned long nff)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
unsigned long p;
|
unsigned long p;
|
||||||
unsigned long ff;
|
unsigned long ff;
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
p = 0;
|
p = 0;
|
||||||
ff = 0;
|
ff = 0;
|
||||||
|
|
||||||
@@ -575,22 +537,15 @@ void
|
|||||||
check_cmd(void (*fn)(void),
|
check_cmd(void (*fn)(void),
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
unsigned long i;
|
unsigned long i = x->i;
|
||||||
|
|
||||||
if (x->cmd[x->i].run != fn)
|
if (x->cmd[i].run != fn)
|
||||||
err(ECANCELED, "Running %s, but cmd %s is set",
|
err(ECANCELED, "Running %s, but cmd %s is set",
|
||||||
name, x->cmd[x->i].str);
|
name, x->cmd[i].str);
|
||||||
|
|
||||||
/*
|
/* prevent second command
|
||||||
* 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++)
|
for (i = 0; i < items(x->cmd); i++)
|
||||||
x->cmd[i].run = cmd_helper_err;
|
x->cmd[i].run = cmd_helper_err;
|
||||||
}
|
}
|
||||||
|
|||||||
+70
-57
@@ -24,21 +24,40 @@
|
|||||||
|
|
||||||
#include "../include/common.h"
|
#include "../include/common.h"
|
||||||
|
|
||||||
/*
|
/* check that a file changed
|
||||||
* 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
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
same_file(int fd, struct stat *st_old,
|
||||||
|
int check_size)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
int saved_errno = errno;
|
||||||
|
|
||||||
|
if (st_old == NULL || fd < 0)
|
||||||
|
goto err_same_file;
|
||||||
|
|
||||||
|
if (fstat(fd, &st) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (st.st_dev != st_old->st_dev ||
|
||||||
|
st.st_ino != st_old->st_ino ||
|
||||||
|
!S_ISREG(st.st_mode))
|
||||||
|
goto err_same_file;
|
||||||
|
|
||||||
|
if (check_size &&
|
||||||
|
st.st_size != st_old->st_size)
|
||||||
|
goto err_same_file;
|
||||||
|
|
||||||
|
errno = saved_errno;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_same_file:
|
||||||
|
|
||||||
|
errno = EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xopen(int *fd_ptr, const char *path, int flags, struct stat *st)
|
xopen(int *fd_ptr, const char *path, int flags, struct stat *st)
|
||||||
{
|
{
|
||||||
@@ -55,10 +74,10 @@ xopen(int *fd_ptr, const char *path, int flags, struct stat *st)
|
|||||||
err(errno, "%s: file not seekable", path);
|
err(errno, "%s: file not seekable", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Ensure x_i_rename() is durable by syncing the
|
||||||
* Ensure rename() is durable by syncing the
|
|
||||||
* directory containing the target file.
|
* directory containing the target file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
fsync_dir(const char *path)
|
fsync_dir(const char *path)
|
||||||
{
|
{
|
||||||
@@ -165,8 +184,7 @@ err_fsync_dir:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* create new tmpfile path
|
||||||
* create new tmpfile path
|
|
||||||
*
|
*
|
||||||
* ON SUCCESS:
|
* ON SUCCESS:
|
||||||
*
|
*
|
||||||
@@ -189,14 +207,14 @@ err_fsync_dir:
|
|||||||
* if local is zero, then 3rd arg (path)
|
* if local is zero, then 3rd arg (path)
|
||||||
* is irrelevant and can be NULL
|
* is irrelevant and can be NULL
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char *
|
char *
|
||||||
new_tmpfile(int *fd, int local, const char *path)
|
new_tmpfile(int *fd, int local, const char *path)
|
||||||
{
|
{
|
||||||
unsigned long maxlen;
|
unsigned long maxlen;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
/*
|
/* please do not modify the
|
||||||
* please do not modify the
|
|
||||||
* strings or I will get mad
|
* strings or I will get mad
|
||||||
*/
|
*/
|
||||||
char tmp_none[] = "";
|
char tmp_none[] = "";
|
||||||
@@ -250,8 +268,7 @@ new_tmpfile(int *fd, int local, const char *path)
|
|||||||
if (local) {
|
if (local) {
|
||||||
base = tmp_none;
|
base = tmp_none;
|
||||||
|
|
||||||
/*
|
/* appended to filename for tmp:
|
||||||
* appended to filename for tmp:
|
|
||||||
*/
|
*/
|
||||||
tmpdir_len = xstrxlen(default_tmpname, maxlen);
|
tmpdir_len = xstrxlen(default_tmpname, maxlen);
|
||||||
} else {
|
} else {
|
||||||
@@ -270,8 +287,7 @@ new_tmpfile(int *fd, int local, const char *path)
|
|||||||
tmppath_len = tmpdir_len + tmpname_len;
|
tmppath_len = tmpdir_len + tmpname_len;
|
||||||
++tmppath_len; /* for '/' or '.' */
|
++tmppath_len; /* for '/' or '.' */
|
||||||
|
|
||||||
/*
|
/* max length -1 of maxlen
|
||||||
* max length -1 of maxlen
|
|
||||||
* for termination
|
* for termination
|
||||||
*/
|
*/
|
||||||
if (tmpdir_len > maxlen - tmpname_len - 1)
|
if (tmpdir_len > maxlen - tmpname_len - 1)
|
||||||
@@ -389,7 +405,6 @@ x_c_tmpdir(void)
|
|||||||
char *t;
|
char *t;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
t = getenv("TMPDIR");
|
|
||||||
t = getenv("TMPDIR");
|
t = getenv("TMPDIR");
|
||||||
|
|
||||||
if (t && *t) {
|
if (t && *t) {
|
||||||
@@ -409,9 +424,9 @@ x_c_tmpdir(void)
|
|||||||
return ".";
|
return ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* portable mkstemp
|
||||||
* portable mkstemp
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
x_i_mkstemp(char *template)
|
x_i_mkstemp(char *template)
|
||||||
{
|
{
|
||||||
@@ -436,7 +451,9 @@ x_i_mkstemp(char *template)
|
|||||||
for (i = 0; i < 100; i++) {
|
for (i = 0; i < 100; i++) {
|
||||||
|
|
||||||
for (j = 0; j < 6; j++) {
|
for (j = 0; j < 6; j++) {
|
||||||
|
|
||||||
r = rlong();
|
r = rlong();
|
||||||
|
|
||||||
p[j] = ch[(unsigned long)(r >> 1) % (sizeof(ch) - 1)];
|
p[j] = ch[(unsigned long)(r >> 1) % (sizeof(ch) - 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,8 +483,7 @@ x_i_mkstemp(char *template)
|
|||||||
* EINTR/EAGAIN looping is done indefinitely.
|
* EINTR/EAGAIN looping is done indefinitely.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/* rw_file_exact() - Read perfectly or die
|
||||||
* rw_file_exact() - Read perfectly or die
|
|
||||||
*
|
*
|
||||||
* Read/write, and absolutely insist on an
|
* Read/write, and absolutely insist on an
|
||||||
* absolute read; e.g. if 100 bytes are
|
* absolute read; e.g. if 100 bytes are
|
||||||
@@ -483,6 +499,7 @@ x_i_mkstemp(char *template)
|
|||||||
* times upon zero-return, to recover,
|
* times upon zero-return, to recover,
|
||||||
* otherwise it will return an error.
|
* otherwise it will return an error.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
long
|
long
|
||||||
rw_file_exact(int fd, unsigned char *mem, unsigned long nrw,
|
rw_file_exact(int fd, unsigned char *mem, unsigned long nrw,
|
||||||
off_t off, int rw_type, int loop_eagain,
|
off_t off, int rw_type, int loop_eagain,
|
||||||
@@ -549,8 +566,7 @@ err_rw_file_exact:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* prw() - portable read-write
|
||||||
* prw() - portable read-write
|
|
||||||
*
|
*
|
||||||
* This implements a portable analog of pwrite()
|
* This implements a portable analog of pwrite()
|
||||||
* and pread() - note that this version is not
|
* and pread() - note that this version is not
|
||||||
@@ -809,19 +825,17 @@ err_is_file:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Check weirdness on buggy libc.
|
||||||
* Check overflows caused by buggy libc.
|
|
||||||
*
|
*
|
||||||
* POSIX can say whatever it wants.
|
* POSIX can say whatever it wants.
|
||||||
* specification != implementation
|
* specification != implementation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
long
|
long
|
||||||
rw_over_nrw(long r, unsigned long nrw)
|
rw_over_nrw(long r, unsigned long nrw)
|
||||||
{
|
{
|
||||||
/*
|
/* not a libc bug, but we
|
||||||
* If a byte length of zero
|
* don't like the number zero
|
||||||
* was requested, that is
|
|
||||||
* clearly a bug. No way.
|
|
||||||
*/
|
*/
|
||||||
if (!nrw)
|
if (!nrw)
|
||||||
goto err_rw_over_nrw;
|
goto err_rw_over_nrw;
|
||||||
@@ -832,8 +846,7 @@ rw_over_nrw(long r, unsigned long nrw)
|
|||||||
if ((unsigned long)
|
if ((unsigned long)
|
||||||
r > X_LONG_MAX) {
|
r > X_LONG_MAX) {
|
||||||
|
|
||||||
/*
|
/* Theoretical buggy libc
|
||||||
* Theoretical buggy libc
|
|
||||||
* check. Extremely academic.
|
* check. Extremely academic.
|
||||||
*
|
*
|
||||||
* Specifications never
|
* Specifications never
|
||||||
@@ -843,12 +856,16 @@ rw_over_nrw(long r, unsigned long nrw)
|
|||||||
*
|
*
|
||||||
* Check this after using
|
* Check this after using
|
||||||
* [p]read() or [p]write()
|
* [p]read() or [p]write()
|
||||||
|
*
|
||||||
|
* NOTE: here, we assume
|
||||||
|
* long integers are the
|
||||||
|
* same size as SSIZE_T
|
||||||
*/
|
*/
|
||||||
|
|
||||||
goto err_rw_over_nrw;
|
goto err_rw_over_nrw;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Theoretical buggy libc:
|
||||||
* Theoretical buggy libc:
|
|
||||||
* Should never return a number of
|
* Should never return a number of
|
||||||
* bytes above the requested length.
|
* bytes above the requested length.
|
||||||
*/
|
*/
|
||||||
@@ -888,35 +905,31 @@ lseek_loop(int fd, off_t off, int whence,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* If a given error loop is enabled,
|
|
||||||
* e.g. EINTR or EAGAIN, an I/O operation
|
|
||||||
* will loop until errno isn't -1 and one
|
|
||||||
* of these, e.g. -1 and EINTR
|
|
||||||
*/
|
|
||||||
int
|
int
|
||||||
try_err(int loop_err, int errval)
|
try_err(int loop_err, int errval)
|
||||||
{
|
{
|
||||||
if (loop_err)
|
if (loop_err)
|
||||||
return errval;
|
return errval;
|
||||||
|
|
||||||
/* errno is never negative,
|
|
||||||
so functions checking it
|
|
||||||
can use it accordingly */
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* portable rename(). WARNING:
|
||||||
* non-atomic rename
|
* not powercut-safe. do this to
|
||||||
|
* use system rename:
|
||||||
|
* #define SYS_RENAME 1
|
||||||
*
|
*
|
||||||
* commented because i can't sacrifice
|
* written academically, but in reality,
|
||||||
* exactly this property. nvmutil tries
|
* nearly all unix systems have rename()
|
||||||
* to protect files against e.g. power loss
|
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
int
|
int
|
||||||
x_i_rename(const char *src, const char *dst)
|
x_i_rename(const char *src, const char *dst)
|
||||||
{
|
{
|
||||||
|
#if defined(SYS_RENAME) &&\
|
||||||
|
SYS_RENAME > 0
|
||||||
|
return rename(src, dst);
|
||||||
|
#else
|
||||||
int sfd, dirfd;
|
int sfd, dirfd;
|
||||||
ssize_t r;
|
ssize_t r;
|
||||||
char buf[8192];
|
char buf[8192];
|
||||||
@@ -955,8 +968,8 @@ x_i_rename(const char *src, const char *dst)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
int
|
||||||
x_i_close(int fd)
|
x_i_close(int fd)
|
||||||
|
|||||||
+55
-144
@@ -3,8 +3,6 @@
|
|||||||
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
|
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
|
||||||
*
|
*
|
||||||
* I/O functions specific to nvmutil.
|
* I/O functions specific to nvmutil.
|
||||||
*
|
|
||||||
* Related: file.c
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
@@ -29,30 +27,22 @@
|
|||||||
void
|
void
|
||||||
open_gbe_file(void)
|
open_gbe_file(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct commands *cmd;
|
struct commands *cmd = &x->cmd[x->i];
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
struct stat _st;
|
|
||||||
int _flags;
|
int _flags;
|
||||||
|
|
||||||
cmd = &x->cmd[x->i];
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
xopen(&f->gbe_fd, f->fname,
|
xopen(&f->gbe_fd, f->fname,
|
||||||
cmd->flags | O_BINARY |
|
cmd->flags | O_BINARY |
|
||||||
O_NOFOLLOW | O_CLOEXEC, &_st);
|
O_NOFOLLOW | O_CLOEXEC, &f->gbe_st);
|
||||||
|
|
||||||
/* inode will be checked later on write */
|
if (f->gbe_st.st_nlink > 1)
|
||||||
f->gbe_dev = _st.st_dev;
|
|
||||||
f->gbe_ino = _st.st_ino;
|
|
||||||
|
|
||||||
if (_st.st_nlink > 1)
|
|
||||||
err(EINVAL,
|
err(EINVAL,
|
||||||
"%s: warning: file has multiple (%lu) hard links\n",
|
"%s: warning: file has multiple (%lu) hard links\n",
|
||||||
f->fname, (unsigned long)_st.st_nlink);
|
f->fname, (unsigned long)f->gbe_st.st_nlink);
|
||||||
|
|
||||||
if (_st.st_nlink == 0)
|
if (f->gbe_st.st_nlink == 0)
|
||||||
err(EIO, "%s: file unlinked while open", f->fname);
|
err(EIO, "%s: file unlinked while open", f->fname);
|
||||||
|
|
||||||
_flags = fcntl(f->gbe_fd, F_GETFL);
|
_flags = fcntl(f->gbe_fd, F_GETFL);
|
||||||
@@ -68,7 +58,7 @@ open_gbe_file(void)
|
|||||||
if (_flags & O_APPEND)
|
if (_flags & O_APPEND)
|
||||||
err(EIO, "%s: O_APPEND flag", f->fname);
|
err(EIO, "%s: O_APPEND flag", f->fname);
|
||||||
|
|
||||||
f->gbe_file_size = _st.st_size;
|
f->gbe_file_size = f->gbe_st.st_size;
|
||||||
|
|
||||||
switch (f->gbe_file_size) {
|
switch (f->gbe_file_size) {
|
||||||
case SIZE_8KB:
|
case SIZE_8KB:
|
||||||
@@ -83,37 +73,14 @@ open_gbe_file(void)
|
|||||||
err(errno, "%s: can't lock", f->fname);
|
err(errno, "%s: can't lock", f->fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* We copy the entire gbe file
|
|
||||||
* to the tmpfile, and then we
|
|
||||||
* work on that. We copy back
|
|
||||||
* afterward. this is the copy.
|
|
||||||
*
|
|
||||||
* we copy to tmpfile even on
|
|
||||||
* read-only commands, for the
|
|
||||||
* double-read verification,
|
|
||||||
* which also benefits cmd_cat.
|
|
||||||
*/
|
|
||||||
void
|
void
|
||||||
copy_gbe(void)
|
copy_gbe(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
read_file();
|
read_file();
|
||||||
|
|
||||||
/*
|
|
||||||
regular operations post-read operate only on the first
|
|
||||||
8KB, because each GbE part is the first 4KB of each
|
|
||||||
half of the file.
|
|
||||||
|
|
||||||
we no longer care about anything past 8KB, until we get
|
|
||||||
to writing, at which point we will flush the buffer
|
|
||||||
again
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (f->gbe_file_size == SIZE_8KB)
|
if (f->gbe_file_size == SIZE_8KB)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -125,15 +92,14 @@ copy_gbe(void)
|
|||||||
void
|
void
|
||||||
read_file(void)
|
read_file(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
struct stat _st;
|
struct stat _st;
|
||||||
long _r;
|
long _r;
|
||||||
|
|
||||||
f = &x->f;
|
/* read main file
|
||||||
|
*/
|
||||||
/* read main file */
|
|
||||||
_r = rw_file_exact(f->gbe_fd, f->buf, f->gbe_file_size,
|
_r = rw_file_exact(f->gbe_fd, f->buf, f->gbe_file_size,
|
||||||
0, IO_PREAD, NO_LOOP_EAGAIN, LOOP_EINTR,
|
0, IO_PREAD, NO_LOOP_EAGAIN, LOOP_EINTR,
|
||||||
MAX_ZERO_RW_RETRY, OFF_ERR);
|
MAX_ZERO_RW_RETRY, OFF_ERR);
|
||||||
@@ -141,8 +107,8 @@ read_file(void)
|
|||||||
if (_r < 0)
|
if (_r < 0)
|
||||||
err(errno, "%s: read failed", f->fname);
|
err(errno, "%s: read failed", f->fname);
|
||||||
|
|
||||||
/* copy to tmpfile */
|
/* copy to tmpfile
|
||||||
|
*/
|
||||||
_r = rw_file_exact(f->tmp_fd, f->buf, f->gbe_file_size,
|
_r = rw_file_exact(f->tmp_fd, f->buf, f->gbe_file_size,
|
||||||
0, IO_PWRITE, NO_LOOP_EAGAIN, LOOP_EINTR,
|
0, IO_PWRITE, NO_LOOP_EAGAIN, LOOP_EINTR,
|
||||||
MAX_ZERO_RW_RETRY, OFF_ERR);
|
MAX_ZERO_RW_RETRY, OFF_ERR);
|
||||||
@@ -151,10 +117,8 @@ read_file(void)
|
|||||||
err(errno, "%s: %s: copy failed",
|
err(errno, "%s: %s: copy failed",
|
||||||
f->fname, f->tname);
|
f->fname, f->tname);
|
||||||
|
|
||||||
/*
|
/* file size comparison
|
||||||
* file size comparison
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (fstat(f->tmp_fd, &_st) == -1)
|
if (fstat(f->tmp_fd, &_st) == -1)
|
||||||
err(errno, "%s: stat", f->tname);
|
err(errno, "%s: stat", f->tname);
|
||||||
|
|
||||||
@@ -164,9 +128,7 @@ read_file(void)
|
|||||||
err(EIO, "%s: %s: not the same size",
|
err(EIO, "%s: %s: not the same size",
|
||||||
f->fname, f->tname);
|
f->fname, f->tname);
|
||||||
|
|
||||||
/*
|
/* needs sync, for verification
|
||||||
* fsync tmp gbe file, because we will compare
|
|
||||||
* its contents to what was read (for safety)
|
|
||||||
*/
|
*/
|
||||||
if (x_i_fsync(f->tmp_fd) == -1)
|
if (x_i_fsync(f->tmp_fd) == -1)
|
||||||
err(errno, "%s: fsync (tmpfile copy)", f->tname);
|
err(errno, "%s: fsync (tmpfile copy)", f->tname);
|
||||||
@@ -182,42 +144,25 @@ read_file(void)
|
|||||||
err(errno, "%s: %s: read contents differ (pre-test)",
|
err(errno, "%s: %s: read contents differ (pre-test)",
|
||||||
f->fname, f->tname);
|
f->fname, f->tname);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
write_gbe_file(void)
|
write_gbe_file(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct commands *cmd;
|
struct commands *cmd = &x->cmd[x->i];
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
struct stat _gbe_st;
|
|
||||||
struct stat _tmp_st;
|
|
||||||
|
|
||||||
unsigned long p;
|
unsigned long p;
|
||||||
unsigned char update_checksum;
|
unsigned char update_checksum;
|
||||||
|
|
||||||
cmd = &x->cmd[x->i];
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
if ((cmd->flags & O_ACCMODE) == O_RDONLY)
|
if ((cmd->flags & O_ACCMODE) == O_RDONLY)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fstat(f->gbe_fd, &_gbe_st) == -1)
|
if (same_file(f->tmp_fd, &f->tmp_st, 0) < 0)
|
||||||
err(errno, "%s: re-check", f->fname);
|
err(errno, "%s: file inode/device changed", f->tname);
|
||||||
if (_gbe_st.st_dev != f->gbe_dev || _gbe_st.st_ino != f->gbe_ino)
|
|
||||||
err(EIO, "%s: file replaced while open", f->fname);
|
|
||||||
if (_gbe_st.st_size != f->gbe_file_size)
|
|
||||||
err(errno, "%s: file size changed before write", f->fname);
|
|
||||||
if (!S_ISREG(_gbe_st.st_mode))
|
|
||||||
err(errno, "%s: file type changed before write", f->fname);
|
|
||||||
|
|
||||||
if (fstat(f->tmp_fd, &_tmp_st) == -1)
|
if (same_file(f->gbe_fd, &f->gbe_st, 1) < 0)
|
||||||
err(errno, "%s: re-check", f->tname);
|
err(errno, "%s: file has changed", f->fname);
|
||||||
if (_tmp_st.st_dev != f->tmp_dev || _tmp_st.st_ino != f->tmp_ino)
|
|
||||||
err(EIO, "%s: file replaced while open", f->tname);
|
|
||||||
if (_tmp_st.st_size != f->gbe_file_size)
|
|
||||||
err(errno, "%s: file size changed before write", f->tname);
|
|
||||||
if (!S_ISREG(_tmp_st.st_mode))
|
|
||||||
err(errno, "%s: file type changed before write", f->tname);
|
|
||||||
|
|
||||||
update_checksum = cmd->chksum_write;
|
update_checksum = cmd->chksum_write;
|
||||||
|
|
||||||
@@ -236,9 +181,9 @@ void
|
|||||||
rw_gbe_file_part(unsigned long p, int rw_type,
|
rw_gbe_file_part(unsigned long p, int rw_type,
|
||||||
const char *rw_type_str)
|
const char *rw_type_str)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct commands *cmd;
|
struct commands *cmd = &x->cmd[x->i];
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
long rval;
|
long rval;
|
||||||
|
|
||||||
@@ -247,9 +192,6 @@ rw_gbe_file_part(unsigned long p, int rw_type,
|
|||||||
unsigned long gbe_rw_size;
|
unsigned long gbe_rw_size;
|
||||||
unsigned char *mem_offset;
|
unsigned char *mem_offset;
|
||||||
|
|
||||||
cmd = &x->cmd[x->i];
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
gbe_rw_size = cmd->rw_size;
|
gbe_rw_size = cmd->rw_size;
|
||||||
|
|
||||||
if (rw_type < IO_PREAD || rw_type > IO_PWRITE)
|
if (rw_type < IO_PREAD || rw_type > IO_PWRITE)
|
||||||
@@ -274,16 +216,13 @@ rw_gbe_file_part(unsigned long p, int rw_type,
|
|||||||
void
|
void
|
||||||
write_to_gbe_bin(void)
|
write_to_gbe_bin(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct commands *cmd;
|
struct commands *cmd = &x->cmd[x->i];
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
int saved_errno;
|
int saved_errno;
|
||||||
int mv;
|
int mv;
|
||||||
|
|
||||||
cmd = &x->cmd[x->i];
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
if ((cmd->flags & O_ACCMODE) != O_RDWR)
|
if ((cmd->flags & O_ACCMODE) != O_RDWR)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -338,11 +277,9 @@ write_to_gbe_bin(void)
|
|||||||
fprintf(stderr, "%s: %s\n",
|
fprintf(stderr, "%s: %s\n",
|
||||||
f->fname, strerror(errno));
|
f->fname, strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
/*
|
|
||||||
* tmpfile removed
|
|
||||||
* by the rename
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
/* removed by rename
|
||||||
|
*/
|
||||||
if (f->tname != NULL)
|
if (f->tname != NULL)
|
||||||
free(f->tname);
|
free(f->tname);
|
||||||
|
|
||||||
@@ -350,12 +287,6 @@ write_to_gbe_bin(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* finally:
|
|
||||||
* must sync to disk!
|
|
||||||
* very nearly done
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!f->io_err_gbe_bin)
|
if (!f->io_err_gbe_bin)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -369,9 +300,9 @@ write_to_gbe_bin(void)
|
|||||||
void
|
void
|
||||||
check_written_part(unsigned long p)
|
check_written_part(unsigned long p)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct commands *cmd;
|
struct commands *cmd = &x->cmd[x->i];
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
long rval;
|
long rval;
|
||||||
|
|
||||||
@@ -380,12 +311,8 @@ check_written_part(unsigned long p)
|
|||||||
off_t file_offset;
|
off_t file_offset;
|
||||||
unsigned char *mem_offset;
|
unsigned char *mem_offset;
|
||||||
|
|
||||||
struct stat st;
|
|
||||||
unsigned char *buf_restore;
|
unsigned char *buf_restore;
|
||||||
|
|
||||||
cmd = &x->cmd[x->i];
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
if (!f->part_modified[p])
|
if (!f->part_modified[p])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -396,15 +323,11 @@ check_written_part(unsigned long p)
|
|||||||
|
|
||||||
memset(f->pad, 0xff, sizeof(f->pad));
|
memset(f->pad, 0xff, sizeof(f->pad));
|
||||||
|
|
||||||
if (fstat(f->gbe_fd, &st) == -1)
|
if (same_file(f->tmp_fd, &f->tmp_st, 0) < 0)
|
||||||
err(errno, "%s: fstat (post-write)", f->fname);
|
err(errno, "%s: file inode/device changed", f->tname);
|
||||||
if (st.st_dev != f->gbe_dev || st.st_ino != f->gbe_ino)
|
|
||||||
err(EIO, "%s: file changed during write", f->fname);
|
|
||||||
|
|
||||||
if (fstat(f->tmp_fd, &st) == -1)
|
if (same_file(f->gbe_fd, &f->gbe_st, 1) < 0)
|
||||||
err(errno, "%s: fstat (post-write)", f->tname);
|
err(errno, "%s: file changed during write", f->fname);
|
||||||
if (st.st_dev != f->tmp_dev || st.st_ino != f->tmp_ino)
|
|
||||||
err(EIO, "%s: file changed during write", f->tname);
|
|
||||||
|
|
||||||
rval = 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);
|
gbe_rw_size, file_offset, IO_PREAD);
|
||||||
@@ -442,13 +365,11 @@ check_written_part(unsigned long p)
|
|||||||
void
|
void
|
||||||
report_io_err_rw(void)
|
report_io_err_rw(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
unsigned long p;
|
unsigned long p;
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
if (!f->io_err_gbe)
|
if (!f->io_err_gbe)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -500,8 +421,8 @@ report_io_err_rw(void)
|
|||||||
int
|
int
|
||||||
gbe_mv(void)
|
gbe_mv(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
int rval;
|
int rval;
|
||||||
|
|
||||||
@@ -511,8 +432,6 @@ gbe_mv(void)
|
|||||||
char *dest_tmp;
|
char *dest_tmp;
|
||||||
int dest_fd;
|
int dest_fd;
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
/* will be set 0 if it doesn't */
|
/* will be set 0 if it doesn't */
|
||||||
tmp_gbe_bin_exists = 1;
|
tmp_gbe_bin_exists = 1;
|
||||||
|
|
||||||
@@ -521,7 +440,7 @@ gbe_mv(void)
|
|||||||
|
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
|
|
||||||
rval = rename(f->tname, f->fname);
|
rval = x_i_rename(f->tname, f->fname);
|
||||||
|
|
||||||
if (rval > -1) {
|
if (rval > -1) {
|
||||||
/*
|
/*
|
||||||
@@ -576,7 +495,7 @@ gbe_mv(void)
|
|||||||
if (x_i_close(dest_fd) == -1)
|
if (x_i_close(dest_fd) == -1)
|
||||||
goto ret_gbe_mv;
|
goto ret_gbe_mv;
|
||||||
|
|
||||||
if (rename(dest_tmp, f->fname) == -1)
|
if (x_i_rename(dest_tmp, f->fname) == -1)
|
||||||
goto ret_gbe_mv;
|
goto ret_gbe_mv;
|
||||||
|
|
||||||
if (fsync_dir(f->fname) < 0) {
|
if (fsync_dir(f->fname) < 0) {
|
||||||
@@ -640,13 +559,11 @@ ret_gbe_mv:
|
|||||||
unsigned char *
|
unsigned char *
|
||||||
gbe_mem_offset(unsigned long p, const char *f_op)
|
gbe_mem_offset(unsigned long p, const char *f_op)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
off_t gbe_off;
|
off_t gbe_off;
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
gbe_off = gbe_x_offset(p, f_op, "mem",
|
gbe_off = gbe_x_offset(p, f_op, "mem",
|
||||||
GBE_PART_SIZE, GBE_WORK_SIZE);
|
GBE_PART_SIZE, GBE_WORK_SIZE);
|
||||||
|
|
||||||
@@ -664,13 +581,11 @@ gbe_mem_offset(unsigned long p, const char *f_op)
|
|||||||
off_t
|
off_t
|
||||||
gbe_file_offset(unsigned long p, const char *f_op)
|
gbe_file_offset(unsigned long p, const char *f_op)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
off_t gbe_file_half_size;
|
off_t gbe_file_half_size;
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
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",
|
return gbe_x_offset(p, f_op, "file",
|
||||||
@@ -681,15 +596,13 @@ off_t
|
|||||||
gbe_x_offset(unsigned long p, const char *f_op, const char *d_type,
|
gbe_x_offset(unsigned long p, const char *f_op, const char *d_type,
|
||||||
off_t nsize, off_t ncmp)
|
off_t nsize, off_t ncmp)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
off_t off;
|
off_t off;
|
||||||
|
|
||||||
check_bin(p, "part number");
|
check_bin(p, "part number");
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
off = ((off_t)p) * (off_t)nsize;
|
off = ((off_t)p) * (off_t)nsize;
|
||||||
|
|
||||||
if (off > ncmp - GBE_PART_SIZE)
|
if (off > ncmp - GBE_PART_SIZE)
|
||||||
@@ -707,13 +620,11 @@ long
|
|||||||
rw_gbe_file_exact(int fd, unsigned char *mem, unsigned long nrw,
|
rw_gbe_file_exact(int fd, unsigned char *mem, unsigned long nrw,
|
||||||
off_t off, int rw_type)
|
off_t off, int rw_type)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
long r;
|
long r;
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
if (io_args(fd, mem, nrw, off, rw_type) == -1)
|
if (io_args(fd, mem, nrw, off, rw_type) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|||||||
@@ -45,9 +45,7 @@ hextonum(char ch_s)
|
|||||||
return 16; /* invalid character */
|
return 16; /* invalid character */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Random numbers
|
||||||
* Portable random
|
|
||||||
* number generator
|
|
||||||
*/
|
*/
|
||||||
unsigned long
|
unsigned long
|
||||||
rlong(void)
|
rlong(void)
|
||||||
|
|||||||
+147
-49
@@ -5,13 +5,6 @@
|
|||||||
* This tool lets you modify Intel GbE NVM (Gigabit Ethernet
|
* This tool lets you modify Intel GbE NVM (Gigabit Ethernet
|
||||||
* Non-Volatile Memory) images, e.g. change the MAC address.
|
* Non-Volatile Memory) images, e.g. change the MAC address.
|
||||||
* These images configure your Intel Gigabit Ethernet adapter.
|
* These images configure your Intel Gigabit Ethernet adapter.
|
||||||
*
|
|
||||||
* This code is designed to be portable, running on as many
|
|
||||||
* Unix and Unix-like systems as possible (mainly BSD/Linux).
|
|
||||||
*
|
|
||||||
* Recommended CFLAGS for Clang/GCC:
|
|
||||||
*
|
|
||||||
* -Os -Wall -Wextra -Werror -pedantic -std=c90
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
@@ -34,40 +27,16 @@
|
|||||||
#include "../include/common.h"
|
#include "../include/common.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Program state/command table
|
* Initialise program state,
|
||||||
* Default config stored here,
|
* load GbE file and verify
|
||||||
* and copied to a newly allocated
|
* data, ready for operation
|
||||||
* buffer in memory, then the pointer
|
* (singleton design)
|
||||||
* 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 *
|
struct xstate *
|
||||||
xstatus(void)
|
xstatus(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
static int first_run = 1;
|
|
||||||
|
|
||||||
static struct xstate us = {
|
static struct xstate us = {
|
||||||
/* .cmd (update cmd[] in the struct if adding to it)
|
/* DO NOT MESS THIS UP, OR THERE WILL BE DEMONS */
|
||||||
DO NOT FORGET. or C will init zeroes/NULLs */
|
|
||||||
|
|
||||||
/* cmd[] members */
|
|
||||||
/* DO NOT MESS THIS UP */
|
|
||||||
/* items must be set *exactly* */
|
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
CMD_DUMP, "dump", cmd_helper_dump, ARGC_3,
|
CMD_DUMP, "dump", cmd_helper_dump, ARGC_3,
|
||||||
@@ -122,36 +91,165 @@ xstatus(void)
|
|||||||
/* .no_cmd (set 0 when a command is found) */
|
/* .no_cmd (set 0 when a command is found) */
|
||||||
1,
|
1,
|
||||||
|
|
||||||
/* .xsize (size of the stuct will be stored here later) */
|
|
||||||
0,
|
|
||||||
|
|
||||||
/* .cat (cat helpers set this) */
|
/* .cat (cat helpers set this) */
|
||||||
-1
|
-1
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int first_run = 1;
|
||||||
|
|
||||||
if (!first_run)
|
if (!first_run)
|
||||||
return &us;
|
return &us;
|
||||||
|
|
||||||
first_run = 0;
|
|
||||||
|
|
||||||
us.xsize = sizeof(us);
|
|
||||||
|
|
||||||
us.f.buf = us.f.real_buf;
|
us.f.buf = us.f.real_buf;
|
||||||
|
|
||||||
us.f.gbe_fd = -1;
|
first_run = 0;
|
||||||
us.f.tmp_fd = -1;
|
us.argv0 = argv[0];
|
||||||
|
|
||||||
us.f.tname = NULL;
|
if (argc > 1)
|
||||||
us.f.fname = NULL;
|
us.f.fname = argv[1];
|
||||||
|
|
||||||
|
if (argc < 3)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
/* https://man.openbsd.org/pledge.2
|
||||||
|
https://man.openbsd.org/unveil.2 */
|
||||||
|
#if defined(__OpenBSD__) && defined(OpenBSD)
|
||||||
|
#if (OpenBSD) >= 604
|
||||||
|
if (pledge("stdio flock rpath wpath cpath unveil", NULL) == -1)
|
||||||
|
err(errno, "pledge plus unveil");
|
||||||
|
#elif (OpenBSD) >= 509
|
||||||
|
if (pledge("stdio flock rpath wpath cpath", NULL) == -1)
|
||||||
|
err(errno, "pledge");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
#if defined(__OpenBSD__) && defined(OpenBSD) && \
|
||||||
|
(OpenBSD) >= 604
|
||||||
|
/* can only use local tmp on openbsd, due to unveil */
|
||||||
|
us.f.tname = new_tmpfile(&us.f.tmp_fd, 1, NULL);
|
||||||
|
#else
|
||||||
|
us.f.tname = new_tmpfile(&us.f.tmp_fd, 0, NULL);
|
||||||
|
#endif
|
||||||
|
if (us.f.tname == NULL)
|
||||||
|
err(errno, "Can't create tmpfile");
|
||||||
|
if (*us.f.tname == '\0')
|
||||||
|
err(errno, "tmp dir is an empty string");
|
||||||
|
|
||||||
|
#if defined(__OpenBSD__) && defined(OpenBSD) && \
|
||||||
|
OpenBSD >= 604
|
||||||
|
if (unveil(f->tname, "rwc") == -1)
|
||||||
|
err(errno, "unveil rwc: %s", f->tname);
|
||||||
|
#endif
|
||||||
|
if (fstat(us.f.tmp_fd, &us.f.tmp_st) < 0)
|
||||||
|
err(errno, "%s: stat", us.f.tname);
|
||||||
|
|
||||||
|
sanitize_command_list();
|
||||||
|
|
||||||
|
/* parse user command */
|
||||||
|
set_cmd(argc, argv);
|
||||||
|
set_cmd_args(argc, argv);
|
||||||
|
|
||||||
|
#if defined(__OpenBSD__) && defined(OpenBSD) && \
|
||||||
|
(OpenBSD) >= 604
|
||||||
|
if ((us.cmd[i].flags & O_ACCMODE) == O_RDONLY) {
|
||||||
|
if (unveil(us.f.fname, "r") == -1)
|
||||||
|
err(errno, "%s: unveil r", us.f.fname);
|
||||||
|
} else {
|
||||||
|
if (unveil(us.f.fname, "rwc") == -1)
|
||||||
|
err(errno, "%s: unveil rw", us.f.tname);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unveil(us.f.tname, "rwc") == -1)
|
||||||
|
err(errno, "%s: unveil rwc", us.f.tname);
|
||||||
|
|
||||||
|
if (unveil(NULL, NULL) == -1)
|
||||||
|
err(errno, "unveil block (rw)");
|
||||||
|
|
||||||
|
if (pledge("stdio flock rpath wpath cpath", NULL) == -1)
|
||||||
|
err(errno, "pledge (kill unveil)");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
open_gbe_file();
|
||||||
|
|
||||||
|
memset(us.f.real_buf, 0, sizeof(us.f.real_buf));
|
||||||
|
memset(us.f.bufcmp, 0, sizeof(us.f.bufcmp));
|
||||||
|
|
||||||
|
/* for good measure */
|
||||||
|
memset(us.f.pad, 0, sizeof(us.f.pad));
|
||||||
|
|
||||||
|
copy_gbe();
|
||||||
|
read_checksums();
|
||||||
|
|
||||||
return &us;
|
return &us;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
err(int nvm_errval, const char *msg, ...)
|
||||||
|
{
|
||||||
|
struct xstate *x = xstatus(0, NULL);
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
if (errno == 0)
|
||||||
|
errno = nvm_errval;
|
||||||
|
if (!errno)
|
||||||
|
errno = ECANCELED;
|
||||||
|
|
||||||
|
(void)exit_cleanup();
|
||||||
|
|
||||||
|
if (x != NULL)
|
||||||
|
fprintf(stderr, "%s: ", getnvmprogname());
|
||||||
|
|
||||||
|
va_start(args, msg);
|
||||||
|
vfprintf(stderr, msg, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
fprintf(stderr, ": %s\n", strerror(errno));
|
||||||
|
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
getnvmprogname(void)
|
||||||
|
{
|
||||||
|
struct xstate *x = xstatus(0, NULL);
|
||||||
|
|
||||||
|
const char *p;
|
||||||
|
static char fallback[] = "nvmutil";
|
||||||
|
|
||||||
|
char *rval = fallback;
|
||||||
|
|
||||||
|
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 rval;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
exit_cleanup(void)
|
exit_cleanup(void)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f;
|
||||||
|
|
||||||
int close_err;
|
int close_err;
|
||||||
|
|||||||
@@ -93,67 +93,14 @@ xstrxlen(const char *scmp, unsigned long maxlen)
|
|||||||
return xstr_index;
|
return xstr_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
err(int nvm_errval, const char *msg, ...)
|
|
||||||
{
|
|
||||||
struct xstate *x = xstatus();
|
|
||||||
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
if (errno == 0)
|
|
||||||
errno = nvm_errval;
|
|
||||||
if (!errno)
|
|
||||||
errno = ECANCELED;
|
|
||||||
|
|
||||||
(void)exit_cleanup();
|
|
||||||
|
|
||||||
if (x != NULL)
|
|
||||||
fprintf(stderr, "%s: ", getnvmprogname());
|
|
||||||
|
|
||||||
va_start(args, msg);
|
|
||||||
vfprintf(stderr, msg, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
fprintf(stderr, ": %s\n", strerror(errno));
|
|
||||||
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *
|
|
||||||
getnvmprogname(void)
|
|
||||||
{
|
|
||||||
struct xstate *x = xstatus();
|
|
||||||
|
|
||||||
const char *p;
|
|
||||||
static char fallback[] = "nvmutil";
|
|
||||||
|
|
||||||
char *rval = fallback;
|
|
||||||
|
|
||||||
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 rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
char *
|
||||||
x_c_strrchr(const char *s, int c)
|
x_c_strrchr(const char *s, int c)
|
||||||
{
|
{
|
||||||
const char *p = NULL;
|
const char *p = NULL;
|
||||||
|
|
||||||
while (*s) {
|
for ( ; *s; s++)
|
||||||
if (*s == (char)c)
|
if (*s == (char)c)
|
||||||
p = s;
|
p = s;
|
||||||
s++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '\0')
|
if (c == '\0')
|
||||||
return (char *)s;
|
return (char *)s;
|
||||||
|
|||||||
+8
-18
@@ -29,20 +29,17 @@
|
|||||||
* GbE NVM files store 16-bit (2-byte) little-endian words.
|
* GbE NVM files store 16-bit (2-byte) little-endian words.
|
||||||
* We must therefore swap the order when reading or writing.
|
* We must therefore swap the order when reading or writing.
|
||||||
*
|
*
|
||||||
* NOTE: The MAC address words are stored big-endian in the
|
* NOTE: The MAC address words are stored big-endian in-file.
|
||||||
* file, but we assume otherwise and adapt accordingly.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned short
|
unsigned short
|
||||||
nvm_word(unsigned long pos16, unsigned long p)
|
nvm_word(unsigned long pos16, unsigned long p)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
unsigned long pos;
|
unsigned long pos;
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
check_nvm_bound(pos16, p);
|
check_nvm_bound(pos16, p);
|
||||||
pos = (pos16 << 1) + (p * GBE_PART_SIZE);
|
pos = (pos16 << 1) + (p * GBE_PART_SIZE);
|
||||||
|
|
||||||
@@ -53,13 +50,11 @@ nvm_word(unsigned long pos16, unsigned long p)
|
|||||||
void
|
void
|
||||||
set_nvm_word(unsigned long pos16, unsigned long p, unsigned short val16)
|
set_nvm_word(unsigned long pos16, unsigned long p, unsigned short val16)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
unsigned long pos;
|
unsigned long pos;
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
check_nvm_bound(pos16, p);
|
check_nvm_bound(pos16, p);
|
||||||
pos = (pos16 << 1) + (p * GBE_PART_SIZE);
|
pos = (pos16 << 1) + (p * GBE_PART_SIZE);
|
||||||
|
|
||||||
@@ -72,10 +67,8 @@ set_nvm_word(unsigned long pos16, unsigned long p, unsigned short val16)
|
|||||||
void
|
void
|
||||||
set_part_modified(unsigned long p)
|
set_part_modified(unsigned long p)
|
||||||
{
|
{
|
||||||
struct xstate *x = xstatus();
|
struct xstate *x = xstatus(0, NULL);
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
|
|
||||||
f = &x->f;
|
|
||||||
|
|
||||||
check_bin(p, "part number");
|
check_bin(p, "part number");
|
||||||
f->part_modified[p] = 1;
|
f->part_modified[p] = 1;
|
||||||
@@ -84,10 +77,7 @@ set_part_modified(unsigned long p)
|
|||||||
void
|
void
|
||||||
check_nvm_bound(unsigned long c, unsigned long p)
|
check_nvm_bound(unsigned long c, unsigned long p)
|
||||||
{
|
{
|
||||||
/*
|
/* Block out of bound NVM access
|
||||||
* NVM_SIZE assumed as the limit, because this
|
|
||||||
* current design assumes that we will only
|
|
||||||
* ever modified the NVM area.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
check_bin(p, "part number");
|
check_bin(p, "part number");
|
||||||
|
|||||||
+9
-108
@@ -5,9 +5,6 @@
|
|||||||
* This tool lets you modify Intel GbE NVM (Gigabit Ethernet
|
* This tool lets you modify Intel GbE NVM (Gigabit Ethernet
|
||||||
* Non-Volatile Memory) images, e.g. change the MAC address.
|
* Non-Volatile Memory) images, e.g. change the MAC address.
|
||||||
* These images configure your Intel Gigabit Ethernet adapter.
|
* These images configure your Intel Gigabit Ethernet adapter.
|
||||||
*
|
|
||||||
* This code is designed to be portable, running on as many
|
|
||||||
* Unix and Unix-like systems as possible (mainly BSD/Linux).
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
@@ -32,115 +29,19 @@
|
|||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct xstate *x;
|
struct xstate *x = xstatus(argc, argv);
|
||||||
struct commands *cmd;
|
struct commands *cmd = &x->cmd[x->i];
|
||||||
struct xfile *f;
|
struct xfile *f = &x->f;
|
||||||
unsigned long i;
|
|
||||||
|
|
||||||
char *tmp_path;
|
unsigned long c;
|
||||||
|
|
||||||
struct stat st;
|
if (cmd->run == NULL)
|
||||||
int fd;
|
err(errno, "Command not set");
|
||||||
|
|
||||||
tmp_path = NULL;
|
cmd->run();
|
||||||
|
|
||||||
#ifndef S_ISREG
|
for (c = 0; c < items(x->cmd); c++)
|
||||||
err(ECANCELED, "Can't determine file types (S_ISREG undefined)");
|
x->cmd[c].run = cmd_helper_err;
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CHAR_BIT
|
|
||||||
err(ECANCELED, "Unknown char size");
|
|
||||||
#else
|
|
||||||
if (CHAR_BIT != 8)
|
|
||||||
err(EINVAL, "Unsupported char size");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (argc < 3)
|
|
||||||
usage();
|
|
||||||
|
|
||||||
#ifdef NVMUTIL_UNVEIL
|
|
||||||
/*
|
|
||||||
* if global tmp is a different filesystem,
|
|
||||||
* unveil would trap on final file rename
|
|
||||||
* and we can't know the path in advance
|
|
||||||
*/
|
|
||||||
tmp_path = new_tmpfile(&fd, 1, NULL);
|
|
||||||
#else
|
|
||||||
tmp_path = new_tmpfile(&fd, 0, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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/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 = x->i;
|
|
||||||
cmd = &x->cmd[i];
|
|
||||||
|
|
||||||
#ifdef NVMUTIL_UNVEIL
|
|
||||||
if ((cmd->flags & O_ACCMODE) == O_RDONLY) {
|
|
||||||
if (unveil(f->fname, "r") == -1)
|
|
||||||
err(errno, "%s: unveil r", f->fname);
|
|
||||||
} else {
|
|
||||||
if (unveil(f->tname, "rwc") == -1)
|
|
||||||
err(errno, "%s: unveil rw", f->tname);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unveil(f->tname, "rwc") == -1)
|
|
||||||
err(errno, "%s: unveil rwc", f->tname);
|
|
||||||
|
|
||||||
if (unveil(NULL, NULL) == -1)
|
|
||||||
err(errno, "unveil block (rw)");
|
|
||||||
|
|
||||||
if (pledge("stdio flock rpath wpath cpath", NULL) == -1)
|
|
||||||
err(errno, "pledge (kill unveil)");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
open_gbe_file();
|
|
||||||
|
|
||||||
memset(f->buf, 0, GBE_BUF_SIZE);
|
|
||||||
memset(f->bufcmp, 0, GBE_BUF_SIZE);
|
|
||||||
|
|
||||||
copy_gbe();
|
|
||||||
|
|
||||||
read_checksums();
|
|
||||||
|
|
||||||
run_cmd();
|
|
||||||
|
|
||||||
if ((cmd->flags & O_ACCMODE) == O_RDWR)
|
if ((cmd->flags & O_ACCMODE) == O_RDWR)
|
||||||
write_to_gbe_bin();
|
write_to_gbe_bin();
|
||||||
|
|||||||
@@ -1,134 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: MIT
|
|
||||||
*
|
|
||||||
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
|
|
||||||
*
|
|
||||||
* Five Year Plan
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Major TODO: split this into multiple files.
|
|
||||||
* This program has become quite large now, mostly
|
|
||||||
* due to all the extra sanity checks / portability.
|
|
||||||
* Make most of nvmutil a *library* for re-use
|
|
||||||
*
|
|
||||||
* TODO: gettimeofday not posible - use portable functions.
|
|
||||||
* TODO: ux fallback: modify the program instead
|
|
||||||
* to run on 16-bit systems: smaller buffers, and do
|
|
||||||
* operations byte-based instead of word-based.
|
|
||||||
*
|
|
||||||
* TODO: _XOPEN_SOURCE 500 probably not needed anymore.
|
|
||||||
* the portable fallbacks alone are likely enough.
|
|
||||||
* e.g. i don't need stdint, and i don't use pwrite/pread
|
|
||||||
* anymore.
|
|
||||||
*
|
|
||||||
* TODO: version detection of various BSDs to detect
|
|
||||||
* arc4random, use that if available. but also work on
|
|
||||||
* older versions of those BSDs (also MacOS) that lack it.
|
|
||||||
*
|
|
||||||
* TODO: portability/testing on non-Unix systems:
|
|
||||||
* old DOS. all windows versions (probably irrelevant
|
|
||||||
* because you can use cygwin/wsl, whatever), classic MacOS,
|
|
||||||
* also test really old unix e.g. sunos and irix. Be/Haiku too!
|
|
||||||
*
|
|
||||||
* TODO: reliance on global variables for status. make
|
|
||||||
* functions use structs passed as args instead, make
|
|
||||||
* functions re-useable (including libraries), etc.
|
|
||||||
*
|
|
||||||
* TODO: bound checks for files per-command, e.g. only
|
|
||||||
* first 6 bytes for CMD_SETMAC
|
|
||||||
*
|
|
||||||
* TODO: in command sanitizer: verify that each given
|
|
||||||
* entry corresponds to the correct function, in the
|
|
||||||
* pointer (this check is currently missing)
|
|
||||||
*
|
|
||||||
* TODO: general modularisierung of the entire codebase.
|
|
||||||
* TODO: better explain copy/swap read inversion trick
|
|
||||||
* by improving existing comments
|
|
||||||
* TODO: lots of overwritten comments in code. tidy it up.
|
|
||||||
*
|
|
||||||
* TODO: use getopt for nvmutil args, so that multiple
|
|
||||||
* operations can be performed, and also on many
|
|
||||||
* files at once (noting limitations with cat)
|
|
||||||
* BONUS: implement own getopt(), for portability
|
|
||||||
*
|
|
||||||
* TODO: document fuzzing / analysis methods
|
|
||||||
* for the code, and:
|
|
||||||
* TODO: implement rigorous unit tests (separate util)
|
|
||||||
* NOTE: this would *include* known good test files
|
|
||||||
* in various configurations, also invalid files.
|
|
||||||
* the tests would likely be portable posix shell
|
|
||||||
* scripts rather than a new C program, but a modularisiert
|
|
||||||
* codebase would allow me to write a separate C
|
|
||||||
* program to test some finer intricacies
|
|
||||||
* TODO: the unit tests would basically test regressions
|
|
||||||
* TODO: after writing back a gbe to file, x_i_close() and
|
|
||||||
* open() it again, read it again, and check that
|
|
||||||
* the contents were written correctly, providing
|
|
||||||
* a warning if they were. do this in the main
|
|
||||||
* program.
|
|
||||||
* TODO: the unit tests would include an aggressive set
|
|
||||||
* of fuzz tests, under controlled conditions
|
|
||||||
*
|
|
||||||
* TODO: also document the layout of Intel GbE files, so
|
|
||||||
* that wily individuals can easily expand the
|
|
||||||
* featureset of nvmutil.
|
|
||||||
* TODO: write a manpage
|
|
||||||
* TODO: simplify the command sanitization, implement more
|
|
||||||
* of it as build time checks, e.g. asserts.
|
|
||||||
* generally remove cleverness from the code, instead
|
|
||||||
* prefyerring readibility
|
|
||||||
* TODO: also document nvmutil's coding style, which is
|
|
||||||
* its own style at this point!
|
|
||||||
* TODO: when all the above (and possibly more) is done,
|
|
||||||
* submit this tool to coreboot with a further change
|
|
||||||
* to their build system that lets users modify
|
|
||||||
* GbE images, especially set MAC addresses, when
|
|
||||||
* including GbE files in coreboot configs.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
BONUS TODO:
|
|
||||||
CI/CD. woodpecker is good enough, sourcehut also has one.
|
|
||||||
tie this in with other things mentioned here,
|
|
||||||
e.g. fuzzer / unit tests
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Major TODO: reproducible builds
|
|
||||||
Test with and without these:
|
|
||||||
|
|
||||||
CFLAGS += -fno-record-gcc-switches
|
|
||||||
CFLAGS += -ffile-prefix-map=$(PWD)=.
|
|
||||||
CFLAGS += -fdebug-prefix-map=$(PWD)=.
|
|
||||||
|
|
||||||
I already avoid unique timestamps per-build,
|
|
||||||
by not using them, e.g. not reporting build
|
|
||||||
time in the program.
|
|
||||||
|
|
||||||
When splitting the nvmutil.c file later, do e.g.:
|
|
||||||
|
|
||||||
SRC = main.c io.c nvm.c cmd.c
|
|
||||||
OBJ = $(SRC:.c=.o)
|
|
||||||
|
|
||||||
^ explicitly declare the order in which to build
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
TODO:
|
|
||||||
further note when fuzzing is implemented:
|
|
||||||
use deterministic randomisation, with a
|
|
||||||
guaranteed seed - so e.g. don't use /dev/urandom
|
|
||||||
in test builds. e.g. just use normal rand()
|
|
||||||
but with a seed e.g. 1234
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
TODO: stricter build flags, e.g.
|
|
||||||
CFLAGS += -fstack-protector-strong
|
|
||||||
CFLAGS += -fno-common
|
|
||||||
CFLAGS += -D_FORTIFY_SOURCE=2
|
|
||||||
CFLAGS += -fPIE
|
|
||||||
|
|
||||||
also consider:
|
|
||||||
-fstack-clash-protection
|
|
||||||
-Wl,-z,relro
|
|
||||||
-Wl,-z,now
|
|
||||||
*/
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user