From 87503e225993ec44fe4de1c4e0bd80d7c215632f Mon Sep 17 00:00:00 2001 From: Henson Choi Date: Tue, 25 Aug 2026 13:58:40 +0900 Subject: [PATCH] Retry open() when it fails with EINTR POSIX allows open() to fail with EINTR, and macOS returns it: an open() that has to sleep can be interrupted, and the filesystem hands the EINTR up rather than asking for a restart, so SA_RESTART does not cover it. A saturated vnode table is one way to get there, because opening an uncached file then waits for a vnode to be reclaimed. We did not retry. BasicOpenFilePerm() retries EMFILE and ENFILE only, so the EINTR reached mdopenfork() as a plain failure and became an ERROR. Mid-statement that is just an error, but in transaction abort it re-enters abort processing and trips the TransactionIdIsValid(proc->xid) assertion in ProcArrayEndTransaction(), whereupon the postmaster takes shared memory for corrupt and restarts the cluster. A 20-way "make check" on macOS 26.6.1 lost 38 of 250 tests to one EINTR that landed in that window; a later run took twelve EINTRs, none of them in an abort, and lost 13. The asymmetry is visible within fd.c, whose read and write paths retry EINTR and whose open() did not. On the machine in question the vnode table sat pinned at its cap, kern.num_vnodes 263168 of kern.maxvnodes 263168. That is what makes the call interruptible at all: with no vnode free, opening an uncached file waits for one to be reclaimed. All six occurrences followed a macOS 26.6.1 update, but the correlation carries no weight, because crash report retention on this machine begins four minutes after the update reboot and no pre-update sample survives. The saturation was not transient either, reading the same two days later, and a full Spotlight reindex was ruled out. What varies is the reclaim pressure at the moment of the call, and that cannot be recovered after the fact. Which signal did the interrupting was never established. Add pg_open(), which retries, and use it in place of open() through the backend, frontend and port layers. The pg_ prefix follows pg_pread and pg_pwrite: it warns that the call is not quite the standard one. Native Windows keeps plain open(), already redirected to pgwin32_open(), which cannot return EINTR. src/timezone/zic.c is left alone, as it tracks the IANA sources. --- src/backend/postmaster/fork_process.c | 2 +- src/backend/postmaster/syslogger.c | 2 +- src/backend/storage/file/fd.c | 4 +-- src/backend/utils/error/elog.c | 4 +-- src/backend/utils/init/miscinit.c | 8 ++--- src/bin/initdb/findtimezone.c | 2 +- src/bin/pg_basebackup/pg_basebackup.c | 2 +- src/bin/pg_basebackup/pg_receivewal.c | 4 +-- src/bin/pg_basebackup/pg_recvlogical.c | 4 +-- src/bin/pg_basebackup/walmethods.c | 10 +++--- src/bin/pg_checksums/pg_checksums.c | 2 +- src/bin/pg_combinebackup/backup_label.c | 6 ++-- src/bin/pg_combinebackup/copy_file.c | 22 ++++++------ src/bin/pg_combinebackup/load_manifest.c | 2 +- src/bin/pg_combinebackup/pg_combinebackup.c | 2 +- src/bin/pg_combinebackup/reconstruct.c | 8 ++--- src/bin/pg_combinebackup/write_manifest.c | 6 ++-- src/bin/pg_ctl/pg_ctl.c | 4 +-- src/bin/pg_dump/pg_backup_tar.c | 4 +-- src/bin/pg_resetwal/pg_resetwal.c | 8 ++--- src/bin/pg_rewind/file_ops.c | 6 ++-- src/bin/pg_rewind/local_source.c | 4 +-- src/bin/pg_rewind/parsexlog.c | 2 +- src/bin/pg_test_fsync/pg_test_fsync.c | 20 +++++------ src/bin/pg_upgrade/exec.c | 4 +-- src/bin/pg_upgrade/file.c | 30 ++++++++-------- src/bin/pg_upgrade/slru_io.c | 6 ++-- src/bin/pg_verifybackup/pg_verifybackup.c | 6 ++-- src/bin/pg_waldump/pg_waldump.c | 2 +- src/bin/pg_walsummary/pg_walsummary.c | 2 +- src/bin/psql/command.c | 2 +- src/bin/psql/input.c | 2 +- src/common/controldata_utils.c | 6 ++-- src/common/file_utils.c | 8 ++--- src/fe_utils/archive.c | 2 +- src/include/port.h | 15 ++++++++ src/interfaces/libpq/fe-lobj.c | 4 +-- src/interfaces/libpq/fe-secure-openssl.c | 2 +- src/port/Makefile | 1 + src/port/meson.build | 1 + src/port/mkdtemp.c | 2 +- src/port/pg_strong_random.c | 2 +- src/port/pgopen.c | 38 ++++++++++++++++++++ src/test/examples/testlo.c | 4 +-- src/test/examples/testlo64.c | 4 +-- src/test/modules/test_cloexec/test_cloexec.c | 4 +-- src/timezone/pgtz.c | 4 +-- 47 files changed, 172 insertions(+), 117 deletions(-) create mode 100644 src/port/pgopen.c diff --git a/src/backend/postmaster/fork_process.c b/src/backend/postmaster/fork_process.c index c6b0c41c6d4..ddbfd7b66d7 100644 --- a/src/backend/postmaster/fork_process.c +++ b/src/backend/postmaster/fork_process.c @@ -96,7 +96,7 @@ fork_process(void) * Use open() not stdio, to ensure we control the open flags. Some * Linux security environments reject anything but O_WRONLY. */ - int fd = open(oomfilename, O_WRONLY, 0); + int fd = pg_open(oomfilename, O_WRONLY, 0); /* We ignore all errors */ if (fd >= 0) diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index b4b599c4c69..11a42ee5ad2 100644 --- a/src/backend/postmaster/syslogger.c +++ b/src/backend/postmaster/syslogger.c @@ -237,7 +237,7 @@ SysLoggerMain(const void *startup_data, size_t startup_data_len) */ if (redirection_done) { - int fd = open(DEVNULL, O_WRONLY, 0); + int fd = pg_open(DEVNULL, O_WRONLY, 0); /* * The closes might look redundant, but they are not: we want to be diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index 190c9974494..fc99d53597b 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -1115,9 +1115,9 @@ BasicOpenFilePerm(const char *fileName, int fileFlags, mode_t fileMode) tryAgain: #ifdef PG_O_DIRECT_USE_F_NOCACHE - fd = open(fileName, fileFlags & ~PG_O_DIRECT, fileMode); + fd = pg_open(fileName, fileFlags & ~PG_O_DIRECT, fileMode); #else - fd = open(fileName, fileFlags, fileMode); + fd = pg_open(fileName, fileFlags, fileMode); #endif if (fd >= 0) diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index b9d2c96b97a..565fa8bbcd1 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -2316,8 +2316,8 @@ DebugFileOpen(void) * * Make sure we can write the file, and find out if it's a tty. */ - if ((fd = open(OutputFileName, O_CREAT | O_APPEND | O_WRONLY, - 0666)) < 0) + if ((fd = pg_open(OutputFileName, O_CREAT | O_APPEND | O_WRONLY, + 0666)) < 0) ereport(FATAL, (errcode_for_file_access(), errmsg("could not open file \"%s\": %m", OutputFileName))); diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index eddce1ce33f..64e35b22b61 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -1223,7 +1223,7 @@ CreateLockFile(const char *filename, bool amPostmaster, * Think not to make the file protection weaker than 0600/0640. See * comments below. */ - fd = open(filename, O_RDWR | O_CREAT | O_EXCL, pg_file_create_mode); + fd = pg_open(filename, O_RDWR | O_CREAT | O_EXCL, pg_file_create_mode); if (fd >= 0) break; /* Success; exit the retry loop */ @@ -1240,7 +1240,7 @@ CreateLockFile(const char *filename, bool amPostmaster, * Read the file to get the old owner's PID. Note race condition * here: file might have been deleted since we tried to create it. */ - fd = open(filename, O_RDONLY, pg_file_create_mode); + fd = pg_open(filename, O_RDONLY, pg_file_create_mode); if (fd < 0) { if (errno == ENOENT) @@ -1530,7 +1530,7 @@ AddToDataDirLockFile(int target_line, const char *str) char srcbuffer[BLCKSZ]; char destbuffer[BLCKSZ]; - fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0); + fd = pg_open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0); if (fd < 0) { ereport(LOG, @@ -1654,7 +1654,7 @@ RecheckDataDirLockFile(void) long file_pid; char buffer[BLCKSZ]; - fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0); + fd = pg_open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0); if (fd < 0) { /* diff --git a/src/bin/initdb/findtimezone.c b/src/bin/initdb/findtimezone.c index c7e8ff6d40b..7c58e7111e1 100644 --- a/src/bin/initdb/findtimezone.c +++ b/src/bin/initdb/findtimezone.c @@ -75,7 +75,7 @@ pg_open_tzfile(const char *name, char *canonname) strcat(fullname, "/"); strcat(fullname, name); - return open(fullname, O_RDONLY | PG_BINARY, 0); + return pg_open(fullname, O_RDONLY | PG_BINARY, 0); } diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c index 8a599fc9869..84ec0057667 100644 --- a/src/bin/pg_basebackup/pg_basebackup.c +++ b/src/bin/pg_basebackup/pg_basebackup.c @@ -1830,7 +1830,7 @@ BaseBackup(char *compression_algorithm, char *compression_detail, pg_fatal("server does not support incremental backup"); /* Open the file. */ - fd = open(incremental_manifest, O_RDONLY | PG_BINARY, 0); + fd = pg_open(incremental_manifest, O_RDONLY | PG_BINARY, 0); if (fd < 0) pg_fatal("could not open file \"%s\": %m", incremental_manifest); diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c index 20506fc3560..1ecb4c95fc5 100644 --- a/src/bin/pg_basebackup/pg_receivewal.c +++ b/src/bin/pg_basebackup/pg_receivewal.c @@ -335,7 +335,7 @@ FindStreamingStart(uint32 *tli) snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name); - fd = open(fullpath, O_RDONLY | PG_BINARY, 0); + fd = pg_open(fullpath, O_RDONLY | PG_BINARY, 0); if (fd < 0) pg_fatal("could not open compressed file \"%s\": %m", fullpath); @@ -381,7 +381,7 @@ FindStreamingStart(uint32 *tli) memset(&dec_opt, 0, sizeof(dec_opt)); snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name); - fd = open(fullpath, O_RDONLY | PG_BINARY, 0); + fd = pg_open(fullpath, O_RDONLY | PG_BINARY, 0); if (fd < 0) pg_fatal("could not open file \"%s\": %m", fullpath); diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c index 40f6f65f757..b8da8050e21 100644 --- a/src/bin/pg_basebackup/pg_recvlogical.c +++ b/src/bin/pg_basebackup/pg_recvlogical.c @@ -344,8 +344,8 @@ StreamLogicalLog(void) if (strcmp(outfile, "-") == 0) outfd = fileno(stdout); else - outfd = open(outfile, O_CREAT | O_APPEND | O_WRONLY | PG_BINARY, - pg_file_create_mode); + outfd = pg_open(outfile, O_CREAT | O_APPEND | O_WRONLY | PG_BINARY, + pg_file_create_mode); if (outfd == -1) { pg_log_error("could not open log file \"%s\": %m", outfile); diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c index 3a6b3b5f45b..f2e878a0151 100644 --- a/src/bin/pg_basebackup/walmethods.c +++ b/src/bin/pg_basebackup/walmethods.c @@ -144,7 +144,7 @@ dir_open_for_write(WalWriteMethod *wwmethod, const char *pathname, * does not do any system calls to fsync() to make changes permanent on * disk. */ - fd = open(tmppath, O_WRONLY | O_CREAT | PG_BINARY, pg_file_create_mode); + fd = pg_open(tmppath, O_WRONLY | O_CREAT | PG_BINARY, pg_file_create_mode); if (fd < 0) { wwmethod->lasterrno = errno; @@ -592,7 +592,7 @@ dir_existsfile(WalWriteMethod *wwmethod, const char *pathname) snprintf(tmppath, sizeof(tmppath), "%s/%s", dir_data->basedir, pathname); - fd = open(tmppath, O_RDONLY | PG_BINARY, 0); + fd = pg_open(tmppath, O_RDONLY | PG_BINARY, 0); if (fd < 0) /* @@ -847,9 +847,9 @@ tar_open_for_write(WalWriteMethod *wwmethod, const char *pathname, /* * We open the tar file only when we first try to write to it. */ - tar_data->fd = open(tar_data->tarfilename, - O_WRONLY | O_CREAT | PG_BINARY, - pg_file_create_mode); + tar_data->fd = pg_open(tar_data->tarfilename, + O_WRONLY | O_CREAT | PG_BINARY, + pg_file_create_mode); if (tar_data->fd < 0) { wwmethod->lasterrno = errno; diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c index 3b3ae23f1a6..9c5ac6137a8 100644 --- a/src/bin/pg_checksums/pg_checksums.c +++ b/src/bin/pg_checksums/pg_checksums.c @@ -186,7 +186,7 @@ scan_file(const char *fn, int segmentno) mode == PG_MODE_CHECK); flags = (mode == PG_MODE_ENABLE) ? O_RDWR : O_RDONLY; - f = open(fn, PG_BINARY | flags, 0); + f = pg_open(fn, PG_BINARY | flags, 0); if (f < 0) pg_fatal("could not open file \"%s\": %m", fn); diff --git a/src/bin/pg_combinebackup/backup_label.c b/src/bin/pg_combinebackup/backup_label.c index b757e772b92..0eb5b387366 100644 --- a/src/bin/pg_combinebackup/backup_label.c +++ b/src/bin/pg_combinebackup/backup_label.c @@ -137,9 +137,9 @@ write_backup_label(char *output_directory, StringInfo buf, snprintf(output_filename, MAXPGPATH, "%s/backup_label", output_directory); - if ((output_fd = open(output_filename, - O_WRONLY | O_CREAT | O_EXCL | PG_BINARY, - pg_file_create_mode)) < 0) + if ((output_fd = pg_open(output_filename, + O_WRONLY | O_CREAT | O_EXCL | PG_BINARY, + pg_file_create_mode)) < 0) pg_fatal("could not open file \"%s\": %m", output_filename); while (buf->cursor < buf->len) diff --git a/src/bin/pg_combinebackup/copy_file.c b/src/bin/pg_combinebackup/copy_file.c index 740b63be559..5f8de3138f7 100644 --- a/src/bin/pg_combinebackup/copy_file.c +++ b/src/bin/pg_combinebackup/copy_file.c @@ -65,7 +65,7 @@ copy_file(const char *src, const char *dst, { int fd; - if ((fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0) + if ((fd = pg_open(src, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("could not open file \"%s\": %m", src); if (close(fd) < 0) pg_fatal("could not close file \"%s\": %m", src); @@ -149,7 +149,7 @@ checksum_file(const char *src, pg_checksum_context *checksum_ctx) if (checksum_ctx->type == CHECKSUM_TYPE_NONE) return; - if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0) + if ((src_fd = pg_open(src, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("could not open file \"%s\": %m", src); buffer = pg_malloc(buffer_size); @@ -181,11 +181,11 @@ copy_file_blocks(const char *src, const char *dst, ssize_t rb; size_t offset = 0; - if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0) + if ((src_fd = pg_open(src, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("could not open file \"%s\": %m", src); - if ((dest_fd = open(dst, O_WRONLY | O_CREAT | O_EXCL | PG_BINARY, - pg_file_create_mode)) < 0) + if ((dest_fd = pg_open(dst, O_WRONLY | O_CREAT | O_EXCL | PG_BINARY, + pg_file_create_mode)) < 0) pg_fatal("could not open file \"%s\": %m", dst); buffer = pg_malloc(buffer_size); @@ -235,11 +235,11 @@ copy_file_clone(const char *src, const char *dest, int src_fd; int dest_fd; - if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0) + if ((src_fd = pg_open(src, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("could not open file \"%s\": %m", src); - if ((dest_fd = open(dest, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, - pg_file_create_mode)) < 0) + if ((dest_fd = pg_open(dest, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, + pg_file_create_mode)) < 0) pg_fatal("could not create file \"%s\": %m", dest); if (ioctl(dest_fd, FICLONE, src_fd) < 0) @@ -278,11 +278,11 @@ copy_file_by_range(const char *src, const char *dest, int dest_fd; ssize_t nbytes; - if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0) + if ((src_fd = pg_open(src, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("could not open file \"%s\": %m", src); - if ((dest_fd = open(dest, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, - pg_file_create_mode)) < 0) + if ((dest_fd = pg_open(dest, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, + pg_file_create_mode)) < 0) pg_fatal("could not create file \"%s\": %m", dest); do diff --git a/src/bin/pg_combinebackup/load_manifest.c b/src/bin/pg_combinebackup/load_manifest.c index 9d2cc1e53ad..7098f38facf 100644 --- a/src/bin/pg_combinebackup/load_manifest.c +++ b/src/bin/pg_combinebackup/load_manifest.c @@ -118,7 +118,7 @@ load_backup_manifest(char *backup_directory) /* Open the manifest file. */ snprintf(pathname, MAXPGPATH, "%s/backup_manifest", backup_directory); - if ((fd = open(pathname, O_RDONLY | PG_BINARY, 0)) < 0) + if ((fd = pg_open(pathname, O_RDONLY | PG_BINARY, 0)) < 0) { if (errno == ENOENT) { diff --git a/src/bin/pg_combinebackup/pg_combinebackup.c b/src/bin/pg_combinebackup/pg_combinebackup.c index 86e2ee37c40..dd140b99e50 100644 --- a/src/bin/pg_combinebackup/pg_combinebackup.c +++ b/src/bin/pg_combinebackup/pg_combinebackup.c @@ -541,7 +541,7 @@ check_backup_label_files(int n_backups, char **backup_dirs) /* Open the backup_label file. */ snprintf(pathbuf, MAXPGPATH, "%s/backup_label", backup_dirs[i]); pg_log_debug("reading \"%s\"", pathbuf); - if ((fd = open(pathbuf, O_RDONLY, 0)) < 0) + if ((fd = pg_open(pathbuf, O_RDONLY, 0)) < 0) pg_fatal("could not open file \"%s\": %m", pathbuf); /* diff --git a/src/bin/pg_combinebackup/reconstruct.c b/src/bin/pg_combinebackup/reconstruct.c index e4b02746127..4d88ebb0c16 100644 --- a/src/bin/pg_combinebackup/reconstruct.c +++ b/src/bin/pg_combinebackup/reconstruct.c @@ -511,7 +511,7 @@ make_rfile(const char *filename, bool missing_ok) rf = pg_malloc0_object(rfile); rf->filename = pstrdup(filename); - if ((rf->fd = open(filename, O_RDONLY | PG_BINARY, 0)) < 0) + if ((rf->fd = pg_open(filename, O_RDONLY | PG_BINARY, 0)) < 0) { if (missing_ok && errno == ENOENT) { @@ -633,9 +633,9 @@ write_reconstructed_file(const char *input_filename, /* Open the output file, except in dry_run mode. */ if (!dry_run && - (wfd = open(output_filename, - O_RDWR | PG_BINARY | O_CREAT | O_EXCL, - pg_file_create_mode)) < 0) + (wfd = pg_open(output_filename, + O_RDWR | PG_BINARY | O_CREAT | O_EXCL, + pg_file_create_mode)) < 0) pg_fatal("could not open file \"%s\": %m", output_filename); /* Read and write the blocks as required. */ diff --git a/src/bin/pg_combinebackup/write_manifest.c b/src/bin/pg_combinebackup/write_manifest.c index c2ab7281266..cdfb97b3e24 100644 --- a/src/bin/pg_combinebackup/write_manifest.c +++ b/src/bin/pg_combinebackup/write_manifest.c @@ -244,9 +244,9 @@ static void flush_manifest(manifest_writer *mwriter) { if (mwriter->fd == -1 && - (mwriter->fd = open(mwriter->pathname, - O_WRONLY | O_CREAT | O_EXCL | PG_BINARY, - pg_file_create_mode)) < 0) + (mwriter->fd = pg_open(mwriter->pathname, + O_WRONLY | O_CREAT | O_EXCL | PG_BINARY, + pg_file_create_mode)) < 0) pg_fatal("could not open file \"%s\": %m", mwriter->pathname); if (mwriter->buf.len > 0) diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index 6c604e2d962..8b9043a2655 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -334,7 +334,7 @@ readfile(const char *path, int *numlines) * snapshot, but in practice, for a small file, it's close enough for the * current use. */ - fd = open(path, O_RDONLY | PG_BINARY, 0); + fd = pg_open(path, O_RDONLY | PG_BINARY, 0); if (fd < 0) return NULL; if (fstat(fd, &statbuf) < 0) @@ -537,7 +537,7 @@ start_postmaster(void) * will have, the log file might end up with permissions settings that * prevent the postmaster from writing on it. */ - int fd = open(log_file, O_RDWR, 0); + int fd = pg_open(log_file, O_RDWR, 0); if (fd == -1) { diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c index 542fdb453fb..35492ad4bb9 100644 --- a/src/bin/pg_dump/pg_backup_tar.c +++ b/src/bin/pg_dump/pg_backup_tar.c @@ -360,8 +360,8 @@ tarOpen(ArchiveHandle *AH, const char *filename, char mode) name = _tempnam(NULL, "pg_temp_"); if (name == NULL) break; - fd = open(name, O_RDWR | O_CREAT | O_EXCL | O_BINARY | - O_TEMPORARY, S_IRUSR | S_IWUSR); + fd = pg_open(name, O_RDWR | O_CREAT | O_EXCL | O_BINARY | + O_TEMPORARY, S_IRUSR | S_IWUSR); free(name); if (fd != -1) /* created a file */ diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c index 1542a56ca4b..390fe7e5151 100644 --- a/src/bin/pg_resetwal/pg_resetwal.c +++ b/src/bin/pg_resetwal/pg_resetwal.c @@ -418,7 +418,7 @@ main(int argc, char *argv[]) * Check for a postmaster lock file --- if there is one, refuse to * proceed, on grounds we might be interfering with a live installation. */ - if ((fd = open("postmaster.pid", O_RDONLY, 0)) < 0) + if ((fd = pg_open("postmaster.pid", O_RDONLY, 0)) < 0) { if (errno != ENOENT) pg_fatal("could not open file \"%s\" for reading: %m", @@ -604,7 +604,7 @@ read_controlfile(void) char *buffer; pg_crc32c crc; - if ((fd = open(XLOG_CONTROL_FILE, O_RDONLY | PG_BINARY, 0)) < 0) + if ((fd = pg_open(XLOG_CONTROL_FILE, O_RDONLY | PG_BINARY, 0)) < 0) { /* * If pg_control is not there at all, or we can't read it, the odds @@ -1180,8 +1180,8 @@ WriteEmptyXLOG(void) unlink(path); - fd = open(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, - pg_file_create_mode); + fd = pg_open(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, + pg_file_create_mode); if (fd < 0) pg_fatal("could not open file \"%s\": %m", path); diff --git a/src/bin/pg_rewind/file_ops.c b/src/bin/pg_rewind/file_ops.c index 3bf6296ed0e..92c3f364239 100644 --- a/src/bin/pg_rewind/file_ops.c +++ b/src/bin/pg_rewind/file_ops.c @@ -65,7 +65,7 @@ open_target_file(const char *path, bool trunc) mode = O_WRONLY | O_CREAT | PG_BINARY; if (trunc) mode |= O_TRUNC; - dstfd = open(dstpath, mode, pg_file_create_mode); + dstfd = pg_open(dstpath, mode, pg_file_create_mode); if (dstfd < 0) pg_fatal("could not open target file \"%s\": %m", dstpath); @@ -222,7 +222,7 @@ truncate_target_file(const char *path, off_t newsize) snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path); - fd = open(dstpath, O_WRONLY, pg_file_create_mode); + fd = pg_open(dstpath, O_WRONLY, pg_file_create_mode); if (fd < 0) pg_fatal("could not open file \"%s\" for truncation: %m", dstpath); @@ -345,7 +345,7 @@ slurpFile(const char *datadir, const char *path, size_t *filesize) snprintf(fullpath, sizeof(fullpath), "%s/%s", datadir, path); - if ((fd = open(fullpath, O_RDONLY | PG_BINARY, 0)) == -1) + if ((fd = pg_open(fullpath, O_RDONLY | PG_BINARY, 0)) == -1) pg_fatal("could not open file \"%s\" for reading: %m", fullpath); diff --git a/src/bin/pg_rewind/local_source.c b/src/bin/pg_rewind/local_source.c index 4841cf01fb7..4a1eacf757e 100644 --- a/src/bin/pg_rewind/local_source.c +++ b/src/bin/pg_rewind/local_source.c @@ -83,7 +83,7 @@ local_queue_fetch_file(rewind_source *source, const char *path, size_t len) snprintf(srcpath, sizeof(srcpath), "%s/%s", datadir, path); /* Open source file for reading */ - srcfd = open(srcpath, O_RDONLY | PG_BINARY, 0); + srcfd = pg_open(srcpath, O_RDONLY | PG_BINARY, 0); if (srcfd < 0) pg_fatal("could not open source file \"%s\": %m", srcpath); @@ -135,7 +135,7 @@ local_queue_fetch_range(rewind_source *source, const char *path, off_t off, snprintf(srcpath, sizeof(srcpath), "%s/%s", datadir, path); - srcfd = open(srcpath, O_RDONLY | PG_BINARY, 0); + srcfd = pg_open(srcpath, O_RDONLY | PG_BINARY, 0); if (srcfd < 0) pg_fatal("could not open source file \"%s\": %m", srcpath); diff --git a/src/bin/pg_rewind/parsexlog.c b/src/bin/pg_rewind/parsexlog.c index 023e23b063c..83d138aef5b 100644 --- a/src/bin/pg_rewind/parsexlog.c +++ b/src/bin/pg_rewind/parsexlog.c @@ -321,7 +321,7 @@ SimpleXLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, snprintf(xlogfpath, MAXPGPATH, "%s/" XLOGDIR "/%s", xlogreader->segcxt.ws_dir, xlogfname); - xlogreadfd = open(xlogfpath, O_RDONLY | PG_BINARY, 0); + xlogreadfd = pg_open(xlogfpath, O_RDONLY | PG_BINARY, 0); if (xlogreadfd < 0) { diff --git a/src/bin/pg_test_fsync/pg_test_fsync.c b/src/bin/pg_test_fsync/pg_test_fsync.c index c51b1271f1f..c8d33bdb43e 100644 --- a/src/bin/pg_test_fsync/pg_test_fsync.c +++ b/src/bin/pg_test_fsync/pg_test_fsync.c @@ -242,7 +242,7 @@ test_open(void) /* * test if we can open the target file */ - if ((tmpfile = open(filename, O_RDWR | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR)) == -1) + if ((tmpfile = pg_open(filename, O_RDWR | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR)) == -1) die("could not open output file"); needs_unlink = 1; if (write(tmpfile, buf, DEFAULT_XLOG_SEG_SIZE) != @@ -265,7 +265,7 @@ open_direct(const char *path, int flags, mode_t mode) flags |= O_DIRECT; #endif - fd = open(path, flags, mode); + fd = pg_open(path, flags, mode); #if !defined(O_DIRECT) && defined(F_NOCACHE) if (fd >= 0 && fcntl(fd, F_NOCACHE, 1) < 0) @@ -332,7 +332,7 @@ test_sync(int writes_per_op) printf(LABEL_FORMAT, "fdatasync"); fflush(stdout); - if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1) + if ((tmpfile = pg_open(filename, O_RDWR | PG_BINARY, 0)) == -1) die("could not open output file"); START_TIMER; for (ops = 0; alarm_triggered == false; ops++) @@ -354,7 +354,7 @@ test_sync(int writes_per_op) printf(LABEL_FORMAT, "fsync"); fflush(stdout); - if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1) + if ((tmpfile = pg_open(filename, O_RDWR | PG_BINARY, 0)) == -1) die("could not open output file"); START_TIMER; for (ops = 0; alarm_triggered == false; ops++) @@ -378,7 +378,7 @@ test_sync(int writes_per_op) fflush(stdout); #ifdef HAVE_FSYNC_WRITETHROUGH - if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1) + if ((tmpfile = pg_open(filename, O_RDWR | PG_BINARY, 0)) == -1) die("could not open output file"); START_TIMER; for (ops = 0; alarm_triggered == false; ops++) @@ -522,7 +522,7 @@ test_file_descriptor_sync(void) START_TIMER; for (ops = 0; alarm_triggered == false; ops++) { - if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1) + if ((tmpfile = pg_open(filename, O_RDWR | PG_BINARY, 0)) == -1) die("could not open output file"); if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ) die("write failed"); @@ -534,7 +534,7 @@ test_file_descriptor_sync(void) * open and close the file again to be consistent with the following * test */ - if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1) + if ((tmpfile = pg_open(filename, O_RDWR | PG_BINARY, 0)) == -1) die("could not open output file"); close(tmpfile); } @@ -550,13 +550,13 @@ test_file_descriptor_sync(void) START_TIMER; for (ops = 0; alarm_triggered == false; ops++) { - if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1) + if ((tmpfile = pg_open(filename, O_RDWR | PG_BINARY, 0)) == -1) die("could not open output file"); if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ) die("write failed"); close(tmpfile); /* reopen file */ - if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1) + if ((tmpfile = pg_open(filename, O_RDWR | PG_BINARY, 0)) == -1) die("could not open output file"); if (fsync(tmpfile) != 0) die("fsync failed"); @@ -578,7 +578,7 @@ test_non_sync(void) printf(LABEL_FORMAT, "write"); fflush(stdout); - if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1) + if ((tmpfile = pg_open(filename, O_RDWR | PG_BINARY, 0)) == -1) die("could not open output file"); START_TIMER; for (ops = 0; alarm_triggered == false; ops++) diff --git a/src/bin/pg_upgrade/exec.c b/src/bin/pg_upgrade/exec.c index a1bdbf373e3..da07020ce27 100644 --- a/src/bin/pg_upgrade/exec.c +++ b/src/bin/pg_upgrade/exec.c @@ -229,7 +229,7 @@ pid_lock_file_exists(const char *datadir) snprintf(path, sizeof(path), "%s/postmaster.pid", datadir); - if ((fd = open(path, O_RDONLY, 0)) < 0) + if ((fd = pg_open(path, O_RDONLY, 0)) < 0) { /* ENOTDIR means we will throw a more useful error later */ if (errno != ENOENT && errno != ENOTDIR) @@ -285,7 +285,7 @@ win32_check_directory_write_permissions(void) * We open a file we would normally create anyway. We do this even in * 'check' mode, which isn't ideal, but this is the best we can do. */ - if ((fd = open(GLOBALS_DUMP_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0) + if ((fd = pg_open(GLOBALS_DUMP_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0) return -1; close(fd); diff --git a/src/bin/pg_upgrade/file.c b/src/bin/pg_upgrade/file.c index af82c0de490..fcf47905eee 100644 --- a/src/bin/pg_upgrade/file.c +++ b/src/bin/pg_upgrade/file.c @@ -43,12 +43,12 @@ cloneFile(const char *src, const char *dst, int src_fd; int dest_fd; - if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0) + if ((src_fd = pg_open(src, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("error while cloning relation \"%s.%s\": could not open file \"%s\": %m", schemaName, relName, src); - if ((dest_fd = open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, - pg_file_create_mode)) < 0) + if ((dest_fd = pg_open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, + pg_file_create_mode)) < 0) pg_fatal("error while cloning relation \"%s.%s\": could not create file \"%s\": %m", schemaName, relName, dst); @@ -83,12 +83,12 @@ copyFile(const char *src, const char *dst, int dest_fd; char *buffer; - if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0) + if ((src_fd = pg_open(src, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("error while copying relation \"%s.%s\": could not open file \"%s\": %m", schemaName, relName, src); - if ((dest_fd = open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, - pg_file_create_mode)) < 0) + if ((dest_fd = pg_open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, + pg_file_create_mode)) < 0) pg_fatal("error while copying relation \"%s.%s\": could not create file \"%s\": %m", schemaName, relName, dst); @@ -152,12 +152,12 @@ copyFileByRange(const char *src, const char *dst, int dest_fd; ssize_t nbytes; - if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0) + if ((src_fd = pg_open(src, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("error while copying relation \"%s.%s\": could not open file \"%s\": %m", schemaName, relName, src); - if ((dest_fd = open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, - pg_file_create_mode)) < 0) + if ((dest_fd = pg_open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, + pg_file_create_mode)) < 0) pg_fatal("error while copying relation \"%s.%s\": could not create file \"%s\": %m", schemaName, relName, dst); @@ -210,12 +210,12 @@ check_file_clone(void) int src_fd; int dest_fd; - if ((src_fd = open(existing_file, O_RDONLY | PG_BINARY, 0)) < 0) + if ((src_fd = pg_open(existing_file, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("could not open file \"%s\": %m", existing_file); - if ((dest_fd = open(new_link_file, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, - pg_file_create_mode)) < 0) + if ((dest_fd = pg_open(new_link_file, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, + pg_file_create_mode)) < 0) pg_fatal("could not create file \"%s\": %m", new_link_file); @@ -247,12 +247,12 @@ check_copy_file_range(void) int src_fd; int dest_fd; - if ((src_fd = open(existing_file, O_RDONLY | PG_BINARY, 0)) < 0) + if ((src_fd = pg_open(existing_file, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("could not open file \"%s\": %m", existing_file); - if ((dest_fd = open(new_link_file, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, - pg_file_create_mode)) < 0) + if ((dest_fd = pg_open(new_link_file, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, + pg_file_create_mode)) < 0) pg_fatal("could not create file \"%s\": %m", new_link_file); diff --git a/src/bin/pg_upgrade/slru_io.c b/src/bin/pg_upgrade/slru_io.c index aa9d59a0d7b..3dd1a687e1c 100644 --- a/src/bin/pg_upgrade/slru_io.c +++ b/src/bin/pg_upgrade/slru_io.c @@ -109,7 +109,7 @@ SlruReadSwitchPageSlow(SlruSegState *state, uint64 pageno) } state->fn = SlruFileName(state, segno); - if ((state->fd = open(state->fn, O_RDONLY | PG_BINARY, 0)) < 0) + if ((state->fd = pg_open(state->fn, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("could not open file \"%s\": %m", state->fn); state->segno = segno; } @@ -215,8 +215,8 @@ SlruWriteSwitchPageSlow(SlruSegState *state, uint64 pageno) /* Create the segment */ state->fn = SlruFileName(state, segno); - if ((state->fd = open(state->fn, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, - pg_file_create_mode)) < 0) + if ((state->fd = pg_open(state->fn, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, + pg_file_create_mode)) < 0) { pg_fatal("could not create file \"%s\": %m", state->fn); } diff --git a/src/bin/pg_verifybackup/pg_verifybackup.c b/src/bin/pg_verifybackup/pg_verifybackup.c index 796eeb6ec04..c9e1d19d836 100644 --- a/src/bin/pg_verifybackup/pg_verifybackup.c +++ b/src/bin/pg_verifybackup/pg_verifybackup.c @@ -418,7 +418,7 @@ parse_manifest_file(char *manifest_path) const size_t chunk_size = READ_CHUNK_SIZE; /* Open the manifest file. */ - if ((fd = open(manifest_path, O_RDONLY | PG_BINARY, 0)) < 0) + if ((fd = pg_open(manifest_path, O_RDONLY | PG_BINARY, 0)) < 0) report_fatal_error("could not open file \"%s\": %m", manifest_path); /* Figure out how big the manifest is. */ @@ -1026,7 +1026,7 @@ verify_tar_file(verifier_context *context, char *relpath, char *fullpath, pg_log_debug("reading \"%s\"", fullpath); /* Open the target file. */ - if ((fd = open(fullpath, O_RDONLY | PG_BINARY, 0)) < 0) + if ((fd = pg_open(fullpath, O_RDONLY | PG_BINARY, 0)) < 0) { report_backup_error(context, "could not open file \"%s\": %m", relpath); @@ -1134,7 +1134,7 @@ verify_file_checksum(verifier_context *context, manifest_file *m, int checksumlen; /* Open the target file. */ - if ((fd = open(fullpath, O_RDONLY | PG_BINARY, 0)) < 0) + if ((fd = pg_open(fullpath, O_RDONLY | PG_BINARY, 0)) < 0) { report_backup_error(context, "could not open file \"%s\": %m", relpath); diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c index cf760d8b236..649c9eeb355 100644 --- a/src/bin/pg_waldump/pg_waldump.c +++ b/src/bin/pg_waldump/pg_waldump.c @@ -187,7 +187,7 @@ open_file_in_directory(const char *directory, const char *fname) Assert(directory != NULL); snprintf(fpath, MAXPGPATH, "%s/%s", directory, fname); - fd = open(fpath, O_RDONLY | PG_BINARY, 0); + fd = pg_open(fpath, O_RDONLY | PG_BINARY, 0); if (fd < 0 && errno != ENOENT) pg_fatal("could not open file \"%s\": %m", fname); diff --git a/src/bin/pg_walsummary/pg_walsummary.c b/src/bin/pg_walsummary/pg_walsummary.c index ad674b7646a..a2bc1131779 100644 --- a/src/bin/pg_walsummary/pg_walsummary.c +++ b/src/bin/pg_walsummary/pg_walsummary.c @@ -104,7 +104,7 @@ main(int argc, char *argv[]) BlockNumber limit_block; ws.filename = argv[optind++]; - if ((ws.fd = open(ws.filename, O_RDONLY | PG_BINARY, 0)) < 0) + if ((ws.fd = pg_open(ws.filename, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("could not open file \"%s\": %m", ws.filename); reader = CreateBlockRefTableReader(walsummary_read_callback, &ws, diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index ee85c05a00d..3dd4e4df9ca 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -4774,7 +4774,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf, fname = (const char *) fnametmp; - fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600); + fd = pg_open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600); if (fd != -1) stream = fdopen(fd, "w"); diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c index 6d37359fc96..67c6d532ad7 100644 --- a/src/bin/psql/input.c +++ b/src/bin/psql/input.c @@ -449,7 +449,7 @@ saveHistory(char *fname, int max_lines) (void) history_truncate_file(fname, nlines); } /* append_history fails if file doesn't already exist :-( */ - fd = open(fname, O_CREAT | O_WRONLY | PG_BINARY, 0600); + fd = pg_open(fname, O_CREAT | O_WRONLY | PG_BINARY, 0600); if (fd >= 0) close(fd); /* append the appropriate number of lines */ diff --git a/src/common/controldata_utils.c b/src/common/controldata_utils.c index 0e8e03c566c..8736c87f899 100644 --- a/src/common/controldata_utils.c +++ b/src/common/controldata_utils.c @@ -94,7 +94,7 @@ retry: errmsg("could not open file \"%s\" for reading: %m", ControlFilePath))); #else - if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1) + if ((fd = pg_open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1) pg_fatal("could not open file \"%s\" for reading: %m", ControlFilePath); #endif @@ -226,8 +226,8 @@ update_controlfile(const char *DataDir, errmsg("could not open file \"%s\": %m", ControlFilePath))); #else - if ((fd = open(ControlFilePath, O_WRONLY | PG_BINARY, - pg_file_create_mode)) == -1) + if ((fd = pg_open(ControlFilePath, O_WRONLY | PG_BINARY, + pg_file_create_mode)) == -1) pg_fatal("could not open file \"%s\": %m", ControlFilePath); #endif diff --git a/src/common/file_utils.c b/src/common/file_utils.c index 390e60bd01f..adae773c84a 100644 --- a/src/common/file_utils.c +++ b/src/common/file_utils.c @@ -62,7 +62,7 @@ do_syncfs(const char *path) { int fd; - fd = open(path, O_RDONLY, 0); + fd = pg_open(path, O_RDONLY, 0); if (fd < 0) { @@ -361,7 +361,7 @@ pre_sync_fname(const char *fname, bool isdir) #ifdef PG_FLUSH_DATA_WORKS int fd; - fd = open(fname, O_RDONLY | PG_BINARY, 0); + fd = pg_open(fname, O_RDONLY | PG_BINARY, 0); if (fd < 0) { @@ -420,7 +420,7 @@ fsync_fname(const char *fname, bool isdir) * unsupported operations, e.g. opening a directory under Windows), and * logging others. */ - fd = open(fname, flags, 0); + fd = pg_open(fname, flags, 0); if (fd < 0) { if (errno == EACCES || (isdir && errno == EISDIR)) @@ -494,7 +494,7 @@ durable_rename(const char *oldfile, const char *newfile) if (fsync_fname(oldfile, false) != 0) return -1; - fd = open(newfile, PG_BINARY | O_RDWR, 0); + fd = pg_open(newfile, PG_BINARY | O_RDWR, 0); if (fd < 0) { if (errno != ENOENT) diff --git a/src/fe_utils/archive.c b/src/fe_utils/archive.c index 712030e9412..0381993b4f7 100644 --- a/src/fe_utils/archive.c +++ b/src/fe_utils/archive.c @@ -71,7 +71,7 @@ RestoreArchivedFile(const char *path, const char *xlogfname, (long long int) expectedSize); else { - int xlogfd = open(xlogpath, O_RDONLY | PG_BINARY, 0); + int xlogfd = pg_open(xlogpath, O_RDONLY | PG_BINARY, 0); if (xlogfd < 0) pg_fatal("could not open file \"%s\" restored from archive: %m", diff --git a/src/include/port.h b/src/include/port.h index 172acf7d02f..8cb8df3f908 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -249,6 +249,21 @@ extern int pg_printf(const char *fmt, ...) pg_attribute_printf(1, 2); #define pg_pwrite pwrite #endif +/* + * We add a pg_ prefix as a warning that this retries EINTR, which POSIX + * permits open() to fail with and macOS does return. An open() that has to + * sleep can be interrupted -- a saturated vnode table, where opening an + * uncached file waits for a vnode to be reclaimed, is one way to get there -- + * and the filesystem hands the EINTR up rather than asking for a restart, so + * SA_RESTART does not cover it. The read and write paths in fd.c retry + * already; open() was the one that did not. + */ +#if defined(WIN32) && !defined(__CYGWIN__) +#define pg_open open +#else +extern int pg_open(const char *path, int flags, mode_t mode); +#endif + /* * We use __VA_ARGS__ for printf to prevent replacing references to * the "printf" format archetype in format() attribute declarations. diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c index 19ebab22ba3..5755c791ba8 100644 --- a/src/interfaces/libpq/fe-lobj.c +++ b/src/interfaces/libpq/fe-lobj.c @@ -663,7 +663,7 @@ lo_import_internal(PGconn *conn, const char *filename, Oid oid) /* * open the file to be read in */ - fd = open(filename, O_RDONLY | PG_BINARY, 0666); + fd = pg_open(filename, O_RDONLY | PG_BINARY, 0666); if (fd < 0) { /* error */ libpq_append_conn_error(conn, "could not open file \"%s\": %s", @@ -767,7 +767,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename) /* * create the file to be written to */ - fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666); + fd = pg_open(filename, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666); if (fd < 0) { /* We must do lo_close before setting the errorMessage */ diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index 91c1fa9bb95..a12d2b70b16 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -740,7 +740,7 @@ SSL_CTX_keylog_cb(const SSL *ssl, const char *line) if (conn == NULL) return; - fd = open(conn->sslkeylogfile, O_WRONLY | O_APPEND | O_CREAT, 0600); + fd = pg_open(conn->sslkeylogfile, O_WRONLY | O_APPEND | O_CREAT, 0600); if (fd == -1) { diff --git a/src/port/Makefile b/src/port/Makefile index 7e9b5877652..6bde03c94ae 100644 --- a/src/port/Makefile +++ b/src/port/Makefile @@ -53,6 +53,7 @@ OBJS = \ pg_strong_random.o \ pgcheckdir.o \ pgmkdirp.o \ + pgopen.o \ pgsleep.o \ pgstrcasecmp.o \ pgstrsignal.o \ diff --git a/src/port/meson.build b/src/port/meson.build index 922b3f64676..19d6267c58f 100644 --- a/src/port/meson.build +++ b/src/port/meson.build @@ -16,6 +16,7 @@ pgport_sources = [ 'pg_strong_random.c', 'pgcheckdir.c', 'pgmkdirp.c', + 'pgopen.c', 'pgsleep.c', 'pgstrcasecmp.c', 'pgstrsignal.c', diff --git a/src/port/mkdtemp.c b/src/port/mkdtemp.c index 7f8edc8a02d..d952eb8480d 100644 --- a/src/port/mkdtemp.c +++ b/src/port/mkdtemp.c @@ -180,7 +180,7 @@ GETTEMP(char *path, int *doopen, int domkdir) if (doopen) { if ((*doopen = - open(path, O_CREAT | O_EXCL | O_RDWR, 0600)) >= 0) + pg_open(path, O_CREAT | O_EXCL | O_RDWR, 0600)) >= 0) return 1; if (errno != EEXIST) return 0; diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c index c8d8a70d896..e774d2edfa4 100644 --- a/src/port/pg_strong_random.c +++ b/src/port/pg_strong_random.c @@ -153,7 +153,7 @@ pg_strong_random(void *buf, size_t len) char *p = buf; ssize_t res; - f = open("/dev/urandom", O_RDONLY, 0); + f = pg_open("/dev/urandom", O_RDONLY, 0); if (f == -1) return false; diff --git a/src/port/pgopen.c b/src/port/pgopen.c new file mode 100644 index 00000000000..c9f266f06cb --- /dev/null +++ b/src/port/pgopen.c @@ -0,0 +1,38 @@ +/*------------------------------------------------------------------------- + * + * pgopen.c + * open() with retry on EINTR + * + * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/port/pgopen.c + * + *------------------------------------------------------------------------- + */ + +#if !defined(WIN32) || defined(__CYGWIN__) + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include + +int +pg_open(const char *path, int flags, mode_t mode) +{ + int fd; + + do + fd = open(path, flags, mode); + while (fd < 0 && errno == EINTR); + + return fd; +} + +#endif /* !WIN32 || __CYGWIN__ */ diff --git a/src/test/examples/testlo.c b/src/test/examples/testlo.c index 0b1d097edff..67f4e34d4bd 100644 --- a/src/test/examples/testlo.c +++ b/src/test/examples/testlo.c @@ -43,7 +43,7 @@ importFile(PGconn *conn, char *filename) /* * open the file to be read in */ - fd = open(filename, O_RDONLY, 0666); + fd = pg_open(filename, O_RDONLY, 0666); if (fd < 0) { /* error */ fprintf(stderr, "cannot open unix file\"%s\"\n", filename); @@ -164,7 +164,7 @@ exportFile(PGconn *conn, Oid lobjId, char *filename) /* * open the file to be written to */ - fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); + fd = pg_open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); if (fd < 0) { /* error */ fprintf(stderr, "cannot open unix file\"%s\"", diff --git a/src/test/examples/testlo64.c b/src/test/examples/testlo64.c index 3698d7f256e..718d7809b06 100644 --- a/src/test/examples/testlo64.c +++ b/src/test/examples/testlo64.c @@ -44,7 +44,7 @@ importFile(PGconn *conn, char *filename) /* * open the file to be read in */ - fd = open(filename, O_RDONLY, 0666); + fd = pg_open(filename, O_RDONLY, 0666); if (fd < 0) { /* error */ fprintf(stderr, "cannot open unix file\"%s\"\n", filename); @@ -187,7 +187,7 @@ exportFile(PGconn *conn, Oid lobjId, char *filename) /* * open the file to be written to */ - fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); + fd = pg_open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); if (fd < 0) { /* error */ fprintf(stderr, "cannot open unix file\"%s\"", diff --git a/src/test/modules/test_cloexec/test_cloexec.c b/src/test/modules/test_cloexec/test_cloexec.c index 40b00e490d7..faaeac24ca8 100644 --- a/src/test/modules/test_cloexec/test_cloexec.c +++ b/src/test/modules/test_cloexec/test_cloexec.c @@ -89,7 +89,7 @@ run_parent_tests(const char *testfile1, const char *testfile2) printf("Parent: Opening test files...\n"); /* Open first file WITH O_CLOEXEC - should NOT be inherited */ - fd1 = open(testfile1, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0600); + fd1 = pg_open(testfile1, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0600); if (fd1 < 0) { fprintf(stderr, "Failed to open %s: %s\n", testfile1, strerror(errno)); @@ -97,7 +97,7 @@ run_parent_tests(const char *testfile1, const char *testfile2) } /* Open second file WITHOUT O_CLOEXEC - should be inherited */ - fd2 = open(testfile2, O_RDWR | O_CREAT | O_TRUNC, 0600); + fd2 = pg_open(testfile2, O_RDWR | O_CREAT | O_TRUNC, 0600); if (fd2 < 0) { fprintf(stderr, "Failed to open %s: %s\n", testfile2, strerror(errno)); diff --git a/src/timezone/pgtz.c b/src/timezone/pgtz.c index 9561d94a67d..a772a20124d 100644 --- a/src/timezone/pgtz.c +++ b/src/timezone/pgtz.c @@ -101,7 +101,7 @@ pg_open_tzfile(const char *name, char *canonname) fullname[fullnamelen] = '/'; /* test above ensured this will fit: */ strcpy(fullname + fullnamelen + 1, name); - result = open(fullname, O_RDONLY | PG_BINARY, 0); + result = pg_open(fullname, O_RDONLY | PG_BINARY, 0); if (result >= 0) return result; /* If that didn't work, fall through to do it the hard way */ @@ -138,7 +138,7 @@ pg_open_tzfile(const char *name, char *canonname) if (canonname) strlcpy(canonname, fullname + orignamelen + 1, TZ_STRLEN_MAX + 1); - return open(fullname, O_RDONLY | PG_BINARY, 0); + return pg_open(fullname, O_RDONLY | PG_BINARY, 0); }