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

Generated by: LCOV version 2.0-1