LCOV - code coverage report
Current view: top level - src/backend/archive - shell_archive.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 30 33 90.9 %
Date: 2024-12-12 16:15:21 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-2024, 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          26 : shell_archive_init(void)
      41             : {
      42          26 :     return &shell_archive_callbacks;
      43             : }
      44             : 
      45             : static bool
      46          86 : shell_archive_configured(ArchiveModuleState *state)
      47             : {
      48          86 :     if (XLogArchiveCommand[0] != '\0')
      49          82 :         return true;
      50             : 
      51           4 :     arch_module_check_errdetail("\"%s\" is not set.",
      52             :                                 "archive_command");
      53           4 :     return false;
      54             : }
      55             : 
      56             : static bool
      57          82 : shell_archive_file(ArchiveModuleState *state, const char *file,
      58             :                    const char *path)
      59             : {
      60             :     char       *xlogarchcmd;
      61          82 :     char       *nativePath = NULL;
      62             :     int         rc;
      63             : 
      64          82 :     if (path)
      65             :     {
      66          82 :         nativePath = pstrdup(path);
      67          82 :         make_native_path(nativePath);
      68             :     }
      69             : 
      70          82 :     xlogarchcmd = replace_percent_placeholders(XLogArchiveCommand,
      71             :                                                "archive_command", "fp",
      72             :                                                file, nativePath);
      73             : 
      74          82 :     ereport(DEBUG3,
      75             :             (errmsg_internal("executing archive command \"%s\"",
      76             :                              xlogarchcmd)));
      77             : 
      78          82 :     fflush(NULL);
      79          82 :     pgstat_report_wait_start(WAIT_EVENT_ARCHIVE_COMMAND);
      80          82 :     rc = system(xlogarchcmd);
      81          82 :     pgstat_report_wait_end();
      82             : 
      83          82 :     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          14 :         int         lev = wait_result_is_any_signal(rc, true) ? FATAL : LOG;
      94             : 
      95          14 :         if (WIFEXITED(rc))
      96             :         {
      97          14 :             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          14 :         pfree(xlogarchcmd);
     129             : 
     130          14 :         return false;
     131             :     }
     132          68 :     pfree(xlogarchcmd);
     133             : 
     134          68 :     elog(DEBUG1, "archived write-ahead log file \"%s\"", file);
     135          68 :     return true;
     136             : }
     137             : 
     138             : static void
     139          26 : shell_archive_shutdown(ArchiveModuleState *state)
     140             : {
     141          26 :     elog(DEBUG1, "archiver process shutting down");
     142          26 : }

Generated by: LCOV version 1.14