LCOV - code coverage report
Current view: top level - src/bin/pg_basebackup - pg_basebackup.c (source / functions) Hit Total Coverage
Test: PostgreSQL 14devel Lines: 554 940 58.9 %
Date: 2021-03-02 10:06:42 Functions: 21 25 84.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pg_basebackup.c - receive a base backup using streaming replication protocol
       4             :  *
       5             :  * Author: Magnus Hagander <magnus@hagander.net>
       6             :  *
       7             :  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
       8             :  *
       9             :  * IDENTIFICATION
      10             :  *        src/bin/pg_basebackup/pg_basebackup.c
      11             :  *-------------------------------------------------------------------------
      12             :  */
      13             : 
      14             : #include "postgres_fe.h"
      15             : 
      16             : #include <unistd.h>
      17             : #include <dirent.h>
      18             : #include <sys/stat.h>
      19             : #include <sys/wait.h>
      20             : #include <signal.h>
      21             : #include <time.h>
      22             : #ifdef HAVE_SYS_SELECT_H
      23             : #include <sys/select.h>
      24             : #endif
      25             : #ifdef HAVE_LIBZ
      26             : #include <zlib.h>
      27             : #endif
      28             : 
      29             : #include "access/xlog_internal.h"
      30             : #include "common/file_perm.h"
      31             : #include "common/file_utils.h"
      32             : #include "common/logging.h"
      33             : #include "common/string.h"
      34             : #include "fe_utils/recovery_gen.h"
      35             : #include "fe_utils/string_utils.h"
      36             : #include "getopt_long.h"
      37             : #include "libpq-fe.h"
      38             : #include "pgtar.h"
      39             : #include "pgtime.h"
      40             : #include "pqexpbuffer.h"
      41             : #include "receivelog.h"
      42             : #include "replication/basebackup.h"
      43             : #include "streamutil.h"
      44             : 
      45             : #define ERRCODE_DATA_CORRUPTED  "XX001"
      46             : 
      47             : typedef struct TablespaceListCell
      48             : {
      49             :     struct TablespaceListCell *next;
      50             :     char        old_dir[MAXPGPATH];
      51             :     char        new_dir[MAXPGPATH];
      52             : } TablespaceListCell;
      53             : 
      54             : typedef struct TablespaceList
      55             : {
      56             :     TablespaceListCell *head;
      57             :     TablespaceListCell *tail;
      58             : } TablespaceList;
      59             : 
      60             : typedef struct WriteTarState
      61             : {
      62             :     int         tablespacenum;
      63             :     char        filename[MAXPGPATH];
      64             :     FILE       *tarfile;
      65             :     char        tarhdr[TAR_BLOCK_SIZE];
      66             :     bool        basetablespace;
      67             :     bool        in_tarhdr;
      68             :     bool        skip_file;
      69             :     bool        is_recovery_guc_supported;
      70             :     bool        is_postgresql_auto_conf;
      71             :     bool        found_postgresql_auto_conf;
      72             :     int         file_padding_len;
      73             :     size_t      tarhdrsz;
      74             :     pgoff_t     filesz;
      75             : #ifdef HAVE_LIBZ
      76             :     gzFile      ztarfile;
      77             : #endif
      78             : } WriteTarState;
      79             : 
      80             : typedef struct UnpackTarState
      81             : {
      82             :     int         tablespacenum;
      83             :     char        current_path[MAXPGPATH];
      84             :     char        filename[MAXPGPATH];
      85             :     const char *mapped_tblspc_path;
      86             :     pgoff_t     current_len_left;
      87             :     int         current_padding;
      88             :     FILE       *file;
      89             : } UnpackTarState;
      90             : 
      91             : typedef struct WriteManifestState
      92             : {
      93             :     char        filename[MAXPGPATH];
      94             :     FILE       *file;
      95             : } WriteManifestState;
      96             : 
      97             : typedef void (*WriteDataCallback) (size_t nbytes, char *buf,
      98             :                                    void *callback_data);
      99             : 
     100             : /*
     101             :  * pg_xlog has been renamed to pg_wal in version 10.  This version number
     102             :  * should be compared with PQserverVersion().
     103             :  */
     104             : #define MINIMUM_VERSION_FOR_PG_WAL  100000
     105             : 
     106             : /*
     107             :  * Temporary replication slots are supported from version 10.
     108             :  */
     109             : #define MINIMUM_VERSION_FOR_TEMP_SLOTS 100000
     110             : 
     111             : /*
     112             :  * Backup manifests are supported from version 13.
     113             :  */
     114             : #define MINIMUM_VERSION_FOR_MANIFESTS   130000
     115             : 
     116             : /*
     117             :  * Different ways to include WAL
     118             :  */
     119             : typedef enum
     120             : {
     121             :     NO_WAL,
     122             :     FETCH_WAL,
     123             :     STREAM_WAL
     124             : } IncludeWal;
     125             : 
     126             : /* Global options */
     127             : static char *basedir = NULL;
     128             : static TablespaceList tablespace_dirs = {NULL, NULL};
     129             : static char *xlog_dir = NULL;
     130             : static char format = 'p';       /* p(lain)/t(ar) */
     131             : static char *label = "pg_basebackup base backup";
     132             : static bool noclean = false;
     133             : static bool checksum_failure = false;
     134             : static bool showprogress = false;
     135             : static bool estimatesize = true;
     136             : static int  verbose = 0;
     137             : static int  compresslevel = 0;
     138             : static IncludeWal includewal = STREAM_WAL;
     139             : static bool fastcheckpoint = false;
     140             : static bool writerecoveryconf = false;
     141             : static bool do_sync = true;
     142             : static int  standby_message_timeout = 10 * 1000;    /* 10 sec = default */
     143             : static pg_time_t last_progress_report = 0;
     144             : static int32 maxrate = 0;       /* no limit by default */
     145             : static char *replication_slot = NULL;
     146             : static bool temp_replication_slot = true;
     147             : static bool create_slot = false;
     148             : static bool no_slot = false;
     149             : static bool verify_checksums = true;
     150             : static bool manifest = true;
     151             : static bool manifest_force_encode = false;
     152             : static char *manifest_checksums = NULL;
     153             : 
     154             : static bool success = false;
     155             : static bool made_new_pgdata = false;
     156             : static bool found_existing_pgdata = false;
     157             : static bool made_new_xlogdir = false;
     158             : static bool found_existing_xlogdir = false;
     159             : static bool made_tablespace_dirs = false;
     160             : static bool found_tablespace_dirs = false;
     161             : 
     162             : /* Progress counters */
     163             : static uint64 totalsize_kb;
     164             : static uint64 totaldone;
     165             : static int  tablespacecount;
     166             : 
     167             : /* Pipe to communicate with background wal receiver process */
     168             : #ifndef WIN32
     169             : static int  bgpipe[2] = {-1, -1};
     170             : #endif
     171             : 
     172             : /* Handle to child process */
     173             : static pid_t bgchild = -1;
     174             : static bool in_log_streamer = false;
     175             : 
     176             : /* End position for xlog streaming, empty string if unknown yet */
     177             : static XLogRecPtr xlogendptr;
     178             : 
     179             : #ifndef WIN32
     180             : static int  has_xlogendptr = 0;
     181             : #else
     182             : static volatile LONG has_xlogendptr = 0;
     183             : #endif
     184             : 
     185             : /* Contents of configuration file to be generated */
     186             : static PQExpBuffer recoveryconfcontents = NULL;
     187             : 
     188             : /* Function headers */
     189             : static void usage(void);
     190             : static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found);
     191             : static void progress_report(int tablespacenum, const char *filename, bool force,
     192             :                             bool finished);
     193             : 
     194             : static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
     195             : static void ReceiveTarCopyChunk(size_t r, char *copybuf, void *callback_data);
     196             : static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
     197             : static void ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf,
     198             :                                          void *callback_data);
     199             : static void ReceiveBackupManifest(PGconn *conn);
     200             : static void ReceiveBackupManifestChunk(size_t r, char *copybuf,
     201             :                                        void *callback_data);
     202             : static void ReceiveBackupManifestInMemory(PGconn *conn, PQExpBuffer buf);
     203             : static void ReceiveBackupManifestInMemoryChunk(size_t r, char *copybuf,
     204             :                                                void *callback_data);
     205             : static void BaseBackup(void);
     206             : 
     207             : static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
     208             :                                  bool segment_finished);
     209             : 
     210             : static const char *get_tablespace_mapping(const char *dir);
     211             : static void tablespace_list_append(const char *arg);
     212             : 
     213             : 
     214             : static void
     215         320 : cleanup_directories_atexit(void)
     216             : {
     217         320 :     if (success || in_log_streamer)
     218         278 :         return;
     219             : 
     220          42 :     if (!noclean && !checksum_failure)
     221             :     {
     222          34 :         if (made_new_pgdata)
     223             :         {
     224          10 :             pg_log_info("removing data directory \"%s\"", basedir);
     225          10 :             if (!rmtree(basedir, true))
     226           0 :                 pg_log_error("failed to remove data directory");
     227             :         }
     228          24 :         else if (found_existing_pgdata)
     229             :         {
     230           0 :             pg_log_info("removing contents of data directory \"%s\"", basedir);
     231           0 :             if (!rmtree(basedir, false))
     232           0 :                 pg_log_error("failed to remove contents of data directory");
     233             :         }
     234             : 
     235          68 :         if (made_new_xlogdir)
     236             :         {
     237           0 :             pg_log_info("removing WAL directory \"%s\"", xlog_dir);
     238           0 :             if (!rmtree(xlog_dir, true))
     239           0 :                 pg_log_error("failed to remove WAL directory");
     240             :         }
     241          34 :         else if (found_existing_xlogdir)
     242             :         {
     243           0 :             pg_log_info("removing contents of WAL directory \"%s\"", xlog_dir);
     244           0 :             if (!rmtree(xlog_dir, false))
     245           0 :                 pg_log_error("failed to remove contents of WAL directory");
     246             :         }
     247             :     }
     248             :     else
     249             :     {
     250           8 :         if ((made_new_pgdata || found_existing_pgdata) && !checksum_failure)
     251           0 :             pg_log_info("data directory \"%s\" not removed at user's request", basedir);
     252             : 
     253           8 :         if (made_new_xlogdir || found_existing_xlogdir)
     254           0 :             pg_log_info("WAL directory \"%s\" not removed at user's request", xlog_dir);
     255             :     }
     256             : 
     257          42 :     if ((made_tablespace_dirs || found_tablespace_dirs) && !checksum_failure)
     258           0 :         pg_log_info("changes to tablespace directories will not be undone");
     259             : }
     260             : 
     261             : static void
     262         294 : disconnect_atexit(void)
     263             : {
     264         294 :     if (conn != NULL)
     265         154 :         PQfinish(conn);
     266         294 : }
     267             : 
     268             : #ifndef WIN32
     269             : /*
     270             :  * On windows, our background thread dies along with the process. But on
     271             :  * Unix, if we have started a subprocess, we want to kill it off so it
     272             :  * doesn't remain running trying to stream data.
     273             :  */
     274             : static void
     275         146 : kill_bgchild_atexit(void)
     276             : {
     277         146 :     if (bgchild > 0)
     278         146 :         kill(bgchild, SIGTERM);
     279         146 : }
     280             : #endif
     281             : 
     282             : /*
     283             :  * Split argument into old_dir and new_dir and append to tablespace mapping
     284             :  * list.
     285             :  */
     286             : static void
     287          38 : tablespace_list_append(const char *arg)
     288             : {
     289          38 :     TablespaceListCell *cell = (TablespaceListCell *) pg_malloc0(sizeof(TablespaceListCell));
     290             :     char       *dst;
     291             :     char       *dst_ptr;
     292             :     const char *arg_ptr;
     293             : 
     294          38 :     dst_ptr = dst = cell->old_dir;
     295        1284 :     for (arg_ptr = arg; *arg_ptr; arg_ptr++)
     296             :     {
     297        1248 :         if (dst_ptr - dst >= MAXPGPATH)
     298             :         {
     299           0 :             pg_log_error("directory name too long");
     300           0 :             exit(1);
     301             :         }
     302             : 
     303        1248 :         if (*arg_ptr == '\\' && *(arg_ptr + 1) == '=')
     304             :             ;                   /* skip backslash escaping = */
     305        1244 :         else if (*arg_ptr == '=' && (arg_ptr == arg || *(arg_ptr - 1) != '\\'))
     306             :         {
     307          38 :             if (*cell->new_dir)
     308             :             {
     309           2 :                 pg_log_error("multiple \"=\" signs in tablespace mapping");
     310           2 :                 exit(1);
     311             :             }
     312             :             else
     313          36 :                 dst = dst_ptr = cell->new_dir;
     314             :         }
     315             :         else
     316        1206 :             *dst_ptr++ = *arg_ptr;
     317             :     }
     318             : 
     319          36 :     if (!*cell->old_dir || !*cell->new_dir)
     320             :     {
     321           6 :         pg_log_error("invalid tablespace mapping format \"%s\", must be \"OLDDIR=NEWDIR\"", arg);
     322           6 :         exit(1);
     323             :     }
     324             : 
     325             :     /*
     326             :      * This check isn't absolutely necessary.  But all tablespaces are created
     327             :      * with absolute directories, so specifying a non-absolute path here would
     328             :      * just never match, possibly confusing users.  It's also good to be
     329             :      * consistent with the new_dir check.
     330             :      */
     331          30 :     if (!is_absolute_path(cell->old_dir))
     332             :     {
     333           2 :         pg_log_error("old directory is not an absolute path in tablespace mapping: %s",
     334             :                      cell->old_dir);
     335           2 :         exit(1);
     336             :     }
     337             : 
     338          28 :     if (!is_absolute_path(cell->new_dir))
     339             :     {
     340           2 :         pg_log_error("new directory is not an absolute path in tablespace mapping: %s",
     341             :                      cell->new_dir);
     342           2 :         exit(1);
     343             :     }
     344             : 
     345             :     /*
     346             :      * Comparisons done with these values should involve similarly
     347             :      * canonicalized path values.  This is particularly sensitive on Windows
     348             :      * where path values may not necessarily use Unix slashes.
     349             :      */
     350          26 :     canonicalize_path(cell->old_dir);
     351          26 :     canonicalize_path(cell->new_dir);
     352             : 
     353          26 :     if (tablespace_dirs.tail)
     354           0 :         tablespace_dirs.tail->next = cell;
     355             :     else
     356          26 :         tablespace_dirs.head = cell;
     357          26 :     tablespace_dirs.tail = cell;
     358          26 : }
     359             : 
     360             : 
     361             : #ifdef HAVE_LIBZ
     362             : static const char *
     363           0 : get_gz_error(gzFile gzf)
     364             : {
     365             :     int         errnum;
     366             :     const char *errmsg;
     367             : 
     368           0 :     errmsg = gzerror(gzf, &errnum);
     369           0 :     if (errnum == Z_ERRNO)
     370           0 :         return strerror(errno);
     371             :     else
     372           0 :         return errmsg;
     373             : }
     374             : #endif
     375             : 
     376             : static void
     377           2 : usage(void)
     378             : {
     379           2 :     printf(_("%s takes a base backup of a running PostgreSQL server.\n\n"),
     380             :            progname);
     381           2 :     printf(_("Usage:\n"));
     382           2 :     printf(_("  %s [OPTION]...\n"), progname);
     383           2 :     printf(_("\nOptions controlling the output:\n"));
     384           2 :     printf(_("  -D, --pgdata=DIRECTORY receive base backup into directory\n"));
     385           2 :     printf(_("  -F, --format=p|t       output format (plain (default), tar)\n"));
     386           2 :     printf(_("  -r, --max-rate=RATE    maximum transfer rate to transfer data directory\n"
     387             :              "                         (in kB/s, or use suffix \"k\" or \"M\")\n"));
     388           2 :     printf(_("  -R, --write-recovery-conf\n"
     389             :              "                         write configuration for replication\n"));
     390           2 :     printf(_("  -T, --tablespace-mapping=OLDDIR=NEWDIR\n"
     391             :              "                         relocate tablespace in OLDDIR to NEWDIR\n"));
     392           2 :     printf(_("      --waldir=WALDIR    location for the write-ahead log directory\n"));
     393           2 :     printf(_("  -X, --wal-method=none|fetch|stream\n"
     394             :              "                         include required WAL files with specified method\n"));
     395           2 :     printf(_("  -z, --gzip             compress tar output\n"));
     396           2 :     printf(_("  -Z, --compress=0-9     compress tar output with given compression level\n"));
     397           2 :     printf(_("\nGeneral options:\n"));
     398           2 :     printf(_("  -c, --checkpoint=fast|spread\n"
     399             :              "                         set fast or spread checkpointing\n"));
     400           2 :     printf(_("  -C, --create-slot      create replication slot\n"));
     401           2 :     printf(_("  -l, --label=LABEL      set backup label\n"));
     402           2 :     printf(_("  -n, --no-clean         do not clean up after errors\n"));
     403           2 :     printf(_("  -N, --no-sync          do not wait for changes to be written safely to disk\n"));
     404           2 :     printf(_("  -P, --progress         show progress information\n"));
     405           2 :     printf(_("  -S, --slot=SLOTNAME    replication slot to use\n"));
     406           2 :     printf(_("  -v, --verbose          output verbose messages\n"));
     407           2 :     printf(_("  -V, --version          output version information, then exit\n"));
     408           2 :     printf(_("      --manifest-checksums=SHA{224,256,384,512}|CRC32C|NONE\n"
     409             :              "                         use algorithm for manifest checksums\n"));
     410           2 :     printf(_("      --manifest-force-encode\n"
     411             :              "                         hex encode all file names in manifest\n"));
     412           2 :     printf(_("      --no-estimate-size do not estimate backup size in server side\n"));
     413           2 :     printf(_("      --no-manifest      suppress generation of backup manifest\n"));
     414           2 :     printf(_("      --no-slot          prevent creation of temporary replication slot\n"));
     415           2 :     printf(_("      --no-verify-checksums\n"
     416             :              "                         do not verify checksums\n"));
     417           2 :     printf(_("  -?, --help             show this help, then exit\n"));
     418           2 :     printf(_("\nConnection options:\n"));
     419           2 :     printf(_("  -d, --dbname=CONNSTR   connection string\n"));
     420           2 :     printf(_("  -h, --host=HOSTNAME    database server host or socket directory\n"));
     421           2 :     printf(_("  -p, --port=PORT        database server port number\n"));
     422           2 :     printf(_("  -s, --status-interval=INTERVAL\n"
     423             :              "                         time between status packets sent to server (in seconds)\n"));
     424           2 :     printf(_("  -U, --username=NAME    connect as specified database user\n"));
     425           2 :     printf(_("  -w, --no-password      never prompt for password\n"));
     426           2 :     printf(_("  -W, --password         force password prompt (should happen automatically)\n"));
     427           2 :     printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
     428           2 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
     429           2 : }
     430             : 
     431             : 
     432             : /*
     433             :  * Called in the background process every time data is received.
     434             :  * On Unix, we check to see if there is any data on our pipe
     435             :  * (which would mean we have a stop position), and if it is, check if
     436             :  * it is time to stop.
     437             :  * On Windows, we are in a single process, so we can just check if it's
     438             :  * time to stop.
     439             :  */
     440             : static bool
     441        6598 : reached_end_position(XLogRecPtr segendpos, uint32 timeline,
     442             :                      bool segment_finished)
     443             : {
     444        6598 :     if (!has_xlogendptr)
     445             :     {
     446             : #ifndef WIN32
     447             :         fd_set      fds;
     448             :         struct timeval tv;
     449             :         int         r;
     450             : 
     451             :         /*
     452             :          * Don't have the end pointer yet - check our pipe to see if it has
     453             :          * been sent yet.
     454             :          */
     455        6458 :         FD_ZERO(&fds);
     456        6458 :         FD_SET(bgpipe[0], &fds);
     457             : 
     458       19374 :         MemSet(&tv, 0, sizeof(tv));
     459             : 
     460        6458 :         r = select(bgpipe[0] + 1, &fds, NULL, NULL, &tv);
     461        6458 :         if (r == 1)
     462             :         {
     463             :             char        xlogend[64];
     464             :             uint32      hi,
     465             :                         lo;
     466             : 
     467        1224 :             MemSet(xlogend, 0, sizeof(xlogend));
     468         136 :             r = read(bgpipe[0], xlogend, sizeof(xlogend) - 1);
     469         136 :             if (r < 0)
     470             :             {
     471           0 :                 pg_log_error("could not read from ready pipe: %m");
     472           0 :                 exit(1);
     473             :             }
     474             : 
     475         136 :             if (sscanf(xlogend, "%X/%X", &hi, &lo) != 2)
     476             :             {
     477           0 :                 pg_log_error("could not parse write-ahead log location \"%s\"",
     478             :                              xlogend);
     479           0 :                 exit(1);
     480             :             }
     481         136 :             xlogendptr = ((uint64) hi) << 32 | lo;
     482         136 :             has_xlogendptr = 1;
     483             : 
     484             :             /*
     485             :              * Fall through to check if we've reached the point further
     486             :              * already.
     487             :              */
     488             :         }
     489             :         else
     490             :         {
     491             :             /*
     492             :              * No data received on the pipe means we don't know the end
     493             :              * position yet - so just say it's not time to stop yet.
     494             :              */
     495        6322 :             return false;
     496             :         }
     497             : #else
     498             : 
     499             :         /*
     500             :          * On win32, has_xlogendptr is set by the main thread, so if it's not
     501             :          * set here, we just go back and wait until it shows up.
     502             :          */
     503             :         return false;
     504             : #endif
     505             :     }
     506             : 
     507             :     /*
     508             :      * At this point we have an end pointer, so compare it to the current
     509             :      * position to figure out if it's time to stop.
     510             :      */
     511         276 :     if (segendpos >= xlogendptr)
     512         272 :         return true;
     513             : 
     514             :     /*
     515             :      * Have end pointer, but haven't reached it yet - so tell the caller to
     516             :      * keep streaming.
     517             :      */
     518           4 :     return false;
     519             : }
     520             : 
     521             : typedef struct
     522             : {
     523             :     PGconn     *bgconn;
     524             :     XLogRecPtr  startptr;
     525             :     char        xlog[MAXPGPATH];    /* directory or tarfile depending on mode */
     526             :     char       *sysidentifier;
     527             :     int         timeline;
     528             : } logstreamer_param;
     529             : 
     530             : static int
     531         138 : LogStreamerMain(logstreamer_param *param)
     532             : {
     533             :     StreamCtl   stream;
     534             : 
     535         138 :     in_log_streamer = true;
     536             : 
     537        1380 :     MemSet(&stream, 0, sizeof(stream));
     538         138 :     stream.startpos = param->startptr;
     539         138 :     stream.timeline = param->timeline;
     540         138 :     stream.sysidentifier = param->sysidentifier;
     541         138 :     stream.stream_stop = reached_end_position;
     542             : #ifndef WIN32
     543         138 :     stream.stop_socket = bgpipe[0];
     544             : #else
     545             :     stream.stop_socket = PGINVALID_SOCKET;
     546             : #endif
     547         138 :     stream.standby_message_timeout = standby_message_timeout;
     548         138 :     stream.synchronous = false;
     549             :     /* fsync happens at the end of pg_basebackup for all data */
     550         138 :     stream.do_sync = false;
     551         138 :     stream.mark_done = true;
     552         138 :     stream.partial_suffix = NULL;
     553         138 :     stream.replication_slot = replication_slot;
     554             : 
     555         138 :     if (format == 'p')
     556         130 :         stream.walmethod = CreateWalDirectoryMethod(param->xlog, 0,
     557         130 :                                                     stream.do_sync);
     558             :     else
     559           8 :         stream.walmethod = CreateWalTarMethod(param->xlog, compresslevel,
     560           8 :                                               stream.do_sync);
     561             : 
     562         138 :     if (!ReceiveXlogStream(param->bgconn, &stream))
     563             : 
     564             :         /*
     565             :          * Any errors will already have been reported in the function process,
     566             :          * but we need to tell the parent that we didn't shutdown in a nice
     567             :          * way.
     568             :          */
     569           2 :         return 1;
     570             : 
     571         136 :     if (!stream.walmethod->finish())
     572             :     {
     573           0 :         pg_log_error("could not finish writing WAL files: %m");
     574           0 :         return 1;
     575             :     }
     576             : 
     577         136 :     PQfinish(param->bgconn);
     578             : 
     579         136 :     if (format == 'p')
     580         128 :         FreeWalDirectoryMethod();
     581             :     else
     582           8 :         FreeWalTarMethod();
     583         136 :     pg_free(stream.walmethod);
     584             : 
     585         136 :     return 0;
     586             : }
     587             : 
     588             : /*
     589             :  * Initiate background process for receiving xlog during the backup.
     590             :  * The background stream will use its own database connection so we can
     591             :  * stream the logfile in parallel with the backups.
     592             :  */
     593             : static void
     594         148 : StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier)
     595             : {
     596             :     logstreamer_param *param;
     597             :     uint32      hi,
     598             :                 lo;
     599             :     char        statusdir[MAXPGPATH];
     600             : 
     601         148 :     param = pg_malloc0(sizeof(logstreamer_param));
     602         148 :     param->timeline = timeline;
     603         148 :     param->sysidentifier = sysidentifier;
     604             : 
     605             :     /* Convert the starting position */
     606         148 :     if (sscanf(startpos, "%X/%X", &hi, &lo) != 2)
     607             :     {
     608           0 :         pg_log_error("could not parse write-ahead log location \"%s\"",
     609             :                      startpos);
     610           0 :         exit(1);
     611             :     }
     612         148 :     param->startptr = ((uint64) hi) << 32 | lo;
     613             :     /* Round off to even segment position */
     614         148 :     param->startptr -= XLogSegmentOffset(param->startptr, WalSegSz);
     615             : 
     616             : #ifndef WIN32
     617             :     /* Create our background pipe */
     618         148 :     if (pipe(bgpipe) < 0)
     619             :     {
     620           0 :         pg_log_error("could not create pipe for background process: %m");
     621           0 :         exit(1);
     622             :     }
     623             : #endif
     624             : 
     625             :     /* Get a second connection */
     626         148 :     param->bgconn = GetConnection();
     627         148 :     if (!param->bgconn)
     628             :         /* Error message already written in GetConnection() */
     629           0 :         exit(1);
     630             : 
     631             :     /* In post-10 cluster, pg_xlog has been renamed to pg_wal */
     632         148 :     snprintf(param->xlog, sizeof(param->xlog), "%s/%s",
     633             :              basedir,
     634         148 :              PQserverVersion(conn) < MINIMUM_VERSION_FOR_PG_WAL ?
     635             :              "pg_xlog" : "pg_wal");
     636             : 
     637             :     /* Temporary replication slots are only supported in 10 and newer */
     638         148 :     if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_TEMP_SLOTS)
     639           0 :         temp_replication_slot = false;
     640             : 
     641             :     /*
     642             :      * Create replication slot if requested
     643             :      */
     644         148 :     if (temp_replication_slot && !replication_slot)
     645         136 :         replication_slot = psprintf("pg_basebackup_%d", (int) PQbackendPID(param->bgconn));
     646         148 :     if (temp_replication_slot || create_slot)
     647             :     {
     648         140 :         if (!CreateReplicationSlot(param->bgconn, replication_slot, NULL,
     649             :                                    temp_replication_slot, true, true, false))
     650           2 :             exit(1);
     651             : 
     652         138 :         if (verbose)
     653             :         {
     654           0 :             if (temp_replication_slot)
     655           0 :                 pg_log_info("created temporary replication slot \"%s\"",
     656             :                             replication_slot);
     657             :             else
     658           0 :                 pg_log_info("created replication slot \"%s\"",
     659             :                             replication_slot);
     660             :         }
     661             :     }
     662             : 
     663         146 :     if (format == 'p')
     664             :     {
     665             :         /*
     666             :          * Create pg_wal/archive_status or pg_xlog/archive_status (and thus
     667             :          * pg_wal or pg_xlog) depending on the target server so we can write
     668             :          * to basedir/pg_wal or basedir/pg_xlog as the directory entry in the
     669             :          * tar file may arrive later.
     670             :          */
     671         136 :         snprintf(statusdir, sizeof(statusdir), "%s/%s/archive_status",
     672             :                  basedir,
     673         136 :                  PQserverVersion(conn) < MINIMUM_VERSION_FOR_PG_WAL ?
     674             :                  "pg_xlog" : "pg_wal");
     675             : 
     676         136 :         if (pg_mkdir_p(statusdir, pg_dir_create_mode) != 0 && errno != EEXIST)
     677             :         {
     678           0 :             pg_log_error("could not create directory \"%s\": %m", statusdir);
     679           0 :             exit(1);
     680             :         }
     681             :     }
     682             : 
     683             :     /*
     684             :      * Start a child process and tell it to start streaming. On Unix, this is
     685             :      * a fork(). On Windows, we create a thread.
     686             :      */
     687             : #ifndef WIN32
     688         146 :     bgchild = fork();
     689         284 :     if (bgchild == 0)
     690             :     {
     691             :         /* in child process */
     692         138 :         exit(LogStreamerMain(param));
     693             :     }
     694         146 :     else if (bgchild < 0)
     695             :     {
     696           0 :         pg_log_error("could not create background process: %m");
     697           0 :         exit(1);
     698             :     }
     699             : 
     700             :     /*
     701             :      * Else we are in the parent process and all is well.
     702             :      */
     703         146 :     atexit(kill_bgchild_atexit);
     704             : #else                           /* WIN32 */
     705             :     bgchild = _beginthreadex(NULL, 0, (void *) LogStreamerMain, param, 0, NULL);
     706             :     if (bgchild == 0)
     707             :     {
     708             :         pg_log_error("could not create background thread: %m");
     709             :         exit(1);
     710             :     }
     711             : #endif
     712         146 : }
     713             : 
     714             : /*
     715             :  * Verify that the given directory exists and is empty. If it does not
     716             :  * exist, it is created. If it exists but is not empty, an error will
     717             :  * be given and the process ended.
     718             :  */
     719             : static void
     720         186 : verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
     721             : {
     722         186 :     switch (pg_check_dir(dirname))
     723             :     {
     724         162 :         case 0:
     725             : 
     726             :             /*
     727             :              * Does not exist, so create
     728             :              */
     729         162 :             if (pg_mkdir_p(dirname, pg_dir_create_mode) == -1)
     730             :             {
     731           0 :                 pg_log_error("could not create directory \"%s\": %m", dirname);
     732           0 :                 exit(1);
     733             :             }
     734         162 :             if (created)
     735         162 :                 *created = true;
     736         162 :             return;
     737          22 :         case 1:
     738             : 
     739             :             /*
     740             :              * Exists, empty
     741             :              */
     742          22 :             if (found)
     743          22 :                 *found = true;
     744          22 :             return;
     745           2 :         case 2:
     746             :         case 3:
     747             :         case 4:
     748             : 
     749             :             /*
     750             :              * Exists, not empty
     751             :              */
     752           2 :             pg_log_error("directory \"%s\" exists but is not empty", dirname);
     753           2 :             exit(1);
     754           0 :         case -1:
     755             : 
     756             :             /*
     757             :              * Access problem
     758             :              */
     759           0 :             pg_log_error("could not access directory \"%s\": %m", dirname);
     760           0 :             exit(1);
     761             :     }
     762             : }
     763             : 
     764             : 
     765             : /*
     766             :  * Print a progress report based on the global variables. If verbose output
     767             :  * is enabled, also print the current file name.
     768             :  *
     769             :  * Progress report is written at maximum once per second, unless the force
     770             :  * parameter is set to true.
     771             :  *
     772             :  * If finished is set to true, this is the last progress report. The cursor
     773             :  * is moved to the next line.
     774             :  */
     775             : static void
     776      186884 : progress_report(int tablespacenum, const char *filename,
     777             :                 bool force, bool finished)
     778             : {
     779             :     int         percent;
     780             :     char        totaldone_str[32];
     781             :     char        totalsize_str[32];
     782             :     pg_time_t   now;
     783             : 
     784      186884 :     if (!showprogress)
     785      186884 :         return;
     786             : 
     787           0 :     now = time(NULL);
     788           0 :     if (now == last_progress_report && !force && !finished)
     789           0 :         return;                 /* Max once per second */
     790             : 
     791           0 :     last_progress_report = now;
     792           0 :     percent = totalsize_kb ? (int) ((totaldone / 1024) * 100 / totalsize_kb) : 0;
     793             : 
     794             :     /*
     795             :      * Avoid overflowing past 100% or the full size. This may make the total
     796             :      * size number change as we approach the end of the backup (the estimate
     797             :      * will always be wrong if WAL is included), but that's better than having
     798             :      * the done column be bigger than the total.
     799             :      */
     800           0 :     if (percent > 100)
     801           0 :         percent = 100;
     802           0 :     if (totaldone / 1024 > totalsize_kb)
     803           0 :         totalsize_kb = totaldone / 1024;
     804             : 
     805             :     /*
     806             :      * Separate step to keep platform-dependent format code out of
     807             :      * translatable strings.  And we only test for INT64_FORMAT availability
     808             :      * in snprintf, not fprintf.
     809             :      */
     810           0 :     snprintf(totaldone_str, sizeof(totaldone_str), INT64_FORMAT,
     811             :              totaldone / 1024);
     812           0 :     snprintf(totalsize_str, sizeof(totalsize_str), INT64_FORMAT, totalsize_kb);
     813             : 
     814             : #define VERBOSE_FILENAME_LENGTH 35
     815           0 :     if (verbose)
     816             :     {
     817           0 :         if (!filename)
     818             : 
     819             :             /*
     820             :              * No filename given, so clear the status line (used for last
     821             :              * call)
     822             :              */
     823           0 :             fprintf(stderr,
     824           0 :                     ngettext("%*s/%s kB (100%%), %d/%d tablespace %*s",
     825             :                              "%*s/%s kB (100%%), %d/%d tablespaces %*s",
     826             :                              tablespacecount),
     827           0 :                     (int) strlen(totalsize_str),
     828             :                     totaldone_str, totalsize_str,
     829             :                     tablespacenum, tablespacecount,
     830             :                     VERBOSE_FILENAME_LENGTH + 5, "");
     831             :         else
     832             :         {
     833           0 :             bool        truncate = (strlen(filename) > VERBOSE_FILENAME_LENGTH);
     834             : 
     835           0 :             fprintf(stderr,
     836           0 :                     ngettext("%*s/%s kB (%d%%), %d/%d tablespace (%s%-*.*s)",
     837             :                              "%*s/%s kB (%d%%), %d/%d tablespaces (%s%-*.*s)",
     838             :                              tablespacecount),
     839           0 :                     (int) strlen(totalsize_str),
     840             :                     totaldone_str, totalsize_str, percent,
     841             :                     tablespacenum, tablespacecount,
     842             :             /* Prefix with "..." if we do leading truncation */
     843             :                     truncate ? "..." : "",
     844             :                     truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
     845             :                     truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
     846             :             /* Truncate filename at beginning if it's too long */
     847           0 :                     truncate ? filename + strlen(filename) - VERBOSE_FILENAME_LENGTH + 3 : filename);
     848             :         }
     849             :     }
     850             :     else
     851           0 :         fprintf(stderr,
     852           0 :                 ngettext("%*s/%s kB (%d%%), %d/%d tablespace",
     853             :                          "%*s/%s kB (%d%%), %d/%d tablespaces",
     854             :                          tablespacecount),
     855           0 :                 (int) strlen(totalsize_str),
     856             :                 totaldone_str, totalsize_str, percent,
     857             :                 tablespacenum, tablespacecount);
     858             : 
     859             :     /*
     860             :      * Stay on the same line if reporting to a terminal and we're not done
     861             :      * yet.
     862             :      */
     863           0 :     fputc((!finished && isatty(fileno(stderr))) ? '\r' : '\n', stderr);
     864             : }
     865             : 
     866             : static int32
     867           0 : parse_max_rate(char *src)
     868             : {
     869             :     double      result;
     870             :     char       *after_num;
     871           0 :     char       *suffix = NULL;
     872             : 
     873           0 :     errno = 0;
     874           0 :     result = strtod(src, &after_num);
     875           0 :     if (src == after_num)
     876             :     {
     877           0 :         pg_log_error("transfer rate \"%s\" is not a valid value", src);
     878           0 :         exit(1);
     879             :     }
     880           0 :     if (errno != 0)
     881             :     {
     882           0 :         pg_log_error("invalid transfer rate \"%s\": %m", src);
     883           0 :         exit(1);
     884             :     }
     885             : 
     886           0 :     if (result <= 0)
     887             :     {
     888             :         /*
     889             :          * Reject obviously wrong values here.
     890             :          */
     891           0 :         pg_log_error("transfer rate must be greater than zero");
     892           0 :         exit(1);
     893             :     }
     894             : 
     895             :     /*
     896             :      * Evaluate suffix, after skipping over possible whitespace. Lack of
     897             :      * suffix means kilobytes.
     898             :      */
     899           0 :     while (*after_num != '\0' && isspace((unsigned char) *after_num))
     900           0 :         after_num++;
     901             : 
     902           0 :     if (*after_num != '\0')
     903             :     {
     904           0 :         suffix = after_num;
     905           0 :         if (*after_num == 'k')
     906             :         {
     907             :             /* kilobyte is the expected unit. */
     908           0 :             after_num++;
     909             :         }
     910           0 :         else if (*after_num == 'M')
     911             :         {
     912           0 :             after_num++;
     913           0 :             result *= 1024.0;
     914             :         }
     915             :     }
     916             : 
     917             :     /* The rest can only consist of white space. */
     918           0 :     while (*after_num != '\0' && isspace((unsigned char) *after_num))
     919           0 :         after_num++;
     920             : 
     921           0 :     if (*after_num != '\0')
     922             :     {
     923           0 :         pg_log_error("invalid --max-rate unit: \"%s\"", suffix);
     924           0 :         exit(1);
     925             :     }
     926             : 
     927             :     /* Valid integer? */
     928           0 :     if ((uint64) result != (uint64) ((uint32) result))
     929             :     {
     930           0 :         pg_log_error("transfer rate \"%s\" exceeds integer range", src);
     931           0 :         exit(1);
     932             :     }
     933             : 
     934             :     /*
     935             :      * The range is checked on the server side too, but avoid the server
     936             :      * connection if a nonsensical value was passed.
     937             :      */
     938           0 :     if (result < MAX_RATE_LOWER || result > MAX_RATE_UPPER)
     939             :     {
     940           0 :         pg_log_error("transfer rate \"%s\" is out of range", src);
     941           0 :         exit(1);
     942             :     }
     943             : 
     944           0 :     return (int32) result;
     945             : }
     946             : 
     947             : /*
     948             :  * Read a stream of COPY data and invoke the provided callback for each
     949             :  * chunk.
     950             :  */
     951             : static void
     952         328 : ReceiveCopyData(PGconn *conn, WriteDataCallback callback,
     953             :                 void *callback_data)
     954             : {
     955             :     PGresult   *res;
     956             : 
     957             :     /* Get the COPY data stream. */
     958         328 :     res = PQgetResult(conn);
     959         328 :     if (PQresultStatus(res) != PGRES_COPY_OUT)
     960             :     {
     961           2 :         pg_log_error("could not get COPY data stream: %s",
     962             :                      PQerrorMessage(conn));
     963           2 :         exit(1);
     964             :     }
     965         326 :     PQclear(res);
     966             : 
     967             :     /* Loop over chunks until done. */
     968             :     while (1)
     969      327000 :     {
     970             :         int         r;
     971             :         char       *copybuf;
     972             : 
     973      327326 :         r = PQgetCopyData(conn, &copybuf, 0);
     974      327326 :         if (r == -1)
     975             :         {
     976             :             /* End of chunk. */
     977         326 :             break;
     978             :         }
     979      327000 :         else if (r == -2)
     980             :         {
     981           0 :             pg_log_error("could not read COPY data: %s",
     982             :                          PQerrorMessage(conn));
     983           0 :             exit(1);
     984             :         }
     985             : 
     986      327000 :         (*callback) (r, copybuf, callback_data);
     987             : 
     988      327000 :         PQfreemem(copybuf);
     989             :     }
     990         326 : }
     991             : 
     992             : /*
     993             :  * Write a piece of tar data
     994             :  */
     995             : static void
     996       17430 : writeTarData(WriteTarState *state, char *buf, int r)
     997             : {
     998             : #ifdef HAVE_LIBZ
     999       17430 :     if (state->ztarfile != NULL)
    1000             :     {
    1001           0 :         errno = 0;
    1002           0 :         if (gzwrite(state->ztarfile, buf, r) != r)
    1003             :         {
    1004             :             /* if write didn't set errno, assume problem is no disk space */
    1005           0 :             if (errno == 0)
    1006           0 :                 errno = ENOSPC;
    1007           0 :             pg_log_error("could not write to compressed file \"%s\": %s",
    1008             :                          state->filename, get_gz_error(state->ztarfile));
    1009           0 :             exit(1);
    1010             :         }
    1011             :     }
    1012             :     else
    1013             : #endif
    1014             :     {
    1015       17430 :         errno = 0;
    1016       17430 :         if (fwrite(buf, r, 1, state->tarfile) != 1)
    1017             :         {
    1018             :             /* if write didn't set errno, assume problem is no disk space */
    1019           0 :             if (errno == 0)
    1020           0 :                 errno = ENOSPC;
    1021           0 :             pg_log_error("could not write to file \"%s\": %m",
    1022             :                          state->filename);
    1023           0 :             exit(1);
    1024             :         }
    1025             :     }
    1026       17430 : }
    1027             : 
    1028             : /*
    1029             :  * Receive a tar format file from the connection to the server, and write
    1030             :  * the data from this file directly into a tar file. If compression is
    1031             :  * enabled, the data will be compressed while written to the file.
    1032             :  *
    1033             :  * The file will be named base.tar[.gz] if it's for the main data directory
    1034             :  * or <tablespaceoid>.tar[.gz] if it's for another tablespace.
    1035             :  *
    1036             :  * No attempt to inspect or validate the contents of the file is done.
    1037             :  */
    1038             : static void
    1039          14 : ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
    1040             : {
    1041             :     char        zerobuf[TAR_BLOCK_SIZE * 2];
    1042             :     WriteTarState state;
    1043             : 
    1044          14 :     memset(&state, 0, sizeof(state));
    1045          14 :     state.tablespacenum = rownum;
    1046          14 :     state.basetablespace = PQgetisnull(res, rownum, 0);
    1047          14 :     state.in_tarhdr = true;
    1048             : 
    1049             :     /* recovery.conf is integrated into postgresql.conf in 12 and newer */
    1050          14 :     if (PQserverVersion(conn) >= MINIMUM_VERSION_FOR_RECOVERY_GUC)
    1051          14 :         state.is_recovery_guc_supported = true;
    1052             : 
    1053          14 :     if (state.basetablespace)
    1054             :     {
    1055             :         /*
    1056             :          * Base tablespaces
    1057             :          */
    1058          10 :         if (strcmp(basedir, "-") == 0)
    1059             :         {
    1060             : #ifdef WIN32
    1061             :             _setmode(fileno(stdout), _O_BINARY);
    1062             : #endif
    1063             : 
    1064             : #ifdef HAVE_LIBZ
    1065           0 :             if (compresslevel != 0)
    1066             :             {
    1067           0 :                 int         fd = dup(fileno(stdout));
    1068             : 
    1069           0 :                 if (fd < 0)
    1070             :                 {
    1071           0 :                     pg_log_error("could not duplicate stdout: %m");
    1072           0 :                     exit(1);
    1073             :                 }
    1074             : 
    1075           0 :                 state.ztarfile = gzdopen(fd, "wb");
    1076           0 :                 if (state.ztarfile == NULL)
    1077             :                 {
    1078           0 :                     pg_log_error("could not open output file: %m");
    1079           0 :                     exit(1);
    1080             :                 }
    1081             : 
    1082           0 :                 if (gzsetparams(state.ztarfile, compresslevel,
    1083             :                                 Z_DEFAULT_STRATEGY) != Z_OK)
    1084             :                 {
    1085           0 :                     pg_log_error("could not set compression level %d: %s",
    1086             :                                  compresslevel, get_gz_error(state.ztarfile));
    1087           0 :                     exit(1);
    1088             :                 }
    1089             :             }
    1090             :             else
    1091             : #endif
    1092           0 :                 state.tarfile = stdout;
    1093           0 :             strcpy(state.filename, "-");
    1094             :         }
    1095             :         else
    1096             :         {
    1097             : #ifdef HAVE_LIBZ
    1098          10 :             if (compresslevel != 0)
    1099             :             {
    1100           0 :                 snprintf(state.filename, sizeof(state.filename),
    1101             :                          "%s/base.tar.gz", basedir);
    1102           0 :                 state.ztarfile = gzopen(state.filename, "wb");
    1103           0 :                 if (gzsetparams(state.ztarfile, compresslevel,
    1104             :                                 Z_DEFAULT_STRATEGY) != Z_OK)
    1105             :                 {
    1106           0 :                     pg_log_error("could not set compression level %d: %s",
    1107             :                                  compresslevel, get_gz_error(state.ztarfile));
    1108           0 :                     exit(1);
    1109             :                 }
    1110             :             }
    1111             :             else
    1112             : #endif
    1113             :             {
    1114          10 :                 snprintf(state.filename, sizeof(state.filename),
    1115             :                          "%s/base.tar", basedir);
    1116          10 :                 state.tarfile = fopen(state.filename, "wb");
    1117             :             }
    1118             :         }
    1119             :     }
    1120             :     else
    1121             :     {
    1122             :         /*
    1123             :          * Specific tablespace
    1124             :          */
    1125             : #ifdef HAVE_LIBZ
    1126           4 :         if (compresslevel != 0)
    1127             :         {
    1128           0 :             snprintf(state.filename, sizeof(state.filename),
    1129             :                      "%s/%s.tar.gz",
    1130             :                      basedir, PQgetvalue(res, rownum, 0));
    1131           0 :             state.ztarfile = gzopen(state.filename, "wb");
    1132           0 :             if (gzsetparams(state.ztarfile, compresslevel,
    1133             :                             Z_DEFAULT_STRATEGY) != Z_OK)
    1134             :             {
    1135           0 :                 pg_log_error("could not set compression level %d: %s",
    1136             :                              compresslevel, get_gz_error(state.ztarfile));
    1137           0 :                 exit(1);
    1138             :             }
    1139             :         }
    1140             :         else
    1141             : #endif
    1142             :         {
    1143           4 :             snprintf(state.filename, sizeof(state.filename), "%s/%s.tar",
    1144             :                      basedir, PQgetvalue(res, rownum, 0));
    1145           4 :             state.tarfile = fopen(state.filename, "wb");
    1146             :         }
    1147             :     }
    1148             : 
    1149             : #ifdef HAVE_LIBZ
    1150          14 :     if (compresslevel != 0)
    1151             :     {
    1152           0 :         if (!state.ztarfile)
    1153             :         {
    1154             :             /* Compression is in use */
    1155           0 :             pg_log_error("could not create compressed file \"%s\": %s",
    1156             :                          state.filename, get_gz_error(state.ztarfile));
    1157           0 :             exit(1);
    1158             :         }
    1159             :     }
    1160             :     else
    1161             : #endif
    1162             :     {
    1163             :         /* Either no zlib support, or zlib support but compresslevel = 0 */
    1164          14 :         if (!state.tarfile)
    1165             :         {
    1166           0 :             pg_log_error("could not create file \"%s\": %m", state.filename);
    1167           0 :             exit(1);
    1168             :         }
    1169             :     }
    1170             : 
    1171          14 :     ReceiveCopyData(conn, ReceiveTarCopyChunk, &state);
    1172             : 
    1173             :     /*
    1174             :      * End of copy data. If requested, and this is the base tablespace, write
    1175             :      * configuration file into the tarfile. When done, close the file (but not
    1176             :      * stdout).
    1177             :      *
    1178             :      * Also, write two completely empty blocks at the end of the tar file, as
    1179             :      * required by some tar programs.
    1180             :      */
    1181             : 
    1182        1806 :     MemSet(zerobuf, 0, sizeof(zerobuf));
    1183             : 
    1184          14 :     if (state.basetablespace && writerecoveryconf)
    1185             :     {
    1186             :         char        header[TAR_BLOCK_SIZE];
    1187             : 
    1188             :         /*
    1189             :          * If postgresql.auto.conf has not been found in the streamed data,
    1190             :          * add recovery configuration to postgresql.auto.conf if recovery
    1191             :          * parameters are GUCs.  If the instance connected to is older than
    1192             :          * 12, create recovery.conf with this data otherwise.
    1193             :          */
    1194           0 :         if (!state.found_postgresql_auto_conf || !state.is_recovery_guc_supported)
    1195             :         {
    1196             :             int         padding;
    1197             : 
    1198           0 :             tarCreateHeader(header,
    1199           0 :                             state.is_recovery_guc_supported ? "postgresql.auto.conf" : "recovery.conf",
    1200             :                             NULL,
    1201           0 :                             recoveryconfcontents->len,
    1202             :                             pg_file_create_mode, 04000, 02000,
    1203             :                             time(NULL));
    1204             : 
    1205           0 :             padding = tarPaddingBytesRequired(recoveryconfcontents->len);
    1206             : 
    1207           0 :             writeTarData(&state, header, sizeof(header));
    1208           0 :             writeTarData(&state, recoveryconfcontents->data,
    1209           0 :                          recoveryconfcontents->len);
    1210           0 :             if (padding)
    1211           0 :                 writeTarData(&state, zerobuf, padding);
    1212             :         }
    1213             : 
    1214             :         /*
    1215             :          * standby.signal is supported only if recovery parameters are GUCs.
    1216             :          */
    1217           0 :         if (state.is_recovery_guc_supported)
    1218             :         {
    1219           0 :             tarCreateHeader(header, "standby.signal", NULL,
    1220             :                             0,  /* zero-length file */
    1221             :                             pg_file_create_mode, 04000, 02000,
    1222             :                             time(NULL));
    1223             : 
    1224           0 :             writeTarData(&state, header, sizeof(header));
    1225             : 
    1226             :             /*
    1227             :              * we don't need to pad out to a multiple of the tar block size
    1228             :              * here, because the file is zero length, which is a multiple of
    1229             :              * any block size.
    1230             :              */
    1231             :         }
    1232             :     }
    1233             : 
    1234             :     /*
    1235             :      * Normally, we emit the backup manifest as a separate file, but when
    1236             :      * we're writing a tarfile to stdout, we don't have that option, so
    1237             :      * include it in the one tarfile we've got.
    1238             :      */
    1239          14 :     if (strcmp(basedir, "-") == 0 && manifest)
    1240             :     {
    1241             :         char        header[TAR_BLOCK_SIZE];
    1242             :         PQExpBufferData buf;
    1243             : 
    1244           0 :         initPQExpBuffer(&buf);
    1245           0 :         ReceiveBackupManifestInMemory(conn, &buf);
    1246           0 :         if (PQExpBufferDataBroken(buf))
    1247             :         {
    1248           0 :             pg_log_error("out of memory");
    1249           0 :             exit(1);
    1250             :         }
    1251           0 :         tarCreateHeader(header, "backup_manifest", NULL, buf.len,
    1252             :                         pg_file_create_mode, 04000, 02000,
    1253             :                         time(NULL));
    1254           0 :         writeTarData(&state, header, sizeof(header));
    1255           0 :         writeTarData(&state, buf.data, buf.len);
    1256           0 :         termPQExpBuffer(&buf);
    1257             :     }
    1258             : 
    1259             :     /* 2 * TAR_BLOCK_SIZE bytes empty data at end of file */
    1260          14 :     writeTarData(&state, zerobuf, sizeof(zerobuf));
    1261             : 
    1262             : #ifdef HAVE_LIBZ
    1263          14 :     if (state.ztarfile != NULL)
    1264             :     {
    1265           0 :         if (gzclose(state.ztarfile) != 0)
    1266             :         {
    1267           0 :             pg_log_error("could not close compressed file \"%s\": %s",
    1268             :                          state.filename, get_gz_error(state.ztarfile));
    1269           0 :             exit(1);
    1270             :         }
    1271             :     }
    1272             :     else
    1273             : #endif
    1274             :     {
    1275          14 :         if (strcmp(basedir, "-") != 0)
    1276             :         {
    1277          14 :             if (fclose(state.tarfile) != 0)
    1278             :             {
    1279           0 :                 pg_log_error("could not close file \"%s\": %m",
    1280             :                              state.filename);
    1281           0 :                 exit(1);
    1282             :             }
    1283             :         }
    1284             :     }
    1285             : 
    1286          14 :     progress_report(rownum, state.filename, true, false);
    1287             : 
    1288             :     /*
    1289             :      * Do not sync the resulting tar file yet, all files are synced once at
    1290             :      * the end.
    1291             :      */
    1292          14 : }
    1293             : 
    1294             : /*
    1295             :  * Receive one chunk of tar-format data from the server.
    1296             :  */
    1297             : static void
    1298       17416 : ReceiveTarCopyChunk(size_t r, char *copybuf, void *callback_data)
    1299             : {
    1300       17416 :     WriteTarState *state = callback_data;
    1301             : 
    1302       17416 :     if (!writerecoveryconf || !state->basetablespace)
    1303             :     {
    1304             :         /*
    1305             :          * When not writing config file, or when not working on the base
    1306             :          * tablespace, we never have to look for an existing configuration
    1307             :          * file in the stream.
    1308             :          */
    1309       17416 :         writeTarData(state, copybuf, r);
    1310             :     }
    1311             :     else
    1312             :     {
    1313             :         /*
    1314             :          * Look for a config file in the existing tar stream. If it's there,
    1315             :          * we must skip it so we can later overwrite it with our own version
    1316             :          * of the file.
    1317             :          *
    1318             :          * To do this, we have to process the individual files inside the TAR
    1319             :          * stream. The stream consists of a header and zero or more chunks,
    1320             :          * each with a length equal to TAR_BLOCK_SIZE. The stream from the
    1321             :          * server is broken up into smaller pieces, so we have to track the
    1322             :          * size of the files to find the next header structure.
    1323             :          */
    1324           0 :         int         rr = r;
    1325           0 :         int         pos = 0;
    1326             : 
    1327           0 :         while (rr > 0)
    1328             :         {
    1329           0 :             if (state->in_tarhdr)
    1330             :             {
    1331             :                 /*
    1332             :                  * We're currently reading a header structure inside the TAR
    1333             :                  * stream, i.e. the file metadata.
    1334             :                  */
    1335           0 :                 if (state->tarhdrsz < TAR_BLOCK_SIZE)
    1336             :                 {
    1337             :                     /*
    1338             :                      * Copy the header structure into tarhdr in case the
    1339             :                      * header is not aligned properly or it's not returned in
    1340             :                      * whole by the last PQgetCopyData call.
    1341             :                      */
    1342             :                     int         hdrleft;
    1343             :                     int         bytes2copy;
    1344             : 
    1345           0 :                     hdrleft = TAR_BLOCK_SIZE - state->tarhdrsz;
    1346           0 :                     bytes2copy = (rr > hdrleft ? hdrleft : rr);
    1347             : 
    1348           0 :                     memcpy(&state->tarhdr[state->tarhdrsz], copybuf + pos,
    1349             :                            bytes2copy);
    1350             : 
    1351           0 :                     rr -= bytes2copy;
    1352           0 :                     pos += bytes2copy;
    1353           0 :                     state->tarhdrsz += bytes2copy;
    1354             :                 }
    1355             :                 else
    1356             :                 {
    1357             :                     /*
    1358             :                      * We have the complete header structure in tarhdr, look
    1359             :                      * at the file metadata: we may want append recovery info
    1360             :                      * into postgresql.auto.conf and skip standby.signal file
    1361             :                      * if recovery parameters are integrated as GUCs, and
    1362             :                      * recovery.conf otherwise. In both cases we must
    1363             :                      * calculate tar padding.
    1364             :                      */
    1365           0 :                     if (state->is_recovery_guc_supported)
    1366             :                     {
    1367           0 :                         state->skip_file =
    1368           0 :                             (strcmp(&state->tarhdr[0], "standby.signal") == 0);
    1369           0 :                         state->is_postgresql_auto_conf =
    1370           0 :                             (strcmp(&state->tarhdr[0], "postgresql.auto.conf") == 0);
    1371             :                     }
    1372             :                     else
    1373           0 :                         state->skip_file =
    1374           0 :                             (strcmp(&state->tarhdr[0], "recovery.conf") == 0);
    1375             : 
    1376           0 :                     state->filesz = read_tar_number(&state->tarhdr[124], 12);
    1377           0 :                     state->file_padding_len =
    1378           0 :                         tarPaddingBytesRequired(state->filesz);
    1379             : 
    1380           0 :                     if (state->is_recovery_guc_supported &&
    1381           0 :                         state->is_postgresql_auto_conf &&
    1382             :                         writerecoveryconf)
    1383           0 :                     {
    1384             :                         /* replace tar header */
    1385             :                         char        header[TAR_BLOCK_SIZE];
    1386             : 
    1387           0 :                         tarCreateHeader(header, "postgresql.auto.conf", NULL,
    1388           0 :                                         state->filesz + recoveryconfcontents->len,
    1389             :                                         pg_file_create_mode, 04000, 02000,
    1390             :                                         time(NULL));
    1391             : 
    1392           0 :                         writeTarData(state, header, sizeof(header));
    1393             :                     }
    1394             :                     else
    1395             :                     {
    1396             :                         /* copy stream with padding */
    1397           0 :                         state->filesz += state->file_padding_len;
    1398             : 
    1399           0 :                         if (!state->skip_file)
    1400             :                         {
    1401             :                             /*
    1402             :                              * If we're not skipping the file, write the tar
    1403             :                              * header unmodified.
    1404             :                              */
    1405           0 :                             writeTarData(state, state->tarhdr, TAR_BLOCK_SIZE);
    1406             :                         }
    1407             :                     }
    1408             : 
    1409             :                     /* Next part is the file, not the header */
    1410           0 :                     state->in_tarhdr = false;
    1411             :                 }
    1412             :             }
    1413             :             else
    1414             :             {
    1415             :                 /*
    1416             :                  * We're processing a file's contents.
    1417             :                  */
    1418           0 :                 if (state->filesz > 0)
    1419             :                 {
    1420             :                     /*
    1421             :                      * We still have data to read (and possibly write).
    1422             :                      */
    1423             :                     int         bytes2write;
    1424             : 
    1425           0 :                     bytes2write = (state->filesz > rr ? rr : state->filesz);
    1426             : 
    1427           0 :                     if (!state->skip_file)
    1428           0 :                         writeTarData(state, copybuf + pos, bytes2write);
    1429             : 
    1430           0 :                     rr -= bytes2write;
    1431           0 :                     pos += bytes2write;
    1432           0 :                     state->filesz -= bytes2write;
    1433             :                 }
    1434           0 :                 else if (state->is_recovery_guc_supported &&
    1435           0 :                          state->is_postgresql_auto_conf &&
    1436             :                          writerecoveryconf)
    1437           0 :                 {
    1438             :                     /* append recovery config to postgresql.auto.conf */
    1439             :                     int         padding;
    1440             :                     int         tailsize;
    1441             : 
    1442           0 :                     tailsize = (TAR_BLOCK_SIZE - state->file_padding_len) + recoveryconfcontents->len;
    1443           0 :                     padding = tarPaddingBytesRequired(tailsize);
    1444             : 
    1445           0 :                     writeTarData(state, recoveryconfcontents->data,
    1446           0 :                                  recoveryconfcontents->len);
    1447             : 
    1448           0 :                     if (padding)
    1449             :                     {
    1450             :                         char        zerobuf[TAR_BLOCK_SIZE];
    1451             : 
    1452           0 :                         MemSet(zerobuf, 0, sizeof(zerobuf));
    1453           0 :                         writeTarData(state, zerobuf, padding);
    1454             :                     }
    1455             : 
    1456             :                     /* skip original file padding */
    1457           0 :                     state->is_postgresql_auto_conf = false;
    1458           0 :                     state->skip_file = true;
    1459           0 :                     state->filesz += state->file_padding_len;
    1460             : 
    1461           0 :                     state->found_postgresql_auto_conf = true;
    1462             :                 }
    1463             :                 else
    1464             :                 {
    1465             :                     /*
    1466             :                      * No more data in the current file, the next piece of
    1467             :                      * data (if any) will be a new file header structure.
    1468             :                      */
    1469           0 :                     state->in_tarhdr = true;
    1470           0 :                     state->skip_file = false;
    1471           0 :                     state->is_postgresql_auto_conf = false;
    1472           0 :                     state->tarhdrsz = 0;
    1473           0 :                     state->filesz = 0;
    1474             :                 }
    1475             :             }
    1476             :         }
    1477             :     }
    1478       17416 :     totaldone += r;
    1479       17416 :     progress_report(state->tablespacenum, state->filename, false, false);
    1480       17416 : }
    1481             : 
    1482             : 
    1483             : /*
    1484             :  * Retrieve tablespace path, either relocated or original depending on whether
    1485             :  * -T was passed or not.
    1486             :  */
    1487             : static const char *
    1488          80 : get_tablespace_mapping(const char *dir)
    1489             : {
    1490             :     TablespaceListCell *cell;
    1491             :     char        canon_dir[MAXPGPATH];
    1492             : 
    1493             :     /* Canonicalize path for comparison consistency */
    1494          80 :     strlcpy(canon_dir, dir, sizeof(canon_dir));
    1495          80 :     canonicalize_path(canon_dir);
    1496             : 
    1497          80 :     for (cell = tablespace_dirs.head; cell; cell = cell->next)
    1498          78 :         if (strcmp(canon_dir, cell->old_dir) == 0)
    1499          78 :             return cell->new_dir;
    1500             : 
    1501           2 :     return dir;
    1502             : }
    1503             : 
    1504             : 
    1505             : /*
    1506             :  * Receive a tar format stream from the connection to the server, and unpack
    1507             :  * the contents of it into a directory. Only files, directories and
    1508             :  * symlinks are supported, no other kinds of special files.
    1509             :  *
    1510             :  * If the data is for the main data directory, it will be restored in the
    1511             :  * specified directory. If it's for another tablespace, it will be restored
    1512             :  * in the original or mapped directory.
    1513             :  */
    1514             : static void
    1515         166 : ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
    1516             : {
    1517             :     UnpackTarState state;
    1518             :     bool        basetablespace;
    1519             : 
    1520         166 :     memset(&state, 0, sizeof(state));
    1521         166 :     state.tablespacenum = rownum;
    1522             : 
    1523         166 :     basetablespace = PQgetisnull(res, rownum, 0);
    1524         166 :     if (basetablespace)
    1525         140 :         strlcpy(state.current_path, basedir, sizeof(state.current_path));
    1526             :     else
    1527          26 :         strlcpy(state.current_path,
    1528          26 :                 get_tablespace_mapping(PQgetvalue(res, rownum, 1)),
    1529             :                 sizeof(state.current_path));
    1530             : 
    1531         166 :     ReceiveCopyData(conn, ReceiveTarAndUnpackCopyChunk, &state);
    1532             : 
    1533             : 
    1534         166 :     if (state.file)
    1535           0 :         fclose(state.file);
    1536             : 
    1537         166 :     progress_report(rownum, state.filename, true, false);
    1538             : 
    1539         166 :     if (state.file != NULL)
    1540             :     {
    1541           0 :         pg_log_error("COPY stream ended before last file was finished");
    1542           0 :         exit(1);
    1543             :     }
    1544             : 
    1545         166 :     if (basetablespace && writerecoveryconf)
    1546           4 :         WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
    1547             : 
    1548             :     /*
    1549             :      * No data is synced here, everything is done for all tablespaces at the
    1550             :      * end.
    1551             :      */
    1552         166 : }
    1553             : 
    1554             : static void
    1555      307016 : ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf, void *callback_data)
    1556             : {
    1557      307016 :     UnpackTarState *state = callback_data;
    1558             : 
    1559      307016 :     if (state->file == NULL)
    1560             :     {
    1561             : #ifndef WIN32
    1562             :         int         filemode;
    1563             : #endif
    1564             : 
    1565             :         /*
    1566             :          * No current file, so this must be the header for a new file
    1567             :          */
    1568      136240 :         if (r != TAR_BLOCK_SIZE)
    1569             :         {
    1570           0 :             pg_log_error("invalid tar block header size: %zu", r);
    1571           0 :             exit(1);
    1572             :         }
    1573      136240 :         totaldone += TAR_BLOCK_SIZE;
    1574             : 
    1575      136240 :         state->current_len_left = read_tar_number(&copybuf[124], 12);
    1576             : 
    1577             : #ifndef WIN32
    1578             :         /* Set permissions on the file */
    1579      136240 :         filemode = read_tar_number(&copybuf[100], 8);
    1580             : #endif
    1581             : 
    1582             :         /*
    1583             :          * All files are padded up to a multiple of TAR_BLOCK_SIZE
    1584             :          */
    1585      136240 :         state->current_padding =
    1586      136240 :             tarPaddingBytesRequired(state->current_len_left);
    1587             : 
    1588             :         /*
    1589             :          * First part of header is zero terminated filename
    1590             :          */
    1591      136240 :         snprintf(state->filename, sizeof(state->filename),
    1592      136240 :                  "%s/%s", state->current_path, copybuf);
    1593      136240 :         if (state->filename[strlen(state->filename) - 1] == '/')
    1594             :         {
    1595             :             /*
    1596             :              * Ends in a slash means directory or symlink to directory
    1597             :              */
    1598        3588 :             if (copybuf[156] == '5')
    1599             :             {
    1600             :                 /*
    1601             :                  * Directory. Remove trailing slash first.
    1602             :                  */
    1603        3562 :                 state->filename[strlen(state->filename) - 1] = '\0';
    1604        3562 :                 if (mkdir(state->filename, pg_dir_create_mode) != 0)
    1605             :                 {
    1606             :                     /*
    1607             :                      * When streaming WAL, pg_wal (or pg_xlog for pre-9.6
    1608             :                      * clusters) will have been created by the wal receiver
    1609             :                      * process. Also, when the WAL directory location was
    1610             :                      * specified, pg_wal (or pg_xlog) has already been created
    1611             :                      * as a symbolic link before starting the actual backup.
    1612             :                      * So just ignore creation failures on related
    1613             :                      * directories.
    1614             :                      */
    1615         408 :                     if (!((pg_str_endswith(state->filename, "/pg_wal") ||
    1616         272 :                            pg_str_endswith(state->filename, "/pg_xlog") ||
    1617         136 :                            pg_str_endswith(state->filename, "/archive_status")) &&
    1618         272 :                           errno == EEXIST))
    1619             :                     {
    1620           0 :                         pg_log_error("could not create directory \"%s\": %m",
    1621             :                                      state->filename);
    1622           0 :                         exit(1);
    1623             :                     }
    1624             :                 }
    1625             : #ifndef WIN32
    1626        3562 :                 if (chmod(state->filename, (mode_t) filemode))
    1627           0 :                     pg_log_error("could not set permissions on directory \"%s\": %m",
    1628             :                                  state->filename);
    1629             : #endif
    1630             :             }
    1631          26 :             else if (copybuf[156] == '2')
    1632             :             {
    1633             :                 /*
    1634             :                  * Symbolic link
    1635             :                  *
    1636             :                  * It's most likely a link in pg_tblspc directory, to the
    1637             :                  * location of a tablespace. Apply any tablespace mapping
    1638             :                  * given on the command line (--tablespace-mapping). (We
    1639             :                  * blindly apply the mapping without checking that the link
    1640             :                  * really is inside pg_tblspc. We don't expect there to be
    1641             :                  * other symlinks in a data directory, but if there are, you
    1642             :                  * can call it an undocumented feature that you can map them
    1643             :                  * too.)
    1644             :                  */
    1645          26 :                 state->filename[strlen(state->filename) - 1] = '\0';  /* Remove trailing slash */
    1646             : 
    1647          26 :                 state->mapped_tblspc_path =
    1648          26 :                     get_tablespace_mapping(&copybuf[157]);
    1649          26 :                 if (symlink(state->mapped_tblspc_path, state->filename) != 0)
    1650             :                 {
    1651           0 :                     pg_log_error("could not create symbolic link from \"%s\" to \"%s\": %m",
    1652             :                                  state->filename, state->mapped_tblspc_path);
    1653           0 :                     exit(1);
    1654             :                 }
    1655             :             }
    1656             :             else
    1657             :             {
    1658           0 :                 pg_log_error("unrecognized link indicator \"%c\"",
    1659             :                              copybuf[156]);
    1660           0 :                 exit(1);
    1661             :             }
    1662        3588 :             return;             /* directory or link handled */
    1663             :         }
    1664             : 
    1665             :         /*
    1666             :          * regular file
    1667             :          */
    1668      132652 :         state->file = fopen(state->filename, "wb");
    1669      132652 :         if (!state->file)
    1670             :         {
    1671           0 :             pg_log_error("could not create file \"%s\": %m", state->filename);
    1672           0 :             exit(1);
    1673             :         }
    1674             : 
    1675             : #ifndef WIN32
    1676      132652 :         if (chmod(state->filename, (mode_t) filemode))
    1677           0 :             pg_log_error("could not set permissions on file \"%s\": %m",
    1678             :                          state->filename);
    1679             : #endif
    1680             : 
    1681      132652 :         if (state->current_len_left == 0)
    1682             :         {
    1683             :             /*
    1684             :              * Done with this file, next one will be a new tar header
    1685             :              */
    1686       22988 :             fclose(state->file);
    1687       22988 :             state->file = NULL;
    1688       22988 :             return;
    1689             :         }
    1690             :     }                           /* new file */
    1691             :     else
    1692             :     {
    1693             :         /*
    1694             :          * Continuing blocks in existing file
    1695             :          */
    1696      170776 :         if (state->current_len_left == 0 && r == state->current_padding)
    1697             :         {
    1698             :             /*
    1699             :              * Received the padding block for this file, ignore it and close
    1700             :              * the file, then move on to the next tar header.
    1701             :              */
    1702        1488 :             fclose(state->file);
    1703        1488 :             state->file = NULL;
    1704        1488 :             totaldone += r;
    1705        1488 :             return;
    1706             :         }
    1707             : 
    1708      169288 :         errno = 0;
    1709      169288 :         if (fwrite(copybuf, r, 1, state->file) != 1)
    1710             :         {
    1711             :             /* if write didn't set errno, assume problem is no disk space */
    1712           0 :             if (errno == 0)
    1713           0 :                 errno = ENOSPC;
    1714           0 :             pg_log_error("could not write to file \"%s\": %m", state->filename);
    1715           0 :             exit(1);
    1716             :         }
    1717      169288 :         totaldone += r;
    1718      169288 :         progress_report(state->tablespacenum, state->filename, false, false);
    1719             : 
    1720      169288 :         state->current_len_left -= r;
    1721      169288 :         if (state->current_len_left == 0 && state->current_padding == 0)
    1722             :         {
    1723             :             /*
    1724             :              * Received the last block, and there is no padding to be
    1725             :              * expected. Close the file and move on to the next tar header.
    1726             :              */
    1727      108176 :             fclose(state->file);
    1728      108176 :             state->file = NULL;
    1729      108176 :             return;
    1730             :         }
    1731             :     }                           /* continuing data in existing file */
    1732             : }
    1733             : 
    1734             : /*
    1735             :  * Receive the backup manifest file and write it out to a file.
    1736             :  */
    1737             : static void
    1738         148 : ReceiveBackupManifest(PGconn *conn)
    1739             : {
    1740             :     WriteManifestState state;
    1741             : 
    1742         148 :     snprintf(state.filename, sizeof(state.filename),
    1743             :              "%s/backup_manifest.tmp", basedir);
    1744         148 :     state.file = fopen(state.filename, "wb");
    1745         148 :     if (state.file == NULL)
    1746             :     {
    1747           0 :         pg_log_error("could not create file \"%s\": %m", state.filename);
    1748           0 :         exit(1);
    1749             :     }
    1750             : 
    1751         148 :     ReceiveCopyData(conn, ReceiveBackupManifestChunk, &state);
    1752             : 
    1753         146 :     fclose(state.file);
    1754         146 : }
    1755             : 
    1756             : /*
    1757             :  * Receive one chunk of the backup manifest file and write it out to a file.
    1758             :  */
    1759             : static void
    1760        2568 : ReceiveBackupManifestChunk(size_t r, char *copybuf, void *callback_data)
    1761             : {
    1762        2568 :     WriteManifestState *state = callback_data;
    1763             : 
    1764        2568 :     errno = 0;
    1765        2568 :     if (fwrite(copybuf, r, 1, state->file) != 1)
    1766             :     {
    1767             :         /* if write didn't set errno, assume problem is no disk space */
    1768           0 :         if (errno == 0)
    1769           0 :             errno = ENOSPC;
    1770           0 :         pg_log_error("could not write to file \"%s\": %m", state->filename);
    1771           0 :         exit(1);
    1772             :     }
    1773        2568 : }
    1774             : 
    1775             : /*
    1776             :  * Receive the backup manifest file and write it out to a file.
    1777             :  */
    1778             : static void
    1779           0 : ReceiveBackupManifestInMemory(PGconn *conn, PQExpBuffer buf)
    1780             : {
    1781           0 :     ReceiveCopyData(conn, ReceiveBackupManifestInMemoryChunk, buf);
    1782           0 : }
    1783             : 
    1784             : /*
    1785             :  * Receive one chunk of the backup manifest file and write it out to a file.
    1786             :  */
    1787             : static void
    1788           0 : ReceiveBackupManifestInMemoryChunk(size_t r, char *copybuf,
    1789             :                                    void *callback_data)
    1790             : {
    1791           0 :     PQExpBuffer buf = callback_data;
    1792             : 
    1793           0 :     appendPQExpBuffer(buf, copybuf, r);
    1794           0 : }
    1795             : 
    1796             : static void
    1797         156 : BaseBackup(void)
    1798             : {
    1799             :     PGresult   *res;
    1800             :     char       *sysidentifier;
    1801             :     TimeLineID  latesttli;
    1802             :     TimeLineID  starttli;
    1803             :     char       *basebkp;
    1804             :     char        escaped_label[MAXPGPATH];
    1805         156 :     char       *maxrate_clause = NULL;
    1806         156 :     char       *manifest_clause = NULL;
    1807         156 :     char       *manifest_checksums_clause = "";
    1808             :     int         i;
    1809             :     char        xlogstart[64];
    1810             :     char        xlogend[64];
    1811             :     int         minServerMajor,
    1812             :                 maxServerMajor;
    1813             :     int         serverVersion,
    1814             :                 serverMajor;
    1815             :     int         writing_to_stdout;
    1816             : 
    1817             :     Assert(conn != NULL);
    1818             : 
    1819             :     /*
    1820             :      * Check server version. BASE_BACKUP command was introduced in 9.1, so we
    1821             :      * can't work with servers older than 9.1.
    1822             :      */
    1823         156 :     minServerMajor = 901;
    1824         156 :     maxServerMajor = PG_VERSION_NUM / 100;
    1825         156 :     serverVersion = PQserverVersion(conn);
    1826         156 :     serverMajor = serverVersion / 100;
    1827         156 :     if (serverMajor < minServerMajor || serverMajor > maxServerMajor)
    1828             :     {
    1829           0 :         const char *serverver = PQparameterStatus(conn, "server_version");
    1830             : 
    1831           0 :         pg_log_error("incompatible server version %s",
    1832             :                      serverver ? serverver : "'unknown'");
    1833           0 :         exit(1);
    1834             :     }
    1835             : 
    1836             :     /*
    1837             :      * If WAL streaming was requested, also check that the server is new
    1838             :      * enough for that.
    1839             :      */
    1840         156 :     if (includewal == STREAM_WAL && !CheckServerVersionForStreaming(conn))
    1841             :     {
    1842             :         /*
    1843             :          * Error message already written in CheckServerVersionForStreaming(),
    1844             :          * but add a hint about using -X none.
    1845             :          */
    1846           0 :         pg_log_info("HINT: use -X none or -X fetch to disable log streaming");
    1847           0 :         exit(1);
    1848             :     }
    1849             : 
    1850             :     /*
    1851             :      * Build contents of configuration file if requested
    1852             :      */
    1853         156 :     if (writerecoveryconf)
    1854           4 :         recoveryconfcontents = GenerateRecoveryConfig(conn, replication_slot);
    1855             : 
    1856             :     /*
    1857             :      * Run IDENTIFY_SYSTEM so we can get the timeline
    1858             :      */
    1859         156 :     if (!RunIdentifySystem(conn, &sysidentifier, &latesttli, NULL, NULL))
    1860           0 :         exit(1);
    1861             : 
    1862             :     /*
    1863             :      * Start the actual backup
    1864             :      */
    1865         156 :     PQescapeStringConn(conn, escaped_label, label, sizeof(escaped_label), &i);
    1866             : 
    1867         156 :     if (maxrate > 0)
    1868           0 :         maxrate_clause = psprintf("MAX_RATE %u", maxrate);
    1869             : 
    1870         156 :     if (manifest)
    1871             :     {
    1872         154 :         if (manifest_force_encode)
    1873           2 :             manifest_clause = "MANIFEST 'force-encode'";
    1874             :         else
    1875         152 :             manifest_clause = "MANIFEST 'yes'";
    1876         154 :         if (manifest_checksums != NULL)
    1877          14 :             manifest_checksums_clause = psprintf("MANIFEST_CHECKSUMS '%s'",
    1878             :                                                  manifest_checksums);
    1879             :     }
    1880             : 
    1881         156 :     if (verbose)
    1882           0 :         pg_log_info("initiating base backup, waiting for checkpoint to complete");
    1883             : 
    1884         156 :     if (showprogress && !verbose)
    1885             :     {
    1886           0 :         fprintf(stderr, "waiting for checkpoint");
    1887           0 :         if (isatty(fileno(stderr)))
    1888           0 :             fprintf(stderr, "\r");
    1889             :         else
    1890           0 :             fprintf(stderr, "\n");
    1891             :     }
    1892             : 
    1893             :     basebkp =
    1894        1092 :         psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s %s %s",
    1895             :                  escaped_label,
    1896         156 :                  estimatesize ? "PROGRESS" : "",
    1897         156 :                  includewal == FETCH_WAL ? "WAL" : "",
    1898         156 :                  fastcheckpoint ? "FAST" : "",
    1899         156 :                  includewal == NO_WAL ? "" : "NOWAIT",
    1900             :                  maxrate_clause ? maxrate_clause : "",
    1901         156 :                  format == 't' ? "TABLESPACE_MAP" : "",
    1902         156 :                  verify_checksums ? "" : "NOVERIFY_CHECKSUMS",
    1903             :                  manifest_clause ? manifest_clause : "",
    1904             :                  manifest_checksums_clause);
    1905             : 
    1906         156 :     if (PQsendQuery(conn, basebkp) == 0)
    1907             :     {
    1908           0 :         pg_log_error("could not send replication command \"%s\": %s",
    1909             :                      "BASE_BACKUP", PQerrorMessage(conn));
    1910           0 :         exit(1);
    1911             :     }
    1912             : 
    1913             :     /*
    1914             :      * Get the starting WAL location
    1915             :      */
    1916         156 :     res = PQgetResult(conn);
    1917         156 :     if (PQresultStatus(res) != PGRES_TUPLES_OK)
    1918             :     {
    1919           2 :         pg_log_error("could not initiate base backup: %s",
    1920             :                      PQerrorMessage(conn));
    1921           2 :         exit(1);
    1922             :     }
    1923         154 :     if (PQntuples(res) != 1)
    1924             :     {
    1925           0 :         pg_log_error("server returned unexpected response to BASE_BACKUP command; got %d rows and %d fields, expected %d rows and %d fields",
    1926             :                      PQntuples(res), PQnfields(res), 1, 2);
    1927           0 :         exit(1);
    1928             :     }
    1929             : 
    1930         154 :     strlcpy(xlogstart, PQgetvalue(res, 0, 0), sizeof(xlogstart));
    1931             : 
    1932         154 :     if (verbose)
    1933           0 :         pg_log_info("checkpoint completed");
    1934             : 
    1935             :     /*
    1936             :      * 9.3 and later sends the TLI of the starting point. With older servers,
    1937             :      * assume it's the same as the latest timeline reported by
    1938             :      * IDENTIFY_SYSTEM.
    1939             :      */
    1940         154 :     if (PQnfields(res) >= 2)
    1941         154 :         starttli = atoi(PQgetvalue(res, 0, 1));
    1942             :     else
    1943           0 :         starttli = latesttli;
    1944         154 :     PQclear(res);
    1945        1386 :     MemSet(xlogend, 0, sizeof(xlogend));
    1946             : 
    1947         154 :     if (verbose && includewal != NO_WAL)
    1948           0 :         pg_log_info("write-ahead log start point: %s on timeline %u",
    1949             :                     xlogstart, starttli);
    1950             : 
    1951             :     /*
    1952             :      * Get the header
    1953             :      */
    1954         154 :     res = PQgetResult(conn);
    1955         154 :     if (PQresultStatus(res) != PGRES_TUPLES_OK)
    1956             :     {
    1957           0 :         pg_log_error("could not get backup header: %s",
    1958             :                      PQerrorMessage(conn));
    1959           0 :         exit(1);
    1960             :     }
    1961         154 :     if (PQntuples(res) < 1)
    1962             :     {
    1963           0 :         pg_log_error("no data returned from server");
    1964           0 :         exit(1);
    1965             :     }
    1966             : 
    1967             :     /*
    1968             :      * Sum up the total size, for progress reporting
    1969             :      */
    1970         154 :     totalsize_kb = totaldone = 0;
    1971         154 :     tablespacecount = PQntuples(res);
    1972         336 :     for (i = 0; i < PQntuples(res); i++)
    1973             :     {
    1974         184 :         totalsize_kb += atol(PQgetvalue(res, i, 2));
    1975             : 
    1976             :         /*
    1977             :          * Verify tablespace directories are empty. Don't bother with the
    1978             :          * first once since it can be relocated, and it will be checked before
    1979             :          * we do anything anyway.
    1980             :          */
    1981         184 :         if (format == 'p' && !PQgetisnull(res, i, 1))
    1982             :         {
    1983          28 :             char       *path = unconstify(char *, get_tablespace_mapping(PQgetvalue(res, i, 1)));
    1984             : 
    1985          28 :             verify_dir_is_empty_or_create(path, &made_tablespace_dirs, &found_tablespace_dirs);
    1986             :         }
    1987             :     }
    1988             : 
    1989             :     /*
    1990             :      * When writing to stdout, require a single tablespace
    1991             :      */
    1992         152 :     writing_to_stdout = format == 't' && strcmp(basedir, "-") == 0;
    1993         152 :     if (writing_to_stdout && PQntuples(res) > 1)
    1994             :     {
    1995           0 :         pg_log_error("can only write single tablespace to stdout, database has %d",
    1996             :                      PQntuples(res));
    1997           0 :         exit(1);
    1998             :     }
    1999             : 
    2000             :     /*
    2001             :      * If we're streaming WAL, start the streaming session before we start
    2002             :      * receiving the actual data chunks.
    2003             :      */
    2004         152 :     if (includewal == STREAM_WAL)
    2005             :     {
    2006         148 :         if (verbose)
    2007           0 :             pg_log_info("starting background WAL receiver");
    2008         148 :         StartLogStreamer(xlogstart, starttli, sysidentifier);
    2009             :     }
    2010             : 
    2011             :     /*
    2012             :      * Start receiving chunks
    2013             :      */
    2014         330 :     for (i = 0; i < PQntuples(res); i++)
    2015             :     {
    2016         180 :         if (format == 't')
    2017          14 :             ReceiveTarFile(conn, res, i);
    2018             :         else
    2019         166 :             ReceiveAndUnpackTarFile(conn, res, i);
    2020             :     }                           /* Loop over all tablespaces */
    2021             : 
    2022             :     /*
    2023             :      * Now receive backup manifest, if appropriate.
    2024             :      *
    2025             :      * If we're writing a tarfile to stdout, ReceiveTarFile will have already
    2026             :      * processed the backup manifest and included it in the output tarfile.
    2027             :      * Such a configuration doesn't allow for writing multiple files.
    2028             :      *
    2029             :      * If we're talking to an older server, it won't send a backup manifest,
    2030             :      * so don't try to receive one.
    2031             :      */
    2032         150 :     if (!writing_to_stdout && manifest)
    2033         148 :         ReceiveBackupManifest(conn);
    2034             : 
    2035         148 :     if (showprogress)
    2036           0 :         progress_report(PQntuples(res), NULL, true, true);
    2037             : 
    2038         148 :     PQclear(res);
    2039             : 
    2040             :     /*
    2041             :      * Get the stop position
    2042             :      */
    2043         148 :     res = PQgetResult(conn);
    2044         148 :     if (PQresultStatus(res) != PGRES_TUPLES_OK)
    2045             :     {
    2046           0 :         pg_log_error("could not get write-ahead log end position from server: %s",
    2047             :                      PQerrorMessage(conn));
    2048           0 :         exit(1);
    2049             :     }
    2050         148 :     if (PQntuples(res) != 1)
    2051             :     {
    2052           0 :         pg_log_error("no write-ahead log end position returned from server");
    2053           0 :         exit(1);
    2054             :     }
    2055         148 :     strlcpy(xlogend, PQgetvalue(res, 0, 0), sizeof(xlogend));
    2056         148 :     if (verbose && includewal != NO_WAL)
    2057           0 :         pg_log_info("write-ahead log end point: %s", xlogend);
    2058         148 :     PQclear(res);
    2059             : 
    2060         148 :     res = PQgetResult(conn);
    2061         148 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    2062             :     {
    2063           6 :         const char *sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
    2064             : 
    2065           6 :         if (sqlstate &&
    2066           6 :             strcmp(sqlstate, ERRCODE_DATA_CORRUPTED) == 0)
    2067             :         {
    2068           6 :             pg_log_error("checksum error occurred");
    2069           6 :             checksum_failure = true;
    2070             :         }
    2071             :         else
    2072             :         {
    2073           0 :             pg_log_error("final receive failed: %s",
    2074             :                          PQerrorMessage(conn));
    2075             :         }
    2076           6 :         exit(1);
    2077             :     }
    2078             : 
    2079         142 :     if (bgchild > 0)
    2080             :     {
    2081             : #ifndef WIN32
    2082             :         int         status;
    2083             :         pid_t       r;
    2084             : #else
    2085             :         DWORD       status;
    2086             : 
    2087             :         /*
    2088             :          * get a pointer sized version of bgchild to avoid warnings about
    2089             :          * casting to a different size on WIN64.
    2090             :          */
    2091             :         intptr_t    bgchild_handle = bgchild;
    2092             :         uint32      hi,
    2093             :                     lo;
    2094             : #endif
    2095             : 
    2096         138 :         if (verbose)
    2097           0 :             pg_log_info("waiting for background process to finish streaming ...");
    2098             : 
    2099             : #ifndef WIN32
    2100         138 :         if (write(bgpipe[1], xlogend, strlen(xlogend)) != strlen(xlogend))
    2101             :         {
    2102           0 :             pg_log_info("could not send command to background pipe: %m");
    2103           0 :             exit(1);
    2104             :         }
    2105             : 
    2106             :         /* Just wait for the background process to exit */
    2107         138 :         r = waitpid(bgchild, &status, 0);
    2108         138 :         if (r == (pid_t) -1)
    2109             :         {
    2110           0 :             pg_log_error("could not wait for child process: %m");
    2111           0 :             exit(1);
    2112             :         }
    2113         138 :         if (r != bgchild)
    2114             :         {
    2115           0 :             pg_log_error("child %d died, expected %d", (int) r, (int) bgchild);
    2116           0 :             exit(1);
    2117             :         }
    2118         138 :         if (status != 0)
    2119             :         {
    2120           2 :             pg_log_error("%s", wait_result_to_str(status));
    2121           2 :             exit(1);
    2122             :         }
    2123             :         /* Exited normally, we're happy! */
    2124             : #else                           /* WIN32 */
    2125             : 
    2126             :         /*
    2127             :          * On Windows, since we are in the same process, we can just store the
    2128             :          * value directly in the variable, and then set the flag that says
    2129             :          * it's there.
    2130             :          */
    2131             :         if (sscanf(xlogend, "%X/%X", &hi, &lo) != 2)
    2132             :         {
    2133             :             pg_log_error("could not parse write-ahead log location \"%s\"",
    2134             :                          xlogend);
    2135             :             exit(1);
    2136             :         }
    2137             :         xlogendptr = ((uint64) hi) << 32 | lo;
    2138             :         InterlockedIncrement(&has_xlogendptr);
    2139             : 
    2140             :         /* First wait for the thread to exit */
    2141             :         if (WaitForSingleObjectEx((HANDLE) bgchild_handle, INFINITE, FALSE) !=
    2142             :             WAIT_OBJECT_0)
    2143             :         {
    2144             :             _dosmaperr(GetLastError());
    2145             :             pg_log_error("could not wait for child thread: %m");
    2146             :             exit(1);
    2147             :         }
    2148             :         if (GetExitCodeThread((HANDLE) bgchild_handle, &status) == 0)
    2149             :         {
    2150             :             _dosmaperr(GetLastError());
    2151             :             pg_log_error("could not get child thread exit status: %m");
    2152             :             exit(1);
    2153             :         }
    2154             :         if (status != 0)
    2155             :         {
    2156             :             pg_log_error("child thread exited with error %u",
    2157             :                          (unsigned int) status);
    2158             :             exit(1);
    2159             :         }
    2160             :         /* Exited normally, we're happy */
    2161             : #endif
    2162             :     }
    2163             : 
    2164             :     /* Free the configuration file contents */
    2165         140 :     destroyPQExpBuffer(recoveryconfcontents);
    2166             : 
    2167             :     /*
    2168             :      * End of copy data. Final result is already checked inside the loop.
    2169             :      */
    2170         140 :     PQclear(res);
    2171         140 :     PQfinish(conn);
    2172         140 :     conn = NULL;
    2173             : 
    2174             :     /*
    2175             :      * Make data persistent on disk once backup is completed. For tar format
    2176             :      * sync the parent directory and all its contents as each tar file was not
    2177             :      * synced after being completed.  In plain format, all the data of the
    2178             :      * base directory is synced, taking into account all the tablespaces.
    2179             :      * Errors are not considered fatal.
    2180             :      */
    2181         140 :     if (do_sync)
    2182             :     {
    2183          34 :         if (verbose)
    2184           0 :             pg_log_info("syncing data to disk ...");
    2185          34 :         if (format == 't')
    2186             :         {
    2187           8 :             if (strcmp(basedir, "-") != 0)
    2188           8 :                 (void) fsync_dir_recurse(basedir);
    2189             :         }
    2190             :         else
    2191             :         {
    2192          26 :             (void) fsync_pgdata(basedir, serverVersion);
    2193             :         }
    2194             :     }
    2195             : 
    2196             :     /*
    2197             :      * After synchronizing data to disk, perform a durable rename of
    2198             :      * backup_manifest.tmp to backup_manifest, if we wrote such a file. This
    2199             :      * way, a failure or system crash before we reach this point will leave us
    2200             :      * without a backup_manifest file, decreasing the chances that a directory
    2201             :      * we leave behind will be mistaken for a valid backup.
    2202             :      */
    2203         140 :     if (!writing_to_stdout && manifest)
    2204             :     {
    2205             :         char        tmp_filename[MAXPGPATH];
    2206             :         char        filename[MAXPGPATH];
    2207             : 
    2208         138 :         if (verbose)
    2209           0 :             pg_log_info("renaming backup_manifest.tmp to backup_manifest");
    2210             : 
    2211         138 :         snprintf(tmp_filename, MAXPGPATH, "%s/backup_manifest.tmp", basedir);
    2212         138 :         snprintf(filename, MAXPGPATH, "%s/backup_manifest", basedir);
    2213             : 
    2214             :         /* durable_rename emits its own log message in case of failure */
    2215         138 :         if (durable_rename(tmp_filename, filename) != 0)
    2216           0 :             exit(1);
    2217             :     }
    2218             : 
    2219         140 :     if (verbose)
    2220           0 :         pg_log_info("base backup completed");
    2221         140 : }
    2222             : 
    2223             : 
    2224             : int
    2225         186 : main(int argc, char **argv)
    2226             : {
    2227             :     static struct option long_options[] = {
    2228             :         {"help", no_argument, NULL, '?'},
    2229             :         {"version", no_argument, NULL, 'V'},
    2230             :         {"pgdata", required_argument, NULL, 'D'},
    2231             :         {"format", required_argument, NULL, 'F'},
    2232             :         {"checkpoint", required_argument, NULL, 'c'},
    2233             :         {"create-slot", no_argument, NULL, 'C'},
    2234             :         {"max-rate", required_argument, NULL, 'r'},
    2235             :         {"write-recovery-conf", no_argument, NULL, 'R'},
    2236             :         {"slot", required_argument, NULL, 'S'},
    2237             :         {"tablespace-mapping", required_argument, NULL, 'T'},
    2238             :         {"wal-method", required_argument, NULL, 'X'},
    2239             :         {"gzip", no_argument, NULL, 'z'},
    2240             :         {"compress", required_argument, NULL, 'Z'},
    2241             :         {"label", required_argument, NULL, 'l'},
    2242             :         {"no-clean", no_argument, NULL, 'n'},
    2243             :         {"no-sync", no_argument, NULL, 'N'},
    2244             :         {"dbname", required_argument, NULL, 'd'},
    2245             :         {"host", required_argument, NULL, 'h'},
    2246             :         {"port", required_argument, NULL, 'p'},
    2247             :         {"username", required_argument, NULL, 'U'},
    2248             :         {"no-password", no_argument, NULL, 'w'},
    2249             :         {"password", no_argument, NULL, 'W'},
    2250             :         {"status-interval", required_argument, NULL, 's'},
    2251             :         {"verbose", no_argument, NULL, 'v'},
    2252             :         {"progress", no_argument, NULL, 'P'},
    2253             :         {"waldir", required_argument, NULL, 1},
    2254             :         {"no-slot", no_argument, NULL, 2},
    2255             :         {"no-verify-checksums", no_argument, NULL, 3},
    2256             :         {"no-estimate-size", no_argument, NULL, 4},
    2257             :         {"no-manifest", no_argument, NULL, 5},
    2258             :         {"manifest-force-encode", no_argument, NULL, 6},
    2259             :         {"manifest-checksums", required_argument, NULL, 7},
    2260             :         {NULL, 0, NULL, 0}
    2261             :     };
    2262             :     int         c;
    2263             : 
    2264             :     int         option_index;
    2265             : 
    2266         186 :     pg_logging_init(argv[0]);
    2267         186 :     progname = get_progname(argv[0]);
    2268         186 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_basebackup"));
    2269             : 
    2270         186 :     if (argc > 1)
    2271             :     {
    2272         184 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
    2273             :         {
    2274           2 :             usage();
    2275           2 :             exit(0);
    2276             :         }
    2277         182 :         else if (strcmp(argv[1], "-V") == 0
    2278         182 :                  || strcmp(argv[1], "--version") == 0)
    2279             :         {
    2280           2 :             puts("pg_basebackup (PostgreSQL) " PG_VERSION);
    2281           2 :             exit(0);
    2282             :         }
    2283             :     }
    2284             : 
    2285         182 :     atexit(cleanup_directories_atexit);
    2286             : 
    2287         792 :     while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
    2288             :                             long_options, &option_index)) != -1)
    2289             :     {
    2290         624 :         switch (c)
    2291             :         {
    2292           8 :             case 'C':
    2293           8 :                 create_slot = true;
    2294           8 :                 break;
    2295         178 :             case 'D':
    2296         178 :                 basedir = pg_strdup(optarg);
    2297         178 :                 break;
    2298          28 :             case 'F':
    2299          28 :                 if (strcmp(optarg, "p") == 0 || strcmp(optarg, "plain") == 0)
    2300          18 :                     format = 'p';
    2301          10 :                 else if (strcmp(optarg, "t") == 0 || strcmp(optarg, "tar") == 0)
    2302          10 :                     format = 't';
    2303             :                 else
    2304             :                 {
    2305           0 :                     pg_log_error("invalid output format \"%s\", must be \"plain\" or \"tar\"",
    2306             :                                  optarg);
    2307           0 :                     exit(1);
    2308             :                 }
    2309          28 :                 break;
    2310           0 :             case 'r':
    2311           0 :                 maxrate = parse_max_rate(optarg);
    2312           0 :                 break;
    2313           4 :             case 'R':
    2314           4 :                 writerecoveryconf = true;
    2315           4 :                 break;
    2316          14 :             case 'S':
    2317             : 
    2318             :                 /*
    2319             :                  * When specifying replication slot name, use a permanent
    2320             :                  * slot.
    2321             :                  */
    2322          14 :                 replication_slot = pg_strdup(optarg);
    2323          14 :                 temp_replication_slot = false;
    2324          14 :                 break;
    2325           4 :             case 2:
    2326           4 :                 no_slot = true;
    2327           4 :                 break;
    2328          38 :             case 'T':
    2329          38 :                 tablespace_list_append(optarg);
    2330          26 :                 break;
    2331          18 :             case 'X':
    2332          18 :                 if (strcmp(optarg, "n") == 0 ||
    2333          18 :                     strcmp(optarg, "none") == 0)
    2334             :                 {
    2335           4 :                     includewal = NO_WAL;
    2336             :                 }
    2337          14 :                 else if (strcmp(optarg, "f") == 0 ||
    2338          14 :                          strcmp(optarg, "fetch") == 0)
    2339             :                 {
    2340           2 :                     includewal = FETCH_WAL;
    2341             :                 }
    2342          12 :                 else if (strcmp(optarg, "s") == 0 ||
    2343          12 :                          strcmp(optarg, "stream") == 0)
    2344             :                 {
    2345          12 :                     includewal = STREAM_WAL;
    2346             :                 }
    2347             :                 else
    2348             :                 {
    2349           0 :                     pg_log_error("invalid wal-method option \"%s\", must be \"fetch\", \"stream\", or \"none\"",
    2350             :                                  optarg);
    2351           0 :                     exit(1);
    2352             :                 }
    2353          18 :                 break;
    2354           2 :             case 1:
    2355           2 :                 xlog_dir = pg_strdup(optarg);
    2356           2 :                 break;
    2357           0 :             case 'l':
    2358           0 :                 label = pg_strdup(optarg);
    2359           0 :                 break;
    2360           2 :             case 'n':
    2361           2 :                 noclean = true;
    2362           2 :                 break;
    2363         108 :             case 'N':
    2364         108 :                 do_sync = false;
    2365         108 :                 break;
    2366           0 :             case 'z':
    2367             : #ifdef HAVE_LIBZ
    2368           0 :                 compresslevel = Z_DEFAULT_COMPRESSION;
    2369             : #else
    2370             :                 compresslevel = 1;  /* will be rejected below */
    2371             : #endif
    2372           0 :                 break;
    2373           0 :             case 'Z':
    2374           0 :                 compresslevel = atoi(optarg);
    2375           0 :                 if (compresslevel < 0 || compresslevel > 9)
    2376             :                 {
    2377           0 :                     pg_log_error("invalid compression level \"%s\"", optarg);
    2378           0 :                     exit(1);
    2379             :                 }
    2380           0 :                 break;
    2381          66 :             case 'c':
    2382          66 :                 if (pg_strcasecmp(optarg, "fast") == 0)
    2383          66 :                     fastcheckpoint = true;
    2384           0 :                 else if (pg_strcasecmp(optarg, "spread") == 0)
    2385           0 :                     fastcheckpoint = false;
    2386             :                 else
    2387             :                 {
    2388           0 :                     pg_log_error("invalid checkpoint argument \"%s\", must be \"fast\" or \"spread\"",
    2389             :                                  optarg);
    2390           0 :                     exit(1);
    2391             :                 }
    2392          66 :                 break;
    2393           0 :             case 'd':
    2394           0 :                 connection_string = pg_strdup(optarg);
    2395           0 :                 break;
    2396          66 :             case 'h':
    2397          66 :                 dbhost = pg_strdup(optarg);
    2398          66 :                 break;
    2399          66 :             case 'p':
    2400          66 :                 dbport = pg_strdup(optarg);
    2401          66 :                 break;
    2402           0 :             case 'U':
    2403           0 :                 dbuser = pg_strdup(optarg);
    2404           0 :                 break;
    2405           0 :             case 'w':
    2406           0 :                 dbgetpassword = -1;
    2407           0 :                 break;
    2408           0 :             case 'W':
    2409           0 :                 dbgetpassword = 1;
    2410           0 :                 break;
    2411           0 :             case 's':
    2412           0 :                 standby_message_timeout = atoi(optarg) * 1000;
    2413           0 :                 if (standby_message_timeout < 0)
    2414             :                 {
    2415           0 :                     pg_log_error("invalid status interval \"%s\"", optarg);
    2416           0 :                     exit(1);
    2417             :                 }
    2418           0 :                 break;
    2419           0 :             case 'v':
    2420           0 :                 verbose++;
    2421           0 :                 break;
    2422           0 :             case 'P':
    2423           0 :                 showprogress = true;
    2424           0 :                 break;
    2425           2 :             case 3:
    2426           2 :                 verify_checksums = false;
    2427           2 :                 break;
    2428           0 :             case 4:
    2429           0 :                 estimatesize = false;
    2430           0 :                 break;
    2431           2 :             case 5:
    2432           2 :                 manifest = false;
    2433           2 :                 break;
    2434           2 :             case 6:
    2435           2 :                 manifest_force_encode = true;
    2436           2 :                 break;
    2437          14 :             case 7:
    2438          14 :                 manifest_checksums = pg_strdup(optarg);
    2439          14 :                 break;
    2440           2 :             default:
    2441             : 
    2442             :                 /*
    2443             :                  * getopt_long already emitted a complaint
    2444             :                  */
    2445           2 :                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2446             :                         progname);
    2447           2 :                 exit(1);
    2448             :         }
    2449             :     }
    2450             : 
    2451             :     /*
    2452             :      * Any non-option arguments?
    2453             :      */
    2454         168 :     if (optind < argc)
    2455             :     {
    2456           0 :         pg_log_error("too many command-line arguments (first is \"%s\")",
    2457             :                      argv[optind]);
    2458           0 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2459             :                 progname);
    2460           0 :         exit(1);
    2461             :     }
    2462             : 
    2463             :     /*
    2464             :      * Required arguments
    2465             :      */
    2466         168 :     if (basedir == NULL)
    2467             :     {
    2468           2 :         pg_log_error("no target directory specified");
    2469           2 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2470             :                 progname);
    2471           2 :         exit(1);
    2472             :     }
    2473             : 
    2474             :     /*
    2475             :      * Mutually exclusive arguments
    2476             :      */
    2477         166 :     if (format == 'p' && compresslevel != 0)
    2478             :     {
    2479           0 :         pg_log_error("only tar mode backups can be compressed");
    2480           0 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2481             :                 progname);
    2482           0 :         exit(1);
    2483             :     }
    2484             : 
    2485         166 :     if (format == 't' && includewal == STREAM_WAL && strcmp(basedir, "-") == 0)
    2486             :     {
    2487           0 :         pg_log_error("cannot stream write-ahead logs in tar mode to stdout");
    2488           0 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2489             :                 progname);
    2490           0 :         exit(1);
    2491             :     }
    2492             : 
    2493         166 :     if (replication_slot && includewal != STREAM_WAL)
    2494             :     {
    2495           2 :         pg_log_error("replication slots can only be used with WAL streaming");
    2496           2 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2497             :                 progname);
    2498           2 :         exit(1);
    2499             :     }
    2500             : 
    2501         164 :     if (no_slot)
    2502             :     {
    2503           4 :         if (replication_slot)
    2504             :         {
    2505           2 :             pg_log_error("--no-slot cannot be used with slot name");
    2506           2 :             fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2507             :                     progname);
    2508           2 :             exit(1);
    2509             :         }
    2510           2 :         temp_replication_slot = false;
    2511             :     }
    2512             : 
    2513         162 :     if (create_slot)
    2514             :     {
    2515           6 :         if (!replication_slot)
    2516             :         {
    2517           2 :             pg_log_error("%s needs a slot to be specified using --slot",
    2518             :                          "--create-slot");
    2519           2 :             fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2520             :                     progname);
    2521           2 :             exit(1);
    2522             :         }
    2523             : 
    2524           4 :         if (no_slot)
    2525             :         {
    2526           0 :             pg_log_error("%s and %s are incompatible options",
    2527             :                          "--create-slot", "--no-slot");
    2528           0 :             fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2529             :                     progname);
    2530           0 :             exit(1);
    2531             :         }
    2532             :     }
    2533             : 
    2534         160 :     if (xlog_dir)
    2535             :     {
    2536           2 :         if (format != 'p')
    2537             :         {
    2538           0 :             pg_log_error("WAL directory location can only be specified in plain mode");
    2539           0 :             fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2540             :                     progname);
    2541           0 :             exit(1);
    2542             :         }
    2543             : 
    2544             :         /* clean up xlog directory name, check it's absolute */
    2545           2 :         canonicalize_path(xlog_dir);
    2546           2 :         if (!is_absolute_path(xlog_dir))
    2547             :         {
    2548           0 :             pg_log_error("WAL directory location must be an absolute path");
    2549           0 :             fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2550             :                     progname);
    2551           0 :             exit(1);
    2552             :         }
    2553             :     }
    2554             : 
    2555             : #ifndef HAVE_LIBZ
    2556             :     if (compresslevel != 0)
    2557             :     {
    2558             :         pg_log_error("this build does not support compression");
    2559             :         exit(1);
    2560             :     }
    2561             : #endif
    2562             : 
    2563         160 :     if (showprogress && !estimatesize)
    2564             :     {
    2565           0 :         pg_log_error("%s and %s are incompatible options",
    2566             :                      "--progress", "--no-estimate-size");
    2567           0 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2568             :                 progname);
    2569           0 :         exit(1);
    2570             :     }
    2571             : 
    2572         160 :     if (!manifest && manifest_checksums != NULL)
    2573             :     {
    2574           0 :         pg_log_error("%s and %s are incompatible options",
    2575             :                      "--no-manifest", "--manifest-checksums");
    2576           0 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2577             :                 progname);
    2578           0 :         exit(1);
    2579             :     }
    2580             : 
    2581         160 :     if (!manifest && manifest_force_encode)
    2582             :     {
    2583           0 :         pg_log_error("%s and %s are incompatible options",
    2584             :                      "--no-manifest", "--manifest-force-encode");
    2585           0 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2586             :                 progname);
    2587           0 :         exit(1);
    2588             :     }
    2589             : 
    2590             :     /* connection in replication mode to server */
    2591         160 :     conn = GetConnection();
    2592         160 :     if (!conn)
    2593             :     {
    2594             :         /* Error message already written in GetConnection() */
    2595           4 :         exit(1);
    2596             :     }
    2597         156 :     atexit(disconnect_atexit);
    2598             : 
    2599             :     /*
    2600             :      * Set umask so that directories/files are created with the same
    2601             :      * permissions as directories/files in the source data directory.
    2602             :      *
    2603             :      * pg_mode_mask is set to owner-only by default and then updated in
    2604             :      * GetConnection() where we get the mode from the server-side with
    2605             :      * RetrieveDataDirCreatePerm() and then call SetDataDirectoryCreatePerm().
    2606             :      */
    2607         156 :     umask(pg_mode_mask);
    2608             : 
    2609             :     /* Backup manifests are supported in 13 and newer versions */
    2610         156 :     if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_MANIFESTS)
    2611           0 :         manifest = false;
    2612             : 
    2613             :     /*
    2614             :      * Verify that the target directory exists, or create it. For plaintext
    2615             :      * backups, always require the directory. For tar backups, require it
    2616             :      * unless we are writing to stdout.
    2617             :      */
    2618         156 :     if (format == 'p' || strcmp(basedir, "-") != 0)
    2619         156 :         verify_dir_is_empty_or_create(basedir, &made_new_pgdata, &found_existing_pgdata);
    2620             : 
    2621             :     /* determine remote server's xlog segment size */
    2622         156 :     if (!RetrieveWalSegSize(conn))
    2623           0 :         exit(1);
    2624             : 
    2625             :     /* Create pg_wal symlink, if required */
    2626         156 :     if (xlog_dir)
    2627             :     {
    2628             :         char       *linkloc;
    2629             : 
    2630           2 :         verify_dir_is_empty_or_create(xlog_dir, &made_new_xlogdir, &found_existing_xlogdir);
    2631             : 
    2632             :         /*
    2633             :          * Form name of the place where the symlink must go. pg_xlog has been
    2634             :          * renamed to pg_wal in post-10 clusters.
    2635             :          */
    2636           2 :         linkloc = psprintf("%s/%s", basedir,
    2637           2 :                            PQserverVersion(conn) < MINIMUM_VERSION_FOR_PG_WAL ?
    2638             :                            "pg_xlog" : "pg_wal");
    2639             : 
    2640             : #ifdef HAVE_SYMLINK
    2641           2 :         if (symlink(xlog_dir, linkloc) != 0)
    2642             :         {
    2643           0 :             pg_log_error("could not create symbolic link \"%s\": %m", linkloc);
    2644           0 :             exit(1);
    2645             :         }
    2646             : #else
    2647             :         pg_log_error("symlinks are not supported on this platform");
    2648             :         exit(1);
    2649             : #endif
    2650           2 :         free(linkloc);
    2651             :     }
    2652             : 
    2653         156 :     BaseBackup();
    2654             : 
    2655         140 :     success = true;
    2656         140 :     return 0;
    2657             : }

Generated by: LCOV version 1.13