LCOV - code coverage report
Current view: top level - src/backend/archive - shell_archive.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 90.9 % 33 30
Test Date: 2026-07-25 22:15:46 Functions: 100.0 % 4 4
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 54.2 % 24 13

             Branch data     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                 :          18 : shell_archive_init(void)
      42                 :             : {
      43                 :          18 :     return &shell_archive_callbacks;
      44                 :             : }
      45                 :             : 
      46                 :             : static bool
      47                 :         380 : shell_archive_configured(ArchiveModuleState *state)
      48                 :             : {
      49         [ +  + ]:         380 :     if (XLogArchiveCommand[0] != '\0')
      50                 :         377 :         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                 :         377 : shell_archive_file(ArchiveModuleState *state, const char *file,
      59                 :             :                    const char *path)
      60                 :             : {
      61                 :             :     char       *xlogarchcmd;
      62                 :         377 :     char       *nativePath = NULL;
      63                 :             :     int         rc;
      64                 :             : 
      65         [ +  - ]:         377 :     if (path)
      66                 :             :     {
      67                 :         377 :         nativePath = pstrdup(path);
      68                 :         377 :         make_native_path(nativePath);
      69                 :             :     }
      70                 :             : 
      71                 :         377 :     xlogarchcmd = replace_percent_placeholders(XLogArchiveCommand,
      72                 :             :                                                "archive_command", "fp",
      73                 :             :                                                file, nativePath);
      74                 :             : 
      75         [ -  + ]:         377 :     ereport(DEBUG3,
      76                 :             :             (errmsg_internal("executing archive command \"%s\"",
      77                 :             :                              xlogarchcmd)));
      78                 :             : 
      79                 :         377 :     fflush(NULL);
      80                 :         377 :     pgstat_report_wait_start(WAIT_EVENT_ARCHIVE_COMMAND);
      81                 :         377 :     rc = system(xlogarchcmd);
      82                 :         377 :     pgstat_report_wait_end();
      83                 :             : 
      84         [ +  + ]:         377 :     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                 :         370 :     pfree(xlogarchcmd);
     134                 :             : 
     135         [ +  + ]:         370 :     elog(DEBUG1, "archived write-ahead log file \"%s\"", file);
     136                 :         370 :     return true;
     137                 :             : }
     138                 :             : 
     139                 :             : static void
     140                 :          18 : shell_archive_shutdown(ArchiveModuleState *state)
     141                 :             : {
     142         [ +  + ]:          18 :     elog(DEBUG1, "archiver process shutting down");
     143                 :          18 : }
        

Generated by: LCOV version 2.0-1