From f94e21532933cf53b28a84d642c06c1fbff4ed03 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. 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, 263168 of 263168, which is what makes the call interruptible at all. All six occurrences followed a macOS 26.6.1 update, but the correlation carries no weight: no pre-update sample survives. 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, and so is src/test/examples/: those programs include no header of ours beyond libpq's, so pg_open() is not even declared there, and testlo.c is printed whole in the large object documentation. --- 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/modules/test_cloexec/test_cloexec.c | 4 +-- src/timezone/pgtz.c | 4 +-- 45 files changed, 168 insertions(+), 113 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 c3b87a19e76..70c883d028e 100644 --- a/src/bin/pg_basebackup/pg_basebackup.c +++ b/src/bin/pg_basebackup/pg_basebackup.c @@ -1825,7 +1825,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 13bd318f672..a801ad3f563 100644 --- a/src/bin/pg_basebackup/pg_receivewal.c +++ b/src/bin/pg_basebackup/pg_receivewal.c @@ -336,7 +336,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); @@ -382,7 +382,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 feba45095e4..c2e11747d42 100644 --- a/src/bin/pg_basebackup/pg_recvlogical.c +++ b/src/bin/pg_basebackup/pg_recvlogical.c @@ -345,8 +345,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 dc4210f58ce..74bef93af81 100644 --- a/src/bin/pg_combinebackup/backup_label.c +++ b/src/bin/pg_combinebackup/backup_label.c @@ -138,9 +138,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 81694144b46..d9eec8c8cfc 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. */ @@ -1030,7 +1030,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); @@ -1138,7 +1138,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 6f0574a8764..3c947481ded 100644 --- a/src/bin/pg_waldump/pg_waldump.c +++ b/src/bin/pg_waldump/pg_waldump.c @@ -188,7 +188,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 1008a46f048..8f2577c37bc 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -4789,7 +4789,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 cad303f31fe..89de5c22c2a 100644 --- a/src/interfaces/libpq/fe-lobj.c +++ b/src/interfaces/libpq/fe-lobj.c @@ -661,7 +661,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", @@ -765,7 +765,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 140cec0e003..213a7526f52 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -778,7 +778,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/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); }