LCOV - code coverage report
Current view: top level - src/backend/postmaster - shell_archive.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16devel Lines: 34 50 68.0 %
Date: 2022-07-06 13:10:06 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * shell_archive.c
       4             :  *
       5             :  * This archiving function uses a user-specified shell command (the
       6             :  * archive_command GUC) to copy write-ahead log files.  It is used as the
       7             :  * default, but other modules may define their own custom archiving logic.
       8             :  *
       9             :  * Copyright (c) 2022, PostgreSQL Global Development Group
      10             :  *
      11             :  * IDENTIFICATION
      12             :  *    src/backend/postmaster/shell_archive.c
      13             :  *
      14             :  *-------------------------------------------------------------------------
      15             :  */
      16             : #include "postgres.h"
      17             : 
      18             : #include <sys/wait.h>
      19             : 
      20             : #include "access/xlog.h"
      21             : #include "pgstat.h"
      22             : #include "postmaster/pgarch.h"
      23             : 
      24             : static bool shell_archive_configured(void);
      25             : static bool shell_archive_file(const char *file, const char *path);
      26             : 
      27             : void
      28          12 : shell_archive_init(ArchiveModuleCallbacks *cb)
      29             : {
      30             :     AssertVariableIsOfType(&shell_archive_init, ArchiveModuleInit);
      31             : 
      32          12 :     cb->check_configured_cb = shell_archive_configured;
      33          12 :     cb->archive_file_cb = shell_archive_file;
      34          12 : }
      35             : 
      36             : static bool
      37          30 : shell_archive_configured(void)
      38             : {
      39          30 :     return XLogArchiveCommand[0] != '\0';
      40             : }
      41             : 
      42             : static bool
      43          30 : shell_archive_file(const char *file, const char *path)
      44             : {
      45             :     char        xlogarchcmd[MAXPGPATH];
      46             :     char       *dp;
      47             :     char       *endp;
      48             :     const char *sp;
      49             :     int         rc;
      50             : 
      51             :     /*
      52             :      * construct the command to be executed
      53             :      */
      54          30 :     dp = xlogarchcmd;
      55          30 :     endp = xlogarchcmd + MAXPGPATH - 1;
      56          30 :     *endp = '\0';
      57             : 
      58        3304 :     for (sp = XLogArchiveCommand; *sp; sp++)
      59             :     {
      60        3274 :         if (*sp == '%')
      61             :         {
      62          60 :             switch (sp[1])
      63             :             {
      64          30 :                 case 'p':
      65             :                     /* %p: relative path of source file */
      66          30 :                     sp++;
      67          30 :                     strlcpy(dp, path, endp - dp);
      68          30 :                     make_native_path(dp);
      69          30 :                     dp += strlen(dp);
      70          30 :                     break;
      71          30 :                 case 'f':
      72             :                     /* %f: filename of source file */
      73          30 :                     sp++;
      74          30 :                     strlcpy(dp, file, endp - dp);
      75          30 :                     dp += strlen(dp);
      76          30 :                     break;
      77           0 :                 case '%':
      78             :                     /* convert %% to a single % */
      79           0 :                     sp++;
      80           0 :                     if (dp < endp)
      81           0 :                         *dp++ = *sp;
      82           0 :                     break;
      83           0 :                 default:
      84             :                     /* otherwise treat the % as not special */
      85           0 :                     if (dp < endp)
      86           0 :                         *dp++ = *sp;
      87           0 :                     break;
      88             :             }
      89             :         }
      90             :         else
      91             :         {
      92        3214 :             if (dp < endp)
      93        3214 :                 *dp++ = *sp;
      94             :         }
      95             :     }
      96          30 :     *dp = '\0';
      97             : 
      98          30 :     ereport(DEBUG3,
      99             :             (errmsg_internal("executing archive command \"%s\"",
     100             :                              xlogarchcmd)));
     101             : 
     102          30 :     pgstat_report_wait_start(WAIT_EVENT_ARCHIVE_COMMAND);
     103          30 :     rc = system(xlogarchcmd);
     104          30 :     pgstat_report_wait_end();
     105             : 
     106          30 :     if (rc != 0)
     107             :     {
     108             :         /*
     109             :          * If either the shell itself, or a called command, died on a signal,
     110             :          * abort the archiver.  We do this because system() ignores SIGINT and
     111             :          * SIGQUIT while waiting; so a signal is very likely something that
     112             :          * should have interrupted us too.  Also die if the shell got a hard
     113             :          * "command not found" type of error.  If we overreact it's no big
     114             :          * deal, the postmaster will just start the archiver again.
     115             :          */
     116           0 :         int         lev = wait_result_is_any_signal(rc, true) ? FATAL : LOG;
     117             : 
     118           0 :         if (WIFEXITED(rc))
     119             :         {
     120           0 :             ereport(lev,
     121             :                     (errmsg("archive command failed with exit code %d",
     122             :                             WEXITSTATUS(rc)),
     123             :                      errdetail("The failed archive command was: %s",
     124             :                                xlogarchcmd)));
     125             :         }
     126           0 :         else if (WIFSIGNALED(rc))
     127             :         {
     128             : #if defined(WIN32)
     129             :             ereport(lev,
     130             :                     (errmsg("archive command was terminated by exception 0x%X",
     131             :                             WTERMSIG(rc)),
     132             :                      errhint("See C include file \"ntstatus.h\" for a description of the hexadecimal value."),
     133             :                      errdetail("The failed archive command was: %s",
     134             :                                xlogarchcmd)));
     135             : #else
     136           0 :             ereport(lev,
     137             :                     (errmsg("archive command was terminated by signal %d: %s",
     138             :                             WTERMSIG(rc), pg_strsignal(WTERMSIG(rc))),
     139             :                      errdetail("The failed archive command was: %s",
     140             :                                xlogarchcmd)));
     141             : #endif
     142             :         }
     143             :         else
     144             :         {
     145           0 :             ereport(lev,
     146             :                     (errmsg("archive command exited with unrecognized status %d",
     147             :                             rc),
     148             :                      errdetail("The failed archive command was: %s",
     149             :                                xlogarchcmd)));
     150             :         }
     151             : 
     152           0 :         return false;
     153             :     }
     154             : 
     155          30 :     elog(DEBUG1, "archived write-ahead log file \"%s\"", file);
     156          30 :     return true;
     157             : }

Generated by: LCOV version 1.14