From 277c0c8e87a1ad3012b606d17c8afc3e785f3d39 Mon Sep 17 00:00:00 2001 From: Leah Rowe Date: Tue, 31 Mar 2026 11:54:41 +0100 Subject: lbutils/file: don't reset errno on successful io some io syscalls may set errno on success. this patch honours that. we try to preserve caller errno, but it is important for debugging not to clobber it. if fs_err_retry errs, then we don't reset errno. if fs_err is successful but errno wasn't set, we restore caller errno. this is done by setting errno to zero in callers, which also restore caller errno. Signed-off-by: Leah Rowe --- util/libreboot-utils/lib/file.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'util') diff --git a/util/libreboot-utils/lib/file.c b/util/libreboot-utils/lib/file.c index b4636865..3f94a4ab 100644 --- a/util/libreboot-utils/lib/file.c +++ b/util/libreboot-utils/lib/file.c @@ -770,6 +770,7 @@ open_file_on_eintr(const char *path, err_exit(EBADF, "%s: open_file_on_eintr: file already open", path); + errno = 0; while (fs_retry(saved_errno, rval = open(path, flags, mode))); @@ -814,6 +815,7 @@ openat_on_eintr(int dirfd, const char *path, 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)))); @@ -834,6 +836,7 @@ openat_on_eintr(int dirfd, const char *path, if_err(path == NULL, EFAULT)) return set_errno(saved_errno, EIO); + errno = 0; while (fs_retry(saved_errno, rval = openat(dirfd, path, flags, mode))); @@ -848,6 +851,7 @@ lseek_on_eintr(int fd, off_t off, int whence, int saved_errno = errno; off_t rval; + errno = 0; while (off_retry(saved_errno, rval = lseek(fd, off, whence))); @@ -865,6 +869,7 @@ mkdirat_on_eintr(int dirfd, if_err(path == NULL, EFAULT)) return set_errno(saved_errno, EIO); + errno = 0; while (fs_retry(saved_errno, rval = mkdirat(dirfd, path, mode))); @@ -883,6 +888,7 @@ read_on_eintr(int fd, if_err(count == 0, EINVAL)) return set_errno(saved_errno, EIO); + errno = 0; while (rw_retry(saved_errno, rval = read(fd, buf, count))); @@ -903,6 +909,7 @@ pread_on_eintr(int fd, if_err(count == 0, EINVAL)) return set_errno(saved_errno, EIO); + errno = 0; while (rw_retry(saved_errno, rval = pread(fd, buf, count, off))); @@ -921,6 +928,7 @@ write_on_eintr(int fd, if_err(count == 0, EINVAL)) return set_errno(saved_errno, EIO); + errno = 0; while (rw_retry(saved_errno, rval = write(fd, buf, count))); @@ -941,6 +949,7 @@ pwrite_on_eintr(int fd, if_err(count == 0, EINVAL)) return set_errno(saved_errno, EIO); + errno = 0; while (rw_retry(saved_errno, rval = pwrite(fd, buf, count, off))); @@ -956,6 +965,7 @@ fsync_on_eintr(int fd) if (if_err(fd < 0, EBADF)) return set_errno(saved_errno, EIO); + errno = 0; while (fs_retry(saved_errno, rval = fsync(fd))); @@ -973,6 +983,7 @@ close_on_eintr(int *fd) if (*fd < 0) return; + errno = 0; while (fs_retry(saved_errno, rval = close(*fd))); @@ -995,9 +1006,28 @@ close_on_eintr(int *fd) errno == EWOULDBLOCK || \ errno == ETXTBSY)) \ return 1; \ - if (rval >= 0) \ + 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 -- cgit v1.2.1