summaryrefslogtreecommitdiff
path: root/util/libreboot-utils/lib
diff options
context:
space:
mode:
authorLeah Rowe <leah@libreboot.org>2026-03-24 18:46:36 +0000
committerLeah Rowe <leah@libreboot.org>2026-03-24 18:46:36 +0000
commitc1befbcd3eb4a51831260c7c7b743a673512e6a5 (patch)
tree04fee08997783de473bdd69d12f6b6cfc4c2b558 /util/libreboot-utils/lib
parent6593e76c6a17d1e0cb82a2f29e832348fa9aa5ca (diff)
util/nvmutil: never do cross-filesystem moves
make a local TMPDIR instead, where gbe.bin is. this avoids the EXDEV errno, so we don't have to handle it, and it's just better performant for everyone. Signed-off-by: Leah Rowe <leah@libreboot.org>
Diffstat (limited to 'util/libreboot-utils/lib')
-rw-r--r--util/libreboot-utils/lib/io.c64
-rw-r--r--util/libreboot-utils/lib/mkhtemp.c92
-rw-r--r--util/libreboot-utils/lib/state.c13
3 files changed, 41 insertions, 128 deletions
diff --git a/util/libreboot-utils/lib/io.c b/util/libreboot-utils/lib/io.c
index de5f8c76..ef87d521 100644
--- a/util/libreboot-utils/lib/io.c
+++ b/util/libreboot-utils/lib/io.c
@@ -458,70 +458,6 @@ gbe_mv(void)
err(errno, "TODO: cross-filesystem atomic writes currently broken");
- /*
- * cross-filesystem: copy into target dir tmp
- */
-
- if (fs_dirname_basename(f->fname,
- &dir, &base, 0) < 0)
- goto ret_gbe_mv;
-
- dirfd = fs_open(dir,
- O_RDONLY | O_DIRECTORY);
-
- if (dirfd < 0)
- goto ret_gbe_mv;
-
- if (fstat(dirfd, &st_dir) < 0)
- goto ret_gbe_mv;
-
- if (new_tmpfile_at(dirfd, &st_dir,
- &dest_fd, &dest_name) < 0)
- goto ret_gbe_mv;
-
- /* copy: tmp to local tmp */
-
- rval = rw_file_exact(f->tmp_fd, f->bufcmp,
- f->gbe_file_size, 0, IO_PREAD,
- NO_LOOP_EAGAIN, LOOP_EINTR,
- MAX_ZERO_RW_RETRY, OFF_ERR);
-
- if (rval < 0)
- goto ret_gbe_mv;
-
- rval = rw_file_exact(dest_fd, f->bufcmp,
- f->gbe_file_size, 0, IO_PWRITE,
- NO_LOOP_EAGAIN, LOOP_EINTR,
- MAX_ZERO_RW_RETRY, OFF_ERR);
-
- if (rval < 0)
- goto ret_gbe_mv;
-
- if (fsync_on_eintr(dest_fd) == -1)
- goto ret_gbe_mv;
-
- if (close_on_eintr(dest_fd) == -1) {
- dest_fd = -1;
- goto ret_gbe_mv;
- }
- dest_fd = -1;
-
- /* atomic replace */
-
- if (fs_rename_at(dirfd, dest_name,
- dirfd, base) == -1)
- goto ret_gbe_mv;
-
- if (fsync_dir(f->fname) < 0) {
- f->io_err_gbe_bin = 1;
- goto ret_gbe_mv;
- }
-
- free_if_null(&dest_name);
- free_if_null(&dir);
-
- tmp_gbe_bin_exists = 0;
-
ret_gbe_mv:
/* TODO: this whole section is bloat.
diff --git a/util/libreboot-utils/lib/mkhtemp.c b/util/libreboot-utils/lib/mkhtemp.c
index d1ebea25..87d7c8dc 100644
--- a/util/libreboot-utils/lib/mkhtemp.c
+++ b/util/libreboot-utils/lib/mkhtemp.c
@@ -27,70 +27,21 @@
#include "../include/common.h"
+/* note: tmpdir is an override of TMPDIR or /tmp or /var/tmp */
int
-new_tmpfile(int *fd, char **path)
+new_tmpfile(int *fd, char **path, char *tmpdir)
{
- return new_tmp_common(fd, path, MKHTEMP_FILE);
+ return new_tmp_common(fd, path, MKHTEMP_FILE, tmpdir);
}
+/* note: tmpdir is an override of TMPDIR or /tmp or /var/tmp */
int
-new_tmpdir(int *fd, char **path)
+new_tmpdir(int *fd, char **path, char *tmpdir)
{
- return new_tmp_common(fd, path, MKHTEMP_DIR);
-}
-
-/* not used by mkhtemp util, but by nvmutil.
- * it leaves an st variable set after return,
- * so that verification can be done on a file
- * being used, before writing it elsewhere
- */
-int
-new_tmpfile_at(int dirfd, struct stat *st_dir,
- int *fd, char **name)
-{
- struct stat st;
- char suffix[] = "tmp.XXXXXXXXXX";
- size_t len;
- char *buf = NULL;
- char *fname;
- int saved_errno = errno;
-
-#if defined(PATH_LEN) && \
- (PATH_LEN) >= 256
- size_t maxlen = PATH_LEN;
-#else
- size_t maxlen = 4096;
-#endif
-
- if (if_err(fd == NULL || name == NULL || st_dir == NULL, EFAULT) ||
- if_err(*fd >= 0, EEXIST) ||
- if_err(dirfd < 0, EBADF) ||
- if_err_sys(slen(suffix, maxlen, &len) < 0) ||
- if_err_sys((malloc(len + 1)) == NULL))
- return -1;
-
- memcpy(buf, suffix, len + 1);
- fname = buf;
-
- *fd = mkhtemp(fd, &st,
- buf, dirfd, fname,
- st_dir, MKHTEMP_FILE);
-
- if (*fd < 0)
- goto err;
-
- *name = buf;
- errno = saved_errno;
-
- return 0;
-
-err:
- free_if_null(&buf);
- close_no_err(fd);
-
- return -1;
+ return new_tmp_common(fd, path, MKHTEMP_DIR, tmpdir);
}
+/* note: tmpdir is an override of TMPDIR or /tmp or /var/tmp */
/* WARNING:
* on error, *path (at **path) may be
NULL, or if the error pertains to
@@ -107,7 +58,8 @@ err:
* default to /tmp or /var/tmp
*/
int
-new_tmp_common(int *fd, char **path, int type)
+new_tmp_common(int *fd, char **path, int type,
+ char *tmpdir)
{
#if defined(PATH_LEN) && \
(PATH_LEN) >= 256
@@ -118,7 +70,6 @@ new_tmp_common(int *fd, char **path, int type)
struct stat st;
char suffix[] = "tmp.XXXXXXXXXX";
- char *tmpdir = NULL;
size_t dirlen;
size_t destlen;
@@ -152,15 +103,25 @@ new_tmp_common(int *fd, char **path, int type)
* (on error, it will not be touched)
*/
-
*fd = -1;
+ if (tmpdir == NULL) { /* no user override */
+#if defined(PERMIT_NON_STICKY_ALWAYS) && \
+ ((PERMIT_NON_STICKY_ALWAYS) > 0)
+ tmpdir = env_tmpdir(PERMIT_NON_STICKY_ALWAYS, &fail_dir, NULL);
+#else
+ tmpdir = env_tmpdir(0, &fail_dir, NULL);
+#endif
+ } else {
+
#if defined(PERMIT_NON_STICKY_ALWAYS) && \
((PERMIT_NON_STICKY_ALWAYS) > 0)
- tmpdir = env_tmpdir(PERMIT_NON_STICKY_ALWAYS, &fail_dir);
+ tmpdir = env_tmpdir(PERMIT_NON_STICKY_ALWAYS, &fail_dir,
+ tmpdir);
#else
- tmpdir = env_tmpdir(0, &fail_dir);
+ tmpdir = env_tmpdir(0, &fail_dir, tmpdir);
#endif
+ }
if (tmpdir == NULL)
goto err;
@@ -241,7 +202,8 @@ err:
*/
char *
-env_tmpdir(int bypass_all_sticky_checks, char **tmpdir)
+env_tmpdir(int bypass_all_sticky_checks, char **tmpdir,
+ char *override_tmpdir)
{
char *t;
int allow_noworld_unsticky;
@@ -250,7 +212,11 @@ env_tmpdir(int bypass_all_sticky_checks, char **tmpdir)
char tmp[] = "/tmp";
char vartmp[] = "/var/tmp";
- t = getenv("TMPDIR");
+ /* tmpdir is a user override, if set */
+ if (override_tmpdir == NULL)
+ t = getenv("TMPDIR");
+ else
+ t = override_tmpdir;
if (t != NULL && *t != '\0') {
diff --git a/util/libreboot-utils/lib/state.c b/util/libreboot-utils/lib/state.c
index 2fc22d52..2d2f6087 100644
--- a/util/libreboot-utils/lib/state.c
+++ b/util/libreboot-utils/lib/state.c
@@ -26,6 +26,9 @@ struct xstate *
xstart(int argc, char *argv[])
{
static int first_run = 1;
+ static char *dir = NULL;
+ static char *base = NULL;
+ char *realdir = NULL;
static struct xstate us = {
{
@@ -107,7 +110,15 @@ xstart(int argc, char *argv[])
us.f.tmp_fd = -1;
us.f.tname = NULL;
- if (new_tmpfile(&us.f.tmp_fd, &us.f.tname) < 0)
+ if ((realdir = realpath(us.f.fname, NULL)) == NULL)
+ err_no_cleanup(errno, "xstart: can't get realpath of %s",
+ us.f.fname);
+
+ if (fs_dirname_basename(realdir, &dir, &base, 0) < 0)
+ err_no_cleanup(errno, "xstart: don't know CWD of %s",
+ us.f.fname);
+
+ if (new_tmpfile(&us.f.tmp_fd, &us.f.tname, dir) < 0)
err_no_cleanup(errno, "%s", us.f.tname);
if (us.f.tname == NULL)