Compare commits

...

17 Commits

Author SHA1 Message Date
Leah Rowe
6fe909f9f7 util/nvmutil: tighter pledge and unveil
call it sooner. set new_state afterward.

i had to uncouple nv from some functions
for this, and i also added some extra
checks especially at exit, about whether
to touch nv (whether it is initialised)

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 22:21:16 +00:00
Leah Rowe
9573d872f3 util/nvmutil: stricter work buf check
check it right after initialisation

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 21:43:37 +00:00
Leah Rowe
d01aedd289 79-character rule must be obeyed
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 21:40:25 +00:00
Leah Rowe
3fba6f2d64 util/nvmutil: fix comment
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 21:24:04 +00:00
Leah Rowe
16d50d42da util/nvmutil: default to clang on make-hell
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 21:00:43 +00:00
Leah Rowe
dcdbd5eda1 util/nvmutil: tidy up memcmp
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 20:35:10 +00:00
Leah Rowe
952a3d52a5 nvmutil: add suffixes to makefile
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 19:39:27 +00:00
Leah Rowe
63f0fe9702 nvmutil: tidy up the makefile
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 19:35:50 +00:00
Leah Rowe
fd1bafecd1 util/nvmutil: portable default make rules
older compilers might not have -std for example.

the code is portable, but old compilers can't
compile with just "make", you have to add lots
of flags

i will now use "make strict" and "make hell"
in testing, but otherwise make without flags
are fine.

move the current strictness to command:

make strict

added an extra command:

make hell

hell uses -Weverything, and is useful with
clang's strict testing, on which i only got
a very small number of errors (it's way less
than a lot of programs would get with this
flag, because -Weverything is REALLY STRICT):

ja, mich nvmutil$ make hell CC=clang
clang -I.   -Wall -Wextra -pedantic -std=c90 -Os -Werror -Weverything nvmutil.c -o nvmutil
In file included from nvmutil.c:35:
./nvmutil.h:225:16: error: padding struct 'struct commands' with 1 byte to align 'rw_size' [-Werror,-Wpadded]
  225 |         unsigned long rw_size; /* within the 4KB GbE part */
      |                       ^
