LCOV - code coverage report
Current view: top level - src/backend/archive - shell_archive.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16beta1 Lines: 28 31 90.3 %
Date: 2023-06-01 11:12:20 Functions: 4 4 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-2023, PostgreSQL Global Development Group
      10             :  *
      11             :  * IDENTIFICATION
      12             :  *    src/backend/archive/shell_archive.c
      13             :  *
      14             :  *-------------------------------------------------------------------------
      15             :  */
      16             : #include "postgres.h"
      17             : 
      18             : #include <sys/wait.h>
      19             : 
      20             : #include "access/xlog.h"
      21             : #include "archive/archive_module.h"
      22             : #include "archive/shell_archive.h"
      23             : #include "common/percentrepl.h"
      24             : #include "pgstat.h"
      25             : 
      26             : static bool shell_archive_configured(ArchiveModuleState *state);
      27             : static bool shell_archive_file(ArchiveModuleState *state,
      28             :                                const char *file,
      29             :                                const char *path);
      30             : static void shell_archive_shutdown(ArchiveModuleState *state);
      31             : 
      32             : static const ArchiveModuleCallbacks shell_archive_callbacks = {
      33             :     .startup_cb = NULL,
      34             :     .check_configured_cb = shell_archive_configured,
      35             :     .archive_file_cb = shell_archive_file,
      36             :     .shutdown_cb = shell_archive_shutdown
      37             : };
      38             : 
      39             : const ArchiveModuleCallbacks *
      40          18 : shell_archive_init(void)
      41             : {
      42          18 :     return &shell_archive_callbacks;
      43             : }
      44             : 
      45             : static bool
      46          48 : shell_archive_configured(ArchiveModuleState *state)
      47             : {
      48          48 :     return XLogArchiveCommand[0] != '\0';
      49             : }
      50             : 
      51             : static bool
      52          48 : shell_archive_file(ArchiveModuleState *state, const char *file,
      53             :                    const char *path)
      54             : {
      55             :     char       *xlogarchcmd;
      56          48 :     char       *nativePath = NULL;
      57             :     int         rc;
      58             : 
      59          48 :     if (path)
      60             :     {
      61          48 :         nativePath = pstrdup(path);
      62          48 :         make_native_path(nativePath);
      63             :     }
      64             : 
      65          48 :     xlogarchcmd = replace_percent_placeholders(XLogArchiveCommand,
      66             :                                                "archive_command", "fp",
      67             :                                                file, nativePath);
      68             : 
      69          48 :     if (nativePath)
      70          48 :         pfree(nativePath);
      71             : 
      72          48 :     ereport(DEBUG3,
      73             :             (errmsg_internal("executing archive command \"%s\"",
      74             :                              xlogarchcmd)));
      75             : 
      76          48 :     fflush(NULL);
      77          48 :     pgstat_report_wait_start(WAIT_EVENT_ARCHIVE_COMMAND);
      78          48 :     rc = system(xlogarchcmd);
      79          48 :     pgstat_report_wait_end();
      80             : 
      81          48 :     if (rc != 0)
      82             :     {
      83             :         /*
      84             :          * If either the shell itself, or a called command, died on a signal,
      85             :          * abort the archiver.  We do this because system() ignores SIGINT and
      86             :          * SIGQUIT while waiting; so a signal is very likely something that
      87             :          * should have interrupted us too.  Also die if the shell got a hard
      88             :          * "command not found" type of error.  If we overreact it's no big
      89             :          * deal, the postmaster will just start the archiver again.
      90             :          */
      91           2 :         int         lev = wait_result_is_any_signal(rc, true) ? FATAL : LOG;
      92             : 
      93           2 :         if (WIFEXITED(rc))
      94             :         {
      95           2 :             ereport(lev,
      96             :                     (errmsg("archive command failed with exit code %d",
      97             :                             WEXITSTATUS(rc)),
      98             :                      errdetail("The failed archive command was: %s",
      99             :                                xlogarchcmd)));
     100             :         }
     101           0 :         else if (WIFSIGNALED(rc))
     102             :         {
     103             : #if defined(WIN32)
     104             :             ereport(lev,
     105             :                     (errmsg("archive command was terminated by exception 0x%X",
     106             :                             WTERMSIG(rc)),
     107             :                      errhint("See C include file \"ntstatus.h\" for a description of the hexadecimal value."),
     108             :                      errdetail("The failed archive command was: %s",
     109             :                                xlogarchcmd)));
     110             : #else
     111           0 :             ereport(lev,
     112             :                     (errmsg("archive command was terminated by signal %d: %s",
     113             :                             WTERMSIG(rc), pg_strsignal(WTERMSIG(rc))),
     114             :                      errdetail("The failed archive command was: %s",
     115             :                                xlogarchcmd)));
     116             : #endif
     117             :         }
     118             :         else
     119             :         {
     120           0 :             ereport(lev,
     121             :                     (errmsg("archive command exited with unrecognized status %d",
     122             :                             rc),
     123             :                      errdetail("The failed archive command was: %s",
     124             :                                xlogarchcmd)));
     125             :         }
     126             : 
     127           2 :         return false;
     128             :     }
     129             : 
     130          46 :     pfree(xlogarchcmd);
     131             : 
     132          46 :     elog(DEBUG1, "archived write-ahead log file \"%s\"", file);
     133          46 :     return true;
     134             : }
     135             : 
     136             : static void
     137          18 : shell_archive_shutdown(ArchiveModuleState *state)
     138             : {
     139          18 :     elog(DEBUG1, "archiver process shutting down");
     140          18 : }

Generated by: LCOV version 1.14