summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
Diffstat (limited to 'util')
-rw-r--r--util/libreboot-utils/include/common.h33
-rw-r--r--util/libreboot-utils/lib/command.c4
-rw-r--r--util/libreboot-utils/lib/file.c608
-rw-r--r--util/libreboot-utils/lib/io.c14
-rw-r--r--util/libreboot-utils/lib/mkhtemp.c6
-rw-r--r--util/libreboot-utils/lib/rand.c30
6 files changed, 273 insertions, 422 deletions
diff --git a/util/libreboot-utils/include/common.h b/util/libreboot-utils/include/common.h
index 12c6c486..bc0eb3b3 100644
--- a/util/libreboot-utils/include/common.h
+++ b/util/libreboot-utils/include/common.h
@@ -88,17 +88,6 @@ int fchmod(int fd, mode_t mode);
#define MAX_ZERO_RW_RETRY 5
#endif
-#ifndef REAL_POS_IO
-#define REAL_POS_IO 1
-#endif
-
-#ifndef LOOP_EAGAIN
-#define LOOP_EAGAIN 1
-#endif
-#ifndef LOOP_EINTR
-#define LOOP_EINTR 1
-#endif
-
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif
@@ -179,9 +168,6 @@ int fchmod(int fd, mode_t mode);
#define ARGC_3 3
#define ARGC_4 4
-#define NO_LOOP_EAGAIN 0
-#define NO_LOOP_EINTR 0
-
/* For checking if an fd is a normal file.
* Portable for old Unix e.g. v7 (S_IFREG),
* 4.2BSD (S_IFMT), POSIX (S_ISREG).
@@ -477,18 +463,15 @@ ssize_t rw_gbe_file_exact(int fd, unsigned char *mem, size_t nrw,
int fsync_dir(const char *path);
ssize_t rw_file_exact(int fd, unsigned char *mem, size_t len,
- off_t off, int rw_type, int loop_eagain, int loop_eintr,
- size_t max_retries, int off_reset);
+ off_t off, int rw_type, size_t max_retries, int off_reset);
ssize_t prw(int fd, void *mem, size_t nrw,
- off_t off, int rw_type, int loop_eagain, int loop_eintr,
- int off_reset);
+ off_t off, int rw_type);
int io_args(int fd, void *mem, size_t nrw,
off_t off, int rw_type);
int check_file(int fd, struct stat *st);
ssize_t rw_over_nrw(ssize_t r, size_t nrw);
off_t lseek_on_eintr(int fd, off_t off,
int whence, int loop_eagain, int loop_eintr);
-int try_err(int loop_err, int errval);
ssize_t read_on_eintr(int fd,
void *buf, size_t count);
ssize_t write_on_eintr(int fd,
@@ -497,6 +480,10 @@ ssize_t pread_on_eintr(int fd,
void *buf, size_t count, off_t off);
ssize_t pwrite_on_eintr(int fd,
void *buf, size_t count, off_t off);
+int off_retry(int saved_errno, off_t rval);
+int sys_retry(int saved_errno, long rval);
+int fs_retry(int saved_errno, int rval);
+int rw_retry(int saved_errno, ssize_t rval);
/* Error handling and cleanup
*/
@@ -557,7 +544,7 @@ int fs_rename_at(int olddirfd, const char *old,
int newdirfd, const char *new);
int fs_open(const char *path, int flags);
void free_and_set_null(char **buf);
-void open_on_eintr(const char *path, int *fd, int flags, mode_t mode,
+void open_file_on_eintr(const char *path, int *fd, int flags, mode_t mode,
struct stat *st);
struct filesystem *rootfs(void);
int fs_resolve_at(int dirfd, const char *path, int flags);
@@ -567,7 +554,7 @@ int fs_open_component(int dirfd, const char *name,
int flags, int is_last);
int fs_dirname_basename(const char *path,
char **dir, char **base, int allow_relative);
-int openat2p(int dirfd, const char *path,
+int openat_on_eintr(int dirfd, const char *path,
int flags, mode_t mode);
int mkdirat_on_eintr(int dirfd,
const char *pathname, mode_t mode);
@@ -631,10 +618,6 @@ 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/libreboot-utils/lib/command.c b/util/libreboot-utils/lib/command.c
index 3ee75628..16ca8346 100644
--- a/util/libreboot-utils/lib/command.c
+++ b/util/libreboot-utils/lib/command.c
@@ -496,8 +496,8 @@ cat_buf(unsigned char *b)
err_exit(errno, "null pointer in cat command");
if (rw_file_exact(STDOUT_FILENO, b,
- GBE_PART_SIZE, 0, IO_WRITE, LOOP_EAGAIN, LOOP_EINTR,
- MAX_ZERO_RW_RETRY, OFF_ERR) < 0)
+ GBE_PART_SIZE, 0, IO_WRITE, MAX_ZERO_RW_RETRY, OFF_ERR)
+ < 0)
err_exit(errno, "stdout: cat");
}
void
diff --git a/util/libreboot-utils/lib/file.c b/util/libreboot-utils/lib/file.c
index 1d2de9b8..42c91843 100644
--- a/util/libreboot-utils/lib/file.c
+++ b/util/libreboot-utils/lib/file.c
@@ -7,6 +7,16 @@
* Be nice to the demon.
*/
+/*
+TODO: putting it here just so it's somewhere:
+PATH_MAX is not reliable as a limit for paths,
+because the real length depends on mount point,
+and specific file systems.
+more correct usage example:
+long max = pathconf("/", _PC_PATH_MAX);
+ */
+
+
#include <sys/types.h>
#include <sys/stat.h>
@@ -150,9 +160,7 @@ err_fsync_dir:
ssize_t
rw_file_exact(int fd, unsigned char *mem, size_t nrw,
- off_t off, int rw_type, int loop_eagain,
- int loop_eintr, size_t max_retries,
- int off_reset)
+ off_t off, int rw_type, size_t max_retries, int off_reset)
{
ssize_t rval;
ssize_t rc;
@@ -198,8 +206,7 @@ rw_file_exact(int fd, unsigned char *mem, size_t nrw,
off_cur = off + (off_t)rc;
rval = prw(fd, mem_cur, nrw_cur, off_cur,
- rw_type, loop_eagain, loop_eintr,
- off_reset);
+ rw_type);
if (rval < 0)
goto err_rw_file_exact;
@@ -237,180 +244,42 @@ err_rw_file_exact:
/* prw() - portable read-write with more
* safety checks than barebones libc
*
- * If you need real pwrite/pread, just compile
- * with flag: REAL_POS_IO=1
- *
* A fallback is provided for regular read/write.
* rw_type can be IO_READ (read), IO_WRITE (write),
* IO_PREAD (pread) or IO_PWRITE
- *
- * loop_eagain does a retry loop on EAGAIN if set
- * loop_eintr does a retry loop on EINTR if set
- *
- * race conditions on non-libc pread/pwrite:
- * if a file offset changes, abort, to mitage.
- *
- * off_reset 1: reset the file offset *once* if
- * a change was detected, assuming
- * nothing else is touching it now
- * off_reset 0: never reset if changed
- *
- * REAL_POS_IO is enabled by default in common.h
- * and the fallback version was written for fun.
- * You should just use the real one (REAL_POS_IO 1),
- * since it is generally more reliable.
*/
ssize_t
prw(int fd, void *mem, size_t nrw,
- off_t off, int rw_type,
- int loop_eagain, int loop_eintr,
- int off_reset)
+ off_t off, int rw_type)
{
ssize_t rval;
ssize_t r;
- int positional_rw;
struct stat st;
-#if !defined(REAL_POS_IO) || \
- REAL_POS_IO < 1
- off_t verified;
- off_t off_orig;
- off_t off_last;
-#endif
int saved_errno = errno;
errno = 0;
- if (io_args(fd, mem, nrw, off, rw_type)
- == -1)
- goto err_prw;
+ if (io_args(fd, mem, nrw, off, rw_type) == -1)
+ return set_errno(saved_errno, EIO);
r = -1;
- /* do not use loop_eagain on
- * normal files
- */
+ if (rw_type == IO_WRITE)
+ r = write_on_eintr(fd, mem, nrw);
+ else if (rw_type == IO_READ)
+ r = read_on_eintr(fd, mem, nrw);
+ else if (rw_type == IO_PWRITE)
+ r = pwrite_on_eintr(fd, mem, nrw, off);
+ else if (rw_type == IO_PREAD)
+ r = pread_on_eintr(fd, mem, nrw, off);
- if (!loop_eagain) {
- /* check whether the file
- * changed
- */
-
- if (check_file(fd, &st) == -1)
- goto err_prw;
- }
-
- if (rw_type >= IO_PREAD)
- positional_rw = 1; /* pread/pwrite */
- else
- positional_rw = 0; /* read/write */
-
-try_rw_again:
-
- if (!positional_rw) {
-#if defined(REAL_POS_IO) && \
- REAL_POS_IO > 0
-real_pread_pwrite:
-#endif
- if (rw_type == IO_WRITE)
- r = write_on_eintr(fd, mem, nrw);
- else if (rw_type == IO_READ)
- r = read_on_eintr(fd, mem, nrw);
-#if defined(REAL_POS_IO) && \
- REAL_POS_IO > 0
- else if (rw_type == IO_PWRITE)
- r = pwrite_on_eintr(fd, mem, nrw, off);
- else if (rw_type == IO_PREAD)
- r = pread_on_eintr(fd, mem, nrw, off);
-#endif
-
- if (r == -1 && (errno == try_err(loop_eintr, EINTR)
- || errno == try_err(loop_eagain, EAGAIN)))
- goto try_rw_again;
-
- rval = rw_over_nrw(r, nrw);
- if (rval < 0)
- goto err_prw;
+ if ((rval = rw_over_nrw(r, nrw)) < 0)
+ return set_errno(saved_errno, EIO);
+ if (rval >= 0 && !errno)
errno = saved_errno;
- return rval;
- }
-
-#if defined(REAL_POS_IO) && \
- REAL_POS_IO > 0
- goto real_pread_pwrite;
-#else
- if ((off_orig = lseek_on_eintr(fd, (off_t)0, SEEK_CUR,
- loop_eagain, loop_eintr)) == (off_t)-1) {
- r = -1;
- } else if (lseek_on_eintr(fd, off, SEEK_SET,
- loop_eagain, loop_eintr) == (off_t)-1) {
- r = -1;
- } else {
- verified = lseek_on_eintr(fd, (off_t)0, SEEK_CUR,
- loop_eagain, loop_eintr);
-
- /* abort if the offset changed,
- * indicating race condition. if
- * off_reset enabled, reset *ONCE*
- */
-
- if (off_reset && off != verified)
- lseek_on_eintr(fd, off, SEEK_SET,
- loop_eagain, loop_eintr);
-
- do {
- /* check offset again, repeatedly.
- * even if off_reset is set, this
- * aborts if offsets change again
- */
-
- verified = lseek_on_eintr(fd, (off_t)0, SEEK_CUR,
- loop_eagain, loop_eintr);
-
- if (off != verified) {
-
- errno = EBUSY;
- goto err_prw;
- }
-
- if (rw_type == IO_PREAD)
- r = read_on_eintr(fd, mem, nrw);
- else if (rw_type == IO_PWRITE)
- r = write_on_eintr(fd, mem, nrw);
-
- if (rw_over_nrw(r, nrw) == -1)
- break;
-
- } while (r == -1 &&
- (errno == try_err(loop_eintr, EINTR) ||
- errno == try_err(loop_eagain, EAGAIN)));
- }
-
- saved_errno = errno;
-
- off_last = lseek_on_eintr(fd, off_orig, SEEK_SET,
- loop_eagain, loop_eintr);
-
- if (off_last != off_orig) {
- errno = saved_errno;
- goto err_prw;
- }
-
- errno = saved_errno;
-
- rval = rw_over_nrw(r, nrw);
- if (rval < 0)
- goto err_prw;
-
- errno = saved_errno;
-
return rval;
-
-#endif
-
-err_prw:
- return set_errno(saved_errno, EIO);
}
int
@@ -456,7 +325,6 @@ err_is_file:
/* POSIX can say whatever it wants.
* specification != implementation
*/
-
ssize_t
rw_over_nrw(ssize_t r, size_t nrw)
{
@@ -466,32 +334,10 @@ rw_over_nrw(ssize_t r, size_t nrw)
if_err(r == -1, 0) ||
if_err((size_t)r > SSIZE_MAX, ERANGE) ||
if_err((size_t)r > nrw, ERANGE))
- goto err_rw_over_nrw;
+ return set_errno(saved_errno, EIO);
errno = saved_errno;
return r;
-
-err_rw_over_nrw:
- return set_errno(saved_errno, EIO);
-}
-
-off_t
-lseek_on_eintr(int fd, off_t off, int whence,
- int loop_eagain, int loop_eintr)
-{
- off_t old;
-
- old = -1;
-
- do {
- old = lseek(fd, off, whence);
- } while (old == (off_t)-1 && (
- errno == try_err(loop_eintr, EINTR) ||
- errno == try_err(loop_eintr, ETXTBSY) ||
- errno == try_err(loop_eagain, EAGAIN) ||
- errno == try_err(loop_eagain, EWOULDBLOCK)));
-
- return old;
}
/* two functions that reduce sloccount by
@@ -514,102 +360,6 @@ if_err_sys(int condition)
return 0;
return 1;
}
-/* errno can never be -1, so you can
- * use this to conditionally set an integer
- * for comparison. see example in lseek_on_eintr
- */
-int
-try_err(int loop_err, int errval)
-{
- if (loop_err)
- return errval;
- return -1;
-}
-
-void
-open_on_eintr(const char *path,
- int *fd, int flags, mode_t mode,
- struct stat *st)
-{
- int r = -1;
- int saved_errno = errno;
-
- if (path == NULL)
- err_exit(EINVAL, "open_on_eintr: null path");
-
- if (fd == NULL)
- err_exit(EFAULT, "%s: open_on_eintr: null fd ptr", path);
-
- if (*fd >= 0)
- err_exit(EBADF, "%s: open_on_eintr: file already open", path);
-
- do {
- r = open(path, flags, mode);
- } while (r == -1 && (
- errno == EINTR || errno == EAGAIN ||
- errno == EWOULDBLOCK || errno == ETXTBSY));
-
- if (r < 0)
- err_exit(errno, "%s: open_on_eintr: could not close", path);
-
- *fd = r;
-
- if (st != NULL) {
- if (fstat(*fd, st) < 0)
- err_exit(errno, "%s: stat", path);
-
- if (!S_ISREG(st->st_mode))
- err_exit(errno, "%s: not a regular file", path);
- }
-
- if (lseek_on_eintr(*fd, 0, SEEK_CUR, 1, 1) == (off_t)-1)
- err_exit(errno, "%s: file not seekable", path);
-
- errno = saved_errno;
-}
-
-void
-close_on_eintr(int *fd)
-{
- int r;
- int saved_errno = errno;
-
- if (fd == NULL)
- err_exit(EINVAL, "close_on_eintr: null pointer");
-
- if (*fd < 0)
- return;
-
- do {
- r = close(*fd);
- } while (r == -1 && (
- errno == EINTR || errno == EAGAIN ||
- errno == EWOULDBLOCK || errno == ETXTBSY));
-
- if (r < 0)
- err_exit(errno, "close_on_eintr: could not close");
-
- *fd = -1;
-
- errno = saved_errno;
-}
-
-int
-fsync_on_eintr(int fd)
-{
- int r;
- int saved_errno = errno;
-
- do {
- r = fsync(fd);
- } while (r == -1 && (errno == EINTR || errno == EAGAIN ||
- errno == ETXTBSY || errno == EWOULDBLOCK));
-
- if (r >= 0)
- errno = saved_errno;
-
- return r;
-}
int
fs_rename_at(int olddirfd, const char *old,
@@ -653,7 +403,7 @@ rootfs(void)
global_fs.rootfd = -1;
- open_on_eintr("/", &global_fs.rootfd,
+ open_file_on_eintr("/", &global_fs.rootfd,
O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0400, NULL);
if (global_fs.rootfd < 0)
@@ -782,7 +532,7 @@ fs_open_component(int dirfd, const char *name,
int fd;
struct stat st;
- fd = openat2p(dirfd, name,
+ fd = openat_on_eintr(dirfd, name,
(is_last ? flags : (O_RDONLY | O_DIRECTORY)) |
O_NOFOLLOW | O_CLOEXEC, (flags & O_CREAT) ? 0600 : 0);
@@ -849,14 +599,55 @@ fs_dirname_basename(const char *path,
return 0;
}
-/* portable wrapper for use of openat2 on linux,
- * with fallback for others e.g. openbsd
+/* TODO: why does this abort, but others
+ e.g. open_file_on_eintr, don't???
*/
+void
+open_file_on_eintr(const char *path,
+ int *fd, int flags, mode_t mode,
+ struct stat *st)
+{
+ int saved_errno = errno;
+ int rval;
+
+ if (path == NULL)
+ err_exit(EINVAL, "open_file_on_eintr: null path");
+ if (fd == NULL)
+ err_exit(EFAULT, "%s: open_file_on_eintr: null fd ptr", path);
+ if (*fd >= 0)
+ err_exit(EBADF,
+ "%s: open_file_on_eintr: file already open", path);
+
+ errno = 0;
+ while (fs_retry(saved_errno,
+ rval = open(path, flags, mode)));
+
+ if (rval < 0)
+ err_exit(errno,
+ "%s: open_file_on_eintr: could not close", path);
+
+ *fd = rval;
+
+ if (st != NULL) {
+ if (fstat(*fd, st) < 0)
+ err_exit(errno, "%s: stat", path);
+
+ if (!S_ISREG(st->st_mode))
+ err_exit(errno, "%s: not a regular file", path);
+ }
+
+ if (lseek_on_eintr(*fd, 0, SEEK_CUR, 1, 1) == (off_t)-1)
+ err_exit(errno, "%s: file not seekable", path);
+
+ errno = saved_errno;
+}
+
+
+#ifdef __linux__ /* we use openat2 on linux */
int
-openat2p(int dirfd, const char *path,
+openat_on_eintr(int dirfd, const char *path,
int flags, mode_t mode)
{
-#ifdef __linux__
struct open_how how = {
.flags = flags,
.mode = mode,
@@ -866,36 +657,51 @@ openat2p(int dirfd, const char *path,
RESOLVE_NO_MAGICLINKS
};
int saved_errno = errno;
- int rval;
-#endif
+ long rval;
if (if_err(dirfd < 0, EBADF) ||
if_err(path == NULL, EFAULT))
+ return set_errno(saved_errno, EIO);
+
+ errno = 0;
+ while (sys_retry(saved_errno,
+ rval = syscall(SYS_openat2, dirfd, path, &how, sizeof(how))));
+
+ if (rval == -1) /* avoid long->int UB for -1 */
return -1;
-retry:
+ return (int)rval;
+}
+#else /* regular openat on non-linux e.g. openbsd */
+int
+openat_on_eintr(int dirfd, const char *path,
+ int flags, mode_t mode)
+{
+ int saved_errno = errno;
+ int rval;
+
+ if (if_err(dirfd < 0, EBADF) ||
+ if_err(path == NULL, EFAULT))
+ return set_errno(saved_errno, EIO);
+
errno = 0;
+ while (fs_retry(saved_errno,
+ rval = openat(dirfd, path, flags, mode)));
-#ifdef __linux__
- /* more secure than regular openat,
- * but linux-only at the time of writing
- */
- rval = syscall(SYS_openat2, dirfd, path, &how, sizeof(how));
-#else
- /* less secure, but e.g. openbsd
- * doesn't have openat2 yet
- */
- rval = openat(dirfd, path, flags, mode);
+ return rval;
+}
#endif
- if (rval == -1 && (
- errno == EINTR ||
- errno == EAGAIN ||
- errno == EWOULDBLOCK ||
- errno == ETXTBSY))
- goto retry;
-
- if (rval >= 0)
- errno = saved_errno;
+
+off_t
+lseek_on_eintr(int fd, off_t off, int whence,
+ int loop_eagain, int loop_eintr)
+{
+ int saved_errno = errno;
+ off_t rval;
+
+ errno = 0;
+ while (off_retry(saved_errno,
+ rval = lseek(fd, off, whence)));
return rval;
}
@@ -909,21 +715,11 @@ mkdirat_on_eintr(int dirfd,
if (if_err(dirfd < 0, EBADF) ||
if_err(path == NULL, EFAULT))
- return -1;
+ return set_errno(saved_errno, EIO);
-retry:
errno = 0;
- rval = mkdirat(dirfd, path, mode);
-
- if (rval == -1 && (
- errno == EINTR ||
- errno == EAGAIN ||
- errno == EWOULDBLOCK ||
- errno == ETXTBSY))
- goto retry;
-
- if (rval >= 0)
- errno = saved_errno;
+ while (fs_retry(saved_errno,
+ rval = mkdirat(dirfd, path, mode)));
return rval;
}
@@ -933,27 +729,18 @@ read_on_eintr(int fd,
void *buf, size_t count)
{
int saved_errno = errno;
- int rval;
+ ssize_t rval;
if (if_err(buf == NULL, EFAULT) ||
if_err(fd < 0, EBADF) ||
if_err(count == 0, EINVAL))
- goto err;
+ return set_errno(saved_errno, EIO);
-retry:
errno = 0;
+ while (rw_retry(saved_errno,
+ rval = read(fd, buf, count)));
- if ((rval = read(fd, buf, count)) == -1 && (
- errno == EINTR ||
- errno == EAGAIN ||
- errno == EWOULDBLOCK ||
- errno == ETXTBSY))
- goto retry;
-
- errno = saved_errno;
return rval;
-err:
- return set_errno(saved_errno, EIO);
}
ssize_t
@@ -962,28 +749,19 @@ pread_on_eintr(int fd,
off_t off)
{
int saved_errno = errno;
- int rval;
+ ssize_t rval;
if (if_err(buf == NULL, EFAULT) ||
if_err(fd < 0, EBADF) ||
if_err(off < 0, EFAULT) ||
if_err(count == 0, EINVAL))
- goto err;
+ return set_errno(saved_errno, EIO);
-retry:
errno = 0;
+ while (rw_retry(saved_errno,
+ rval = pread(fd, buf, count, off)));
- if ((rval = pread(fd, buf, count, off)) == -1 && (
- errno == EINTR ||
- errno == EAGAIN ||
- errno == EWOULDBLOCK ||
- errno == ETXTBSY))
- goto retry;
-
- errno = saved_errno;
return rval;
-err:
- return set_errno(saved_errno, EIO);
}
ssize_t
@@ -991,27 +769,18 @@ write_on_eintr(int fd,
void *buf, size_t count)
{
int saved_errno = errno;
- int rval;
+ ssize_t rval;
if (if_err(buf == NULL, EFAULT) ||
if_err(fd < 0, EBADF) ||
if_err(count == 0, EINVAL))
- goto err;
+ return set_errno(saved_errno, EIO);
-retry:
errno = 0;
+ while (rw_retry(saved_errno,
+ rval = write(fd, buf, count)));
- if ((rval = write(fd, buf, count)) == -1 && (
- errno == EINTR ||
- errno == EAGAIN ||
- errno == EWOULDBLOCK ||
- errno == ETXTBSY))
- goto retry;
-
- errno = saved_errno;
return rval;
-err:
- return set_errno(saved_errno, EIO);
}
ssize_t
@@ -1020,26 +789,127 @@ pwrite_on_eintr(int fd,
off_t off)
{
int saved_errno = errno;
- int rval;
+ ssize_t rval;
if (if_err(buf == NULL, EFAULT) ||
if_err(fd < 0, EBADF) ||
if_err(off < 0, EFAULT) ||
if_err(count == 0, EINVAL))
- goto err;
+ return set_errno(saved_errno, EIO);
-retry:
errno = 0;
+ while (rw_retry(saved_errno,
+ rval = pwrite(fd, buf, count, off)));
+
+ return rval;
+}
- if ((rval = pwrite(fd, buf, count, off)) == -1 && (
- errno == EINTR ||
- errno == EAGAIN ||
- errno == EWOULDBLOCK ||
- errno == ETXTBSY))
- goto retry;
+int
+fsync_on_eintr(int fd)
+{
+ int saved_errno = errno;
+ int rval;
+
+ if (if_err(fd < 0, EBADF))
+ return set_errno(saved_errno, EIO);
+
+ errno = 0;
+ while (fs_retry(saved_errno,
+ rval = fsync(fd)));
- errno = saved_errno;
return rval;
-err:
- return set_errno(saved_errno, EIO);
+}
+
+void
+close_on_eintr(int *fd)
+{
+ int saved_errno = errno;
+ int rval;
+
+ if (fd == NULL)
+ err_exit(EINVAL, "close_on_eintr: null pointer");
+ if (*fd < 0)
+ return;
+
+ errno = 0;
+ while (fs_retry(saved_errno,
+ rval = close(*fd)));
+
+ if (rval < 0)
+ err_exit(errno, "close_on_eintr: could not close");
+
+ *fd = -1;
+}
+
+/* unified eintr looping.
+ * differently typed functions
+ * to avoid potential UB
+ *
+ * ONE MACRO TO RULE THEM ALL:
+ */
+#define fs_err_retry() \
+ if ((rval == -1) && \
+ (errno == EINTR)) \
+ return 1; \
+ if (rval >= 0 && !errno) \
+ errno = saved_errno; \
+ return 0
+/*
+ * Regarding the errno logic above:
+ * on success, it is permitted that
+ * a syscall could still set errno.
+ * We reset errno after storingit
+ * for later preservation, in functions
+ * that call *_retry() functions.
+ *
+ * They rely ultimately on this
+ * macro for errno restoration. We
+ * assume therefore that errno was
+ * reset to zero before the retry
+ * loop. If errno is then *set* on
+ * success, we leave it alone. Otherwise,
+ * we restore the caller's saved errno.
+ *
+ * This offers some consistency, while
+ * complying with POSIX specification.
+ */
+
+
+/* retry switch for offset-based
+ * functions e.g. lseek
+ */
+/* retry switch for functions that
+ return long status e.g. linux syscall
+ */
+int
+off_retry(int saved_errno, off_t rval)
+{
+ fs_err_retry();
+}
+
+/* retry switch for functions that
+ return long status e.g. linux syscall
+ */
+int
+sys_retry(int saved_errno, long rval)
+{
+ fs_err_retry();
+}
+
+/* retry switch for functions that
+ return int status e.g. mkdirat
+ */
+int
+fs_retry(int saved_errno, int rval)
+{
+ fs_err_retry();
+}
+
+/* retry switch for functions that
+ return rw count in ssize_t e.g. read()
+ */
+int
+rw_retry(int saved_errno, ssize_t rval)
+{
+ fs_err_retry();
}
diff --git a/util/libreboot-utils/lib/io.c b/util/libreboot-utils/lib/io.c
index 4938cdc8..f74ce261 100644
--- a/util/libreboot-utils/lib/io.c
+++ b/util/libreboot-utils/lib/io.c
@@ -33,7 +33,7 @@ open_gbe_file(void)
f->gbe_fd = -1;
- open_on_eintr(f->fname, &f->gbe_fd,
+ open_file_on_eintr(f->fname, &f->gbe_fd,
O_NOFOLLOW | O_CLOEXEC | O_NOCTTY,
((cmd->flags & O_ACCMODE) == O_RDONLY) ? 0400 : 0600,
&f->gbe_st);
@@ -104,8 +104,7 @@ read_file(void)
/* read main file
*/
_r = rw_file_exact(f->gbe_fd, f->buf, f->gbe_file_size,
- 0, IO_PREAD, NO_LOOP_EAGAIN, LOOP_EINTR,
- MAX_ZERO_RW_RETRY, OFF_ERR);
+ 0, IO_PREAD, MAX_ZERO_RW_RETRY, OFF_ERR);
if (_r < 0)
err_exit(errno, "%s: read failed", f->fname);
@@ -113,8 +112,7 @@ read_file(void)
/* copy to tmpfile
*/
_r = rw_file_exact(f->tmp_fd, f->buf, f->gbe_file_size,
- 0, IO_PWRITE, NO_LOOP_EAGAIN, LOOP_EINTR,
- MAX_ZERO_RW_RETRY, OFF_ERR);
+ 0, IO_PWRITE, MAX_ZERO_RW_RETRY, OFF_ERR);
if (_r < 0)
err_exit(errno, "%s: %s: copy failed",
@@ -137,8 +135,7 @@ read_file(void)
err_exit(errno, "%s: fsync (tmpfile copy)", f->tname);
_r = 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);
+ 0, IO_PREAD, MAX_ZERO_RW_RETRY, OFF_ERR);
if (_r < 0)
err_exit(errno, "%s: read failed (cmp)", f->tname);
@@ -570,8 +567,7 @@ rw_gbe_file_exact(int fd, unsigned char *mem, size_t nrw,
goto err_rw_gbe_file_exact;
r = rw_file_exact(fd, mem, nrw, off, rw_type,
- NO_LOOP_EAGAIN, LOOP_EINTR, MAX_ZERO_RW_RETRY,
- OFF_ERR);
+ MAX_ZERO_RW_RETRY, OFF_ERR);
return rw_over_nrw(r, nrw);
diff --git a/util/libreboot-utils/lib/mkhtemp.c b/util/libreboot-utils/lib/mkhtemp.c
index 7a73befb..7589a410 100644
--- a/util/libreboot-utils/lib/mkhtemp.c
+++ b/util/libreboot-utils/lib/mkhtemp.c
@@ -624,7 +624,7 @@ mkhtemp_try_create(int dirfd,
}
#endif
- *fd = openat2p(dirfd, fname_copy,
+ *fd = openat_on_eintr(dirfd, fname_copy,
O_RDWR | O_CREAT | O_EXCL |
O_NOFOLLOW | O_CLOEXEC | O_NOCTTY, 0600);
@@ -648,7 +648,7 @@ mkhtemp_try_create(int dirfd,
if (fd_verify_dir_identity(dirfd, st_dir_initial) < 0)
goto err;
- if ((*fd = openat2p(dirfd, fname_copy,
+ if ((*fd = openat_on_eintr(dirfd, fname_copy,
O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0)) < 0)
goto err;
@@ -662,7 +662,7 @@ mkhtemp_try_create(int dirfd,
}
- /* NOTE: openat2p and mkdirat_on_eintr
+ /* NOTE: openat_on_eintr and mkdirat_on_eintr
* already handled EINTR/EAGAIN looping
*/
diff --git a/util/libreboot-utils/lib/rand.c b/util/libreboot-utils/lib/rand.c
index 9da8d9eb..20dc33cd 100644
--- a/util/libreboot-utils/lib/rand.c
+++ b/util/libreboot-utils/lib/rand.c
@@ -143,28 +143,30 @@ rset(void *buf, size_t n)
goto out;
#else
size_t off = 0;
- ssize_t rc = 0;
+
+retry_rand:
#if defined(USE_URANDOM) && \
((USE_URANDOM) > 0)
+ ssize_t rc;
int fd = -1;
- open_on_eintr("/dev/urandom", &fd, O_RDONLY, 0400, NULL);
-retry_rand:
- if ((rc = read_on_eintr(fd,
- (unsigned char *)buf + off, n - off)) < 0) {
+
+ open_file_on_eintr("/dev/urandom", &fd, O_RDONLY, 0400, NULL);
+
+ while (rw_retry(saved_errno,
+ rc = read_on_eintr(fd,
+ (unsigned char *)buf + off, n - off, 0)));
#elif defined(__linux__)
-retry_rand:
- if ((rc = (ssize_t)syscall(SYS_getrandom,
- (unsigned char *)buf + off, n - off, 0)) < 0) {
+ long rc;
+ while (sys_retry(saved_errno,
+ rc = syscall(SYS_getrandom,
+ (unsigned char *)buf + off, n - off, 0)));
#else
#error Unsupported operating system (possibly unsecure randomisation)
#endif
- if (errno == EINTR ||
- errno == EAGAIN)
- goto retry_rand;
- goto err; /* possibly unsupported by kernel */
- }
+ if (rc < 0)
+ goto err;
if (rc == 0)
goto err; /* prevent infinite loop on fatal err */
@@ -176,7 +178,7 @@ retry_rand:
((USE_URANDOM) > 0)
close_on_eintr(&fd);
#endif
- goto out;
+
#endif
out:
errno = saved_errno;