./nvmutil.h:217:8: error: padding size of 'struct commands' with 4 bytes to alignment boundary [-Werror,-Wpadded]
  217 | struct commands {
      |        ^
./nvmutil.h:235:8: error: padding size of 'struct xfile' with 4 bytes to alignment boundary [-Werror,-Wpadded]
  235 | struct xfile {
      |        ^
./nvmutil.h:288:16: error: padding struct 'struct xstate' with 4 bytes to align 'xsize' [-Werror,-Wpadded]
  288 |         unsigned long xsize;
      |                       ^
nvmutil.c:617:43: error: implicit conversion changes signedness: 'off_t' (aka 'long') to 'unsigned long' [-Werror,-Wsign-conversion]
  617 |         _r = rw_file_exact(f->gbe_fd, f->buf, f->gbe_file_size,
      |              ~~~~~~~~~~~~~                    ~~~^~~~~~~~~~~~~
nvmutil.c:626:43: error: implicit conversion changes signedness: 'off_t' (aka 'long') to 'unsigned long' [-Werror,-Wsign-conversion]
  626 |         _r = rw_file_exact(f->tmp_fd, f->buf, f->gbe_file_size,
      |              ~~~~~~~~~~~~~                    ~~~^~~~~~~~~~~~~
nvmutil.c:654:46: error: implicit conversion changes signedness: 'off_t' (aka 'long') to 'unsigned long' [-Werror,-Wsign-conversion]
  654 |         _r = rw_file_exact(f->tmp_fd, f->bufcmp, f->gbe_file_size,
      |              ~~~~~~~~~~~~~                       ~~~^~~~~~~~~~~~~
nvmutil.c:661:39: error: implicit conversion changes signedness: 'off_t' (aka 'long') to 'unsigned long' [-Werror,-Wsign-conversion]
  661 |         if (x_i_memcmp(f->buf, f->bufcmp, f->gbe_file_size) != 0)
      |             ~~~~~~~~~~                    ~~~^~~~~~~~~~~~~
nvmutil.c:702:23: error: implicit conversion loses integer precision: 'int' to 'unsigned char' [-Werror,-Wimplicit-int-conversion]
  702 |                 f->part_valid[_p] = good_checksum(_p);
      |                                   ~ ^~~~~~~~~~~~~~~~~
nvmutil.c:1045:21: error: implicit conversion loses integer precision: 'int' to 'unsigned char' [-Werror,-Wimplicit-int-conversion]
 1045 |         f->part_valid[0] = good_checksum(0);
      |                          ~ ^~~~~~~~~~~~~~~~
nvmutil.c:1046:21: error: implicit conversion loses integer precision: 'int' to 'unsigned char' [-Werror,-Wimplicit-int-conversion]
 1046 |         f->part_valid[1] = good_checksum(1);
      |                          ~ ^~~~~~~~~~~~~~~~
nvmutil.c:1170:45: error: implicit conversion changes signedness: 'off_t' (aka 'long') to 'unsigned long' [-Werror,-Wsign-conversion]
 1170 |                     (unsigned long)(p * (f->gbe_file_size >> 1)));
      |                                       ~  ~~~~~~~~~~~~~~~~~^~~~
nvmutil.c:1269:37: error: implicit conversion loses integer precision: 'int' to 'unsigned short' [-Werror,-Wimplicit-int-conversion]
 1269 |         return (unsigned short)f->buf[pos] |
      |         ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
 1270 |             ((unsigned short)f->buf[pos + 1] << 8);
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nvmutil.c:1610:9: error: implicit conversion changes signedness: 'off_t' (aka 'long') to 'unsigned long' [-Werror,-Wsign-conversion]
 1609 |         r = rw_file_exact(f->tmp_fd, f->bufcmp,
      |             ~~~~~~~~~~~~~
 1610 |             f->gbe_file_size, 0, IO_PREAD,
      |             ~~~^~~~~~~~~~~~~
nvmutil.c:1618:9: error: implicit conversion changes signedness: 'off_t' (aka 'long') to 'unsigned long' [-Werror,-Wsign-conversion]
 1617 |         r = rw_file_exact(dest_fd, f->bufcmp,
      |             ~~~~~~~~~~~~~
 1618 |             f->gbe_file_size, 0, IO_PWRITE,
      |             ~~~^~~~~~~~~~~~~
nvmutil.c:1609:6: error: implicit conversion loses integer precision: 'long' to 'int' [-Werror,-Wshorten-64-to-32]
 1609 |         r = rw_file_exact(f->tmp_fd, f->bufcmp,
      |           ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1610 |             f->gbe_file_size, 0, IO_PREAD,
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1611 |             NO_LOOP_EAGAIN, LOOP_EINTR,
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1612 |             MAX_ZERO_RW_RETRY, OFF_ERR);
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~
nvmutil.c:1617:6: error: implicit conversion loses integer precision: 'long' to 'int' [-Werror,-Wshorten-64-to-32]
 1617 |         r = rw_file_exact(dest_fd, f->bufcmp,
      |           ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1618 |             f->gbe_file_size, 0, IO_PWRITE,
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1619 |             NO_LOOP_EAGAIN, LOOP_EINTR,
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1620 |             MAX_ZERO_RW_RETRY, OFF_ERR);
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~
nvmutil.c:1936:45: error: implicit conversion changes signedness: 'long' to 'unsigned long' [-Werror,-Wsign-conversion]
 1936 |                 if (rv >= 0 && (unsigned long)rv > (nrw - rc))
      |                                                         ~ ^~
nvmutil.c:2193:27: error: signed shift result (0x8000000000000000) sets the sign bit of the shift expression's type ('long') and becomes negative [-Werror,-Wshift-sign-overflow]
 2193 |         if (nrw > (unsigned long)X_LONG_MAX)
      |                                  ^~~~~~~~~~
./nvmutil.h:147:38: note: expanded from macro 'X_LONG_MAX'
  147 | #define X_LONG_MAX ((long)(~((long)1 << (sizeof(long)*CHAR_BIT-1))))
      |                              ~~~~~~~ ^  ~~~~~~~~~~~~~~~~~~~~~~~~~
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.
make: *** [Makefile:42: hell] Fehler 1

in a future commit, i intend to fix all of these issues,
so that the code reliably compiles in hell-mode.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 19:08:49 +00:00
Leah Rowe
5ab3b11446 util/nvmutil: move asserts to header
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 18:30:07 +00:00
Leah Rowe
2cb1797acc nvmutil: extremely defensive CHAR_BIT test
this program needs bits to be 8

some obscure systems set it to something else

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 18:28:01 +00:00
Leah Rowe
cb8ac86bd4 util/nvmutil: add defensive buffer check
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 18:19:40 +00:00
Leah Rowe
b00fb6127e util/nvmutil: remove stale comment
and add another

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 18:09:34 +00:00
Leah Rowe
15b8cd7833 util/nvmutil: fix randomness in mkstemp
i need to re-initialise r each time.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 17:36:11 +00:00
Leah Rowe
0db9cc321f util/nvmutil: split up copy_gbe
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 17:29:07 +00:00
Leah Rowe
6e63106dae util/nvmuti: make fsync_dir() generic
yes, this begins the next phase of nvmutil:

remove global status in functions that should be
generic, and make functions that are not generic,
generic. make everything as re-useable in a library
as possible.

most of the program is error control, as it should
be, but much of it is mixed in with functions
that really should just be split up for libraries.

so that is what i'm now beginning.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 16:59:50 +00:00
Leah Rowe
6b1757da57 prototype for new_state() in nvmutil
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-17 08:09:27 +00:00
3 changed files with 240 additions and 170 deletions

View File

@@ -3,25 +3,42 @@
# Copyright (c) 2023 Riku Viitanen <riku.viitanen@protonmail.com>
CC?=cc
CSTD?=-std=c90
WERROR?=-Werror
CWARN?=-Wall -Wextra -pedantic
COPT?=-Os
CFLAGS?=$(CWARN) $(CSTD)
HELLCC?=clang
CFLAGS?=
LDFLAGS?=
DESTDIR?=
PREFIX?=/usr/local
INSTALL?=install
LDIR?=-I.
OPTS=$(LDIR) $(COPT) $(WERROR) $(CFLAGS) $(LDFLAGS)
.SUFFIXES:
# maybe add -I. here when running make
# e.g. make LDIR=-I.
LDIR?=
PORTABLE?=$(LDIR) $(CFLAGS)
WARN?=$(PORTABLE) -Wall -Wextra
STRICT?=$(WARN) -std=c90 -pedantic -Werror
HELLFLAGS?=$(STRICT) -Weverything
# program name
PROG=nvmutil
all: $(PROG)
$(PROG): nvmutil.c
$(CC) $(OPTS) nvmutil.c -o $(PROG)
$(PROG): $(PROG).c
$(CC) $(PORTABLE) $(PROG).c -o $(PROG) $(LDFLAGS)
warn: $(PROG).c
$(CC) $(WARN) $(PROG).c -o $(PROG) $(LDFLAGS)
strict: $(PROG).c
$(CC) $(STRICT) $(PROG).c -o $(PROG) $(LDFLAGS)
# clang-only extreme warnings (not portable)
hell: $(PROG).c
$(HELLCC) $(HELLFLAGS) $(PROG).c -o $(PROG) $(LDFLAGS)
install: $(PROG)
$(INSTALL) -d $(DESTDIR)$(PREFIX)/bin
@@ -36,4 +53,4 @@ clean:
distclean: clean
.PHONY: all install uninstall clean distclean
.PHONY: all warn strict hell install uninstall clean distclean

View File

@@ -94,7 +94,7 @@ new_xstate(void)
/* ->mac */
{NULL, "xx:xx:xx:xx:xx:xx", {0, 0, 0}}, /* .str, .rmac, .mac_buf */
/* .buf */
/* .f */
{0},
/* .argv0 (for our getprogname implementation) */
@@ -144,30 +144,29 @@ new_xstate(void)
return xs_new;
}
struct xstate *nv = NULL;
static struct xstate *nv = NULL;
int
main(int argc, char *argv[])
{
struct commands *cmd;
struct xfile *f;
int fd;
struct stat st;
char *tmp_path = NULL;
unsigned long *i;
nv = new_xstate();
if (nv == NULL)
err(errno, NULL);
nv->argv0 = argv[0];
if (argc < 3)
usage();
#ifndef CHAR_BIT
err(ECANCELED, "Unknown char size");
#else
if (CHAR_BIT != 8)
err(EINVAL, "Unsupported char size");
#endif
f = &nv->f;
f->fname = argv[1];
if (argc < 3)
usage();
#ifdef NVMUTIL_UNVEIL
/*
@@ -175,12 +174,12 @@ main(int argc, char *argv[])
* unveil would trap on final file rename
* and we can't know the path in advance
*/
f->tname = new_tmpfile(&f->tmp_fd, 1, NULL);
tmp_path = new_tmpfile(&fd, 1, NULL);
#else
f->tname = new_tmpfile(&f->tmp_fd, 0, NULL);
tmp_path = new_tmpfile(&fd, 0, NULL);
#endif
if (f->tname == NULL)
if (tmp_path == NULL)
err(errno, "Can't create tmpfile");
#ifdef NVMUTIL_PLEDGE
@@ -197,6 +196,26 @@ main(int argc, char *argv[])
#endif
#endif
nv = new_xstate();
if (nv == NULL)
err(errno, NULL);
if (nv->f.buf == NULL)
err(EINVAL, "Work buffer not initialised");
nv->argv0 = argv[0];
f = &nv->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);
@@ -207,11 +226,11 @@ main(int argc, char *argv[])
#ifdef NVMUTIL_UNVEIL
if (cmd->flags == O_RDONLY) {
if (unveil(fname, "r") == -1)
err(errno, "%s: unveil r", fname);
if (unveil(f->fname, "r") == -1)
err(errno, "%s: unveil r", f->fname);
} else {
if (unveil(fname, "rwc") == -1)
err(errno, "%s: unveil rw", fname);
if (unveil(f->tname, "rwc") == -1)
err(errno, "%s: unveil rw", f->tname);
}
if (unveil(tname, "rwc") == -1)
@@ -506,19 +525,18 @@ open_gbe_file(void)
err(EINVAL, "File size must be 8KB, 16KB or 128KB");
}
if (lock_file(f->gbe_fd) == -1)
if (lock_file(f->gbe_fd, cmd->flags) == -1)
err(errno, "%s: can't lock", f->fname);
}
int
lock_file(int fd)
lock_file(int fd, int flags)
{
struct flock fl;
struct commands *cmd = &nv->cmd[nv->i];
memset(&fl, 0, sizeof(fl));
if (cmd->flags == O_RDONLY)
if ((flags & O_ACCMODE) == O_RDONLY)
fl.l_type = F_RDLCK;
else
fl.l_type = F_WRLCK;
@@ -531,6 +549,21 @@ lock_file(int fd)
return 0;
}
/*
* TODO: make generic. S_ISREG: check every other
* type, erring only if it doesn't match what was
* passed as type requested.
* also:
* have variable need_seek, only err on seek if
* need_seek is set.
* also consider the stat check in this generic
* context
* make tthe return type an int, not a void.
* return -1 with errno set to indicate error,
* though the syscalls mostly handle that.
* save errno before lseek, resetting it after
* the check if return >-1
*/
void
xopen(int *fd_ptr, const char *path, int flags, struct stat *st)
{
@@ -560,6 +593,31 @@ xopen(int *fd_ptr, const char *path, int flags, struct stat *st)
*/
void
copy_gbe(void)
{
struct xfile *f = &nv->f;
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)
return;
x_v_memcpy(f->buf + (unsigned long)GBE_PART_SIZE,
f->buf + (unsigned long)(f->gbe_file_size >> 1),
(unsigned long)GBE_PART_SIZE);
}
void
read_file(void)
{
long _r;
struct stat _st;
@@ -614,23 +672,6 @@ copy_gbe(void)
if (x_i_memcmp(f->buf, f->bufcmp, f->gbe_file_size) != 0)
err(errno, "%s: %s: read contents differ (pre-test)",
f->fname, f->tname);
/*
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)
return;
x_v_memcpy(f->buf + (unsigned long)GBE_PART_SIZE,
f->buf + (unsigned long)(f->gbe_file_size >> 1),
(unsigned long)GBE_PART_SIZE);
}
void
@@ -1434,7 +1475,6 @@ check_written_part(unsigned long p)
gbe_rw_size = cmd->rw_size;
/* invert not needed for pwrite */
mem_offset = gbe_mem_offset(p, "pwrite");
file_offset = (off_t)gbe_file_offset(p, "pwrite");
@@ -1553,8 +1593,10 @@ gbe_mv(void)
tmp_gbe_bin_exists = 0;
if (fsync_dir(f->fname) < 0)
if (fsync_dir(f->fname) < 0) {
f->io_err_gbe_bin = 1;
r = -1;
}
goto ret_gbe_mv;
}
@@ -1600,8 +1642,10 @@ gbe_mv(void)
if (rename(dest_tmp, f->fname) == -1)
goto ret_gbe_mv;
if (fsync_dir(f->fname) < 0)
if (fsync_dir(f->fname) < 0) {
f->io_err_gbe_bin = 1;
goto ret_gbe_mv;
}
free(dest_tmp);
dest_tmp = NULL;
@@ -1611,8 +1655,10 @@ ret_gbe_mv:
if (f->gbe_fd > -1) {
if (x_i_close(f->gbe_fd) < 0)
r = -1;
if (fsync_dir(f->fname) < 0)
if (fsync_dir(f->fname) < 0) {
f->io_err_gbe_bin = 1;
r = -1;
}
f->gbe_fd = -1;
}
@@ -1656,8 +1702,6 @@ ret_gbe_mv:
int
fsync_dir(const char *path)
{
struct xfile *f = &nv->f;
#if defined(PATH_LEN) && \
(PATH_LEN) >= 256
unsigned long maxlen = PATH_LEN;
@@ -1742,7 +1786,7 @@ err_fsync_dir:
errno = EIO;
if (errno != saved_errno)
fprintf(stderr, "%s: %s\n", f->fname, strerror(errno));
fprintf(stderr, "%s: %s\n", path, strerror(errno));
if (dirbuf != NULL)
free(dirbuf);
@@ -1750,7 +1794,6 @@ err_fsync_dir:
if (dfd > -1)
x_i_close(dfd);
f->io_err_gbe_bin = 1;
errno = saved_errno;
return -1;
@@ -2308,8 +2351,6 @@ usage(void)
void
err(int nvm_errval, const char *msg, ...)
{
struct xfile *f = &nv->f;
va_list args;
if (errno == 0)
@@ -2325,12 +2366,7 @@ err(int nvm_errval, const char *msg, ...)
vfprintf(stderr, msg, args);
va_end(args);
fprintf(stderr, ": %s", strerror(errno));
fprintf(stderr, "\n");
if (f->tname != NULL)
free(f->tname);
fprintf(stderr, ": %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
@@ -2338,28 +2374,32 @@ err(int nvm_errval, const char *msg, ...)
int
exit_cleanup(void)
{
struct xfile *f = &nv->f;
struct xfile *f;
int close_err = 0;
int saved_errno = errno;
if (f->gbe_fd > -1) {
if (x_i_close(f->gbe_fd) == -1)
close_err = 1;
f->gbe_fd = -1;
}
if (nv != NULL) {
f = &nv->f;
if (f->tmp_fd > -1) {
if (x_i_close(f->tmp_fd) == -1)
close_err = 1;
}
if (f->gbe_fd > -1) {
if (x_i_close(f->gbe_fd) == -1)
close_err = 1;
f->gbe_fd = -1;
}
if (f->tname != NULL) {
if (unlink(f->tname) == -1)
close_err = 1;
}
if (f->tmp_fd > -1) {
if (x_i_close(f->tmp_fd) == -1)
close_err = 1;
}
f->tmp_fd = -1;
if (f->tname != NULL) {
if (unlink(f->tname) == -1)
close_err = 1;
}
f->tmp_fd = -1;
}
if (saved_errno)
errno = saved_errno;
@@ -2413,8 +2453,6 @@ getnvmprogname(void)
char *
new_tmpfile(int *fd, int local, const char *path)
{
struct xfile *f = &nv->f;
unsigned long maxlen;
struct stat st;
@@ -2531,7 +2569,20 @@ new_tmpfile(int *fd, int local, const char *path)
if (x_i_fchmod(fd_tmp, 0600) == -1)
goto err_new_tmpfile;
if (lock_file(fd_tmp) == -1)
flags = fcntl(fd_tmp, F_GETFL);
if (flags == -1)
goto err_new_tmpfile;
/*
* O_APPEND would permit offsets
* to be ignored, which breaks
* positional read/write
*/
if (flags & O_APPEND)
goto err_new_tmpfile;
if (lock_file(fd_tmp, flags) == -1)
goto err_new_tmpfile;
if (fstat(fd_tmp, &st) == -1)
@@ -2550,10 +2601,6 @@ new_tmpfile(int *fd, int local, const char *path)
if (lseek(fd_tmp, 0, SEEK_CUR) == (off_t)-1)
goto err_new_tmpfile;
/* inode will be checked later on write */
f->tmp_dev = st.st_dev;
f->tmp_ino = st.st_ino;
/* tmpfile has >1 hardlinks */
if (st.st_nlink > 1)
goto err_new_tmpfile;
@@ -2562,19 +2609,6 @@ new_tmpfile(int *fd, int local, const char *path)
if (st.st_nlink == 0)
goto err_new_tmpfile;
flags = fcntl(fd_tmp, F_GETFL);
if (flags == -1)
goto err_new_tmpfile;
/*
* O_APPEND would permit offsets
* to be ignored, which breaks
* positional read/write
*/
if (flags & O_APPEND)
goto err_new_tmpfile;
*fd = fd_tmp;
return dest;
@@ -2601,8 +2635,10 @@ x_i_mkstemp(char *template)
unsigned long len;
char *p;
char ch[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
unsigned long r = rlong();
char ch[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
unsigned long r;
len = xstrxlen(template, PATH_LEN);
@@ -2614,8 +2650,10 @@ x_i_mkstemp(char *template)
for (i = 0; i < 100; i++) {
for (j = 0; j < 6; j++)
for (j = 0; j < 6; j++) {
r = rlong();
p[j] = ch[r % (sizeof(ch) - 1)];
}
fd = open(template, O_RDWR | O_CREAT | O_EXCL, 0600);
@@ -2647,6 +2685,13 @@ x_c_strrchr(const char *s, int c)
return (char *)p;
}
/*
* non-atomic rename
*
* commented because i can't sacrifice
* exactly this property. nvmutil tries
* to protect files against e.g. power loss
*/
/*
int
x_i_rename(const char *src, const char *dst)
@@ -2743,12 +2788,9 @@ x_i_memcmp(const void *a, const void *b, unsigned long n)
const unsigned char *pa = (const unsigned char *)a;
const unsigned char *pb = (const unsigned char *)b;
while (n--) {
for ( ; n--; ++pa, ++pb)
if (*pa != *pb)
return *pa - *pb;
pa++;
pb++;
}
return 0;
}
@@ -2838,63 +2880,3 @@ x_i_fsync(int fd)
return r;
}
/* type asserts */
typedef char static_assert_char_is_8_bits[(CHAR_BIT == 8) ? 1 : -1];
typedef char static_assert_char_is_1[(sizeof(char) == 1) ? 1 : -1];
typedef char static_assert_unsigned_char_is_1[
(sizeof(unsigned char) == 1) ? 1 : -1];
typedef char static_assert_unsigned_short_is_2[
(sizeof(unsigned short) >= 2) ? 1 : -1];
typedef char static_assert_short_is_2[(sizeof(short) >= 2) ? 1 : -1];
typedef char static_assert_unsigned_int_is_4[
(sizeof(unsigned int) >= 4) ? 1 : -1];
typedef char static_assert_unsigned_long_is_4[
(sizeof(unsigned long) >= 4) ? 1 : -1];
typedef char static_assert_int_ge_32[(sizeof(int) >= 4) ? 1 : -1];
typedef char static_assert_twos_complement[
((-1 & 3) == 3) ? 1 : -1
];
typedef char assert_unsigned_long_ptr[
(sizeof(unsigned long) >= sizeof(void *)) ? 1 : -1
];
/*
* We set _FILE_OFFSET_BITS 64, but we only handle
* but we only need smaller files, so require 4-bytes.
* Some operating systems ignore the define, hence assert:
*/
typedef char static_assert_off_t_is_32[(sizeof(off_t) >= 4) ? 1 : -1];
/*
* asserts (variables/defines sanity check)
*/
typedef char assert_argc3[(ARGC_3==3)?1:-1];
typedef char assert_argc4[(ARGC_4==4)?1:-1];
typedef char assert_read[(IO_READ==0)?1:-1];
typedef char assert_write[(IO_WRITE==1)?1:-1];
typedef char assert_pread[(IO_PREAD==2)?1:-1];
typedef char assert_pwrite[(IO_PWRITE==3)?1:-1];
typedef char assert_pathlen[(PATH_LEN>=256)?1:-1];
/* commands */
typedef char assert_cmd_dump[(CMD_DUMP==0)?1:-1];
typedef char assert_cmd_setmac[(CMD_SETMAC==1)?1:-1];
typedef char assert_cmd_swap[(CMD_SWAP==2)?1:-1];
typedef char assert_cmd_copy[(CMD_COPY==3)?1:-1];
typedef char assert_cmd_cat[(CMD_CAT==4)?1:-1];
typedef char assert_cmd_cat16[(CMD_CAT16==5)?1:-1];
typedef char assert_cmd_cat128[(CMD_CAT128==6)?1:-1];
/* bool */
typedef char bool_arg_nopart[(ARG_NOPART==0)?1:-1];
typedef char bool_arg_part[(ARG_PART==1)?1:-1];
typedef char bool_skip_checksum_read[(SKIP_CHECKSUM_READ==0)?1:-1];
typedef char bool_checksum_read[(CHECKSUM_READ==1)?1:-1];
typedef char bool_skip_checksum_write[(SKIP_CHECKSUM_WRITE==0)?1:-1];
typedef char bool_checksum_write[(CHECKSUM_WRITE==1)?1:-1];
typedef char bool_loop_eintr[(LOOP_EINTR==1||LOOP_EINTR==0)?1:-1];
typedef char bool_loop_eagain[(LOOP_EAGAIN==1||LOOP_EAGAIN==0)?1:-1];
typedef char bool_no_loop_eintr[(NO_LOOP_EINTR==0)?1:-1];
typedef char bool_no_loop_eagain[(NO_LOOP_EAGAIN==0)?1:-1];
typedef char bool_off_err[(OFF_ERR==0)?1:-1];
typedef char bool_off_reset[(OFF_RESET==0||OFF_RESET==1)?1:-1];

View File

@@ -66,6 +66,10 @@
#define EXIT_SUCCESS 0
#endif
#ifndef O_ACCMODE
#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
@@ -291,6 +295,7 @@ struct xstate {
static struct xstate *new_xstate(void);
/*
* Sanitize command tables.
@@ -310,7 +315,7 @@ int xstrxcmp(const char *a, const char *b, unsigned long maxlen);
* Prep files for reading
*/
void open_gbe_file(void);
int lock_file(int fd);
int lock_file(int fd, int flags);
void xopen(int *fd, const char *path, int flags, struct stat *st);
/*
@@ -320,6 +325,7 @@ void xopen(int *fd, const char *path, int flags, struct stat *st);
* After this, we can run commands.
*/
void copy_gbe(void);
void read_file(void);
void read_checksums(void);
int good_checksum(unsigned long partnum);
@@ -460,4 +466,69 @@ unsigned long x_conv_fd(char *buf,
unsigned long n);
int x_i_fsync(int fd);
/* asserts */
/* type asserts */
typedef char static_assert_char_is_8_bits[(CHAR_BIT == 8) ? 1 : -1];
typedef char static_assert_char_is_1[(sizeof(char) == 1) ? 1 : -1];
typedef char static_assert_unsigned_char_is_1[
(sizeof(unsigned char) == 1) ? 1 : -1];
typedef char static_assert_unsigned_short_is_2[
(sizeof(unsigned short) >= 2) ? 1 : -1];
typedef char static_assert_short_is_2[(sizeof(short) >= 2) ? 1 : -1];
typedef char static_assert_unsigned_int_is_4[
(sizeof(unsigned int) >= 4) ? 1 : -1];
typedef char static_assert_unsigned_long_is_4[
(sizeof(unsigned long) >= 4) ? 1 : -1];
typedef char static_assert_int_ge_32[(sizeof(int) >= 4) ? 1 : -1];
typedef char static_assert_twos_complement[
((-1 & 3) == 3) ? 1 : -1
];
typedef char assert_unsigned_long_ptr[
(sizeof(unsigned long) >= sizeof(void *)) ? 1 : -1
];
/*
* We set _FILE_OFFSET_BITS 64, but we only handle
* but we only need smaller files, so require 4-bytes.
* Some operating systems ignore the define, hence assert:
*/
typedef char static_assert_off_t_is_32[(sizeof(off_t) >= 4) ? 1 : -1];
/*
* asserts (variables/defines sanity check)
*/
typedef char assert_argc3[(ARGC_3==3)?1:-1];
typedef char assert_argc4[(ARGC_4==4)?1:-1];
typedef char assert_read[(IO_READ==0)?1:-1];
typedef char assert_write[(IO_WRITE==1)?1:-1];
typedef char assert_pread[(IO_PREAD==2)?1:-1];
typedef char assert_pwrite[(IO_PWRITE==3)?1:-1];
typedef char assert_pathlen[(PATH_LEN>=256)?1:-1];
/* commands */
typedef char assert_cmd_dump[(CMD_DUMP==0)?1:-1];
typedef char assert_cmd_setmac[(CMD_SETMAC==1)?1:-1];
typedef char assert_cmd_swap[(CMD_SWAP==2)?1:-1];
typedef char assert_cmd_copy[(CMD_COPY==3)?1:-1];
typedef char assert_cmd_cat[(CMD_CAT==4)?1:-1];
typedef char assert_cmd_cat16[(CMD_CAT16==5)?1:-1];
typedef char assert_cmd_cat128[(CMD_CAT128==6)?1:-1];
/* bool */
typedef char bool_arg_nopart[(ARG_NOPART==0)?1:-1];
typedef char bool_arg_part[(ARG_PART==1)?1:-1];
typedef char bool_skip_checksum_read[(SKIP_CHECKSUM_READ==0)?1:-1];
typedef char bool_checksum_read[(CHECKSUM_READ==1)?1:-1];
typedef char bool_skip_checksum_write[(SKIP_CHECKSUM_WRITE==0)?1:-1];
typedef char bool_checksum_write[(CHECKSUM_WRITE==1)?1:-1];
typedef char bool_loop_eintr[(LOOP_EINTR==1||LOOP_EINTR==0)?1:-1];
typedef char bool_loop_eagain[(LOOP_EAGAIN==1||LOOP_EAGAIN==0)?1:-1];
typedef char bool_no_loop_eintr[(NO_LOOP_EINTR==0)?1:-1];
typedef char bool_no_loop_eagain[(NO_LOOP_EAGAIN==0)?1:-1];
typedef char bool_off_err[(OFF_ERR==0)?1:-1];
typedef char bool_off_reset[(OFF_RESET==0||OFF_RESET==1)?1:-1];
#endif