Re: log files and permissions - Mailing list pgsql-hackers

From Martin Pihlak
Subject Re: log files and permissions
Date
Msg-id 4C3AF035.4090603@gmail.com
Whole thread Raw
In response to Re: log files and permissions  (Itagaki Takahiro <itagaki.takahiro@gmail.com>)
Responses Re: log files and permissions
List pgsql-hackers
Itagaki Takahiro wrote:
> I checked "log_file_mode GUC" patch, and found a couple of Windows-specific
> and translation issues.

Thank you for the review. Attached patch attempts to fix these issues.

> * fchmod() is not available on some platforms, including Windows.
>     fh = fopen(filename, mode);
>     setvbuf(fh, NULL, LBF_MODE, 0);
>     fchmod(fileno(fh), Log_file_mode);
>

I've changed that to using chmod(), that should be available everywhere and
is already used in several places in Postgres code.

> * How does the file mode work on Windows?
> If it doesn't work, we should explain it in docs.

Indeed it seems that chmod() doesn't actually do anything useful on Windows.
So I've added a documentation note about it and put an #ifndef WIN32 around
the chmod() call.

> It might look a duplication of codes, but I think this form is better
> because we can reuse the existing translation catalogs.
>     if (am_rotating)
>         ereport(FATAL, ... "could not create log file ...);
>     else
>         ereport(LOG, ... "could not open new log file ...);
>

Fixed.

regards,
Martin

*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
***************
*** 2789,2794 **** local0.*    /var/log/postgresql
--- 2789,2814 ----
        </listitem>
       </varlistentry>

+      <varlistentry id="guc-log-file-mode" xreflabel="log_file_mode">
+       <term><varname>log_file_mode</varname> (<type>integer</type>)</term>
+       <indexterm>
+        <primary><varname>log_file_mode</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         On Unix systems this parameter sets the permissions for log files
+         when <varname>logging_collector</varname> is enabled. On Microsoft
+         Windows the file mode will be ignored. The value is an octal number
+         consisting of 3 digits signifying the permissions for the user, group
+         and others.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line.
+        </para>
+       </listitem>
+      </varlistentry>
+
       <varlistentry id="guc-log-rotation-age" xreflabel="log_rotation_age">
        <term><varname>log_rotation_age</varname> (<type>integer</type>)</term>
        <indexterm>
*** a/src/backend/commands/variable.c
--- b/src/backend/commands/variable.c
***************
*** 914,916 **** show_role(void)
--- 914,946 ----

      return endptr + 1;
  }
+
+
+ /*
+  * LOG_FILE_MODE
+  */
+
+ extern int Log_file_mode;        /* in guc.c */
+
+ /*
+  * assign_log_file_mode: GUC assign_hook for log_file_mode
+  */
+ const char *
+ assign_log_file_mode(const char *value, bool doit, GucSource source)
+ {
+     char *endptr;
+     long file_mode = strtol(value, &endptr, 8);
+
+     if (!*value || *endptr || file_mode < 0 || file_mode > 0777)
+     {
+         ereport(GUC_complaint_elevel(source),
+                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                  errmsg("invalid value for parameter \"log_file_mode\"")));
+         return NULL;
+     }
+
+     if (doit)
+         Log_file_mode = (int) file_mode;
+
+     return value;
+ }
*** a/src/backend/postmaster/syslogger.c
--- b/src/backend/postmaster/syslogger.c
***************
*** 73,78 **** int            Log_RotationSize = 10 * 1024;
--- 73,79 ----
  char       *Log_directory = NULL;
  char       *Log_filename = NULL;
  bool        Log_truncate_on_rotation = false;
+ int            Log_file_mode = 0600;

  /*
   * Globally visible state (used by elog.c)
***************
*** 135,140 **** static void syslogger_parseArgs(int argc, char *argv[]);
--- 136,142 ----
  static void process_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
  static void flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
  static void open_csvlogfile(void);
+ static FILE *logfile_open(const char *filename, const char *mode, bool am_rotating);

  #ifdef WIN32
  static unsigned int __stdcall pipeThread(void *arg);
***************
*** 516,530 **** SysLogger_Start(void)
       */
      filename = logfile_getname(time(NULL), NULL);

!     syslogFile = fopen(filename, "a");
!
!     if (!syslogFile)
!         ereport(FATAL,
!                 (errcode_for_file_access(),
!                  (errmsg("could not create log file \"%s\": %m",
!                          filename))));
!
!     setvbuf(syslogFile, NULL, LBF_MODE, 0);

      pfree(filename);

--- 518,524 ----
       */
      filename = logfile_getname(time(NULL), NULL);

!     syslogFile = logfile_open(filename, "a", false);

      pfree(filename);

***************
*** 1004,1018 **** open_csvlogfile(void)

      filename = logfile_getname(time(NULL), ".csv");

!     fh = fopen(filename, "a");
!
!     if (!fh)
!         ereport(FATAL,
!                 (errcode_for_file_access(),
!                  (errmsg("could not create log file \"%s\": %m",
!                          filename))));
!
!     setvbuf(fh, NULL, LBF_MODE, 0);

  #ifdef WIN32
      _setmode(_fileno(fh), _O_TEXT);        /* use CRLF line endings on Windows */
--- 998,1004 ----

      filename = logfile_getname(time(NULL), ".csv");

!     fh = logfile_open(filename, "a", false);

  #ifdef WIN32
      _setmode(_fileno(fh), _O_TEXT);        /* use CRLF line endings on Windows */
***************
*** 1025,1030 **** open_csvlogfile(void)
--- 1011,1050 ----
  }

  /*
+  * Open the logfile, set permissions and buffering options.
+  */
+ static FILE *
+ logfile_open(const char *filename, const char *mode, bool am_rotating)
+ {
+     FILE   *fh;
+
+     fh = fopen(filename, mode);
+
+     if (fh)
+     {
+         setvbuf(fh, NULL, LBF_MODE, 0);
+ #ifndef WIN32
+         chmod(filename, Log_file_mode);
+ #endif
+     }
+     else
+     {
+         if (am_rotating)
+             ereport(LOG,
+                     (errcode_for_file_access(),
+                      errmsg("could not create new log file \"%s\": %m",
+                              filename)));
+         else
+             ereport(FATAL,
+                     (errcode_for_file_access(),
+                      errmsg("could not create log file \"%s\": %m",
+                              filename)));
+     }
+
+     return fh;
+ }
+
+ /*
   * perform logfile rotation
   */
  static void
***************
*** 1070,1088 **** logfile_rotate(bool time_based_rotation, int size_rotation_for)
          if (Log_truncate_on_rotation && time_based_rotation &&
              last_file_name != NULL &&
              strcmp(filename, last_file_name) != 0)
!             fh = fopen(filename, "w");
          else
