diff options
Diffstat (limited to 'util')
| -rw-r--r-- | util/libreboot-utils/include/common.h | 33 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/command.c | 4 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/file.c | 608 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/io.c | 14 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/mkhtemp.c | 6 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/rand.c | 30 |
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; |
