LCOV - differential code coverage report
Current view: top level - src/bin/pg_basebackup - pg_receivewal.c (source / functions) Coverage Total Hit UNC UBC GBC GNC CBC DUB DCB
Current: ba12a202ce1b5581dc0ed149cf3f637d7897ad5d vs 2866d8c7dbfc9d882a7d80fef93fbbe763709932 Lines: 78.3 % 374 293 1 80 1 1 291 1 2
Current Date: 2026-08-27 14:31:44 +0300 Functions: 90.0 % 10 9 1 2 7
Baseline: lcov-20260827-baseline Branches: 66.9 % 245 164 81 2 162
Baseline Date: 2026-08-27 14:31:58 +0300 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 100.0 % 1 1 1
(30,360] days: 80.0 % 5 4 1 4
(360..) days: 78.3 % 368 288 80 1 287
Function coverage date bins:
(360..) days: 90.0 % 10 9 1 2 7
Branch coverage date bins:
(7,30] days: 100.0 % 2 2 2
(30,360] days: 75.0 % 12 9 3 9
(360..) days: 66.2 % 231 153 78 153

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * pg_receivewal.c - receive streaming WAL data and write it
                                  4                 :                :  *                    to a local file.
                                  5                 :                :  *
                                  6                 :                :  * Author: Magnus Hagander <magnus@hagander.net>
                                  7                 :                :  *
                                  8                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                  9                 :                :  *
                                 10                 :                :  * IDENTIFICATION
                                 11                 :                :  *        src/bin/pg_basebackup/pg_receivewal.c
                                 12                 :                :  *-------------------------------------------------------------------------
                                 13                 :                :  */
                                 14                 :                : 
                                 15                 :                : #include "postgres_fe.h"
                                 16                 :                : 
                                 17                 :                : #include <dirent.h>
                                 18                 :                : #include <limits.h>
                                 19                 :                : #include <signal.h>
                                 20                 :                : #include <sys/stat.h>
                                 21                 :                : #include <unistd.h>
                                 22                 :                : 
                                 23                 :                : #ifdef USE_LZ4
                                 24                 :                : #include <lz4frame.h>
                                 25                 :                : #endif
                                 26                 :                : #ifdef HAVE_LIBZ
                                 27                 :                : #include <zlib.h>
                                 28                 :                : #endif
                                 29                 :                : 
                                 30                 :                : #include "access/xlog_internal.h"
                                 31                 :                : #include "common/file_perm.h"
                                 32                 :                : #include "common/logging.h"
                                 33                 :                : #include "common/pg_parse_lsn.h"
                                 34                 :                : #include "fe_utils/option_utils.h"
                                 35                 :                : #include "getopt_long.h"
                                 36                 :                : #include "libpq-fe.h"
                                 37                 :                : #include "receivelog.h"
                                 38                 :                : #include "streamutil.h"
                                 39                 :                : 
                                 40                 :                : /* Time to sleep between reconnection attempts */
                                 41                 :                : #define RECONNECT_SLEEP_TIME 5
                                 42                 :                : 
                                 43                 :                : /* Global options */
                                 44                 :                : static char *basedir = NULL;
                                 45                 :                : static int  verbose = 0;
                                 46                 :                : static int  compresslevel = 0;
                                 47                 :                : static bool noloop = false;
                                 48                 :                : static int  standby_message_timeout = 10 * 1000;    /* 10 sec = default */
                                 49                 :                : static volatile sig_atomic_t time_to_stop = false;
                                 50                 :                : static bool do_create_slot = false;
                                 51                 :                : static bool slot_exists_ok = false;
                                 52                 :                : static bool do_drop_slot = false;
                                 53                 :                : static bool do_sync = true;
                                 54                 :                : static bool synchronous = false;
                                 55                 :                : static char *replication_slot = NULL;
                                 56                 :                : static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE;
                                 57                 :                : static XLogRecPtr endpos = InvalidXLogRecPtr;
                                 58                 :                : 
                                 59                 :                : 
                                 60                 :                : static void usage(void);
                                 61                 :                : static DIR *get_destination_dir(char *dest_folder);
                                 62                 :                : static void close_destination_dir(DIR *dest_dir, char *dest_folder);
                                 63                 :                : static XLogRecPtr FindStreamingStart(uint32 *tli);
                                 64                 :                : static void StreamLog(void);
                                 65                 :                : static bool stop_streaming(XLogRecPtr xlogpos, uint32 timeline,
                                 66                 :                :                            bool segment_finished);
                                 67                 :                : 
                                 68                 :                : static void
 2798 peter@eisentraut.org       69                 :CBC           9 : disconnect_atexit(void)
                                 70                 :                : {
                                 71         [ +  + ]:              9 :     if (conn != NULL)
                                 72                 :              3 :         PQfinish(conn);
                                 73                 :              9 : }
                                 74                 :                : 
                                 75                 :                : static void
 5419 magnus@hagander.net        76                 :              1 : usage(void)
                                 77                 :                : {
 3394 peter_e@gmx.net            78                 :              1 :     printf(_("%s receives PostgreSQL streaming write-ahead logs.\n\n"),
                                 79                 :                :            progname);
 5419 magnus@hagander.net        80                 :              1 :     printf(_("Usage:\n"));
                                 81                 :              1 :     printf(_("  %s [OPTION]...\n"), progname);
 5189 peter_e@gmx.net            82                 :              1 :     printf(_("\nOptions:\n"));
 3394                            83                 :              1 :     printf(_("  -D, --directory=DIR    receive write-ahead log files into this directory\n"));
 3272                            84                 :              1 :     printf(_("  -E, --endpos=LSN       exit after receiving the specified LSN\n"));
 3998                            85                 :              1 :     printf(_("      --if-not-exists    do not error if slot already exists when creating a slot\n"));
 5140 alvherre@alvh.no-ip.       86                 :              1 :     printf(_("  -n, --no-loop          do not loop on connection lost\n"));
 3224 rhaas@postgresql.org       87                 :              1 :     printf(_("      --no-sync          do not wait for changes to be written safely to disk\n"));
 4337 peter_e@gmx.net            88                 :              1 :     printf(_("  -s, --status-interval=SECS\n"
                                 89                 :                :              "                         time between status packets sent to server (default: %d)\n"), (standby_message_timeout / 1000));
                                 90                 :              1 :     printf(_("  -S, --slot=SLOTNAME    replication slot to use\n"));
 3394                            91                 :              1 :     printf(_("      --synchronous      flush write-ahead log immediately after writing\n"));
 5140 alvherre@alvh.no-ip.       92                 :              1 :     printf(_("  -v, --verbose          output verbose messages\n"));
                                 93                 :              1 :     printf(_("  -V, --version          output version information, then exit\n"));
 1597 michael@paquier.xyz        94                 :              1 :     printf(_("  -Z, --compress=METHOD[:DETAIL]\n"
                                 95                 :                :              "                         compress as specified\n"));
 5140 alvherre@alvh.no-ip.       96                 :              1 :     printf(_("  -?, --help             show this help, then exit\n"));
 5419 magnus@hagander.net        97                 :              1 :     printf(_("\nConnection options:\n"));
 4931 heikki.linnakangas@i       98                 :              1 :     printf(_("  -d, --dbname=CONNSTR   connection string\n"));
 5140 alvherre@alvh.no-ip.       99                 :              1 :     printf(_("  -h, --host=HOSTNAME    database server host or socket directory\n"));
                                100                 :              1 :     printf(_("  -p, --port=PORT        database server port number\n"));
                                101                 :              1 :     printf(_("  -U, --username=NAME    connect as specified database user\n"));
                                102                 :              1 :     printf(_("  -w, --no-password      never prompt for password\n"));
                                103                 :              1 :     printf(_("  -W, --password         force password prompt (should happen automatically)\n"));
 4343 andres@anarazel.de        104                 :              1 :     printf(_("\nOptional actions:\n"));
                                105                 :              1 :     printf(_("      --create-slot      create a new replication slot (for the slot's name see --slot)\n"));
                                106                 :              1 :     printf(_("      --drop-slot        drop the replication slot (for the slot's name see --slot)\n"));
 2372 peter@eisentraut.org      107                 :              1 :     printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
                                108                 :              1 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
 5419 magnus@hagander.net       109                 :              1 : }
                                110                 :                : 
                                111                 :                : 
                                112                 :                : /*
                                113                 :                :  * Check if the filename looks like a WAL file, letting caller know if this
                                114                 :                :  * WAL segment is partial and/or compressed.
                                115                 :                :  */
                                116                 :                : static bool
 1757 michael@paquier.xyz       117                 :             23 : is_xlogfilename(const char *filename, bool *ispartial,
                                118                 :                :                 pg_compress_algorithm *wal_compression_algorithm)
                                119                 :                : {
                                120                 :             23 :     size_t      fname_len = strlen(filename);
                                121                 :             23 :     size_t      xlog_pattern_len = strspn(filename, "0123456789ABCDEF");
                                122                 :                : 
                                123                 :                :     /* File does not look like a WAL file */
                                124         [ +  + ]:             23 :     if (xlog_pattern_len != XLOG_FNAME_LEN)
                                125                 :             14 :         return false;
                                126                 :                : 
                                127                 :                :     /* File looks like a completed uncompressed WAL file */
                                128         [ -  + ]:              9 :     if (fname_len == XLOG_FNAME_LEN)
                                129                 :                :     {
 1757 michael@paquier.xyz       130                 :UBC           0 :         *ispartial = false;
 1598                           131                 :              0 :         *wal_compression_algorithm = PG_COMPRESSION_NONE;
 1757                           132                 :              0 :         return true;
                                133                 :                :     }
                                134                 :                : 
                                135                 :                :     /* File looks like a completed gzip-compressed WAL file */
 1757 michael@paquier.xyz       136         [ +  + ]:CBC           9 :     if (fname_len == XLOG_FNAME_LEN + strlen(".gz") &&
                                137         [ +  - ]:              2 :         strcmp(filename + XLOG_FNAME_LEN, ".gz") == 0)
                                138                 :                :     {
                                139                 :              2 :         *ispartial = false;
 1598                           140                 :              2 :         *wal_compression_algorithm = PG_COMPRESSION_GZIP;
 1757                           141                 :              2 :         return true;
                                142                 :                :     }
                                143                 :                : 
                                144                 :                :     /* File looks like a completed LZ4-compressed WAL file */
 1756                           145         [ +  + ]:              7 :     if (fname_len == XLOG_FNAME_LEN + strlen(".lz4") &&
                                146         [ +  - ]:              1 :         strcmp(filename + XLOG_FNAME_LEN, ".lz4") == 0)
                                147                 :                :     {
                                148                 :              1 :         *ispartial = false;
 1598                           149                 :              1 :         *wal_compression_algorithm = PG_COMPRESSION_LZ4;
 1756                           150                 :              1 :         return true;
                                151                 :                :     }
                                152                 :                : 
                                153                 :                :     /* File looks like a partial uncompressed WAL file */
 1757                           154         [ +  + ]:              6 :     if (fname_len == XLOG_FNAME_LEN + strlen(".partial") &&
                                155         [ +  - ]:              3 :         strcmp(filename + XLOG_FNAME_LEN, ".partial") == 0)
                                156                 :                :     {
                                157                 :              3 :         *ispartial = true;
 1598                           158                 :              3 :         *wal_compression_algorithm = PG_COMPRESSION_NONE;
 1757                           159                 :              3 :         return true;
                                160                 :                :     }
                                161                 :                : 
                                162                 :                :     /* File looks like a partial gzip-compressed WAL file */
                                163         [ +  + ]:              3 :     if (fname_len == XLOG_FNAME_LEN + strlen(".gz.partial") &&
                                164         [ +  - ]:              2 :         strcmp(filename + XLOG_FNAME_LEN, ".gz.partial") == 0)
                                165                 :                :     {
                                166                 :              2 :         *ispartial = true;
 1598                           167                 :              2 :         *wal_compression_algorithm = PG_COMPRESSION_GZIP;
 1757                           168                 :              2 :         return true;
                                169                 :                :     }
                                170                 :                : 
                                171                 :                :     /* File looks like a partial LZ4-compressed WAL file */
 1756                           172         [ +  - ]:              1 :     if (fname_len == XLOG_FNAME_LEN + strlen(".lz4.partial") &&
                                173         [ +  - ]:              1 :         strcmp(filename + XLOG_FNAME_LEN, ".lz4.partial") == 0)
                                174                 :                :     {
                                175                 :              1 :         *ispartial = true;
 1598                           176                 :              1 :         *wal_compression_algorithm = PG_COMPRESSION_LZ4;
 1756                           177                 :              1 :         return true;
                                178                 :                :     }
                                179                 :                : 
                                180                 :                :     /* File does not look like something we know */
 1757 michael@paquier.xyz       181                 :UBC           0 :     return false;
                                182                 :                : }
                                183                 :                : 
                                184                 :                : static bool
 4970 heikki.linnakangas@i      185                 :CBC         128 : stop_streaming(XLogRecPtr xlogpos, uint32 timeline, bool segment_finished)
                                186                 :                : {
                                187                 :                :     static uint32 prevtimeline = 0;
                                188                 :                :     static XLogRecPtr prevpos = InvalidXLogRecPtr;
                                189                 :                : 
                                190                 :                :     /* we assume that we get called once at the end of each segment */
 5207 magnus@hagander.net       191   [ +  -  +  + ]:            128 :     if (verbose && segment_finished)
  416 alvherre@kurilemu.de      192                 :              6 :         pg_log_info("finished segment at %X/%08X (timeline %u)",
                                193                 :                :                     LSN_FORMAT_ARGS(xlogpos),
                                194                 :                :                     timeline);
                                195                 :                : 
  294                           196   [ +  -  +  + ]:            128 :     if (XLogRecPtrIsValid(endpos) && endpos < xlogpos)
                                197                 :                :     {
 3272 peter_e@gmx.net           198         [ +  - ]:             12 :         if (verbose)
  416 alvherre@kurilemu.de      199                 :             12 :             pg_log_info("stopped log streaming at %X/%08X (timeline %u)",
                                200                 :                :                         LSN_FORMAT_ARGS(xlogpos),
                                201                 :                :                         timeline);
 3272 peter_e@gmx.net           202                 :             12 :         time_to_stop = true;
                                203                 :             12 :         return true;
                                204                 :                :     }
                                205                 :                : 
                                206                 :                :     /*
                                207                 :                :      * Note that we report the previous, not current, position here. After a
                                208                 :                :      * timeline switch, xlogpos points to the beginning of the segment because
                                209                 :                :      * that's where we always begin streaming. Reporting the end of previous
                                210                 :                :      * timeline isn't totally accurate, because the next timeline can begin
                                211                 :                :      * slightly before the end of the WAL that we received on the previous
                                212                 :                :      * timeline, but it's close enough for reporting purposes.
                                213                 :                :      */
 3299                           214   [ +  -  +  +  :            116 :     if (verbose && prevtimeline != 0 && prevtimeline != timeline)
                                              +  + ]
  416 alvherre@kurilemu.de      215                 :              1 :         pg_log_info("switched to timeline %u at %X/%08X",
                                216                 :                :                     timeline,
                                217                 :                :                     LSN_FORMAT_ARGS(prevpos));
                                218                 :                : 
 4970 heikki.linnakangas@i      219                 :            116 :     prevtimeline = timeline;
                                220                 :            116 :     prevpos = xlogpos;
                                221                 :                : 
 3272 peter_e@gmx.net           222         [ -  + ]:            116 :     if (time_to_stop)
                                223                 :                :     {
 3299 peter_e@gmx.net           224         [ #  # ]:UBC           0 :         if (verbose)
 2705 peter@eisentraut.org      225                 :              0 :             pg_log_info("received interrupt signal, exiting");
 5419 magnus@hagander.net       226                 :              0 :         return true;
                                227                 :                :     }
 5419 magnus@hagander.net       228                 :CBC         116 :     return false;
                                229                 :                : }
                                230                 :                : 
                                231                 :                : 
                                232                 :                : /*
                                233                 :                :  * Get destination directory.
                                234                 :                :  */
                                235                 :                : static DIR *
 4343 andres@anarazel.de        236                 :             14 : get_destination_dir(char *dest_folder)
                                237                 :                : {
                                238                 :                :     DIR        *dir;
                                239                 :                : 
                                240         [ -  + ]:             14 :     Assert(dest_folder != NULL);
                                241                 :             14 :     dir = opendir(dest_folder);
                                242         [ -  + ]:             14 :     if (dir == NULL)
 1602 tgl@sss.pgh.pa.us         243                 :UBC           0 :         pg_fatal("could not open directory \"%s\": %m", dest_folder);
                                244                 :                : 
 4343 andres@anarazel.de        245                 :CBC          14 :     return dir;
                                246                 :                : }
                                247                 :                : 
                                248                 :                : 
                                249                 :                : /*
                                250                 :                :  * Close existing directory.
                                251                 :                :  */
                                252                 :                : static void
                                253                 :             14 : close_destination_dir(DIR *dest_dir, char *dest_folder)
                                254                 :                : {
                                255   [ +  -  +  - ]:             14 :     Assert(dest_dir != NULL && dest_folder != NULL);
                                256         [ -  + ]:             14 :     if (closedir(dest_dir))
 1602 tgl@sss.pgh.pa.us         257                 :UBC           0 :         pg_fatal("could not close directory \"%s\": %m", dest_folder);
 4343 andres@anarazel.de        258                 :CBC          14 : }
                                259                 :                : 
                                260                 :                : 
                                261                 :                : /*
                                262                 :                :  * Determine starting location for streaming, based on any existing xlog
                                263                 :                :  * segments in the directory. We start at the end of the last one that is
                                264                 :                :  * complete (size matches wal segment size), on the timeline with highest ID.
                                265                 :                :  *
                                266                 :                :  * If there are no WAL files in the directory, returns InvalidXLogRecPtr.
                                267                 :                :  */
                                268                 :                : static XLogRecPtr
 4970 heikki.linnakangas@i      269                 :              7 : FindStreamingStart(uint32 *tli)
                                270                 :                : {
                                271                 :                :     DIR        *dir;
                                272                 :                :     struct dirent *dirent;
 5177                           273                 :              7 :     XLogSegNo   high_segno = 0;
 4970                           274                 :              7 :     uint32      high_tli = 0;
 4721                           275                 :              7 :     bool        high_ispartial = false;
                                276                 :                : 
 4343 andres@anarazel.de        277                 :              7 :     dir = get_destination_dir(basedir);
                                278                 :                : 
 4542 bruce@momjian.us          279         [ +  + ]:             30 :     while (errno = 0, (dirent = readdir(dir)) != NULL)
                                280                 :                :     {
                                281                 :                :         uint32      tli;
                                282                 :                :         XLogSegNo   segno;
                                283                 :                :         pg_compress_algorithm wal_compression_algorithm;
                                284                 :                :         bool        ispartial;
                                285                 :                : 
 1757 michael@paquier.xyz       286         [ +  + ]:             23 :         if (!is_xlogfilename(dirent->d_name,
                                287                 :                :                              &ispartial, &wal_compression_algorithm))
 5419 magnus@hagander.net       288                 :             14 :             continue;
                                289                 :                : 
                                290                 :                :         /*
                                291                 :                :          * Looks like an xlog file. Parse its position.
                                292                 :                :          */
 3264 andres@anarazel.de        293                 :              9 :         XLogFromFileName(dirent->d_name, &tli, &segno, WalSegSz);
                                294                 :                : 
                                295                 :                :         /*
                                296                 :                :          * Check that the segment has the right size, if it's supposed to be
                                297                 :                :          * completed.  For non-compressed segments just check the on-disk size
                                298                 :                :          * and see if it matches a completed segment.  For gzip-compressed
                                299                 :                :          * segments, look at the last 4 bytes of the compressed file, which is
                                300                 :                :          * where the uncompressed size is located for files with a size lower
                                301                 :                :          * than 4GB, and then compare it to the size of a completed segment.
                                302                 :                :          * The 4 last bytes correspond to the ISIZE member according to
                                303                 :                :          * http://www.zlib.org/rfc-gzip.html.
                                304                 :                :          *
                                305                 :                :          * For LZ4-compressed segments, uncompress the file in a throw-away
                                306                 :                :          * buffer keeping track of the uncompressed size, then compare it to
                                307                 :                :          * the size of a completed segment.  Per its protocol, LZ4 does not
                                308                 :                :          * store the uncompressed size of an object by default.  contentSize
                                309                 :                :          * is one possible way to do that, but we need to rely on a method
                                310                 :                :          * where WAL segments could have been compressed by a different source
                                311                 :                :          * than pg_receivewal, like an archive_command with lz4.
                                312                 :                :          */
 1598 michael@paquier.xyz       313   [ +  +  -  + ]:              9 :         if (!ispartial && wal_compression_algorithm == PG_COMPRESSION_NONE)
 5419 magnus@hagander.net       314                 :UBC           0 :         {
                                315                 :                :             struct stat statbuf;
                                316                 :                :             char        fullpath[MAXPGPATH * 2];
                                317                 :                : 
 4721 heikki.linnakangas@i      318                 :              0 :             snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name);
                                319         [ #  # ]:              0 :             if (stat(fullpath, &statbuf) != 0)
 1602 tgl@sss.pgh.pa.us         320                 :              0 :                 pg_fatal("could not stat file \"%s\": %m", fullpath);
                                321                 :                : 
 3264 andres@anarazel.de        322         [ #  # ]:              0 :             if (statbuf.st_size != WalSegSz)
                                323                 :                :             {
 2163 peter@eisentraut.org      324                 :              0 :                 pg_log_warning("segment file \"%s\" has incorrect size %lld, skipping",
                                325                 :                :                                dirent->d_name, (long long int) statbuf.st_size);
 5419 magnus@hagander.net       326                 :              0 :                 continue;
                                327                 :                :             }
                                328                 :                :         }
 1598 michael@paquier.xyz       329   [ +  +  +  + ]:CBC           9 :         else if (!ispartial && wal_compression_algorithm == PG_COMPRESSION_GZIP)
 3509 magnus@hagander.net       330                 :              2 :         {
                                331                 :                :             int         fd;
                                332                 :                :             char        buf[4];
                                333                 :                :             int         bytes_out;
                                334                 :                :             char        fullpath[MAXPGPATH * 2];
                                335                 :                :             ssize_t     r;
                                336                 :                : 
                                337                 :              2 :             snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name);
                                338                 :                : 
 2904 michael@paquier.xyz       339                 :              2 :             fd = open(fullpath, O_RDONLY | PG_BINARY, 0);
 3509 magnus@hagander.net       340         [ -  + ]:              2 :             if (fd < 0)
 1602 tgl@sss.pgh.pa.us         341                 :UBC           0 :                 pg_fatal("could not open compressed file \"%s\": %m",
                                342                 :                :                          fullpath);
 3389 bruce@momjian.us          343         [ -  + ]:CBC           2 :             if (lseek(fd, (off_t) (-4), SEEK_END) < 0)
 1602 tgl@sss.pgh.pa.us         344                 :UBC           0 :                 pg_fatal("could not seek in compressed file \"%s\": %m",
                                345                 :                :                          fullpath);
  553 peter@eisentraut.org      346                 :CBC           2 :             r = read(fd, buf, sizeof(buf));
 2962 michael@paquier.xyz       347         [ -  + ]:              2 :             if (r != sizeof(buf))
                                348                 :                :             {
 2962 michael@paquier.xyz       349         [ #  # ]:UBC           0 :                 if (r < 0)
 1602 tgl@sss.pgh.pa.us         350                 :              0 :                     pg_fatal("could not read compressed file \"%s\": %m",
                                351                 :                :                              fullpath);
                                352                 :                :                 else
   43 peter@eisentraut.org      353                 :UNC           0 :                     pg_fatal("could not read compressed file \"%s\": read %zd of %zu",
                                354                 :                :                              fullpath, r, sizeof(buf));
                                355                 :                :             }
                                356                 :                : 
 3509 magnus@hagander.net       357                 :CBC           2 :             close(fd);
                                358                 :              2 :             bytes_out = (buf[3] << 24) | (buf[2] << 16) |
 3389 bruce@momjian.us          359                 :              2 :                 (buf[1] << 8) | buf[0];
                                360                 :                : 
 3264 andres@anarazel.de        361         [ -  + ]:              2 :             if (bytes_out != WalSegSz)
                                362                 :                :             {
 2705 peter@eisentraut.org      363                 :UBC           0 :                 pg_log_warning("compressed segment file \"%s\" has incorrect uncompressed size %d, skipping",
                                364                 :                :                                dirent->d_name, bytes_out);
 3509 magnus@hagander.net       365                 :              0 :                 continue;
                                366                 :                :             }
                                367                 :                :         }
 1598 michael@paquier.xyz       368   [ +  +  +  - ]:CBC           7 :         else if (!ispartial && wal_compression_algorithm == PG_COMPRESSION_LZ4)
                                369                 :                :         {
                                370                 :                : #ifdef USE_LZ4
                                371                 :                : #define LZ4_CHUNK_SZ    64 * 1024   /* 64kB as maximum chunk size read */
                                372                 :                :             int         fd;
                                373                 :                :             ssize_t     r;
 1756                           374                 :              1 :             size_t      uncompressed_size = 0;
                                375                 :                :             char        fullpath[MAXPGPATH * 2];
                                376                 :                :             char       *outbuf;
                                377                 :                :             char       *readbuf;
                                378                 :              1 :             LZ4F_decompressionContext_t ctx = NULL;
                                379                 :                :             LZ4F_decompressOptions_t dec_opt;
                                380                 :                :             LZ4F_errorCode_t status;
                                381                 :                : 
                                382                 :              1 :             memset(&dec_opt, 0, sizeof(dec_opt));
                                383                 :              1 :             snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name);
                                384                 :                : 
                                385                 :              1 :             fd = open(fullpath, O_RDONLY | PG_BINARY, 0);
                                386         [ -  + ]:              1 :             if (fd < 0)
 1602 tgl@sss.pgh.pa.us         387                 :UBC           0 :                 pg_fatal("could not open file \"%s\": %m", fullpath);
                                388                 :                : 
 1756 michael@paquier.xyz       389                 :CBC           1 :             status = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
                                390         [ -  + ]:              1 :             if (LZ4F_isError(status))
 1602 tgl@sss.pgh.pa.us         391                 :UBC           0 :                 pg_fatal("could not create LZ4 decompression context: %s",
                                392                 :                :                          LZ4F_getErrorName(status));
                                393                 :                : 
 1756 michael@paquier.xyz       394                 :CBC           1 :             outbuf = pg_malloc0(LZ4_CHUNK_SZ);
                                395                 :              1 :             readbuf = pg_malloc0(LZ4_CHUNK_SZ);
                                396                 :                :             do
                                397                 :                :             {
                                398                 :                :                 char       *readp;
                                399                 :                :                 char       *readend;
                                400                 :                : 
                                401                 :              2 :                 r = read(fd, readbuf, LZ4_CHUNK_SZ);
                                402         [ -  + ]:              2 :                 if (r < 0)
 1602 tgl@sss.pgh.pa.us         403                 :UBC           0 :                     pg_fatal("could not read file \"%s\": %m", fullpath);
                                404                 :                : 
                                405                 :                :                 /* Done reading the file */
 1756 michael@paquier.xyz       406         [ +  + ]:CBC           2 :                 if (r == 0)
                                407                 :              1 :                     break;
                                408                 :                : 
                                409                 :                :                 /* Process one chunk */
                                410                 :              1 :                 readp = readbuf;
                                411                 :              1 :                 readend = readbuf + r;
                                412         [ +  + ]:             17 :                 while (readp < readend)
                                413                 :                :                 {
                                414                 :             16 :                     size_t      out_size = LZ4_CHUNK_SZ;
                                415                 :             16 :                     size_t      read_size = readend - readp;
                                416                 :                : 
                                417                 :             16 :                     memset(outbuf, 0, LZ4_CHUNK_SZ);
                                418                 :             16 :                     status = LZ4F_decompress(ctx, outbuf, &out_size,
                                419                 :                :                                              readp, &read_size, &dec_opt);
                                420         [ -  + ]:             16 :                     if (LZ4F_isError(status))
 1602 tgl@sss.pgh.pa.us         421                 :UBC           0 :                         pg_fatal("could not decompress file \"%s\": %s",
                                422                 :                :                                  fullpath,
                                423                 :                :                                  LZ4F_getErrorName(status));
                                424                 :                : 
 1756 michael@paquier.xyz       425                 :CBC          16 :                     readp += read_size;
                                426                 :             16 :                     uncompressed_size += out_size;
                                427                 :                :                 }
                                428                 :                : 
                                429                 :                :                 /*
                                430                 :                :                  * No need to continue reading the file when the
                                431                 :                :                  * uncompressed_size exceeds WalSegSz, even if there are still
                                432                 :                :                  * data left to read. However, if uncompressed_size is equal
                                433                 :                :                  * to WalSegSz, it should verify that there is no more data to
                                434                 :                :                  * read.
                                435                 :                :                  */
                                436   [ +  -  +  - ]:              1 :             } while (uncompressed_size <= WalSegSz && r > 0);
                                437                 :                : 
                                438                 :              1 :             close(fd);
                                439                 :              1 :             pg_free(outbuf);
                                440                 :              1 :             pg_free(readbuf);
                                441                 :                : 
                                442                 :              1 :             status = LZ4F_freeDecompressionContext(ctx);
                                443         [ -  + ]:              1 :             if (LZ4F_isError(status))
 1602 tgl@sss.pgh.pa.us         444                 :UBC           0 :                 pg_fatal("could not free LZ4 decompression context: %s",
                                445                 :                :                          LZ4F_getErrorName(status));
                                446                 :                : 
 1756 michael@paquier.xyz       447         [ -  + ]:CBC           1 :             if (uncompressed_size != WalSegSz)
                                448                 :                :             {
 1753 tgl@sss.pgh.pa.us         449                 :UBC           0 :                 pg_log_warning("compressed segment file \"%s\" has incorrect uncompressed size %zu, skipping",
                                450                 :                :                                dirent->d_name, uncompressed_size);
 1756 michael@paquier.xyz       451                 :              0 :                 continue;
                                452                 :                :             }
                                453                 :                : #else
                                454                 :                :             pg_log_error("cannot check file \"%s\": compression with %s not supported by this build",
                                455                 :                :                          dirent->d_name, "LZ4");
                                456                 :                :             exit(1);
                                457                 :                : #endif
                                458                 :                :         }
                                459                 :                : 
                                460                 :                :         /* Looks like a valid segment. Remember that we saw it. */
 4721 heikki.linnakangas@i      461         [ +  + ]:CBC           9 :         if ((segno > high_segno) ||
                                462   [ +  +  +  - ]:              4 :             (segno == high_segno && tli > high_tli) ||
                                463   [ +  +  +  -  :              4 :             (segno == high_segno && tli == high_tli && high_ispartial && !ispartial))
                                        -  +  -  - ]
                                464                 :                :         {
                                465                 :              5 :             high_segno = segno;
                                466                 :              5 :             high_tli = tli;
                                467                 :              5 :             high_ispartial = ispartial;
                                468                 :                :         }
                                469                 :                :     }
                                470                 :                : 
 4542 bruce@momjian.us          471         [ -  + ]:              7 :     if (errno)
 1602 tgl@sss.pgh.pa.us         472                 :UBC           0 :         pg_fatal("could not read directory \"%s\": %m", basedir);
                                473                 :                : 
 4343 andres@anarazel.de        474                 :CBC           7 :     close_destination_dir(dir, basedir);
                                475                 :                : 
 5177 heikki.linnakangas@i      476         [ +  + ]:              7 :     if (high_segno > 0)
                                477                 :                :     {
                                478                 :                :         XLogRecPtr  high_ptr;
                                479                 :                : 
                                480                 :                :         /*
                                481                 :                :          * Move the starting pointer to the start of the next segment, if the
                                482                 :                :          * highest one we saw was completed. Otherwise start streaming from
                                483                 :                :          * the beginning of the .partial segment.
                                484                 :                :          */
 4721                           485         [ -  + ]:              3 :         if (!high_ispartial)
 4721 heikki.linnakangas@i      486                 :UBC           0 :             high_segno++;
                                487                 :                : 
 2971 alvherre@alvh.no-ip.      488                 :CBC           3 :         XLogSegNoOffsetToRecPtr(high_segno, 0, WalSegSz, high_ptr);
                                489                 :                : 
 4970 heikki.linnakangas@i      490                 :              3 :         *tli = high_tli;
 5419 magnus@hagander.net       491                 :              3 :         return high_ptr;
                                492                 :                :     }
                                493                 :                :     else
 4970 heikki.linnakangas@i      494                 :              4 :         return InvalidXLogRecPtr;
                                495                 :                : }
                                496                 :                : 
                                497                 :                : /*
                                498                 :                :  * Start the log streaming
                                499                 :                :  */
                                500                 :                : static void
 5419 magnus@hagander.net       501                 :              7 : StreamLog(void)
                                502                 :                : {
                                503                 :                :     XLogRecPtr  serverpos;
                                504                 :                :     TimeLineID  servertli;
 1503 peter@eisentraut.org      505                 :              7 :     StreamCtl   stream = {0};
                                506                 :                :     char       *sysidentifier;
                                507                 :                : 
                                508                 :                :     /*
                                509                 :                :      * Connect in replication mode to the server
                                510                 :                :      */
 4331 fujii@postgresql.org      511         [ -  + ]:              7 :     if (conn == NULL)
 4331 fujii@postgresql.org      512                 :UBC           0 :         conn = GetConnection();
 5205 magnus@hagander.net       513         [ -  + ]:CBC           7 :     if (!conn)
                                514                 :                :         /* Error message already written in GetConnection() */
                                515                 :              1 :         return;
                                516                 :                : 
 4906 heikki.linnakangas@i      517         [ -  + ]:              7 :     if (!CheckServerVersionForStreaming(conn))
                                518                 :                :     {
                                519                 :                :         /*
                                520                 :                :          * Error message already written in CheckServerVersionForStreaming().
                                521                 :                :          * There's no hope of recovering from a version mismatch, so don't
                                522                 :                :          * retry.
                                523                 :                :          */
 2798 peter@eisentraut.org      524                 :UBC           0 :         exit(1);
                                525                 :                :     }
                                526                 :                : 
                                527                 :                :     /*
                                528                 :                :      * Identify server, obtaining start LSN position and current timeline ID
                                529                 :                :      * at the same time, necessary if not valid data can be found in the
                                530                 :                :      * existing output directory.
                                531                 :                :      */
 1804 michael@paquier.xyz       532         [ -  + ]:CBC           7 :     if (!RunIdentifySystem(conn, &sysidentifier, &servertli, &serverpos, NULL))
 2798 peter@eisentraut.org      533                 :UBC           0 :         exit(1);
                                534                 :                : 
                                535                 :                :     /*
                                536                 :                :      * Figure out where to start streaming.  First scan the local directory.
                                537                 :                :      */
 3821 magnus@hagander.net       538                 :CBC           7 :     stream.startpos = FindStreamingStart(&stream.timeline);
  294 alvherre@kurilemu.de      539         [ +  + ]:              7 :     if (!XLogRecPtrIsValid(stream.startpos))
                                540                 :                :     {
                                541                 :                :         /*
                                542                 :                :          * Try to get the starting point from the slot if any.  This is
                                543                 :                :          * supported in PostgreSQL 15 and newer.
                                544                 :                :          */
 1766 michael@paquier.xyz       545   [ +  +  +  - ]:              7 :         if (replication_slot != NULL &&
                                546                 :              3 :             PQserverVersion(conn) >= 150000)
                                547                 :                :         {
                                548         [ +  + ]:              3 :             if (!GetSlotInformation(conn, replication_slot, &stream.startpos,
                                549                 :                :                                     &stream.timeline))
                                550                 :                :             {
                                551                 :                :                 /* Error is logged by GetSlotInformation() */
                                552                 :              1 :                 return;
                                553                 :                :             }
                                554                 :                :         }
                                555                 :                : 
                                556                 :                :         /*
                                557                 :                :          * If it the starting point is still not known, use the current WAL
                                558                 :                :          * flush value as last resort.
                                559                 :                :          */
  294 alvherre@kurilemu.de      560         [ +  + ]:              3 :         if (!XLogRecPtrIsValid(stream.startpos))
                                561                 :                :         {
 1766 michael@paquier.xyz       562                 :              1 :             stream.startpos = serverpos;
                                563                 :              1 :             stream.timeline = servertli;
                                564                 :                :         }
                                565                 :                :     }
                                566                 :                : 
  294 alvherre@kurilemu.de      567   [ +  -  +  - ]:              6 :     Assert(XLogRecPtrIsValid(stream.startpos) &&
                                568                 :                :            stream.timeline != 0);
                                569                 :                : 
                                570                 :                :     /*
                                571                 :                :      * Always start streaming at the beginning of a segment
                                572                 :                :      */
 3264 andres@anarazel.de        573                 :              6 :     stream.startpos -= XLogSegmentOffset(stream.startpos, WalSegSz);
                                574                 :                : 
                                575                 :                :     /*
                                576                 :                :      * Start the replication
                                577                 :                :      */
 5419 magnus@hagander.net       578         [ +  - ]:              6 :     if (verbose)
  416 alvherre@kurilemu.de      579                 :              6 :         pg_log_info("starting log streaming at %X/%08X (timeline %u)",
                                580                 :                :                     LSN_FORMAT_ARGS(stream.startpos),
                                581                 :                :                     stream.timeline);
                                582                 :                : 
 3821 magnus@hagander.net       583                 :              6 :     stream.stream_stop = stop_streaming;
 3409 tgl@sss.pgh.pa.us         584                 :              6 :     stream.stop_socket = PGINVALID_SOCKET;
 3821 magnus@hagander.net       585                 :              6 :     stream.standby_message_timeout = standby_message_timeout;
                                586                 :              6 :     stream.synchronous = synchronous;
 3224 rhaas@postgresql.org      587                 :              6 :     stream.do_sync = do_sync;
 3821 magnus@hagander.net       588                 :              6 :     stream.mark_done = false;
 1757 michael@paquier.xyz       589                 :             12 :     stream.walmethod = CreateWalDirectoryMethod(basedir,
                                590                 :                :                                                 compression_algorithm,
                                591                 :                :                                                 compresslevel,
 3509 magnus@hagander.net       592                 :              6 :                                                 stream.do_sync);
 3821                           593                 :              6 :     stream.partial_suffix = ".partial";
 3510                           594                 :              6 :     stream.replication_slot = replication_slot;
 1804 michael@paquier.xyz       595                 :              6 :     stream.sysidentifier = sysidentifier;
                                596                 :                : 
 3821 magnus@hagander.net       597                 :              6 :     ReceiveXlogStream(conn, &stream);
                                598                 :                : 
 1438 rhaas@postgresql.org      599         [ -  + ]:              6 :     if (!stream.walmethod->ops->finish(stream.walmethod))
                                600                 :                :     {
 2705 peter@eisentraut.org      601                 :UBC           0 :         pg_log_info("could not finish writing WAL files: %m");
 3595 magnus@hagander.net       602                 :              0 :         return;
                                603                 :                :     }
                                604                 :                : 
 5411 magnus@hagander.net       605                 :CBC           6 :     PQfinish(conn);
 2798 peter@eisentraut.org      606                 :              6 :     conn = NULL;
                                607                 :                : 
 1438 rhaas@postgresql.org      608                 :              6 :     stream.walmethod->ops->free(stream.walmethod);
                                609                 :                : }
                                610                 :                : 
                                611                 :                : /*
                                612                 :                :  * When SIGINT/SIGTERM are caught, just tell the system to exit at the next
                                613                 :                :  * possible moment.
                                614                 :                :  */
                                615                 :                : #ifndef WIN32
                                616                 :                : 
                                617                 :                : static void
 1443 tgl@sss.pgh.pa.us         618                 :UBC           0 : sigexit_handler(SIGNAL_ARGS)
                                619                 :                : {
 3272 peter_e@gmx.net           620                 :              0 :     time_to_stop = true;
 5419 magnus@hagander.net       621                 :              0 : }
                                622                 :                : #endif
                                623                 :                : 
                                624                 :                : int
 5419 magnus@hagander.net       625                 :CBC          19 : main(int argc, char **argv)
                                626                 :                : {
                                627                 :                :     static struct option long_options[] = {
                                628                 :                :         {"help", no_argument, NULL, '?'},
                                629                 :                :         {"version", no_argument, NULL, 'V'},
                                630                 :                :         {"directory", required_argument, NULL, 'D'},
                                631                 :                :         {"dbname", required_argument, NULL, 'd'},
                                632                 :                :         {"endpos", required_argument, NULL, 'E'},
                                633                 :                :         {"host", required_argument, NULL, 'h'},
                                634                 :                :         {"port", required_argument, NULL, 'p'},
                                635                 :                :         {"username", required_argument, NULL, 'U'},
                                636                 :                :         {"no-loop", no_argument, NULL, 'n'},
                                637                 :                :         {"no-password", no_argument, NULL, 'w'},
                                638                 :                :         {"password", no_argument, NULL, 'W'},
                                639                 :                :         {"status-interval", required_argument, NULL, 's'},
                                640                 :                :         {"slot", required_argument, NULL, 'S'},
                                641                 :                :         {"verbose", no_argument, NULL, 'v'},
                                642                 :                :         {"compress", required_argument, NULL, 'Z'},
                                643                 :                : /* action */
                                644                 :                :         {"create-slot", no_argument, NULL, 1},
                                645                 :                :         {"drop-slot", no_argument, NULL, 2},
                                646                 :                :         {"if-not-exists", no_argument, NULL, 3},
                                647                 :                :         {"synchronous", no_argument, NULL, 4},
                                648                 :                :         {"no-sync", no_argument, NULL, 5},
                                649                 :                :         {NULL, 0, NULL, 0}
                                650                 :                :     };
                                651                 :                : 
                                652                 :                :     int         c;
                                653                 :                :     int         option_index;
                                654                 :                :     char       *db_name;
                                655                 :                :     pg_compress_specification compression_spec;
 1597 michael@paquier.xyz       656                 :             19 :     char       *compression_detail = NULL;
                                657                 :             19 :     char       *compression_algorithm_str = "none";
                                658                 :             19 :     char       *error_detail = NULL;
                                659                 :                : 
 2705 peter@eisentraut.org      660                 :             19 :     pg_logging_init(argv[0]);
 5419 magnus@hagander.net       661                 :             19 :     progname = get_progname(argv[0]);
 3895 alvherre@alvh.no-ip.      662                 :             19 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_basebackup"));
                                663                 :                : 
 5419 magnus@hagander.net       664         [ +  + ]:             19 :     if (argc > 1)
                                665                 :                :     {
                                666   [ +  +  -  + ]:             18 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
                                667                 :                :         {
                                668                 :              1 :             usage();
                                669                 :              1 :             exit(0);
                                670                 :                :         }
 5140 alvherre@alvh.no-ip.      671         [ +  - ]:             17 :         else if (strcmp(argv[1], "-V") == 0 ||
                                672         [ +  + ]:             17 :                  strcmp(argv[1], "--version") == 0)
                                673                 :                :         {
 3486 rhaas@postgresql.org      674                 :              1 :             puts("pg_receivewal (PostgreSQL) " PG_VERSION);
 5419 magnus@hagander.net       675                 :              1 :             exit(0);
                                676                 :                :         }
                                677                 :                :     }
                                678                 :                : 
 1354 peter@eisentraut.org      679                 :             68 :     while ((c = getopt_long(argc, argv, "d:D:E:h:np:s:S:U:vwWZ:",
 5419 magnus@hagander.net       680         [ +  + ]:             68 :                             long_options, &option_index)) != -1)
                                681                 :                :     {
                                682   [ -  +  +  -  :             54 :         switch (c)
                                     +  -  -  +  -  
                                     +  -  -  +  +  
                                        +  -  +  +  
                                                 + ]
                                683                 :                :         {
 1354 peter@eisentraut.org      684                 :UBC           0 :             case 'd':
                                685                 :              0 :                 connection_string = pg_strdup(optarg);
                                686                 :              0 :                 break;
 5419 magnus@hagander.net       687                 :CBC          11 :             case 'D':
 5077 tgl@sss.pgh.pa.us         688                 :             11 :                 basedir = pg_strdup(optarg);
 5419 magnus@hagander.net       689                 :             11 :                 break;
 1354 peter@eisentraut.org      690                 :              9 :             case 'E':
   15 fujii@postgresql.org      691         [ +  + ]:GNC           9 :                 if (!pg_parse_lsn(optarg, &endpos))
 1354 peter@eisentraut.org      692                 :GBC           2 :                     pg_fatal("could not parse end position \"%s\"", optarg);
 4931 heikki.linnakangas@i      693                 :CBC           7 :                 break;
 5419 magnus@hagander.net       694                 :UBC           0 :             case 'h':
 5077 tgl@sss.pgh.pa.us         695                 :              0 :                 dbhost = pg_strdup(optarg);
 5419 magnus@hagander.net       696                 :              0 :                 break;
 1354 peter@eisentraut.org      697                 :CBC           7 :             case 'n':
                                698                 :              7 :                 noloop = true;
                                699                 :              7 :                 break;
 5419 magnus@hagander.net       700                 :UBC           0 :             case 'p':
 5077 tgl@sss.pgh.pa.us         701                 :              0 :                 dbport = pg_strdup(optarg);
 5419 magnus@hagander.net       702                 :              0 :                 break;
                                703                 :              0 :             case 's':
 1860 michael@paquier.xyz       704         [ #  # ]:              0 :                 if (!option_parse_int(optarg, "-s/--status-interval", 0,
                                705                 :                :                                       INT_MAX / 1000,
                                706                 :                :                                       &standby_message_timeout))
 5419 magnus@hagander.net       707                 :              0 :                     exit(1);
 1860 michael@paquier.xyz       708                 :              0 :                 standby_message_timeout *= 1000;
 5419 magnus@hagander.net       709                 :              0 :                 break;
 4591 rhaas@postgresql.org      710                 :CBC           5 :             case 'S':
                                711                 :              5 :                 replication_slot = pg_strdup(optarg);
                                712                 :              5 :                 break;
 1354 peter@eisentraut.org      713                 :UBC           0 :             case 'U':
                                714                 :              0 :                 dbuser = pg_strdup(optarg);
 5205 magnus@hagander.net       715                 :              0 :                 break;
 5419 magnus@hagander.net       716                 :CBC           7 :             case 'v':
                                717                 :              7 :                 verbose++;
                                718                 :              7 :                 break;
 1354 peter@eisentraut.org      719                 :UBC           0 :             case 'w':
                                720                 :              0 :                 dbgetpassword = -1;
                                721                 :              0 :                 break;
                                722                 :              0 :             case 'W':
                                723                 :              0 :                 dbgetpassword = 1;
                                724                 :              0 :                 break;
 3509 magnus@hagander.net       725                 :CBC           3 :             case 'Z':
 1597 michael@paquier.xyz       726                 :              3 :                 parse_compress_options(optarg, &compression_algorithm_str,
                                727                 :                :                                        &compression_detail);
 3509 magnus@hagander.net       728                 :              3 :                 break;
 4343 andres@anarazel.de        729                 :              3 :             case 1:
                                730                 :              3 :                 do_create_slot = true;
                                731                 :              3 :                 break;
                                732                 :              2 :             case 2:
                                733                 :              2 :                 do_drop_slot = true;
                                734                 :              2 :                 break;
 4300 fujii@postgresql.org      735                 :UBC           0 :             case 3:
 4064 andres@anarazel.de        736                 :              0 :                 slot_exists_ok = true;
                                737                 :              0 :                 break;
 4064 andres@anarazel.de        738                 :CBC           2 :             case 4:
 4300 fujii@postgresql.org      739                 :              2 :                 synchronous = true;
                                740                 :              2 :                 break;
 3224 rhaas@postgresql.org      741                 :              4 :             case 5:
                                742                 :              4 :                 do_sync = false;
                                743                 :              4 :                 break;
 5419 magnus@hagander.net       744                 :              1 :             default:
                                745                 :                :                 /* getopt_long already emitted a complaint */
 1602 tgl@sss.pgh.pa.us         746                 :              1 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 5419 magnus@hagander.net       747                 :              1 :                 exit(1);
                                748                 :                :         }
                                749                 :                :     }
                                750                 :                : 
                                751                 :                :     /*
                                752                 :                :      * Any non-option arguments?
                                753                 :                :      */
                                754         [ -  + ]:             14 :     if (optind < argc)
                                755                 :                :     {
 2705 peter@eisentraut.org      756                 :UBC           0 :         pg_log_error("too many command-line arguments (first is \"%s\")",
                                757                 :                :                      argv[optind]);
 1602 tgl@sss.pgh.pa.us         758                 :              0 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 5419 magnus@hagander.net       759                 :              0 :         exit(1);
                                760                 :                :     }
                                761                 :                : 
 4119 peter_e@gmx.net           762   [ +  +  +  + ]:CBC          14 :     if (do_drop_slot && do_create_slot)
                                763                 :                :     {
 2705 peter@eisentraut.org      764                 :              1 :         pg_log_error("cannot use --create-slot together with --drop-slot");
 1602 tgl@sss.pgh.pa.us         765                 :              1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 4343 andres@anarazel.de        766                 :              1 :         exit(1);
                                767                 :                :     }
                                768                 :                : 
 4119 peter_e@gmx.net           769   [ +  +  +  -  :             13 :     if (replication_slot == NULL && (do_drop_slot || do_create_slot))
                                              +  + ]
                                770                 :                :     {
                                771                 :                :         /* translator: %s is an option name */
 2705 peter@eisentraut.org      772         [ -  + ]:              1 :         pg_log_error("%s needs a slot to be specified using --slot",
                                773                 :                :                      do_drop_slot ? "--drop-slot" : "--create-slot");
 1602 tgl@sss.pgh.pa.us         774                 :              1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 4343 andres@anarazel.de        775                 :              1 :         exit(1);
                                776                 :                :     }
                                777                 :                : 
 3224 rhaas@postgresql.org      778   [ +  +  +  + ]:             12 :     if (synchronous && !do_sync)
                                779                 :                :     {
 2705 peter@eisentraut.org      780                 :              1 :         pg_log_error("cannot use --synchronous together with --no-sync");
 1602 tgl@sss.pgh.pa.us         781                 :              1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 3224 rhaas@postgresql.org      782                 :              1 :         exit(1);
                                783                 :                :     }
                                784                 :                : 
                                785                 :                :     /*
                                786                 :                :      * Required arguments
                                787                 :                :      */
 4035 andres@anarazel.de        788   [ +  +  +  +  :             11 :     if (basedir == NULL && !do_drop_slot && !do_create_slot)
                                              +  + ]
                                789                 :                :     {
 2705 peter@eisentraut.org      790                 :              1 :         pg_log_error("no target directory specified");
 1602 tgl@sss.pgh.pa.us         791                 :              1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 5419 magnus@hagander.net       792                 :              1 :         exit(1);
                                793                 :                :     }
                                794                 :                : 
                                795                 :                :     /*
                                796                 :                :      * Compression options
                                797                 :                :      */
 1597 michael@paquier.xyz       798         [ -  + ]:             10 :     if (!parse_compress_algorithm(compression_algorithm_str,
                                799                 :                :                                   &compression_algorithm))
 1433 peter@eisentraut.org      800                 :UBC           0 :         pg_fatal("unrecognized compression algorithm: \"%s\"",
                                801                 :                :                  compression_algorithm_str);
                                802                 :                : 
 1597 michael@paquier.xyz       803                 :CBC          10 :     parse_compress_specification(compression_algorithm, compression_detail,
                                804                 :                :                                  &compression_spec);
                                805                 :             10 :     error_detail = validate_compress_specification(&compression_spec);
                                806         [ +  + ]:             10 :     if (error_detail != NULL)
                                807                 :              1 :         pg_fatal("invalid compression specification: %s",
                                808                 :                :                  error_detail);
                                809                 :                : 
                                810                 :                :     /* Extract the compression level */
 1443                           811                 :              9 :     compresslevel = compression_spec.level;
                                812                 :                : 
                                813         [ -  + ]:              9 :     if (compression_algorithm == PG_COMPRESSION_ZSTD)
 1443 michael@paquier.xyz       814                 :UBC           0 :         pg_fatal("compression with %s is not yet supported", "ZSTD");
                                815                 :                : 
                                816                 :                :     /*
                                817                 :                :      * Check existence of destination folder.
                                818                 :                :      */
 4035 andres@anarazel.de        819   [ +  +  +  + ]:CBC           9 :     if (!do_drop_slot && !do_create_slot)
                                820                 :                :     {
 4114 bruce@momjian.us          821                 :              7 :         DIR        *dir = get_destination_dir(basedir);
                                822                 :                : 
 4343 andres@anarazel.de        823                 :              7 :         close_destination_dir(dir, basedir);
                                824                 :                :     }
                                825                 :                : 
                                826                 :                :     /*
                                827                 :                :      * Obtain a connection before doing anything.
                                828                 :                :      */
                                829                 :              9 :     conn = GetConnection();
                                830         [ -  + ]:              9 :     if (!conn)
                                831                 :                :         /* error message already written in GetConnection() */
 4343 andres@anarazel.de        832                 :UBC           0 :         exit(1);
 2798 peter@eisentraut.org      833                 :CBC           9 :     atexit(disconnect_atexit);
                                834                 :                : 
                                835                 :                :     /*
                                836                 :                :      * Trap signals.  (Don't do this until after the initial password prompt,
                                837                 :                :      * if one is needed, in GetConnection.)
                                838                 :                :      */
                                839                 :                : #ifndef WIN32
 1443 dgustafsson@postgres      840                 :              9 :     pqsignal(SIGINT, sigexit_handler);
                                841                 :              9 :     pqsignal(SIGTERM, sigexit_handler);
                                842                 :                : #endif
                                843                 :                : 
                                844                 :                :     /*
                                845                 :                :      * Run IDENTIFY_SYSTEM to make sure we've successfully have established a
                                846                 :                :      * replication connection and haven't connected using a database specific
                                847                 :                :      * connection.
                                848                 :                :      */
 4343 andres@anarazel.de        849         [ -  + ]:              9 :     if (!RunIdentifySystem(conn, NULL, NULL, NULL, &db_name))
 2798 peter@eisentraut.org      850                 :UBC           0 :         exit(1);
                                851                 :                : 
                                852                 :                :     /*
                                853                 :                :      * Check that there is a database associated with connection, none should
                                854                 :                :      * be defined in this context.
                                855                 :                :      */
 4343 andres@anarazel.de        856         [ -  + ]:CBC           9 :     if (db_name)
 1602 tgl@sss.pgh.pa.us         857                 :UBC           0 :         pg_fatal("replication connection using slot \"%s\" is unexpectedly database specific",
                                858                 :                :                  replication_slot);
                                859                 :                : 
                                860                 :                :     /*
                                861                 :                :      * Set umask so that directories/files are created with the same
                                862                 :                :      * permissions as directories/files in the source data directory.
                                863                 :                :      *
                                864                 :                :      * pg_mode_mask is set to owner-only by default and then updated in
                                865                 :                :      * GetConnection() where we get the mode from the server-side with
                                866                 :                :      * RetrieveDataDirCreatePerm() and then call SetDataDirectoryCreatePerm().
                                867                 :                :      */
 1804 michael@paquier.xyz       868                 :CBC           9 :     umask(pg_mode_mask);
                                869                 :                : 
                                870                 :                :     /*
                                871                 :                :      * Drop a replication slot.
                                872                 :                :      */
 4343 andres@anarazel.de        873         [ +  + ]:              9 :     if (do_drop_slot)
                                874                 :                :     {
                                875         [ -  + ]:              1 :         if (verbose)
 2654 tgl@sss.pgh.pa.us         876                 :UBC           0 :             pg_log_info("dropping replication slot \"%s\"", replication_slot);
                                877                 :                : 
 4343 andres@anarazel.de        878         [ -  + ]:CBC           1 :         if (!DropReplicationSlot(conn, replication_slot))
 2798 peter@eisentraut.org      879                 :UBC           0 :             exit(1);
 2798 peter@eisentraut.org      880                 :CBC           1 :         exit(0);
                                881                 :                :     }
                                882                 :                : 
                                883                 :                :     /* Create a replication slot */
 4343 andres@anarazel.de        884         [ +  + ]:              8 :     if (do_create_slot)
                                885                 :                :     {
                                886         [ -  + ]:              1 :         if (verbose)
 2705 peter@eisentraut.org      887                 :UBC           0 :             pg_log_info("creating replication slot \"%s\"", replication_slot);
                                888                 :                : 
 3257 peter_e@gmx.net           889         [ -  + ]:CBC           1 :         if (!CreateReplicationSlot(conn, replication_slot, NULL, false, true, false,
                                890                 :                :                                    slot_exists_ok, false, false))
 2798 peter@eisentraut.org      891                 :UBC           0 :             exit(1);
 2798 peter@eisentraut.org      892                 :CBC           1 :         exit(0);
                                893                 :                :     }
                                894                 :                : 
                                895                 :                :     /* determine remote server's xlog segment size */
 1804 michael@paquier.xyz       896         [ -  + ]:              7 :     if (!RetrieveWalSegSize(conn))
 1804 michael@paquier.xyz       897                 :UBC           0 :         exit(1);
                                898                 :                : 
                                899                 :                :     /*
                                900                 :                :      * Don't close the connection here so that subsequent StreamLog() can
                                901                 :                :      * reuse it.
                                902                 :                :      */
                                903                 :                : 
                                904                 :                :     while (true)
                                905                 :                :     {
 5205 magnus@hagander.net       906                 :CBC           7 :         StreamLog();
 3272 peter_e@gmx.net           907         [ +  + ]:              7 :         if (time_to_stop)
                                908                 :                :         {
                                909                 :                :             /*
                                910                 :                :              * We've been Ctrl-C'ed or end of streaming position has been
                                911                 :                :              * willingly reached, so exit without an error code.
                                912                 :                :              */
 5205 magnus@hagander.net       913                 :              6 :             exit(0);
                                914                 :                :         }
                                915         [ +  - ]:              1 :         else if (noloop)
 1602 tgl@sss.pgh.pa.us         916                 :              1 :             pg_fatal("disconnected");
                                917                 :                :         else
                                918                 :                :         {
                                919                 :                :             /* translator: check source for value for %d */
 2705 peter@eisentraut.org      920                 :UBC           0 :             pg_log_info("disconnected; waiting %d seconds to try again",
                                921                 :                :                         RECONNECT_SLEEP_TIME);
 5205 magnus@hagander.net       922                 :              0 :             pg_usleep(RECONNECT_SLEEP_TIME * 1000000);
                                923                 :                :         }
                                924                 :                :     }
                                925                 :                : }
        

Generated by: LCOV version 2.0-1