summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/nvmutil/Makefile37
-rw-r--r--util/nvmutil/nvmutil.c239
-rw-r--r--util/nvmutil/nvmutil.h71
3 files changed, 202 insertions, 145 deletions
diff --git a/util/nvmutil/Makefile b/util/nvmutil/Makefile
index 025e87e1..6488ca43 100644
--- a/util/nvmutil/Makefile
+++ b/util/nvmutil/Makefile
@@ -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
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c
index f6374a7a..f938d2cb 100644
--- a/util/nvmutil/nvmutil.c
+++ b/util/nvmutil/nvmutil.c
@@ -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) */
@@ -151,23 +151,22 @@ main(int argc, char *argv[])
{
struct commands *cmd;
struct xfile *f;
+ int fd;
+ struct stat st;
- unsigned long *i;
-
- nv = new_xstate();
- if (nv == NULL)
- err(errno, NULL);
+ char *tmp_path = NULL;
- nv->argv0 = argv[0];
- if (argc < 3)
- usage();
+ unsigned long *i;
+#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)
{
@@ -1442,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");
@@ -2319,8 +2351,6 @@ usage(void)
void
err(int nvm_errval, const char *msg, ...)
{
- struct xfile *f = &nv->f;
-
va_list args;
if (errno == 0)
@@ -2336,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);
}
@@ -2349,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;
@@ -2424,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;
@@ -2542,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)
@@ -2561,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;
@@ -2573,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;
@@ -2612,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);
@@ -2625,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);
@@ -2659,6 +2686,13 @@ x_c_strrchr(const char *s, int c)
}
/*
+ * non-atomic rename
+ *
+ * commented because i can't sacrifice
+ * exactly this property. nvmutil tries
+ * to protect files against e.g. power loss
+ */
+/*
int
x_i_rename(const char *src, const char *dst)
{
@@ -2754,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;
}
@@ -2849,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];
-
diff --git a/util/nvmutil/nvmutil.h b/util/nvmutil/nvmutil.h
index 20e66dd9..c278481e 100644
--- a/util/nvmutil/nvmutil.h
+++ b/util/nvmutil/nvmutil.h
@@ -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
@@ -311,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);
/*
@@ -462,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