diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index 62dec87..98f8170 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -1858,8 +1858,7 @@ qtext_store(const char *query, int query_len, *query_offset = off; /* Now write the data into the successfully-reserved part of the file */ - fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDWR | O_CREAT | PG_BINARY, - S_IRUSR | S_IWUSR); + fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDWR | O_CREAT | PG_BINARY); if (fd < 0) goto error; @@ -1923,7 +1922,7 @@ qtext_load_file(Size *buffer_size) int fd; struct stat stat; - fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDONLY | PG_BINARY, 0); + fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDONLY | PG_BINARY); if (fd < 0) { if (errno != ENOENT) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index cd82c04..6c84082 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -812,6 +812,44 @@ include_dir 'conf.d' + + file_mode_mask (integer) + + file_mode_mask configuration parameter + + + + + Sets the file mode mask (umask) for the data directory. The parameter + value is expected to be a numeric mode specified in the format + accepted by the chmod and + umask system calls. (To use the customary octal + format the number must start with a 0 (zero).) + + + + The default file_mode_mask is 0077, + meaning that the only the database owner can read and write files in + the data directory. For example, setting the + file_mode_mask to 0027 would allow + any user in the same group as the database owner to read all database + files, which would be useful for producing a backup using a relatively + unprivileged user. + + + + Note that changing this parameter does not automatically change the + mode of existing files in the cluster. This must be done manually by + an administator. + + + + This parameter can only be set at server start. + + + + + bonjour (boolean) diff --git a/doc/src/sgml/ref/initdb.sgml b/doc/src/sgml/ref/initdb.sgml index 1aaa490..bd1f849 100644 --- a/doc/src/sgml/ref/initdb.sgml +++ b/doc/src/sgml/ref/initdb.sgml @@ -296,6 +296,25 @@ PostgreSQL documentation + + + + + Sets the file mode mask (umask) for the data directory. The parameter + value is expected to be a numeric mode specified in the format + accepted by the chmod and + umask system calls. (To use the customary octal + format the number must start with a 0 (zero).) + + + + Specifying this parameter will automatically set + in postgresql.conf. + + + + + diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c index c7b283c..53a2acc 100644 --- a/src/backend/access/heap/rewriteheap.c +++ b/src/backend/access/heap/rewriteheap.c @@ -1010,8 +1010,7 @@ logical_rewrite_log_mapping(RewriteState state, TransactionId xid, src->off = 0; memcpy(src->path, path, sizeof(path)); src->vfd = PathNameOpenFile(path, - O_CREAT | O_EXCL | O_WRONLY | PG_BINARY, - S_IRUSR | S_IWUSR); + O_CREAT | O_EXCL | O_WRONLY | PG_BINARY); if (src->vfd < 0) ereport(ERROR, (errcode_for_file_access(), @@ -1130,8 +1129,7 @@ heap_xlog_logical_rewrite(XLogReaderState *r) xlrec->mapped_xid, XLogRecGetXid(r)); fd = OpenTransientFile(path, - O_CREAT | O_WRONLY | PG_BINARY, - S_IRUSR | S_IWUSR); + O_CREAT | O_WRONLY | PG_BINARY); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), @@ -1249,7 +1247,7 @@ CheckPointLogicalRewriteHeap(void) } else { - int fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0); + int fd = OpenTransientFile(path, O_RDONLY | PG_BINARY); /* * The file cannot vanish due to concurrency since this function diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c index a66ef5c..f385b79 100644 --- a/src/backend/access/transam/slru.c +++ b/src/backend/access/transam/slru.c @@ -594,7 +594,7 @@ SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int pageno) SlruFileName(ctl, path, segno); - fd = OpenTransientFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR); + fd = OpenTransientFile(path, O_RDWR | PG_BINARY); if (fd < 0) { /* expected: file doesn't exist */ @@ -649,7 +649,7 @@ SlruPhysicalReadPage(SlruCtl ctl, int pageno, int slotno) * SlruPhysicalWritePage). Hence, if we are InRecovery, allow the case * where the file doesn't exist, and return zeroes instead. */ - fd = OpenTransientFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR); + fd = OpenTransientFile(path, O_RDWR | PG_BINARY); if (fd < 0) { if (errno != ENOENT || !InRecovery) @@ -796,8 +796,7 @@ SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, SlruFlush fdata) * don't use O_EXCL or O_TRUNC or anything like that. */ SlruFileName(ctl, path, segno); - fd = OpenTransientFile(path, O_RDWR | O_CREAT | PG_BINARY, - S_IRUSR | S_IWUSR); + fd = OpenTransientFile(path, O_RDWR | O_CREAT | PG_BINARY); if (fd < 0) { slru_errcause = SLRU_OPEN_FAILED; diff --git a/src/backend/access/transam/timeline.c b/src/backend/access/transam/timeline.c index 1fdc591..baa766a 100644 --- a/src/backend/access/transam/timeline.c +++ b/src/backend/access/transam/timeline.c @@ -306,8 +306,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, unlink(tmppath); /* do not use get_sync_bit() here --- want to fsync only at end of fill */ - fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL, - S_IRUSR | S_IWUSR); + fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), @@ -324,7 +323,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, else TLHistoryFilePath(path, parentTLI); - srcfd = OpenTransientFile(path, O_RDONLY, 0); + srcfd = OpenTransientFile(path, O_RDONLY); if (srcfd < 0) { if (errno != ENOENT) @@ -452,8 +451,7 @@ writeTimeLineHistoryFile(TimeLineID tli, char *content, int size) unlink(tmppath); /* do not use get_sync_bit() here --- want to fsync only at end of fill */ - fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL, - S_IRUSR | S_IWUSR); + fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index 0a8edb9..1f02dd1 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -1151,7 +1151,7 @@ ReadTwoPhaseFile(TransactionId xid, bool give_warnings) TwoPhaseFilePath(path, xid); - fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0); + fd = OpenTransientFile(path, O_RDONLY | PG_BINARY); if (fd < 0) { if (give_warnings) @@ -1533,8 +1533,7 @@ RecreateTwoPhaseFile(TransactionId xid, void *content, int len) TwoPhaseFilePath(path, xid); fd = OpenTransientFile(path, - O_CREAT | O_TRUNC | O_WRONLY | PG_BINARY, - S_IRUSR | S_IWUSR); + O_CREAT | O_TRUNC | O_WRONLY | PG_BINARY); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 8973583..eed7dda 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -3156,8 +3156,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock) */ if (*use_existent) { - fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method), - S_IRUSR | S_IWUSR); + fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method)); if (fd < 0) { if (errno != ENOENT) @@ -3182,8 +3181,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock) unlink(tmppath); /* do not use get_sync_bit() here --- want to fsync only at end of fill */ - fd = BasicOpenFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, - S_IRUSR | S_IWUSR); + fd = BasicOpenFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), @@ -3275,8 +3273,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock) *use_existent = false; /* Now open original target segment (might not be file I just made) */ - fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method), - S_IRUSR | S_IWUSR); + fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method)); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), @@ -3317,7 +3314,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno, * Open the source file */ XLogFilePath(path, srcTLI, srcsegno); - srcfd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0); + srcfd = OpenTransientFile(path, O_RDONLY | PG_BINARY); if (srcfd < 0) ereport(ERROR, (errcode_for_file_access(), @@ -3331,8 +3328,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno, unlink(tmppath); /* do not use get_sync_bit() here --- want to fsync only at end of fill */ - fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, - S_IRUSR | S_IWUSR); + fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), @@ -3504,8 +3500,7 @@ XLogFileOpen(XLogSegNo segno) XLogFilePath(path, ThisTimeLineID, segno); - fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method), - S_IRUSR | S_IWUSR); + fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method)); if (fd < 0) ereport(PANIC, (errcode_for_file_access(), @@ -3571,7 +3566,7 @@ XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli, snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname); } - fd = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0); + fd = BasicOpenFile(path, O_RDONLY | PG_BINARY); if (fd >= 0) { /* Success! */ @@ -4065,7 +4060,7 @@ ValidateXLOGDirectoryStructure(void) { ereport(LOG, (errmsg("creating missing WAL directory \"%s\"", path))); - if (mkdir(path, S_IRWXU) < 0) + if (mkdir(path, PG_DEFAULT_DIR_MODE) < 0) ereport(FATAL, (errmsg("could not create missing directory \"%s\": %m", path))); @@ -4404,8 +4399,7 @@ WriteControlFile(void) memcpy(buffer, ControlFile, sizeof(ControlFileData)); fd = BasicOpenFile(XLOG_CONTROL_FILE, - O_RDWR | O_CREAT | O_EXCL | PG_BINARY, - S_IRUSR | S_IWUSR); + O_RDWR | O_CREAT | O_EXCL | PG_BINARY); if (fd < 0) ereport(PANIC, (errcode_for_file_access(), @@ -4444,8 +4438,7 @@ ReadControlFile(void) * Read data... */ fd = BasicOpenFile(XLOG_CONTROL_FILE, - O_RDWR | PG_BINARY, - S_IRUSR | S_IWUSR); + O_RDWR | PG_BINARY); if (fd < 0) ereport(PANIC, (errcode_for_file_access(), @@ -4624,8 +4617,7 @@ UpdateControlFile(void) FIN_CRC32C(ControlFile->crc); fd = BasicOpenFile(XLOG_CONTROL_FILE, - O_RDWR | PG_BINARY, - S_IRUSR | S_IWUSR); + O_RDWR | PG_BINARY); if (fd < 0) ereport(PANIC, (errcode_for_file_access(), diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index 8b99b78..96ac73f 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -687,7 +687,7 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count) XLogFilePath(path, tli, sendSegNo); - sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0); + sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY); if (sendFile < 0) { diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index 11ee536..578b46b 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -428,7 +428,7 @@ GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence) /* Check for existing file of same name */ rpath = relpath(rnode, MAIN_FORKNUM); - fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY, 0); + fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY); if (fd >= 0) { diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index f9c2620..312ac07 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -151,7 +151,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo) else { /* Directory creation failed? */ - if (mkdir(dir, S_IRWXU) < 0) + if (mkdir(dir, PG_DEFAULT_DIR_MODE) < 0) { char *parentdir; @@ -173,7 +173,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo) get_parent_directory(parentdir); get_parent_directory(parentdir); /* Can't create parent and it doesn't already exist? */ - if (mkdir(parentdir, S_IRWXU) < 0 && errno != EEXIST) + if (mkdir(parentdir, PG_DEFAULT_DIR_MODE) < 0 && errno != EEXIST) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", @@ -184,7 +184,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo) parentdir = pstrdup(dir); get_parent_directory(parentdir); /* Can't create parent and it doesn't already exist? */ - if (mkdir(parentdir, S_IRWXU) < 0 && errno != EEXIST) + if (mkdir(parentdir, PG_DEFAULT_DIR_MODE) < 0 && errno != EEXIST) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", @@ -192,7 +192,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo) pfree(parentdir); /* Create database directory */ - if (mkdir(dir, S_IRWXU) < 0) + if (mkdir(dir, PG_DEFAULT_DIR_MODE) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", @@ -610,7 +610,7 @@ create_tablespace_directories(const char *location, const Oid tablespaceoid) * The creation of the version directory prevents more than one tablespace * in a single location. */ - if (mkdir(location_with_version_dir, S_IRWXU) < 0) + if (mkdir(location_with_version_dir, PG_DEFAULT_DIR_MODE) < 0) { if (errno == EEXIST) ereport(ERROR, diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c index f537aff..c0c8d94 100644 --- a/src/backend/libpq/be-fsstubs.c +++ b/src/backend/libpq/be-fsstubs.c @@ -462,7 +462,7 @@ lo_import_internal(text *filename, Oid lobjOid) * open the file to be read in */ text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf)); - fd = OpenTransientFile(fnamebuf, O_RDONLY | PG_BINARY, S_IRWXU); + fd = OpenTransientFile(fnamebuf, O_RDONLY | PG_BINARY); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), @@ -538,8 +538,8 @@ be_lo_export(PG_FUNCTION_ARGS) */ text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf)); oumask = umask(S_IWGRP | S_IWOTH); - fd = OpenTransientFile(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + fd = OpenTransientFilePerm(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); umask(oumask); if (fd < 0) ereport(ERROR, diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 6831342..9fbd2a9 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -579,9 +579,10 @@ PostmasterMain(int argc, char *argv[]) IsPostmasterEnvironment = true; /* - * for security, no dir or file created can be group or other accessible + * Initially set most restrictive umask in case any files are + * accidentally created before file_mode_mask is loaded from GUC. */ - umask(S_IRWXG | S_IRWXO); + umask(file_mode_mask); /* * Initialize random(3) so we don't get the same values in every run. @@ -854,6 +855,9 @@ PostmasterMain(int argc, char *argv[]) ExitPostmaster(0); } + /* Reset the file mode creation mask now that GUC has been loaded. */ + umask(file_mode_mask); + /* Verify that DataDir looks reasonable */ checkDataDir(); @@ -1496,25 +1500,20 @@ checkDataDir(void) #endif /* - * Check if the directory has group or world access. If so, reject. - * - * It would be possible to allow weaker constraints (for example, allow - * group access) but we cannot make a general assumption that that is - * okay; for example there are platforms where nearly all users - * customarily belong to the same group. Perhaps this test should be - * configurable. + * Check if the directory has the correct permissions. If not, then reject. * * XXX temporarily suppress check when on Windows, because there may not * be proper support for Unix-y file permissions. Need to think of a * reasonable check to apply on Windows. */ #if !defined(WIN32) && !defined(__CYGWIN__) - if (stat_buf.st_mode & (S_IRWXG | S_IRWXO)) + if (stat_buf.st_mode & file_mode_mask) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("data directory \"%s\" has group or world access", + errmsg("data directory \"%s\" has incorrect permissions", DataDir), - errdetail("Permissions should be u=rwx (0700)."))); + errdetail("Permissions should be (%04o).", + (PG_DEFAULT_DIR_MODE & ~file_mode_mask)))); #endif /* Look for PG_VERSION before looking for pg_control */ @@ -4400,7 +4399,7 @@ internal_forkexec(int argc, char *argv[], Port *port) * As in OpenTemporaryFileInTablespace, try to make the temp-file * directory */ - mkdir(PG_TEMP_FILES_DIR, S_IRWXU); + mkdir(PG_TEMP_FILES_DIR, PG_DEFAULT_DIR_MODE); fp = AllocateFile(tmpfilename, PG_BINARY_W); if (!fp) diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index aaefdae..f7b1cb5 100644 --- a/src/backend/postmaster/syslogger.c +++ b/src/backend/postmaster/syslogger.c @@ -41,6 +41,7 @@ #include "postmaster/postmaster.h" #include "postmaster/syslogger.h" #include "storage/dsm.h" +#include "storage/fd.h" #include "storage/ipc.h" #include "storage/latch.h" #include "storage/pg_shmem.h" @@ -322,7 +323,7 @@ SysLoggerMain(int argc, char *argv[]) /* * Also, create new directory if not present; ignore errors */ - mkdir(Log_directory, S_IRWXU); + mkdir(Log_directory, PG_DEFAULT_DIR_MODE); } if (strcmp(Log_filename, currentLogFilename) != 0) { @@ -564,7 +565,7 @@ SysLogger_Start(void) /* * Create log directory if not present; ignore errors */ - mkdir(Log_directory, S_IRWXU); + mkdir(Log_directory, PG_DEFAULT_DIR_MODE); /* * The initial logfile is created right in the postmaster, to verify that diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c index bf84c68..51d54ab 100644 --- a/src/backend/replication/logical/origin.c +++ b/src/backend/replication/logical/origin.c @@ -527,8 +527,7 @@ CheckPointReplicationOrigin(void) * CheckpointLock. */ tmpfd = OpenTransientFile((char *) tmppath, - O_CREAT | O_EXCL | O_WRONLY | PG_BINARY, - S_IRUSR | S_IWUSR); + O_CREAT | O_EXCL | O_WRONLY | PG_BINARY); if (tmpfd < 0) ereport(PANIC, (errcode_for_file_access(), @@ -637,7 +636,7 @@ StartupReplicationOrigin(void) elog(DEBUG2, "starting up replication origin progress state"); - fd = OpenTransientFile((char *) path, O_RDONLY | PG_BINARY, 0); + fd = OpenTransientFile((char *) path, O_RDONLY | PG_BINARY); /* * might have had max_replication_slots == 0 last run, or we just brought diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c index 8aac670..af7edea 100644 --- a/src/backend/replication/logical/reorderbuffer.c +++ b/src/backend/replication/logical/reorderbuffer.c @@ -2103,8 +2103,7 @@ ReorderBufferSerializeTXN(ReorderBuffer *rb, ReorderBufferTXN *txn) /* open segment, create it if necessary */ fd = OpenTransientFile(path, - O_CREAT | O_WRONLY | O_APPEND | PG_BINARY, - S_IRUSR | S_IWUSR); + O_CREAT | O_WRONLY | O_APPEND | PG_BINARY); if (fd < 0) ereport(ERROR, @@ -2345,7 +2344,7 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn, NameStr(MyReplicationSlot->data.name), txn->xid, (uint32) (recptr >> 32), (uint32) recptr); - *fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0); + *fd = OpenTransientFile(path, O_RDONLY | PG_BINARY); if (*fd < 0 && errno == ENOENT) { *fd = -1; @@ -3030,7 +3029,7 @@ ApplyLogicalMappingFile(HTAB *tuplecid_data, Oid relid, const char *fname) LogicalRewriteMappingData map; sprintf(path, "pg_logical/mappings/%s", fname); - fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0); + fd = OpenTransientFile(path, O_RDONLY | PG_BINARY); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index 6f19cdc..961b0f9 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -1574,8 +1574,7 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn) /* we have valid data now, open tempfile and write it there */ fd = OpenTransientFile(tmppath, - O_CREAT | O_EXCL | O_WRONLY | PG_BINARY, - S_IRUSR | S_IWUSR); + O_CREAT | O_EXCL | O_WRONLY | PG_BINARY); if (fd < 0) ereport(ERROR, (errmsg("could not open file \"%s\": %m", path))); @@ -1655,7 +1654,7 @@ SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn) sprintf(path, "pg_logical/snapshots/%X-%X.snap", (uint32) (lsn >> 32), (uint32) lsn); - fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0); + fd = OpenTransientFile(path, O_RDONLY | PG_BINARY); if (fd < 0 && errno == ENOENT) return false; diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c index 10d69d0..7e8b50e 100644 --- a/src/backend/replication/slot.c +++ b/src/backend/replication/slot.c @@ -1011,7 +1011,7 @@ CreateSlotOnDisk(ReplicationSlot *slot) rmtree(tmppath, true); /* Create and fsync the temporary slot directory. */ - if (mkdir(tmppath, S_IRWXU) < 0) + if (mkdir(tmppath, PG_DEFAULT_DIR_MODE) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", @@ -1072,9 +1072,7 @@ SaveSlotToPath(ReplicationSlot *slot, const char *dir, int elevel) sprintf(tmppath, "%s/state.tmp", dir); sprintf(path, "%s/state", dir); - fd = OpenTransientFile(tmppath, - O_CREAT | O_EXCL | O_WRONLY | PG_BINARY, - S_IRUSR | S_IWUSR); + fd = OpenTransientFile(tmppath, O_CREAT | O_EXCL | O_WRONLY | PG_BINARY); if (fd < 0) { ereport(elevel, @@ -1187,7 +1185,7 @@ RestoreSlotFromDisk(const char *name) elog(DEBUG1, "restoring replication slot from \"%s\"", path); - fd = OpenTransientFile(path, O_RDWR | PG_BINARY, 0); + fd = OpenTransientFile(path, O_RDWR | PG_BINARY); /* * We do not need to handle this as we are rename()ing the directory into diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 9cf9eb0..e1af7a3 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -437,7 +437,7 @@ SendTimeLineHistory(TimeLineHistoryCmd *cmd) pq_sendint(&buf, len, 4); /* col1 len */ pq_sendbytes(&buf, histfname, len); - fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0666); + fd = OpenTransientFile(path, O_RDONLY | PG_BINARY); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), @@ -2031,7 +2031,7 @@ retry: XLogFilePath(path, curFileTimeLine, sendSegNo); - sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0); + sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY); if (sendFile < 0) { /* diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c index 101da47..0e078f5 100644 --- a/src/backend/storage/file/copydir.c +++ b/src/backend/storage/file/copydir.c @@ -41,7 +41,7 @@ copydir(char *fromdir, char *todir, bool recurse) char fromfile[MAXPGPATH]; char tofile[MAXPGPATH]; - if (mkdir(todir, S_IRWXU) != 0) + if (mkdir(todir, PG_DEFAULT_DIR_MODE) != 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", todir))); @@ -148,14 +148,13 @@ copy_file(char *fromfile, char *tofile) /* * Open the files */ - srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY, 0); + srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY); if (srcfd < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open file \"%s\": %m", fromfile))); - dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, - S_IRUSR | S_IWUSR); + dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY); if (dstfd < 0) ereport(ERROR, (errcode_for_file_access(), diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index fd02fc0..46caf90 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -138,6 +138,8 @@ int max_files_per_process = 1000; */ int max_safe_fds = 32; /* default if not changed */ +/* The file mode creation mask for creating new files and directories. */ +int file_mode_mask = PG_DEFAULT_MODE_MASK; /* Debugging.... */ @@ -604,7 +606,7 @@ durable_rename(const char *oldfile, const char *newfile, int elevel) if (fsync_fname_ext(oldfile, false, false, elevel) != 0) return -1; - fd = OpenTransientFile((char *) newfile, PG_BINARY | O_RDWR, 0); + fd = OpenTransientFile((char *) newfile, PG_BINARY | O_RDWR); if (fd < 0) { if (errno != ENOENT) @@ -896,7 +898,7 @@ set_max_safe_fds(void) * this module wouldn't have any open files to close at that point anyway. */ int -BasicOpenFile(FileName fileName, int fileFlags, int fileMode) +BasicOpenFilePerm(FileName fileName, int fileFlags, int fileMode) { int fd; @@ -922,6 +924,12 @@ tryAgain: return -1; /* failure */ } +int +BasicOpenFile(FileName fileName, int fileFlags) +{ + return BasicOpenFilePerm(fileName, fileFlags, PG_DEFAULT_FILE_MODE); +} + #if defined(FDDEBUG) static void @@ -1047,8 +1055,8 @@ LruInsert(File file) * overall system file table being full. So, be prepared to release * another FD if necessary... */ - vfdP->fd = BasicOpenFile(vfdP->fileName, vfdP->fileFlags, - vfdP->fileMode); + vfdP->fd = BasicOpenFilePerm(vfdP->fileName, vfdP->fileFlags, + vfdP->fileMode); if (vfdP->fd < 0) { DO_DB(elog(LOG, "re-open failed: %m")); @@ -1263,13 +1271,19 @@ FileInvalidate(File file) * (which should always be $PGDATA when this code is running). */ File -PathNameOpenFile(FileName fileName, int fileFlags, int fileMode) +PathNameOpenFile(FileName fileName, int fileFlags) +{ + return PathNameOpenFilePerm(fileName, fileFlags, PG_DEFAULT_FILE_MODE); +} + +File +PathNameOpenFilePerm(FileName fileName, int fileFlags, int fileMode) { char *fnamecopy; File file; Vfd *vfdP; - DO_DB(elog(LOG, "PathNameOpenFile: %s %x %o", + DO_DB(elog(LOG, "PathNameOpenFilePerm: %s %x %o", fileName, fileFlags, fileMode)); /* @@ -1287,7 +1301,7 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode) /* Close excess kernel FDs. */ ReleaseLruFiles(); - vfdP->fd = BasicOpenFile(fileName, fileFlags, fileMode); + vfdP->fd = BasicOpenFilePerm(fileName, fileFlags, fileMode); if (vfdP->fd < 0) { @@ -1424,8 +1438,7 @@ OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError) * temp file that can be reused. */ file = PathNameOpenFile(tempfilepath, - O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, - 0600); + O_RDWR | O_CREAT | O_TRUNC | PG_BINARY); if (file <= 0) { /* @@ -1436,11 +1449,10 @@ OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError) * just did the same thing. If it doesn't work then we'll bomb out on * the second create attempt, instead. */ - mkdir(tempdirpath, S_IRWXU); + mkdir(tempdirpath, PG_DEFAULT_DIR_MODE); file = PathNameOpenFile(tempfilepath, - O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, - 0600); + O_RDWR | O_CREAT | O_TRUNC | PG_BINARY); if (file <= 0 && rejectError) elog(ERROR, "could not create temporary file \"%s\": %m", tempfilepath); @@ -2090,7 +2102,7 @@ TryAgain: * Like AllocateFile, but returns an unbuffered fd like open(2) */ int -OpenTransientFile(FileName fileName, int fileFlags, int fileMode) +OpenTransientFilePerm(FileName fileName, int fileFlags, int fileMode) { int fd; @@ -2107,7 +2119,7 @@ OpenTransientFile(FileName fileName, int fileFlags, int fileMode) /* Close excess kernel FDs. */ ReleaseLruFiles(); - fd = BasicOpenFile(fileName, fileFlags, fileMode); + fd = BasicOpenFilePerm(fileName, fileFlags, fileMode); if (fd >= 0) { @@ -2124,6 +2136,12 @@ OpenTransientFile(FileName fileName, int fileFlags, int fileMode) return -1; /* failure */ } +int +OpenTransientFile(FileName fileName, int fileFlags) +{ + return OpenTransientFilePerm(fileName, fileFlags, PG_DEFAULT_FILE_MODE); +} + /* * Routines that want to initiate a pipe stream should use OpenPipeStream * rather than plain popen(). This lets fd.c deal with freeing FDs if @@ -3030,7 +3048,7 @@ pre_sync_fname(const char *fname, bool isdir, int elevel) if (isdir) return; - fd = OpenTransientFile((char *) fname, O_RDONLY | PG_BINARY, 0); + fd = OpenTransientFile((char *) fname, O_RDONLY | PG_BINARY); if (fd < 0) { @@ -3090,7 +3108,7 @@ fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel) else flags |= O_RDONLY; - fd = OpenTransientFile((char *) fname, flags, 0); + fd = OpenTransientFile((char *) fname, flags); /* * Some OSs don't allow us to open directories at all (Windows returns diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c index b2c9cdc..80ee4fa 100644 --- a/src/backend/storage/ipc/dsm_impl.c +++ b/src/backend/storage/ipc/dsm_impl.c @@ -283,7 +283,7 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size, * returning. */ flags = O_RDWR | (op == DSM_OP_CREATE ? O_CREAT | O_EXCL : 0); - if ((fd = shm_open(name, flags, 0600)) == -1) + if ((fd = shm_open(name, flags, PG_DEFAULT_FILE_MODE)) == -1) { if (errno != EEXIST) ereport(elevel, @@ -834,7 +834,7 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size, /* Create new segment or open an existing one for attach or resize. */ flags = O_RDWR | (op == DSM_OP_CREATE ? O_CREAT | O_EXCL : 0); - if ((fd = OpenTransientFile(name, flags, 0600)) == -1) + if ((fd = OpenTransientFile(name, flags)) == -1) { if (errno != EEXIST) ereport(elevel, diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c index ffd91f5..dfc5b75 100644 --- a/src/backend/storage/ipc/ipc.c +++ b/src/backend/storage/ipc/ipc.c @@ -28,6 +28,7 @@ #include "postmaster/autovacuum.h" #endif #include "storage/dsm.h" +#include "storage/fd.h" #include "storage/ipc.h" #include "tcop/tcopprot.h" @@ -132,8 +133,8 @@ proc_exit(int code) else snprintf(gprofDirName, 32, "gprof/%d", (int) getpid()); - mkdir("gprof", S_IRWXU | S_IRWXG | S_IRWXO); - mkdir(gprofDirName, S_IRWXU | S_IRWXG | S_IRWXO); + mkdir("gprof", PG_DEFAULT_DIR_MODE); + mkdir(gprofDirName, PG_DEFAULT_DIR_MODE); chdir(gprofDirName); } #endif diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c index 6c17b54..cf951a2 100644 --- a/src/backend/storage/smgr/md.c +++ b/src/backend/storage/smgr/md.c @@ -303,7 +303,7 @@ mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo) path = relpath(reln->smgr_rnode, forkNum); - fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600); + fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY); if (fd < 0) { @@ -316,7 +316,7 @@ mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo) * already, even if isRedo is not set. (See also mdopen) */ if (isRedo || IsBootstrapProcessingMode()) - fd = PathNameOpenFile(path, O_RDWR | PG_BINARY, 0600); + fd = PathNameOpenFile(path, O_RDWR | PG_BINARY); if (fd < 0) { /* be sure to report the error reported by create, not open */ @@ -429,7 +429,7 @@ mdunlinkfork(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo) /* truncate(2) would be easier here, but Windows hasn't got it */ int fd; - fd = OpenTransientFile(path, O_RDWR | PG_BINARY, 0); + fd = OpenTransientFile(path, O_RDWR | PG_BINARY); if (fd >= 0) { int save_errno; @@ -582,7 +582,7 @@ mdopen(SMgrRelation reln, ForkNumber forknum, int behavior) path = relpath(reln->smgr_rnode, forknum); - fd = PathNameOpenFile(path, O_RDWR | PG_BINARY, 0600); + fd = PathNameOpenFile(path, O_RDWR | PG_BINARY); if (fd < 0) { @@ -593,7 +593,7 @@ mdopen(SMgrRelation reln, ForkNumber forknum, int behavior) * substitute for mdcreate() in bootstrap mode only. (See mdcreate) */ if (IsBootstrapProcessingMode()) - fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600); + fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY); if (fd < 0) { if ((behavior & EXTENSION_RETURN_NULL) && @@ -1779,7 +1779,7 @@ _mdfd_openseg(SMgrRelation reln, ForkNumber forknum, BlockNumber segno, fullpath = _mdfd_segpath(reln, forknum, segno); /* open the file */ - fd = PathNameOpenFile(fullpath, O_RDWR | PG_BINARY | oflags, 0600); + fd = PathNameOpenFile(fullpath, O_RDWR | PG_BINARY | oflags); pfree(fullpath); diff --git a/src/backend/utils/cache/relmapper.c b/src/backend/utils/cache/relmapper.c index c9d6e44..fe68b5b 100644 --- a/src/backend/utils/cache/relmapper.c +++ b/src/backend/utils/cache/relmapper.c @@ -643,8 +643,7 @@ load_relmap_file(bool shared) } /* Read data ... */ - fd = OpenTransientFile(mapfilename, - O_RDONLY | PG_BINARY, S_IRUSR | S_IWUSR); + fd = OpenTransientFile(mapfilename, O_RDONLY | PG_BINARY); if (fd < 0) ereport(FATAL, (errcode_for_file_access(), @@ -742,9 +741,7 @@ write_relmap_file(bool shared, RelMapFile *newmap, realmap = &local_map; } - fd = OpenTransientFile(mapfilename, - O_WRONLY | O_CREAT | PG_BINARY, - S_IRUSR | S_IWUSR); + fd = OpenTransientFile(mapfilename, O_WRONLY | O_CREAT | PG_BINARY); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 0707f66..bb3e471 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -190,6 +190,7 @@ static void assign_application_name(const char *newval, void *extra); static bool check_cluster_name(char **newval, void **extra, GucSource source); static const char *show_unix_socket_permissions(void); static const char *show_log_file_mode(void); +static const char *show_file_mode_mask(void); /* Private functions in guc-file.l that need to be called from guc.c */ static ConfigVariable *ProcessConfigFileInternal(GucContext context, @@ -2841,6 +2842,18 @@ static struct config_int ConfigureNamesInt[] = 4096, 64, MAX_KILOBYTES, NULL, NULL, NULL }, + { + {"file_mode_mask", PGC_POSTMASTER, UNGROUPED, + gettext_noop("Sets the file mode creation mask for the backend process."), + gettext_noop("The parameter value is expected to be a numeric mode" + "specification in the form accepted by the chmod and " + "umask system calls. (To use the customary octal " + "format the number must start with a 0 (zero).)") + }, + &file_mode_mask, + PG_DEFAULT_MODE_MASK, 0000, 0777, + NULL, NULL, show_file_mode_mask + }, /* End-of-list marker */ { @@ -7186,8 +7199,7 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt) * truncate and reuse it. */ Tmpfd = BasicOpenFile(AutoConfTmpFileName, - O_CREAT | O_RDWR | O_TRUNC, - S_IRUSR | S_IWUSR); + O_CREAT | O_RDWR | O_TRUNC); if (Tmpfd < 0) ereport(ERROR, (errcode_for_file_access(), @@ -10444,6 +10456,15 @@ show_unix_socket_permissions(void) } static const char * +show_file_mode_mask(void) +{ + static char buf[8]; + + snprintf(buf, sizeof(buf), "%04o", file_mode_mask); + return buf; +} + +static const char * show_log_file_mode(void) { static char buf[8]; diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 157d775..81fd9da 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -49,6 +49,7 @@ #external_pid_file = '' # write an extra PID file # (change requires restart) +#file_mode_mask = 0077 #------------------------------------------------------------------------------ # CONNECTIONS AND AUTHENTICATION diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 1ed0d20..283ec09 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -110,6 +110,15 @@ static const char *const auth_methods_local[] = { NULL }; +/* File mode to use with chmod on files. */ +#define PG_DEFAULT_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) + +/* File mode to use with chmod on directories. */ +#define PG_DEFAULT_DIR_MODE (S_IRWXU | S_IRWXG | S_IRWXO) + +/* Default file mode creation mask. */ +#define PG_DEFAULT_MODE_MASK (S_IRWXG | S_IRWXO) + /* * these values are passed in by makefile defines */ @@ -139,6 +148,7 @@ static bool sync_only = false; static bool show_setting = false; static bool data_checksums = false; static char *xlog_dir = ""; +static mode_t file_mode_mask = PG_DEFAULT_MODE_MASK; /* internal vars */ @@ -1095,6 +1105,11 @@ setup_config(void) conflines = replace_token(conflines, "#dynamic_shared_memory_type = posix", repltok); + snprintf(repltok, sizeof(repltok), "file_mode_mask = %04o", + file_mode_mask); + conflines = replace_token(conflines, "#file_mode_mask = 0077", + repltok); + #if DEFAULT_BACKEND_FLUSH_AFTER > 0 snprintf(repltok, sizeof(repltok), "#backend_flush_after = %dkB", DEFAULT_BACKEND_FLUSH_AFTER * (BLCKSZ / 1024)); @@ -1131,7 +1146,7 @@ setup_config(void) snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data); writefile(path, conflines); - if (chmod(path, S_IRUSR | S_IWUSR) != 0) + if (chmod(path, (PG_DEFAULT_FILE_MODE & ~file_mode_mask)) != 0) { fprintf(stderr, _("%s: could not change permissions of \"%s\": %s\n"), progname, path, strerror(errno)); @@ -1151,7 +1166,7 @@ setup_config(void) sprintf(path, "%s/postgresql.auto.conf", pg_data); writefile(path, autoconflines); - if (chmod(path, S_IRUSR | S_IWUSR) != 0) + if (chmod(path, (PG_DEFAULT_FILE_MODE & ~file_mode_mask)) != 0) { fprintf(stderr, _("%s: could not change permissions of \"%s\": %s\n"), progname, path, strerror(errno)); @@ -1235,7 +1250,7 @@ setup_config(void) snprintf(path, sizeof(path), "%s/pg_hba.conf", pg_data); writefile(path, conflines); - if (chmod(path, S_IRUSR | S_IWUSR) != 0) + if (chmod(path, (PG_DEFAULT_FILE_MODE & ~file_mode_mask)) != 0) { fprintf(stderr, _("%s: could not change permissions of \"%s\": %s\n"), progname, path, strerror(errno)); @@ -1251,7 +1266,7 @@ setup_config(void) snprintf(path, sizeof(path), "%s/pg_ident.conf", pg_data); writefile(path, conflines); - if (chmod(path, S_IRUSR | S_IWUSR) != 0) + if (chmod(path, (PG_DEFAULT_FILE_MODE & ~file_mode_mask)) != 0) { fprintf(stderr, _("%s: could not change permissions of \"%s\": %s\n"), progname, path, strerror(errno)); @@ -2243,6 +2258,7 @@ usage(const char *progname) printf(_(" --auth-local=METHOD default authentication method for local-socket connections\n")); printf(_(" [-D, --pgdata=]DATADIR location for this database cluster\n")); printf(_(" -E, --encoding=ENCODING set default encoding for new databases\n")); + printf(_(" -u, --file-mode-mask=MASK set default file mode creation mask (umask)\n")); printf(_(" --locale=LOCALE set default locale for new databases\n")); printf(_(" --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n" " --lc-monetary=, --lc-numeric=, --lc-time=LOCALE\n" @@ -2624,7 +2640,7 @@ create_data_directory(void) pg_data); fflush(stdout); - if (pg_mkdir_p(pg_data, S_IRWXU) != 0) + if (pg_mkdir_p(pg_data, PG_DEFAULT_DIR_MODE) != 0) { fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"), progname, pg_data, strerror(errno)); @@ -2642,7 +2658,7 @@ create_data_directory(void) pg_data); fflush(stdout); - if (chmod(pg_data, S_IRWXU) != 0) + if (chmod(pg_data, (PG_DEFAULT_DIR_MODE & ~file_mode_mask)) != 0) { fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"), progname, pg_data, strerror(errno)); @@ -2710,7 +2726,8 @@ create_xlog_or_symlink(void) xlog_dir); fflush(stdout); - if (pg_mkdir_p(xlog_dir, S_IRWXU) != 0) + printf("MASK: %04o\n", file_mode_mask); + if (pg_mkdir_p(xlog_dir, PG_DEFAULT_DIR_MODE) != 0) { fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"), progname, xlog_dir, strerror(errno)); @@ -2728,7 +2745,8 @@ create_xlog_or_symlink(void) xlog_dir); fflush(stdout); - if (chmod(xlog_dir, S_IRWXU) != 0) + printf("MASK: %04o\n", file_mode_mask); + if (chmod(xlog_dir, (PG_DEFAULT_DIR_MODE & ~file_mode_mask)) != 0) { fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"), progname, xlog_dir, strerror(errno)); @@ -2778,7 +2796,7 @@ create_xlog_or_symlink(void) else { /* Without -X option, just make the subdirectory normally */ - if (mkdir(subdirloc, S_IRWXU) < 0) + if (mkdir(subdirloc, PG_DEFAULT_DIR_MODE) < 0) { fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"), progname, subdirloc, strerror(errno)); @@ -2814,7 +2832,9 @@ initialize_data_directory(void) setup_signals(); - umask(S_IRWXG | S_IRWXO); + /* Set the file mode creation mask. */ + umask(file_mode_mask); + printf(_("Initializing with file mode creation mask: %04o\n"), file_mode_mask); create_data_directory(); @@ -2834,7 +2854,7 @@ initialize_data_directory(void) * The parent directory already exists, so we only need mkdir() not * pg_mkdir_p() here, which avoids some failure modes; cf bug #13853. */ - if (mkdir(path, S_IRWXU) < 0) + if (mkdir(path, PG_DEFAULT_DIR_MODE) < 0) { fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"), progname, path, strerror(errno)); @@ -2942,6 +2962,7 @@ main(int argc, char *argv[]) {"sync-only", no_argument, NULL, 'S'}, {"waldir", required_argument, NULL, 'X'}, {"data-checksums", no_argument, NULL, 'k'}, + {"file-mode-mask", required_argument, NULL, 'u'}, {NULL, 0, NULL, 0} }; @@ -2983,7 +3004,7 @@ main(int argc, char *argv[]) /* process command-line options */ - while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:", long_options, &option_index)) != -1) + while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:u:", long_options, &option_index)) != -1) { switch (c) { @@ -3074,6 +3095,9 @@ main(int argc, char *argv[]) case 'X': xlog_dir = pg_strdup(optarg); break; + case 'u': + file_mode_mask = strtoul(optarg, NULL, 8); + break; default: /* getopt_long already emitted a complaint */ fprintf(stderr, _("Try \"%s --help\" for more information.\n"), diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index 1a43a2c..6660b7b 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -22,7 +22,7 @@ * Use them for all file activity... * * File fd; - * fd = PathNameOpenFile("foo", O_RDONLY, 0600); + * fd = PathNameOpenFile("foo", O_RDONLY); * * AllocateFile(); * FreeFile(); @@ -59,13 +59,21 @@ extern int max_files_per_process; */ extern int max_safe_fds; +/* The file mode creation mask for creating new files and directories. */ +extern int file_mode_mask; + +/* Define default modes and masks. */ +#define PG_DEFAULT_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) +#define PG_DEFAULT_DIR_MODE (S_IRWXU | S_IRWXG | S_IRWXO) +#define PG_DEFAULT_MODE_MASK (S_IRWXG | S_IRWXO) /* * prototypes for functions in fd.c */ /* Operations on virtual Files --- equivalent to Unix kernel file ops */ -extern File PathNameOpenFile(FileName fileName, int fileFlags, int fileMode); +extern File PathNameOpenFilePerm(FileName fileName, int fileFlags, int fileMode); +extern File PathNameOpenFile(FileName fileName, int fileFlags); extern File OpenTemporaryFile(bool interXact); extern void FileClose(File file); extern int FilePrefetch(File file, off_t offset, int amount); @@ -94,11 +102,13 @@ extern struct dirent *ReadDir(DIR *dir, const char *dirname); extern int FreeDir(DIR *dir); /* Operations to allow use of a plain kernel FD, with automatic cleanup */ -extern int OpenTransientFile(FileName fileName, int fileFlags, int fileMode); +extern int OpenTransientFilePerm(FileName fileName, int fileFlags, int fileMode); +extern int OpenTransientFile(FileName fileName, int fileFlags); extern int CloseTransientFile(int fd); /* If you've really really gotta have a plain kernel FD, use this */ -extern int BasicOpenFile(FileName fileName, int fileFlags, int fileMode); +extern int BasicOpenFilePerm(FileName fileName, int fileFlags, int fileMode); +extern int BasicOpenFile(FileName fileName, int fileFlags); /* Miscellaneous support routines */ extern void InitFileAccess(void);