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

Generated by: LCOV version 2.0-1