PostgreSQL currently requires the file mode mask (umask) to be 0077.
However, this precludes the possibility of a user in the postgres group
performing a backup (or whatever). Now that
pg_start_backup()/pg_stop_backup() privileges can be delegated to an
unprivileged user, it makes sense to also allow a (relatively)
unprivileged user to perform the backup at the file system level as well.
This patch introduces a new initdb param, -u/-file-mode-mask, and a new
GUC, file_mode_mask, to allow the default mode of files and directories
in the $PGDATA directory to be modified.
This obviously required mode changes in a number of places, so at the
same time the BasicOpenFile(), OpenTransientFile(), and
PathNameOpenFile() have been split into versions that either use the
default permissions or allow custom permissions. In the end there was
only one call to the custom permission version (be-fsstubs.c:505) for
all three variants.
The following three calls (at the least) need to be reviewed:
bin/pg_dump/pg_backup_directory.c:194
src/port/mkdtemp.c:190
bin/pg_basebackup.c:599:655:1399
And this call needs serious consideration:
bin/pg_rewind/file_ops.c:214
Besides that there should be tests to make sure the masks are working as
expected and these could be added to the initdb TAP tests, though no
mask tests exist at this time. Making sure all file operations produce
the correct modes would need to be placed in a new module, perhaps the
new backup tests proposed in [1].
Adam Brightwell developed the patch based on an initial concept by me
and Stephen Frost. I added the refactoring in fd.c and some additional
documentation.
This patch applies cleanly on 016c990 but may fare badly over time due
to the number of files modified.
--
-David
[email protected]
[1]
https://www.postgresql.org/message-id/[email protected]
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 1b390a2..2371878 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -812,6 +812,38 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
+ <varlistentry id="guc-file-mode-mask" xreflabel="file_mode_mask">
+ <term><varname>file_mode_mask</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>file_mode_mask</> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ 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 <function>chmod</function> and
+ <function>umask</function> system calls. (To use the customary octal
+ format the number must start with a <literal>0</literal> (zero).)
+ </para>
+
+ <para>
+ The default <literal>file_mode_mask</literal> is
<literal>0077</literal>,
+ meaning that the only the database owner can read and write files in
+ the data directory. For example, setting the
+ <literal>file_mode_mask</literal> to <literal>0027</literal> 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.
+ </para>
+
+ <para>
+ This parameter can only be set at server start.
+ </para>
+
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-bonjour" xreflabel="bonjour">
<term><varname>bonjour</varname> (<type>boolean</type>)
<indexterm>
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 271c492..bfb6c7d 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();
@@ -1489,25 +1493,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 */
@@ -4393,7 +4392,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 13a0301..684944d 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"
@@ -320,7 +321,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)
{
@@ -555,7 +556,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);
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers