Header And Logo

PostgreSQL
| The world's most advanced open source database.

syslogger.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * syslogger.c
00004  *
00005  * The system logger (syslogger) appeared in Postgres 8.0. It catches all
00006  * stderr output from the postmaster, backends, and other subprocesses
00007  * by redirecting to a pipe, and writes it to a set of logfiles.
00008  * It's possible to have size and age limits for the logfile configured
00009  * in postgresql.conf. If these limits are reached or passed, the
00010  * current logfile is closed and a new one is created (rotated).
00011  * The logfiles are stored in a subdirectory (configurable in
00012  * postgresql.conf), using a user-selectable naming scheme.
00013  *
00014  * Author: Andreas Pflug <[email protected]>
00015  *
00016  * Copyright (c) 2004-2013, PostgreSQL Global Development Group
00017  *
00018  *
00019  * IDENTIFICATION
00020  *    src/backend/postmaster/syslogger.c
00021  *
00022  *-------------------------------------------------------------------------
00023  */
00024 #include "postgres.h"
00025 
00026 #include <fcntl.h>
00027 #include <limits.h>
00028 #include <signal.h>
00029 #include <time.h>
00030 #include <unistd.h>
00031 #include <sys/stat.h>
00032 #include <sys/time.h>
00033 
00034 #include "lib/stringinfo.h"
00035 #include "libpq/pqsignal.h"
00036 #include "miscadmin.h"
00037 #include "nodes/pg_list.h"
00038 #include "pgtime.h"
00039 #include "postmaster/fork_process.h"
00040 #include "postmaster/postmaster.h"
00041 #include "postmaster/syslogger.h"
00042 #include "storage/ipc.h"
00043 #include "storage/latch.h"
00044 #include "storage/pg_shmem.h"
00045 #include "utils/guc.h"
00046 #include "utils/ps_status.h"
00047 #include "utils/timestamp.h"
00048 
00049 /*
00050  * We really want line-buffered mode for logfile output, but Windows does
00051  * not have it, and interprets _IOLBF as _IOFBF (bozos).  So use _IONBF
00052  * instead on Windows.
00053  */
00054 #ifdef WIN32
00055 #define LBF_MODE    _IONBF
00056 #else
00057 #define LBF_MODE    _IOLBF
00058 #endif
00059 
00060 /*
00061  * We read() into a temp buffer twice as big as a chunk, so that any fragment
00062  * left after processing can be moved down to the front and we'll still have
00063  * room to read a full chunk.
00064  */
00065 #define READ_BUF_SIZE (2 * PIPE_CHUNK_SIZE)
00066 
00067 
00068 /*
00069  * GUC parameters.  Logging_collector cannot be changed after postmaster
00070  * start, but the rest can change at SIGHUP.
00071  */
00072 bool        Logging_collector = false;
00073 int         Log_RotationAge = HOURS_PER_DAY * MINS_PER_HOUR;
00074 int         Log_RotationSize = 10 * 1024;
00075 char       *Log_directory = NULL;
00076 char       *Log_filename = NULL;
00077 bool        Log_truncate_on_rotation = false;
00078 int         Log_file_mode = S_IRUSR | S_IWUSR;
00079 
00080 /*
00081  * Globally visible state (used by elog.c)
00082  */
00083 bool        am_syslogger = false;
00084 
00085 extern bool redirection_done;
00086 
00087 /*
00088  * Private state
00089  */
00090 static pg_time_t next_rotation_time;
00091 static bool pipe_eof_seen = false;
00092 static bool rotation_disabled = false;
00093 static FILE *syslogFile = NULL;
00094 static FILE *csvlogFile = NULL;
00095 NON_EXEC_STATIC pg_time_t first_syslogger_file_time = 0;
00096 static char *last_file_name = NULL;
00097 static char *last_csv_file_name = NULL;
00098 static Latch sysLoggerLatch;
00099 
00100 /*
00101  * Buffers for saving partial messages from different backends.
00102  *
00103  * Keep NBUFFER_LISTS lists of these, with the entry for a given source pid
00104  * being in the list numbered (pid % NBUFFER_LISTS), so as to cut down on
00105  * the number of entries we have to examine for any one incoming message.
00106  * There must never be more than one entry for the same source pid.
00107  *
00108  * An inactive buffer is not removed from its list, just held for re-use.
00109  * An inactive buffer has pid == 0 and undefined contents of data.
00110  */
00111 typedef struct
00112 {
00113     int32       pid;            /* PID of source process */
00114     StringInfoData data;        /* accumulated data, as a StringInfo */
00115 } save_buffer;
00116 
00117 #define NBUFFER_LISTS 256
00118 static List *buffer_lists[NBUFFER_LISTS];
00119 
00120 /* These must be exported for EXEC_BACKEND case ... annoying */
00121 #ifndef WIN32
00122 int         syslogPipe[2] = {-1, -1};
00123 #else
00124 HANDLE      syslogPipe[2] = {0, 0};
00125 #endif
00126 
00127 #ifdef WIN32
00128 static HANDLE threadHandle = 0;
00129 static CRITICAL_SECTION sysloggerSection;
00130 #endif
00131 
00132 /*
00133  * Flags set by interrupt handlers for later service in the main loop.
00134  */
00135 static volatile sig_atomic_t got_SIGHUP = false;
00136 static volatile sig_atomic_t rotation_requested = false;
00137 
00138 
00139 /* Local subroutines */
00140 #ifdef EXEC_BACKEND
00141 static pid_t syslogger_forkexec(void);
00142 static void syslogger_parseArgs(int argc, char *argv[]);
00143 #endif
00144 NON_EXEC_STATIC void SysLoggerMain(int argc, char *argv[]) __attribute__((noreturn));
00145 static void process_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
00146 static void flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
00147 static void open_csvlogfile(void);
00148 static FILE *logfile_open(const char *filename, const char *mode,
00149              bool allow_errors);
00150 
00151 #ifdef WIN32
00152 static unsigned int __stdcall pipeThread(void *arg);
00153 #endif
00154 static void logfile_rotate(bool time_based_rotation, int size_rotation_for);
00155 static char *logfile_getname(pg_time_t timestamp, const char *suffix);
00156 static void set_next_rotation_time(void);
00157 static void sigHupHandler(SIGNAL_ARGS);
00158 static void sigUsr1Handler(SIGNAL_ARGS);
00159 
00160 
00161 /*
00162  * Main entry point for syslogger process
00163  * argc/argv parameters are valid only in EXEC_BACKEND case.
00164  */
00165 NON_EXEC_STATIC void
00166 SysLoggerMain(int argc, char *argv[])
00167 {
00168 #ifndef WIN32
00169     char        logbuffer[READ_BUF_SIZE];
00170     int         bytes_in_logbuffer = 0;
00171 #endif
00172     char       *currentLogDir;
00173     char       *currentLogFilename;
00174     int         currentLogRotationAge;
00175     pg_time_t   now;
00176 
00177     IsUnderPostmaster = true;   /* we are a postmaster subprocess now */
00178 
00179     MyProcPid = getpid();       /* reset MyProcPid */
00180 
00181     MyStartTime = time(NULL);   /* set our start time in case we call elog */
00182     now = MyStartTime;
00183 
00184 #ifdef EXEC_BACKEND
00185     syslogger_parseArgs(argc, argv);
00186 #endif   /* EXEC_BACKEND */
00187 
00188     am_syslogger = true;
00189 
00190     init_ps_display("logger process", "", "", "");
00191 
00192     /*
00193      * If we restarted, our stderr is already redirected into our own input
00194      * pipe.  This is of course pretty useless, not to mention that it
00195      * interferes with detecting pipe EOF.  Point stderr to /dev/null. This
00196      * assumes that all interesting messages generated in the syslogger will
00197      * come through elog.c and will be sent to write_syslogger_file.
00198      */
00199     if (redirection_done)
00200     {
00201         int         fd = open(DEVNULL, O_WRONLY, 0);
00202 
00203         /*
00204          * The closes might look redundant, but they are not: we want to be
00205          * darn sure the pipe gets closed even if the open failed.  We can
00206          * survive running with stderr pointing nowhere, but we can't afford
00207          * to have extra pipe input descriptors hanging around.
00208          */
00209         close(fileno(stdout));
00210         close(fileno(stderr));
00211         if (fd != -1)
00212         {
00213             dup2(fd, fileno(stdout));
00214             dup2(fd, fileno(stderr));
00215             close(fd);
00216         }
00217     }
00218 
00219     /*
00220      * Syslogger's own stderr can't be the syslogPipe, so set it back to text
00221      * mode if we didn't just close it. (It was set to binary in
00222      * SubPostmasterMain).
00223      */
00224 #ifdef WIN32
00225     else
00226         _setmode(_fileno(stderr), _O_TEXT);
00227 #endif
00228 
00229     /*
00230      * Also close our copy of the write end of the pipe.  This is needed to
00231      * ensure we can detect pipe EOF correctly.  (But note that in the restart
00232      * case, the postmaster already did this.)
00233      */
00234 #ifndef WIN32
00235     if (syslogPipe[1] >= 0)
00236         close(syslogPipe[1]);
00237     syslogPipe[1] = -1;
00238 #else
00239     if (syslogPipe[1])
00240         CloseHandle(syslogPipe[1]);
00241     syslogPipe[1] = 0;
00242 #endif
00243 
00244     /*
00245      * If possible, make this process a group leader, so that the postmaster
00246      * can signal any child processes too.  (syslogger probably never has any
00247      * child processes, but for consistency we make all postmaster child
00248      * processes do this.)
00249      */
00250 #ifdef HAVE_SETSID
00251     if (setsid() < 0)
00252         elog(FATAL, "setsid() failed: %m");
00253 #endif
00254 
00255     InitializeLatchSupport();       /* needed for latch waits */
00256 
00257     /* Initialize private latch for use by signal handlers */
00258     InitLatch(&sysLoggerLatch);
00259 
00260     /*
00261      * Properly accept or ignore signals the postmaster might send us
00262      *
00263      * Note: we ignore all termination signals, and instead exit only when all
00264      * upstream processes are gone, to ensure we don't miss any dying gasps of
00265      * broken backends...
00266      */
00267 
00268     pqsignal(SIGHUP, sigHupHandler);    /* set flag to read config file */
00269     pqsignal(SIGINT, SIG_IGN);
00270     pqsignal(SIGTERM, SIG_IGN);
00271     pqsignal(SIGQUIT, SIG_IGN);
00272     pqsignal(SIGALRM, SIG_IGN);
00273     pqsignal(SIGPIPE, SIG_IGN);
00274     pqsignal(SIGUSR1, sigUsr1Handler);  /* request log rotation */
00275     pqsignal(SIGUSR2, SIG_IGN);
00276 
00277     /*
00278      * Reset some signals that are accepted by postmaster but not here
00279      */
00280     pqsignal(SIGCHLD, SIG_DFL);
00281     pqsignal(SIGTTIN, SIG_DFL);
00282     pqsignal(SIGTTOU, SIG_DFL);
00283     pqsignal(SIGCONT, SIG_DFL);
00284     pqsignal(SIGWINCH, SIG_DFL);
00285 
00286     PG_SETMASK(&UnBlockSig);
00287 
00288 #ifdef WIN32
00289     /* Fire up separate data transfer thread */
00290     InitializeCriticalSection(&sysloggerSection);
00291     EnterCriticalSection(&sysloggerSection);
00292 
00293     threadHandle = (HANDLE) _beginthreadex(NULL, 0, pipeThread, NULL, 0, NULL);
00294     if (threadHandle == 0)
00295         elog(FATAL, "could not create syslogger data transfer thread: %m");
00296 #endif   /* WIN32 */
00297 
00298     /*
00299      * Remember active logfile's name.  We recompute this from the reference
00300      * time because passing down just the pg_time_t is a lot cheaper than
00301      * passing a whole file path in the EXEC_BACKEND case.
00302      */
00303     last_file_name = logfile_getname(first_syslogger_file_time, NULL);
00304 
00305     /* remember active logfile parameters */
00306     currentLogDir = pstrdup(Log_directory);
00307     currentLogFilename = pstrdup(Log_filename);
00308     currentLogRotationAge = Log_RotationAge;
00309     /* set next planned rotation time */
00310     set_next_rotation_time();
00311 
00312     /* main worker loop */
00313     for (;;)
00314     {
00315         bool        time_based_rotation = false;
00316         int         size_rotation_for = 0;
00317         long        cur_timeout;
00318         int         cur_flags;
00319 
00320 #ifndef WIN32
00321         int         rc;
00322 #endif
00323 
00324         /* Clear any already-pending wakeups */
00325         ResetLatch(&sysLoggerLatch);
00326 
00327         /*
00328          * Process any requests or signals received recently.
00329          */
00330         if (got_SIGHUP)
00331         {
00332             got_SIGHUP = false;
00333             ProcessConfigFile(PGC_SIGHUP);
00334 
00335             /*
00336              * Check if the log directory or filename pattern changed in
00337              * postgresql.conf. If so, force rotation to make sure we're
00338              * writing the logfiles in the right place.
00339              */
00340             if (strcmp(Log_directory, currentLogDir) != 0)
00341             {
00342                 pfree(currentLogDir);
00343                 currentLogDir = pstrdup(Log_directory);
00344                 rotation_requested = true;
00345 
00346                 /*
00347                  * Also, create new directory if not present; ignore errors
00348                  */
00349                 mkdir(Log_directory, S_IRWXU);
00350             }
00351             if (strcmp(Log_filename, currentLogFilename) != 0)
00352             {
00353                 pfree(currentLogFilename);
00354                 currentLogFilename = pstrdup(Log_filename);
00355                 rotation_requested = true;
00356             }
00357 
00358             /*
00359              * If rotation time parameter changed, reset next rotation time,
00360              * but don't immediately force a rotation.
00361              */
00362             if (currentLogRotationAge != Log_RotationAge)
00363             {
00364                 currentLogRotationAge = Log_RotationAge;
00365                 set_next_rotation_time();
00366             }
00367 
00368             /*
00369              * If we had a rotation-disabling failure, re-enable rotation
00370              * attempts after SIGHUP, and force one immediately.
00371              */
00372             if (rotation_disabled)
00373             {
00374                 rotation_disabled = false;
00375                 rotation_requested = true;
00376             }
00377         }
00378 
00379         if (Log_RotationAge > 0 && !rotation_disabled)
00380         {
00381             /* Do a logfile rotation if it's time */
00382             now = (pg_time_t) time(NULL);
00383             if (now >= next_rotation_time)
00384                 rotation_requested = time_based_rotation = true;
00385         }
00386 
00387         if (!rotation_requested && Log_RotationSize > 0 && !rotation_disabled)
00388         {
00389             /* Do a rotation if file is too big */
00390             if (ftell(syslogFile) >= Log_RotationSize * 1024L)
00391             {
00392                 rotation_requested = true;
00393                 size_rotation_for |= LOG_DESTINATION_STDERR;
00394             }
00395             if (csvlogFile != NULL &&
00396                 ftell(csvlogFile) >= Log_RotationSize * 1024L)
00397             {
00398                 rotation_requested = true;
00399                 size_rotation_for |= LOG_DESTINATION_CSVLOG;
00400             }
00401         }
00402 
00403         if (rotation_requested)
00404         {
00405             /*
00406              * Force rotation when both values are zero. It means the request
00407              * was sent by pg_rotate_logfile.
00408              */
00409             if (!time_based_rotation && size_rotation_for == 0)
00410                 size_rotation_for = LOG_DESTINATION_STDERR | LOG_DESTINATION_CSVLOG;
00411             logfile_rotate(time_based_rotation, size_rotation_for);
00412         }
00413 
00414         /*
00415          * Calculate time till next time-based rotation, so that we don't
00416          * sleep longer than that.  We assume the value of "now" obtained
00417          * above is still close enough.  Note we can't make this calculation
00418          * until after calling logfile_rotate(), since it will advance
00419          * next_rotation_time.
00420          *
00421          * Also note that we need to beware of overflow in calculation of the
00422          * timeout: with large settings of Log_RotationAge, next_rotation_time
00423          * could be more than INT_MAX msec in the future.  In that case we'll
00424          * wait no more than INT_MAX msec, and try again.
00425          */
00426         if (Log_RotationAge > 0 && !rotation_disabled)
00427         {
00428             pg_time_t   delay;
00429 
00430             delay = next_rotation_time - now;
00431             if (delay > 0)
00432             {
00433                 if (delay > INT_MAX / 1000)
00434                     delay = INT_MAX / 1000;
00435                 cur_timeout = delay * 1000L;    /* msec */
00436             }
00437             else
00438                 cur_timeout = 0;
00439             cur_flags = WL_TIMEOUT;
00440         }
00441         else
00442         {
00443             cur_timeout = -1L;
00444             cur_flags = 0;
00445         }
00446 
00447         /*
00448          * Sleep until there's something to do
00449          */
00450 #ifndef WIN32
00451         rc = WaitLatchOrSocket(&sysLoggerLatch,
00452                                WL_LATCH_SET | WL_SOCKET_READABLE | cur_flags,
00453                                syslogPipe[0],
00454                                cur_timeout);
00455 
00456         if (rc & WL_SOCKET_READABLE)
00457         {
00458             int         bytesRead;
00459 
00460             bytesRead = read(syslogPipe[0],
00461                              logbuffer + bytes_in_logbuffer,
00462                              sizeof(logbuffer) - bytes_in_logbuffer);
00463             if (bytesRead < 0)
00464             {
00465                 if (errno != EINTR)
00466                     ereport(LOG,
00467                             (errcode_for_socket_access(),
00468                              errmsg("could not read from logger pipe: %m")));
00469             }
00470             else if (bytesRead > 0)
00471             {
00472                 bytes_in_logbuffer += bytesRead;
00473                 process_pipe_input(logbuffer, &bytes_in_logbuffer);
00474                 continue;
00475             }
00476             else
00477             {
00478                 /*
00479                  * Zero bytes read when select() is saying read-ready means
00480                  * EOF on the pipe: that is, there are no longer any processes
00481                  * with the pipe write end open.  Therefore, the postmaster
00482                  * and all backends are shut down, and we are done.
00483                  */
00484                 pipe_eof_seen = true;
00485 
00486                 /* if there's any data left then force it out now */
00487                 flush_pipe_input(logbuffer, &bytes_in_logbuffer);
00488             }
00489         }
00490 #else                           /* WIN32 */
00491 
00492         /*
00493          * On Windows we leave it to a separate thread to transfer data and
00494          * detect pipe EOF.  The main thread just wakes up to handle SIGHUP
00495          * and rotation conditions.
00496          *
00497          * Server code isn't generally thread-safe, so we ensure that only one
00498          * of the threads is active at a time by entering the critical section
00499          * whenever we're not sleeping.
00500          */
00501         LeaveCriticalSection(&sysloggerSection);
00502 
00503         (void) WaitLatch(&sysLoggerLatch,
00504                          WL_LATCH_SET | cur_flags,
00505                          cur_timeout);
00506 
00507         EnterCriticalSection(&sysloggerSection);
00508 #endif   /* WIN32 */
00509 
00510         if (pipe_eof_seen)
00511         {
00512             /*
00513              * seeing this message on the real stderr is annoying - so we make
00514              * it DEBUG1 to suppress in normal use.
00515              */
00516             ereport(DEBUG1,
00517                     (errmsg("logger shutting down")));
00518 
00519             /*
00520              * Normal exit from the syslogger is here.  Note that we
00521              * deliberately do not close syslogFile before exiting; this is to
00522              * allow for the possibility of elog messages being generated
00523              * inside proc_exit.  Regular exit() will take care of flushing
00524              * and closing stdio channels.
00525              */
00526             proc_exit(0);
00527         }
00528     }
00529 }
00530 
00531 /*
00532  * Postmaster subroutine to start a syslogger subprocess.
00533  */
00534 int
00535 SysLogger_Start(void)
00536 {
00537     pid_t       sysloggerPid;
00538     char       *filename;
00539 
00540     if (!Logging_collector)
00541         return 0;
00542 
00543     /*
00544      * If first time through, create the pipe which will receive stderr
00545      * output.
00546      *
00547      * If the syslogger crashes and needs to be restarted, we continue to use
00548      * the same pipe (indeed must do so, since extant backends will be writing
00549      * into that pipe).
00550      *
00551      * This means the postmaster must continue to hold the read end of the
00552      * pipe open, so we can pass it down to the reincarnated syslogger. This
00553      * is a bit klugy but we have little choice.
00554      */
00555 #ifndef WIN32
00556     if (syslogPipe[0] < 0)
00557     {
00558         if (pipe(syslogPipe) < 0)
00559             ereport(FATAL,
00560                     (errcode_for_socket_access(),
00561                      (errmsg("could not create pipe for syslog: %m"))));
00562     }
00563 #else
00564     if (!syslogPipe[0])
00565     {
00566         SECURITY_ATTRIBUTES sa;
00567 
00568         memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
00569         sa.nLength = sizeof(SECURITY_ATTRIBUTES);
00570         sa.bInheritHandle = TRUE;
00571 
00572         if (!CreatePipe(&syslogPipe[0], &syslogPipe[1], &sa, 32768))
00573             ereport(FATAL,
00574                     (errcode_for_file_access(),
00575                      (errmsg("could not create pipe for syslog: %m"))));
00576     }
00577 #endif
00578 
00579     /*
00580      * Create log directory if not present; ignore errors
00581      */
00582     mkdir(Log_directory, S_IRWXU);
00583 
00584     /*
00585      * The initial logfile is created right in the postmaster, to verify that
00586      * the Log_directory is writable.  We save the reference time so that
00587      * the syslogger child process can recompute this file name.
00588      *
00589      * It might look a bit strange to re-do this during a syslogger restart,
00590      * but we must do so since the postmaster closed syslogFile after the
00591      * previous fork (and remembering that old file wouldn't be right anyway).
00592      * Note we always append here, we won't overwrite any existing file.  This
00593      * is consistent with the normal rules, because by definition this is not
00594      * a time-based rotation.
00595      */
00596     first_syslogger_file_time = time(NULL);
00597     filename = logfile_getname(first_syslogger_file_time, NULL);
00598 
00599     syslogFile = logfile_open(filename, "a", false);
00600 
00601     pfree(filename);
00602 
00603 #ifdef EXEC_BACKEND
00604     switch ((sysloggerPid = syslogger_forkexec()))
00605 #else
00606     switch ((sysloggerPid = fork_process()))
00607 #endif
00608     {
00609         case -1:
00610             ereport(LOG,
00611                     (errmsg("could not fork system logger: %m")));
00612             return 0;
00613 
00614 #ifndef EXEC_BACKEND
00615         case 0:
00616             /* in postmaster child ... */
00617             /* Close the postmaster's sockets */
00618             ClosePostmasterPorts(true);
00619 
00620             /* Lose the postmaster's on-exit routines */
00621             on_exit_reset();
00622 
00623             /* Drop our connection to postmaster's shared memory, as well */
00624             PGSharedMemoryDetach();
00625 
00626             /* do the work */
00627             SysLoggerMain(0, NULL);
00628             break;
00629 #endif
00630 
00631         default:
00632             /* success, in postmaster */
00633 
00634             /* now we redirect stderr, if not done already */
00635             if (!redirection_done)
00636             {
00637 #ifndef WIN32
00638                 fflush(stdout);
00639                 if (dup2(syslogPipe[1], fileno(stdout)) < 0)
00640                     ereport(FATAL,
00641                             (errcode_for_file_access(),
00642                              errmsg("could not redirect stdout: %m")));
00643                 fflush(stderr);
00644                 if (dup2(syslogPipe[1], fileno(stderr)) < 0)
00645                     ereport(FATAL,
00646                             (errcode_for_file_access(),
00647                              errmsg("could not redirect stderr: %m")));
00648                 /* Now we are done with the write end of the pipe. */
00649                 close(syslogPipe[1]);
00650                 syslogPipe[1] = -1;
00651 #else
00652                 int         fd;
00653 
00654                 /*
00655                  * open the pipe in binary mode and make sure stderr is binary
00656                  * after it's been dup'ed into, to avoid disturbing the pipe
00657                  * chunking protocol.
00658                  */
00659                 fflush(stderr);
00660                 fd = _open_osfhandle((intptr_t) syslogPipe[1],
00661                                      _O_APPEND | _O_BINARY);
00662                 if (dup2(fd, _fileno(stderr)) < 0)
00663                     ereport(FATAL,
00664                             (errcode_for_file_access(),
00665                              errmsg("could not redirect stderr: %m")));
00666                 close(fd);
00667                 _setmode(_fileno(stderr), _O_BINARY);
00668 
00669                 /*
00670                  * Now we are done with the write end of the pipe.
00671                  * CloseHandle() must not be called because the preceding
00672                  * close() closes the underlying handle.
00673                  */
00674                 syslogPipe[1] = 0;
00675 #endif
00676                 redirection_done = true;
00677             }
00678 
00679             /* postmaster will never write the file; close it */
00680             fclose(syslogFile);
00681             syslogFile = NULL;
00682             return (int) sysloggerPid;
00683     }
00684 
00685     /* we should never reach here */
00686     return 0;
00687 }
00688 
00689 
00690 #ifdef EXEC_BACKEND
00691 
00692 /*
00693  * syslogger_forkexec() -
00694  *
00695  * Format up the arglist for, then fork and exec, a syslogger process
00696  */
00697 static pid_t
00698 syslogger_forkexec(void)
00699 {
00700     char       *av[10];
00701     int         ac = 0;
00702     char        filenobuf[32];
00703 
00704     av[ac++] = "postgres";
00705     av[ac++] = "--forklog";
00706     av[ac++] = NULL;            /* filled in by postmaster_forkexec */
00707 
00708     /* static variables (those not passed by write_backend_variables) */
00709 #ifndef WIN32
00710     if (syslogFile != NULL)
00711         snprintf(filenobuf, sizeof(filenobuf), "%d",
00712                  fileno(syslogFile));
00713     else
00714         strcpy(filenobuf, "-1");
00715 #else                           /* WIN32 */
00716     if (syslogFile != NULL)
00717         snprintf(filenobuf, sizeof(filenobuf), "%ld",
00718                  (long) _get_osfhandle(_fileno(syslogFile)));
00719     else
00720         strcpy(filenobuf, "0");
00721 #endif   /* WIN32 */
00722     av[ac++] = filenobuf;
00723 
00724     av[ac] = NULL;
00725     Assert(ac < lengthof(av));
00726 
00727     return postmaster_forkexec(ac, av);
00728 }
00729 
00730 /*
00731  * syslogger_parseArgs() -
00732  *
00733  * Extract data from the arglist for exec'ed syslogger process
00734  */
00735 static void
00736 syslogger_parseArgs(int argc, char *argv[])
00737 {
00738     int         fd;
00739 
00740     Assert(argc == 4);
00741     argv += 3;
00742 
00743 #ifndef WIN32
00744     fd = atoi(*argv++);
00745     if (fd != -1)
00746     {
00747         syslogFile = fdopen(fd, "a");
00748         setvbuf(syslogFile, NULL, LBF_MODE, 0);
00749     }
00750 #else                           /* WIN32 */
00751     fd = atoi(*argv++);
00752     if (fd != 0)
00753     {
00754         fd = _open_osfhandle(fd, _O_APPEND | _O_TEXT);
00755         if (fd > 0)
00756         {
00757             syslogFile = fdopen(fd, "a");
00758             setvbuf(syslogFile, NULL, LBF_MODE, 0);
00759         }
00760     }
00761 #endif   /* WIN32 */
00762 }
00763 #endif   /* EXEC_BACKEND */
00764 
00765 
00766 /* --------------------------------
00767  *      pipe protocol handling
00768  * --------------------------------
00769  */
00770 
00771 /*
00772  * Process data received through the syslogger pipe.
00773  *
00774  * This routine interprets the log pipe protocol which sends log messages as
00775  * (hopefully atomic) chunks - such chunks are detected and reassembled here.
00776  *
00777  * The protocol has a header that starts with two nul bytes, then has a 16 bit
00778  * length, the pid of the sending process, and a flag to indicate if it is
00779  * the last chunk in a message. Incomplete chunks are saved until we read some
00780  * more, and non-final chunks are accumulated until we get the final chunk.
00781  *
00782  * All of this is to avoid 2 problems:
00783  * . partial messages being written to logfiles (messes rotation), and
00784  * . messages from different backends being interleaved (messages garbled).
00785  *
00786  * Any non-protocol messages are written out directly. These should only come
00787  * from non-PostgreSQL sources, however (e.g. third party libraries writing to
00788  * stderr).
00789  *
00790  * logbuffer is the data input buffer, and *bytes_in_logbuffer is the number
00791  * of bytes present.  On exit, any not-yet-eaten data is left-justified in
00792  * logbuffer, and *bytes_in_logbuffer is updated.
00793  */
00794 static void
00795 process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
00796 {
00797     char       *cursor = logbuffer;
00798     int         count = *bytes_in_logbuffer;
00799     int         dest = LOG_DESTINATION_STDERR;
00800 
00801     /* While we have enough for a header, process data... */
00802     while (count >= (int) sizeof(PipeProtoHeader))
00803     {
00804         PipeProtoHeader p;
00805         int         chunklen;
00806 
00807         /* Do we have a valid header? */
00808         memcpy(&p, cursor, sizeof(PipeProtoHeader));
00809         if (p.nuls[0] == '\0' && p.nuls[1] == '\0' &&
00810             p.len > 0 && p.len <= PIPE_MAX_PAYLOAD &&
00811             p.pid != 0 &&
00812             (p.is_last == 't' || p.is_last == 'f' ||
00813              p.is_last == 'T' || p.is_last == 'F'))
00814         {
00815             List       *buffer_list;
00816             ListCell   *cell;
00817             save_buffer *existing_slot = NULL,
00818                        *free_slot = NULL;
00819             StringInfo  str;
00820 
00821             chunklen = PIPE_HEADER_SIZE + p.len;
00822 
00823             /* Fall out of loop if we don't have the whole chunk yet */
00824             if (count < chunklen)
00825                 break;
00826 
00827             dest = (p.is_last == 'T' || p.is_last == 'F') ?
00828                 LOG_DESTINATION_CSVLOG : LOG_DESTINATION_STDERR;
00829 
00830             /* Locate any existing buffer for this source pid */
00831             buffer_list = buffer_lists[p.pid % NBUFFER_LISTS];
00832             foreach(cell, buffer_list)
00833             {
00834                 save_buffer *buf = (save_buffer *) lfirst(cell);
00835 
00836                 if (buf->pid == p.pid)
00837                 {
00838                     existing_slot = buf;
00839                     break;
00840                 }
00841                 if (buf->pid == 0 && free_slot == NULL)
00842                     free_slot = buf;
00843             }
00844 
00845             if (p.is_last == 'f' || p.is_last == 'F')
00846             {
00847                 /*
00848                  * Save a complete non-final chunk in a per-pid buffer
00849                  */
00850                 if (existing_slot != NULL)
00851                 {
00852                     /* Add chunk to data from preceding chunks */
00853                     str = &(existing_slot->data);
00854                     appendBinaryStringInfo(str,
00855                                            cursor + PIPE_HEADER_SIZE,
00856                                            p.len);
00857                 }
00858                 else
00859                 {
00860                     /* First chunk of message, save in a new buffer */
00861                     if (free_slot == NULL)
00862                     {
00863                         /*
00864                          * Need a free slot, but there isn't one in the list,
00865                          * so create a new one and extend the list with it.
00866                          */
00867                         free_slot = palloc(sizeof(save_buffer));
00868                         buffer_list = lappend(buffer_list, free_slot);
00869                         buffer_lists[p.pid % NBUFFER_LISTS] = buffer_list;
00870                     }
00871                     free_slot->pid = p.pid;
00872                     str = &(free_slot->data);
00873                     initStringInfo(str);
00874                     appendBinaryStringInfo(str,
00875                                            cursor + PIPE_HEADER_SIZE,
00876                                            p.len);
00877                 }
00878             }
00879             else
00880             {
00881                 /*
00882                  * Final chunk --- add it to anything saved for that pid, and
00883                  * either way write the whole thing out.
00884                  */
00885                 if (existing_slot != NULL)
00886                 {
00887                     str = &(existing_slot->data);
00888                     appendBinaryStringInfo(str,
00889                                            cursor + PIPE_HEADER_SIZE,
00890                                            p.len);
00891                     write_syslogger_file(str->data, str->len, dest);
00892                     /* Mark the buffer unused, and reclaim string storage */
00893                     existing_slot->pid = 0;
00894                     pfree(str->data);
00895                 }
00896                 else
00897                 {
00898                     /* The whole message was one chunk, evidently. */
00899                     write_syslogger_file(cursor + PIPE_HEADER_SIZE, p.len,
00900                                          dest);
00901                 }
00902             }
00903 
00904             /* Finished processing this chunk */
00905             cursor += chunklen;
00906             count -= chunklen;
00907         }
00908         else
00909         {
00910             /* Process non-protocol data */
00911 
00912             /*
00913              * Look for the start of a protocol header.  If found, dump data
00914              * up to there and repeat the loop.  Otherwise, dump it all and
00915              * fall out of the loop.  (Note: we want to dump it all if at all
00916              * possible, so as to avoid dividing non-protocol messages across
00917              * logfiles.  We expect that in many scenarios, a non-protocol
00918              * message will arrive all in one read(), and we want to respect
00919              * the read() boundary if possible.)
00920              */
00921             for (chunklen = 1; chunklen < count; chunklen++)
00922             {
00923                 if (cursor[chunklen] == '\0')
00924                     break;
00925             }
00926             /* fall back on the stderr log as the destination */
00927             write_syslogger_file(cursor, chunklen, LOG_DESTINATION_STDERR);
00928             cursor += chunklen;
00929             count -= chunklen;
00930         }
00931     }
00932 
00933     /* We don't have a full chunk, so left-align what remains in the buffer */
00934     if (count > 0 && cursor != logbuffer)
00935         memmove(logbuffer, cursor, count);
00936     *bytes_in_logbuffer = count;
00937 }
00938 
00939 /*
00940  * Force out any buffered data
00941  *
00942  * This is currently used only at syslogger shutdown, but could perhaps be
00943  * useful at other times, so it is careful to leave things in a clean state.
00944  */
00945 static void
00946 flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
00947 {
00948     int         i;
00949 
00950     /* Dump any incomplete protocol messages */
00951     for (i = 0; i < NBUFFER_LISTS; i++)
00952     {
00953         List       *list = buffer_lists[i];
00954         ListCell   *cell;
00955 
00956         foreach(cell, list)
00957         {
00958             save_buffer *buf = (save_buffer *) lfirst(cell);
00959 
00960             if (buf->pid != 0)
00961             {
00962                 StringInfo  str = &(buf->data);
00963 
00964                 write_syslogger_file(str->data, str->len,
00965                                      LOG_DESTINATION_STDERR);
00966                 /* Mark the buffer unused, and reclaim string storage */
00967                 buf->pid = 0;
00968                 pfree(str->data);
00969             }
00970         }
00971     }
00972 
00973     /*
00974      * Force out any remaining pipe data as-is; we don't bother trying to
00975      * remove any protocol headers that may exist in it.
00976      */
00977     if (*bytes_in_logbuffer > 0)
00978         write_syslogger_file(logbuffer, *bytes_in_logbuffer,
00979                              LOG_DESTINATION_STDERR);
00980     *bytes_in_logbuffer = 0;
00981 }
00982 
00983 
00984 /* --------------------------------
00985  *      logfile routines
00986  * --------------------------------
00987  */
00988 
00989 /*
00990  * Write text to the currently open logfile
00991  *
00992  * This is exported so that elog.c can call it when am_syslogger is true.
00993  * This allows the syslogger process to record elog messages of its own,
00994  * even though its stderr does not point at the syslog pipe.
00995  */
00996 void
00997 write_syslogger_file(const char *buffer, int count, int destination)
00998 {
00999     int         rc;
01000     FILE       *logfile;
01001 
01002     if (destination == LOG_DESTINATION_CSVLOG && csvlogFile == NULL)
01003         open_csvlogfile();
01004 
01005     logfile = destination == LOG_DESTINATION_CSVLOG ? csvlogFile : syslogFile;
01006     rc = fwrite(buffer, 1, count, logfile);
01007 
01008     /* can't use ereport here because of possible recursion */
01009     if (rc != count)
01010         write_stderr("could not write to log file: %s\n", strerror(errno));
01011 }
01012 
01013 #ifdef WIN32
01014 
01015 /*
01016  * Worker thread to transfer data from the pipe to the current logfile.
01017  *
01018  * We need this because on Windows, WaitforMultipleObjects does not work on
01019  * unnamed pipes: it always reports "signaled", so the blocking ReadFile won't
01020  * allow for SIGHUP; and select is for sockets only.
01021  */
01022 static unsigned int __stdcall
01023 pipeThread(void *arg)
01024 {
01025     char        logbuffer[READ_BUF_SIZE];
01026     int         bytes_in_logbuffer = 0;
01027 
01028     for (;;)
01029     {
01030         DWORD       bytesRead;
01031         BOOL        result;
01032 
01033         result = ReadFile(syslogPipe[0],
01034                           logbuffer + bytes_in_logbuffer,
01035                           sizeof(logbuffer) - bytes_in_logbuffer,
01036                           &bytesRead, 0);
01037 
01038         /*
01039          * Enter critical section before doing anything that might touch
01040          * global state shared by the main thread. Anything that uses
01041          * palloc()/pfree() in particular are not safe outside the critical
01042          * section.
01043          */
01044         EnterCriticalSection(&sysloggerSection);
01045         if (!result)
01046         {
01047             DWORD       error = GetLastError();
01048 
01049             if (error == ERROR_HANDLE_EOF ||
01050                 error == ERROR_BROKEN_PIPE)
01051                 break;
01052             _dosmaperr(error);
01053             ereport(LOG,
01054                     (errcode_for_file_access(),
01055                      errmsg("could not read from logger pipe: %m")));
01056         }
01057         else if (bytesRead > 0)
01058         {
01059             bytes_in_logbuffer += bytesRead;
01060             process_pipe_input(logbuffer, &bytes_in_logbuffer);
01061         }
01062 
01063         /*
01064          * If we've filled the current logfile, nudge the main thread to do a
01065          * log rotation.
01066          */
01067         if (Log_RotationSize > 0)
01068         {
01069             if (ftell(syslogFile) >= Log_RotationSize * 1024L ||
01070                 (csvlogFile != NULL && ftell(csvlogFile) >= Log_RotationSize * 1024L))
01071                 SetLatch(&sysLoggerLatch);
01072         }
01073         LeaveCriticalSection(&sysloggerSection);
01074     }
01075 
01076     /* We exit the above loop only upon detecting pipe EOF */
01077     pipe_eof_seen = true;
01078 
01079     /* if there's any data left then force it out now */
01080     flush_pipe_input(logbuffer, &bytes_in_logbuffer);
01081 
01082     /* set the latch to waken the main thread, which will quit */
01083     SetLatch(&sysLoggerLatch);
01084 
01085     LeaveCriticalSection(&sysloggerSection);
01086     _endthread();
01087     return 0;
01088 }
01089 #endif   /* WIN32 */
01090 
01091 /*
01092  * Open the csv log file - we do this opportunistically, because
01093  * we don't know if CSV logging will be wanted.
01094  *
01095  * This is only used the first time we open the csv log in a given syslogger
01096  * process, not during rotations.  As with opening the main log file, we
01097  * always append in this situation.
01098  */
01099 static void
01100 open_csvlogfile(void)
01101 {
01102     char       *filename;
01103 
01104     filename = logfile_getname(time(NULL), ".csv");
01105 
01106     csvlogFile = logfile_open(filename, "a", false);
01107 
01108     if (last_csv_file_name != NULL)     /* probably shouldn't happen */
01109         pfree(last_csv_file_name);
01110 
01111     last_csv_file_name = filename;
01112 }
01113 
01114 /*
01115  * Open a new logfile with proper permissions and buffering options.
01116  *
01117  * If allow_errors is true, we just log any open failure and return NULL
01118  * (with errno still correct for the fopen failure).
01119  * Otherwise, errors are treated as fatal.
01120  */
01121 static FILE *
01122 logfile_open(const char *filename, const char *mode, bool allow_errors)
01123 {
01124     FILE       *fh;
01125     mode_t      oumask;
01126 
01127     /*
01128      * Note we do not let Log_file_mode disable IWUSR, since we certainly want
01129      * to be able to write the files ourselves.
01130      */
01131     oumask = umask((mode_t) ((~(Log_file_mode | S_IWUSR)) & (S_IRWXU | S_IRWXG | S_IRWXO)));
01132     fh = fopen(filename, mode);
01133     umask(oumask);
01134 
01135     if (fh)
01136     {
01137         setvbuf(fh, NULL, LBF_MODE, 0);
01138 
01139 #ifdef WIN32
01140         /* use CRLF line endings on Windows */
01141         _setmode(_fileno(fh), _O_TEXT);
01142 #endif
01143     }
01144     else
01145     {
01146         int         save_errno = errno;
01147 
01148         ereport(allow_errors ? LOG : FATAL,
01149                 (errcode_for_file_access(),
01150                  errmsg("could not open log file \"%s\": %m",
01151                         filename)));
01152         errno = save_errno;
01153     }
01154 
01155     return fh;
01156 }
01157 
01158 /*
01159  * perform logfile rotation
01160  */
01161 static void
01162 logfile_rotate(bool time_based_rotation, int size_rotation_for)
01163 {
01164     char       *filename;
01165     char       *csvfilename = NULL;
01166     pg_time_t   fntime;
01167     FILE       *fh;
01168 
01169     rotation_requested = false;
01170 
01171     /*
01172      * When doing a time-based rotation, invent the new logfile name based on
01173      * the planned rotation time, not current time, to avoid "slippage" in the
01174      * file name when we don't do the rotation immediately.
01175      */
01176     if (time_based_rotation)
01177         fntime = next_rotation_time;
01178     else
01179         fntime = time(NULL);
01180     filename = logfile_getname(fntime, NULL);
01181     if (csvlogFile != NULL)
01182         csvfilename = logfile_getname(fntime, ".csv");
01183 
01184     /*
01185      * Decide whether to overwrite or append.  We can overwrite if (a)
01186      * Log_truncate_on_rotation is set, (b) the rotation was triggered by
01187      * elapsed time and not something else, and (c) the computed file name is
01188      * different from what we were previously logging into.
01189      *
01190      * Note: last_file_name should never be NULL here, but if it is, append.
01191      */
01192     if (time_based_rotation || (size_rotation_for & LOG_DESTINATION_STDERR))
01193     {
01194         if (Log_truncate_on_rotation && time_based_rotation &&
01195             last_file_name != NULL &&
01196             strcmp(filename, last_file_name) != 0)
01197             fh = logfile_open(filename, "w", true);
01198         else
01199             fh = logfile_open(filename, "a", true);
01200 
01201         if (!fh)
01202         {
01203             /*
01204              * ENFILE/EMFILE are not too surprising on a busy system; just
01205              * keep using the old file till we manage to get a new one.
01206              * Otherwise, assume something's wrong with Log_directory and stop
01207              * trying to create files.
01208              */
01209             if (errno != ENFILE && errno != EMFILE)
01210             {
01211                 ereport(LOG,
01212                         (errmsg("disabling automatic rotation (use SIGHUP to re-enable)")));
01213                 rotation_disabled = true;
01214             }
01215 
01216             if (filename)
01217                 pfree(filename);
01218             if (csvfilename)
01219                 pfree(csvfilename);
01220             return;
01221         }
01222 
01223         fclose(syslogFile);
01224         syslogFile = fh;
01225 
01226         /* instead of pfree'ing filename, remember it for next time */
01227         if (last_file_name != NULL)
01228             pfree(last_file_name);
01229         last_file_name = filename;
01230         filename = NULL;
01231     }
01232 
01233     /* Same as above, but for csv file. */
01234 
01235     if (csvlogFile != NULL &&
01236         (time_based_rotation || (size_rotation_for & LOG_DESTINATION_CSVLOG)))
01237     {
01238         if (Log_truncate_on_rotation && time_based_rotation &&
01239             last_csv_file_name != NULL &&
01240             strcmp(csvfilename, last_csv_file_name) != 0)
01241             fh = logfile_open(csvfilename, "w", true);
01242         else
01243             fh = logfile_open(csvfilename, "a", true);
01244 
01245         if (!fh)
01246         {
01247             /*
01248              * ENFILE/EMFILE are not too surprising on a busy system; just
01249              * keep using the old file till we manage to get a new one.
01250              * Otherwise, assume something's wrong with Log_directory and stop
01251              * trying to create files.
01252              */
01253             if (errno != ENFILE && errno != EMFILE)
01254             {
01255                 ereport(LOG,
01256                         (errmsg("disabling automatic rotation (use SIGHUP to re-enable)")));
01257                 rotation_disabled = true;
01258             }
01259 
01260             if (filename)
01261                 pfree(filename);
01262             if (csvfilename)
01263                 pfree(csvfilename);
01264             return;
01265         }
01266 
01267         fclose(csvlogFile);
01268         csvlogFile = fh;
01269 
01270         /* instead of pfree'ing filename, remember it for next time */
01271         if (last_csv_file_name != NULL)
01272             pfree(last_csv_file_name);
01273         last_csv_file_name = csvfilename;
01274         csvfilename = NULL;
01275     }
01276 
01277     if (filename)
01278         pfree(filename);
01279     if (csvfilename)
01280         pfree(csvfilename);
01281 
01282     set_next_rotation_time();
01283 }
01284 
01285 
01286 /*
01287  * construct logfile name using timestamp information
01288  *
01289  * If suffix isn't NULL, append it to the name, replacing any ".log"
01290  * that may be in the pattern.
01291  *
01292  * Result is palloc'd.
01293  */
01294 static char *
01295 logfile_getname(pg_time_t timestamp, const char *suffix)
01296 {
01297     char       *filename;
01298     int         len;
01299 
01300     filename = palloc(MAXPGPATH);
01301 
01302     snprintf(filename, MAXPGPATH, "%s/", Log_directory);
01303 
01304     len = strlen(filename);
01305 
01306     /* treat Log_filename as a strftime pattern */
01307     pg_strftime(filename + len, MAXPGPATH - len, Log_filename,
01308                 pg_localtime(&timestamp, log_timezone));
01309 
01310     if (suffix != NULL)
01311     {
01312         len = strlen(filename);
01313         if (len > 4 && (strcmp(filename + (len - 4), ".log") == 0))
01314             len -= 4;
01315         strlcpy(filename + len, suffix, MAXPGPATH - len);
01316     }
01317 
01318     return filename;
01319 }
01320 
01321 /*
01322  * Determine the next planned rotation time, and store in next_rotation_time.
01323  */
01324 static void
01325 set_next_rotation_time(void)
01326 {
01327     pg_time_t   now;
01328     struct pg_tm *tm;
01329     int         rotinterval;
01330 
01331     /* nothing to do if time-based rotation is disabled */
01332     if (Log_RotationAge <= 0)
01333         return;
01334 
01335     /*
01336      * The requirements here are to choose the next time > now that is a
01337      * "multiple" of the log rotation interval.  "Multiple" can be interpreted
01338      * fairly loosely.  In this version we align to log_timezone rather than
01339      * GMT.
01340      */
01341     rotinterval = Log_RotationAge * SECS_PER_MINUTE;    /* convert to seconds */
01342     now = (pg_time_t) time(NULL);
01343     tm = pg_localtime(&now, log_timezone);
01344     now += tm->tm_gmtoff;
01345     now -= now % rotinterval;
01346     now += rotinterval;
01347     now -= tm->tm_gmtoff;
01348     next_rotation_time = now;
01349 }
01350 
01351 /* --------------------------------
01352  *      signal handler routines
01353  * --------------------------------
01354  */
01355 
01356 /* SIGHUP: set flag to reload config file */
01357 static void
01358 sigHupHandler(SIGNAL_ARGS)
01359 {
01360     int         save_errno = errno;
01361 
01362     got_SIGHUP = true;
01363     SetLatch(&sysLoggerLatch);
01364 
01365     errno = save_errno;
01366 }
01367 
01368 /* SIGUSR1: set flag to rotate logfile */
01369 static void
01370 sigUsr1Handler(SIGNAL_ARGS)
01371 {
01372     int         save_errno = errno;
01373 
01374     rotation_requested = true;
01375     SetLatch(&sysLoggerLatch);
01376 
01377     errno = save_errno;
01378 }