!             fh = fopen(filename, "a");

          if (!fh)
          {
              int            saveerrno = errno;

-             ereport(LOG,
-                     (errcode_for_file_access(),
-                      errmsg("could not open new log file \"%s\": %m",
-                             filename)));
-
              /*
               * ENFILE/EMFILE are not too surprising on a busy system; just
               * keep using the old file till we manage to get a new one.
--- 1090,1103 ----
          if (Log_truncate_on_rotation && time_based_rotation &&
              last_file_name != NULL &&
              strcmp(filename, last_file_name) != 0)
!             fh = logfile_open(filename, "w", true);
          else
!             fh = logfile_open(filename, "a", true);

          if (!fh)
          {
              int            saveerrno = errno;

              /*
               * ENFILE/EMFILE are not too surprising on a busy system; just
               * keep using the old file till we manage to get a new one.
***************
*** 1128,1146 **** logfile_rotate(bool time_based_rotation, int size_rotation_for)
          if (Log_truncate_on_rotation && time_based_rotation &&
              last_csv_file_name != NULL &&
              strcmp(csvfilename, last_csv_file_name) != 0)
!             fh = fopen(csvfilename, "w");
          else
!             fh = fopen(csvfilename, "a");

          if (!fh)
          {
              int            saveerrno = errno;

-             ereport(LOG,
-                     (errcode_for_file_access(),
-                      errmsg("could not open new log file \"%s\": %m",
-                             csvfilename)));
-
              /*
               * ENFILE/EMFILE are not too surprising on a busy system; just
               * keep using the old file till we manage to get a new one.
--- 1143,1156 ----
          if (Log_truncate_on_rotation && time_based_rotation &&
              last_csv_file_name != NULL &&
              strcmp(csvfilename, last_csv_file_name) != 0)
!             fh = logfile_open(csvfilename, "w", true);
          else
!             fh = logfile_open(csvfilename, "a", true);

          if (!fh)
          {
              int            saveerrno = errno;

              /*
               * ENFILE/EMFILE are not too surprising on a busy system; just
               * keep using the old file till we manage to get a new one.
***************
*** 1162,1169 **** logfile_rotate(bool time_based_rotation, int size_rotation_for)
              return;
          }

-         setvbuf(fh, NULL, LBF_MODE, 0);
-
  #ifdef WIN32
          _setmode(_fileno(fh), _O_TEXT); /* use CRLF line endings on Windows */
  #endif
--- 1172,1177 ----
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
***************
*** 412,417 **** static char *server_version_string;
--- 412,418 ----
  static int    server_version_num;
  static char *timezone_string;
  static char *log_timezone_string;
+ static char *log_file_mode_string;
  static char *timezone_abbreviations_string;
  static char *XactIsoLevel_string;
  static char *data_directory;
***************
*** 2243,2248 **** static struct config_string ConfigureNamesString[] =
--- 2244,2258 ----
      },

      {
+         {"log_file_mode", PGC_SIGHUP, LOGGING_WHERE,
+             gettext_noop("Sets the file permissions for log files."),
+             NULL
+         },
+         &log_file_mode_string,
+         "0600", assign_log_file_mode
+     },
+
+     {
          {"DateStyle", PGC_USERSET, CLIENT_CONN_LOCALE,
              gettext_noop("Sets the display format for date and time values."),
              gettext_noop("Also controls interpretation of ambiguous "
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 265,270 ****
--- 265,271 ----
                      # can be absolute or relative to PGDATA
  #log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'    # log file name pattern,
                      # can include strftime() escapes
+ #log_file_mode = 0600            # creation mode for log files, octal
  #log_truncate_on_rotation = off        # If on, an existing log file of the
                      # same name as the new log file will be
                      # truncated rather than appended to.
*** a/src/include/commands/variable.h
--- b/src/include/commands/variable.h
***************
*** 35,39 **** extern const char *show_role(void);
--- 35,42 ----
  extern const char *assign_session_authorization(const char *value,
                               bool doit, GucSource source);
  extern const char *show_session_authorization(void);
+ const char *assign_log_file_mode(const char *value,
+                             bool doit, GucSource source);
+ const char *show_log_file_mode(void);

  #endif   /* VARIABLE_H */
*** a/src/include/postmaster/syslogger.h
--- b/src/include/postmaster/syslogger.h
***************
*** 68,73 **** extern int    Log_RotationSize;
--- 68,74 ----
  extern PGDLLIMPORT char *Log_directory;
  extern PGDLLIMPORT char *Log_filename;
  extern bool Log_truncate_on_rotation;
+ extern int Log_file_mode;

  extern bool am_syslogger;


pgsql-hackers by date:

Previous
From: Magnus Hagander
Date:
Subject: Re: Re: [COMMITTERS] pgsql: Add support for TCP keepalives on Windows, both for backend and
Next
From: Mike Fowler
Date:
Subject: Re: [PATCH] Re: Issue: Deprecation of the XML2 module 'xml_is_well_formed' function