PostgreSQL Source Code  git master
pg_basebackup.c File Reference
#include "postgres_fe.h"
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
#include "access/xlog_internal.h"
#include "common/file_perm.h"
#include "common/file_utils.h"
#include "common/logging.h"
#include "common/string.h"
#include "fe_utils/recovery_gen.h"
#include "fe_utils/string_utils.h"
#include "getopt_long.h"
#include "libpq-fe.h"
#include "pgtar.h"
#include "pgtime.h"
#include "pqexpbuffer.h"
#include "receivelog.h"
#include "replication/basebackup.h"
#include "streamutil.h"
Include dependency graph for pg_basebackup.c:

Go to the source code of this file.

Data Structures

struct  TablespaceListCell
 
struct  TablespaceList
 
struct  WriteTarState
 
struct  UnpackTarState
 
struct  WriteManifestState
 
struct  logstreamer_param
 

Macros

#define ERRCODE_DATA_CORRUPTED   "XX001"
 
#define MINIMUM_VERSION_FOR_PG_WAL   100000
 
#define MINIMUM_VERSION_FOR_TEMP_SLOTS   100000
 
#define MINIMUM_VERSION_FOR_MANIFESTS   130000
 
#define VERBOSE_FILENAME_LENGTH   35
 

Typedefs

typedef struct TablespaceListCell TablespaceListCell
 
typedef struct TablespaceList TablespaceList
 
typedef struct WriteTarState WriteTarState
 
typedef struct UnpackTarState UnpackTarState
 
typedef struct WriteManifestState WriteManifestState
 
typedef void(* WriteDataCallback) (size_t nbytes, char *buf, void *callback_data)
 

Enumerations

enum  IncludeWal { NO_WAL, FETCH_WAL, STREAM_WAL }
 

Functions

static void usage (void)
 
static void verify_dir_is_empty_or_create (char *dirname, bool *created, bool *found)
 
static void progress_report (int tablespacenum, const char *filename, bool force)
 
static void ReceiveTarFile (PGconn *conn, PGresult *res, int rownum)
 
static void ReceiveTarCopyChunk (size_t r, char *copybuf, void *callback_data)
 
static void ReceiveAndUnpackTarFile (PGconn *conn, PGresult *res, int rownum)
 
static void ReceiveTarAndUnpackCopyChunk (size_t r, char *copybuf, void *callback_data)
 
static void ReceiveBackupManifest (PGconn *conn)
 
static void ReceiveBackupManifestChunk (size_t r, char *copybuf, void *callback_data)
 
static void ReceiveBackupManifestInMemory (PGconn *conn, PQExpBuffer buf)
 
static void ReceiveBackupManifestInMemoryChunk (size_t r, char *copybuf, void *callback_data)
 
static void BaseBackup (void)
 
static bool reached_end_position (XLogRecPtr segendpos, uint32 timeline, bool segment_finished)
 
static const char * get_tablespace_mapping (const char *dir)
 
static void tablespace_list_append (const char *arg)
 
static void cleanup_directories_atexit (void)
 
static void disconnect_atexit (void)
 
static void kill_bgchild_atexit (void)
 
static int LogStreamerMain (logstreamer_param *param)
 
static void StartLogStreamer (char *startpos, uint32 timeline, char *sysidentifier)
 
static int32 parse_max_rate (char *src)
 
static void ReceiveCopyData (PGconn *conn, WriteDataCallback callback, void *callback_data)
 
static void writeTarData (WriteTarState *state, char *buf, int r)
 
int main (int argc, char **argv)
 

Variables

static char * basedir = NULL
 
static TablespaceList tablespace_dirs = {NULL, NULL}
 
static char * xlog_dir = NULL
 
static char format = 'p'
 
static char * label = "pg_basebackup base backup"
 
static bool noclean = false
 
static bool checksum_failure = false
 
static bool showprogress = false
 
static bool estimatesize = true
 
static int verbose = 0
 
static int compresslevel = 0
 
static IncludeWal includewal = STREAM_WAL
 
static bool fastcheckpoint = false
 
static bool writerecoveryconf = false
 
static bool do_sync = true
 
static int standby_message_timeout = 10 * 1000
 
static pg_time_t last_progress_report = 0
 
static int32 maxrate = 0
 
static char * replication_slot = NULL
 
static bool temp_replication_slot = true
 
static bool create_slot = false
 
static bool no_slot = false
 
static bool verify_checksums = true
 
static bool manifest = true
 
static bool manifest_force_encode = false
 
static char * manifest_checksums = NULL
 
static bool success = false
 
static bool made_new_pgdata = false
 
static bool found_existing_pgdata = false
 
static bool made_new_xlogdir = false
 
static bool found_existing_xlogdir = false
 
static bool made_tablespace_dirs = false
 
static bool found_tablespace_dirs = false
 
static uint64 totalsize_kb
 
static uint64 totaldone
 
static int tablespacecount
 
static int bgpipe [2] = {-1, -1}
 
static pid_t bgchild = -1
 
static bool in_log_streamer = false
 
static XLogRecPtr xlogendptr
 
static int has_xlogendptr = 0
 
static PQExpBuffer recoveryconfcontents = NULL
 

Macro Definition Documentation

◆ ERRCODE_DATA_CORRUPTED

◆ MINIMUM_VERSION_FOR_MANIFESTS

#define MINIMUM_VERSION_FOR_MANIFESTS   130000

Definition at line 114 of file pg_basebackup.c.

Referenced by main().

◆ MINIMUM_VERSION_FOR_PG_WAL

#define MINIMUM_VERSION_FOR_PG_WAL   100000

Definition at line 104 of file pg_basebackup.c.

Referenced by main(), and StartLogStreamer().

◆ MINIMUM_VERSION_FOR_TEMP_SLOTS

#define MINIMUM_VERSION_FOR_TEMP_SLOTS   100000

Definition at line 109 of file pg_basebackup.c.

Referenced by StartLogStreamer().

◆ VERBOSE_FILENAME_LENGTH

#define VERBOSE_FILENAME_LENGTH   35

Referenced by progress_report().

Typedef Documentation

◆ TablespaceList

◆ TablespaceListCell

◆ UnpackTarState

◆ WriteDataCallback

typedef void(* WriteDataCallback) (size_t nbytes, char *buf, void *callback_data)

Definition at line 97 of file pg_basebackup.c.

◆ WriteManifestState

◆ WriteTarState

typedef struct WriteTarState WriteTarState

Enumeration Type Documentation

◆ IncludeWal

enum IncludeWal
Enumerator
NO_WAL 
FETCH_WAL 
STREAM_WAL 

Definition at line 119 of file pg_basebackup.c.

120 {
121  NO_WAL,
122  FETCH_WAL,
123  STREAM_WAL
124 } IncludeWal;
IncludeWal

Function Documentation

◆ BaseBackup()

static void BaseBackup ( void  )
static

Definition at line 1791 of file pg_basebackup.c.

References _dosmaperr(), Assert, basedir, bgchild, bgpipe, CheckServerVersionForStreaming(), checksum_failure, conn, destroyPQExpBuffer(), do_sync, durable_rename(), ERRCODE_DATA_CORRUPTED, estimatesize, fastcheckpoint, FETCH_WAL, filename, format, found_tablespace_dirs, fprintf, fsync_dir_recurse(), fsync_pgdata(), GenerateRecoveryConfig(), get_tablespace_mapping(), has_xlogendptr, i, includewal, label, made_tablespace_dirs, manifest, manifest_checksums, manifest_force_encode, MAXPGPATH, maxrate, MemSet, NO_WAL, PG_DIAG_SQLSTATE, pg_log_error, pg_log_info, PGRES_COMMAND_OK, PGRES_TUPLES_OK, PQclear(), PQerrorMessage(), PQescapeStringConn(), PQfinish(), PQgetisnull(), PQgetResult(), PQgetvalue(), PQnfields(), PQntuples(), PQparameterStatus(), PQresultErrorField(), PQresultStatus(), PQsendQuery(), PQserverVersion(), progress_report(), psprintf(), ReceiveAndUnpackTarFile(), ReceiveBackupManifest(), ReceiveTarFile(), replication_slot, RunIdentifySystem(), showprogress, snprintf, StartLogStreamer(), status(), STREAM_WAL, strlcpy(), tablespacecount, totaldone, totalsize_kb, unconstify, verbose, verify_checksums, verify_dir_is_empty_or_create(), wait_result_to_str(), write, writerecoveryconf, and xlogendptr.

Referenced by main().

1792 {
1793  PGresult *res;
1794  char *sysidentifier;
1795  TimeLineID latesttli;
1796  TimeLineID starttli;
1797  char *basebkp;
1798  char escaped_label[MAXPGPATH];
1799  char *maxrate_clause = NULL;
1800  char *manifest_clause = NULL;
1801  char *manifest_checksums_clause = "";
1802  int i;
1803  char xlogstart[64];
1804  char xlogend[64];
1805  int minServerMajor,
1806  maxServerMajor;
1807  int serverVersion,
1808  serverMajor;
1809  int writing_to_stdout;
1810 
1811  Assert(conn != NULL);
1812 
1813  /*
1814  * Check server version. BASE_BACKUP command was introduced in 9.1, so we
1815  * can't work with servers older than 9.1.
1816  */
1817  minServerMajor = 901;
1818  maxServerMajor = PG_VERSION_NUM / 100;
1819  serverVersion = PQserverVersion(conn);
1820  serverMajor = serverVersion / 100;
1821  if (serverMajor < minServerMajor || serverMajor > maxServerMajor)
1822  {
1823  const char *serverver = PQparameterStatus(conn, "server_version");
1824 
1825  pg_log_error("incompatible server version %s",
1826  serverver ? serverver : "'unknown'");
1827  exit(1);
1828  }
1829 
1830  /*
1831  * If WAL streaming was requested, also check that the server is new
1832  * enough for that.
1833  */
1835  {
1836  /*
1837  * Error message already written in CheckServerVersionForStreaming(),
1838  * but add a hint about using -X none.
1839  */
1840  pg_log_info("HINT: use -X none or -X fetch to disable log streaming");
1841  exit(1);
1842  }
1843 
1844  /*
1845  * Build contents of configuration file if requested
1846  */
1847  if (writerecoveryconf)
1849 
1850  /*
1851  * Run IDENTIFY_SYSTEM so we can get the timeline
1852  */
1853  if (!RunIdentifySystem(conn, &sysidentifier, &latesttli, NULL, NULL))
1854  exit(1);
1855 
1856  /*
1857  * Start the actual backup
1858  */
1859  PQescapeStringConn(conn, escaped_label, label, sizeof(escaped_label), &i);
1860 
1861  if (maxrate > 0)
1862  maxrate_clause = psprintf("MAX_RATE %u", maxrate);
1863 
1864  if (manifest)
1865  {
1867  manifest_clause = "MANIFEST 'force-encode'";
1868  else
1869  manifest_clause = "MANIFEST 'yes'";
1870  if (manifest_checksums != NULL)
1871  manifest_checksums_clause = psprintf("MANIFEST_CHECKSUMS '%s'",
1873  }
1874 
1875  if (verbose)
1876  pg_log_info("initiating base backup, waiting for checkpoint to complete");
1877 
1878  if (showprogress && !verbose)
1879  {
1880  fprintf(stderr, "waiting for checkpoint");
1881  if (isatty(fileno(stderr)))
1882  fprintf(stderr, "\r");
1883  else
1884  fprintf(stderr, "\n");
1885  }
1886 
1887  basebkp =
1888  psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s %s %s",
1889  escaped_label,
1890  estimatesize ? "PROGRESS" : "",
1891  includewal == FETCH_WAL ? "WAL" : "",
1892  fastcheckpoint ? "FAST" : "",
1893  includewal == NO_WAL ? "" : "NOWAIT",
1894  maxrate_clause ? maxrate_clause : "",
1895  format == 't' ? "TABLESPACE_MAP" : "",
1896  verify_checksums ? "" : "NOVERIFY_CHECKSUMS",
1897  manifest_clause ? manifest_clause : "",
1898  manifest_checksums_clause);
1899 
1900  if (PQsendQuery(conn, basebkp) == 0)
1901  {
1902  pg_log_error("could not send replication command \"%s\": %s",
1903  "BASE_BACKUP", PQerrorMessage(conn));
1904  exit(1);
1905  }
1906 
1907  /*
1908  * Get the starting WAL location
1909  */
1910  res = PQgetResult(conn);
1911  if (PQresultStatus(res) != PGRES_TUPLES_OK)
1912  {
1913  pg_log_error("could not initiate base backup: %s",
1914  PQerrorMessage(conn));
1915  exit(1);
1916  }
1917  if (PQntuples(res) != 1)
1918  {
1919  pg_log_error("server returned unexpected response to BASE_BACKUP command; got %d rows and %d fields, expected %d rows and %d fields",
1920  PQntuples(res), PQnfields(res), 1, 2);
1921  exit(1);
1922  }
1923 
1924  strlcpy(xlogstart, PQgetvalue(res, 0, 0), sizeof(xlogstart));
1925 
1926  if (verbose)
1927  pg_log_info("checkpoint completed");
1928 
1929  /*
1930  * 9.3 and later sends the TLI of the starting point. With older servers,
1931  * assume it's the same as the latest timeline reported by
1932  * IDENTIFY_SYSTEM.
1933  */
1934  if (PQnfields(res) >= 2)
1935  starttli = atoi(PQgetvalue(res, 0, 1));
1936  else
1937  starttli = latesttli;
1938  PQclear(res);
1939  MemSet(xlogend, 0, sizeof(xlogend));
1940 
1941  if (verbose && includewal != NO_WAL)
1942  pg_log_info("write-ahead log start point: %s on timeline %u",
1943  xlogstart, starttli);
1944 
1945  /*
1946  * Get the header
1947  */
1948  res = PQgetResult(conn);
1949  if (PQresultStatus(res) != PGRES_TUPLES_OK)
1950  {
1951  pg_log_error("could not get backup header: %s",
1952  PQerrorMessage(conn));
1953  exit(1);
1954  }
1955  if (PQntuples(res) < 1)
1956  {
1957  pg_log_error("no data returned from server");
1958  exit(1);
1959  }
1960 
1961  /*
1962  * Sum up the total size, for progress reporting
1963  */
1964  totalsize_kb = totaldone = 0;
1965  tablespacecount = PQntuples(res);
1966  for (i = 0; i < PQntuples(res); i++)
1967  {
1968  totalsize_kb += atol(PQgetvalue(res, i, 2));
1969 
1970  /*
1971  * Verify tablespace directories are empty. Don't bother with the
1972  * first once since it can be relocated, and it will be checked before
1973  * we do anything anyway.
1974  */
1975  if (format == 'p' && !PQgetisnull(res, i, 1))
1976  {
1977  char *path = unconstify(char *, get_tablespace_mapping(PQgetvalue(res, i, 1)));
1978 
1980  }
1981  }
1982 
1983  /*
1984  * When writing to stdout, require a single tablespace
1985  */
1986  writing_to_stdout = format == 't' && strcmp(basedir, "-") == 0;
1987  if (writing_to_stdout && PQntuples(res) > 1)
1988  {
1989  pg_log_error("can only write single tablespace to stdout, database has %d",
1990  PQntuples(res));
1991  exit(1);
1992  }
1993 
1994  /*
1995  * If we're streaming WAL, start the streaming session before we start
1996  * receiving the actual data chunks.
1997  */
1998  if (includewal == STREAM_WAL)
1999  {
2000  if (verbose)
2001  pg_log_info("starting background WAL receiver");
2002  StartLogStreamer(xlogstart, starttli, sysidentifier);
2003  }
2004 
2005  /*
2006  * Start receiving chunks
2007  */
2008  for (i = 0; i < PQntuples(res); i++)
2009  {
2010  if (format == 't')
2011  ReceiveTarFile(conn, res, i);
2012  else
2013  ReceiveAndUnpackTarFile(conn, res, i);
2014  } /* Loop over all tablespaces */
2015 
2016  /*
2017  * Now receive backup manifest, if appropriate.
2018  *
2019  * If we're writing a tarfile to stdout, ReceiveTarFile will have already
2020  * processed the backup manifest and included it in the output tarfile.
2021  * Such a configuration doesn't allow for writing multiple files.
2022  *
2023  * If we're talking to an older server, it won't send a backup manifest,
2024  * so don't try to receive one.
2025  */
2026  if (!writing_to_stdout && manifest)
2028 
2029  if (showprogress)
2030  {
2031  progress_report(PQntuples(res), NULL, true);
2032  if (isatty(fileno(stderr)))
2033  fprintf(stderr, "\n"); /* Need to move to next line */
2034  }
2035 
2036  PQclear(res);
2037 
2038  /*
2039  * Get the stop position
2040  */
2041  res = PQgetResult(conn);
2042  if (PQresultStatus(res) != PGRES_TUPLES_OK)
2043  {
2044  pg_log_error("could not get write-ahead log end position from server: %s",
2045  PQerrorMessage(conn));
2046  exit(1);
2047  }
2048  if (PQntuples(res) != 1)
2049  {
2050  pg_log_error("no write-ahead log end position returned from server");
2051  exit(1);
2052  }
2053  strlcpy(xlogend, PQgetvalue(res, 0, 0), sizeof(xlogend));
2054  if (verbose && includewal != NO_WAL)
2055  pg_log_info("write-ahead log end point: %s", xlogend);
2056  PQclear(res);
2057 
2058  res = PQgetResult(conn);
2059  if (PQresultStatus(res) != PGRES_COMMAND_OK)
2060  {
2061  const char *sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
2062 
2063  if (sqlstate &&
2064  strcmp(sqlstate, ERRCODE_DATA_CORRUPTED) == 0)
2065  {
2066  pg_log_error("checksum error occurred");
2067  checksum_failure = true;
2068  }
2069  else
2070  {
2071  pg_log_error("final receive failed: %s",
2072  PQerrorMessage(conn));
2073  }
2074  exit(1);
2075  }
2076 
2077  if (bgchild > 0)
2078  {
2079 #ifndef WIN32
2080  int status;
2081  pid_t r;
2082 #else
2083  DWORD status;
2084 
2085  /*
2086  * get a pointer sized version of bgchild to avoid warnings about
2087  * casting to a different size on WIN64.
2088  */
2089  intptr_t bgchild_handle = bgchild;
2090  uint32 hi,
2091  lo;
2092 #endif
2093 
2094  if (verbose)
2095  pg_log_info("waiting for background process to finish streaming ...");
2096 
2097 #ifndef WIN32
2098  if (write(bgpipe[1], xlogend, strlen(xlogend)) != strlen(xlogend))
2099  {
2100  pg_log_info("could not send command to background pipe: %m");
2101  exit(1);
2102  }
2103 
2104  /* Just wait for the background process to exit */
2105  r = waitpid(bgchild, &status, 0);
2106  if (r == (pid_t) -1)
2107  {
2108  pg_log_error("could not wait for child process: %m");
2109  exit(1);
2110  }
2111  if (r != bgchild)
2112  {
2113  pg_log_error("child %d died, expected %d", (int) r, (int) bgchild);
2114  exit(1);
2115  }
2116  if (status != 0)
2117  {
2118  pg_log_error("%s", wait_result_to_str(status));
2119  exit(1);
2120  }
2121  /* Exited normally, we're happy! */
2122 #else /* WIN32 */
2123 
2124  /*
2125  * On Windows, since we are in the same process, we can just store the
2126  * value directly in the variable, and then set the flag that says
2127  * it's there.
2128  */
2129  if (sscanf(xlogend, "%X/%X", &hi, &lo) != 2)
2130  {
2131  pg_log_error("could not parse write-ahead log location \"%s\"",
2132  xlogend);
2133  exit(1);
2134  }
2135  xlogendptr = ((uint64) hi) << 32 | lo;
2136  InterlockedIncrement(&has_xlogendptr);
2137 
2138  /* First wait for the thread to exit */
2139  if (WaitForSingleObjectEx((HANDLE) bgchild_handle, INFINITE, FALSE) !=
2140  WAIT_OBJECT_0)
2141  {
2142  _dosmaperr(GetLastError());
2143  pg_log_error("could not wait for child thread: %m");
2144  exit(1);
2145  }
2146  if (GetExitCodeThread((HANDLE) bgchild_handle, &status) == 0)
2147  {
2148  _dosmaperr(GetLastError());
2149  pg_log_error("could not get child thread exit status: %m");
2150  exit(1);
2151  }
2152  if (status != 0)
2153  {
2154  pg_log_error("child thread exited with error %u",
2155  (unsigned int) status);
2156  exit(1);
2157  }
2158  /* Exited normally, we're happy */
2159 #endif
2160  }
2161 
2162  /* Free the configuration file contents */
2164 
2165  /*
2166  * End of copy data. Final result is already checked inside the loop.
2167  */
2168  PQclear(res);
2169  PQfinish(conn);
2170  conn = NULL;
2171 
2172  /*
2173  * Make data persistent on disk once backup is completed. For tar format
2174  * sync the parent directory and all its contents as each tar file was not
2175  * synced after being completed. In plain format, all the data of the
2176  * base directory is synced, taking into account all the tablespaces.
2177  * Errors are not considered fatal.
2178  */
2179  if (do_sync)
2180  {
2181  if (verbose)
2182  pg_log_info("syncing data to disk ...");
2183  if (format == 't')
2184  {
2185  if (strcmp(basedir, "-") != 0)
2186  (void) fsync_dir_recurse(basedir);
2187  }
2188  else
2189  {
2190  (void) fsync_pgdata(basedir, serverVersion);
2191  }
2192  }
2193 
2194  /*
2195  * After synchronizing data to disk, perform a durable rename of
2196  * backup_manifest.tmp to backup_manifest, if we wrote such a file. This
2197  * way, a failure or system crash before we reach this point will leave us
2198  * without a backup_manifest file, decreasing the chances that a directory
2199  * we leave behind will be mistaken for a valid backup.
2200  */
2201  if (!writing_to_stdout && manifest)
2202  {
2203  char tmp_filename[MAXPGPATH];
2204  char filename[MAXPGPATH];
2205 
2206  if (verbose)
2207  pg_log_info("renaming backup_manifest.tmp to backup_manifest");
2208 
2209  snprintf(tmp_filename, MAXPGPATH, "%s/backup_manifest.tmp", basedir);
2210  snprintf(filename, MAXPGPATH, "%s/backup_manifest", basedir);
2211 
2212  /* durable_rename emits its own log message in case of failure */
2213  if (durable_rename(tmp_filename, filename) != 0)
2214  exit(1);
2215  }
2216 
2217  if (verbose)
2218  pg_log_info("base backup completed");
2219 }
int PQnfields(const PGresult *res)
Definition: fe-exec.c:2777
static PQExpBuffer recoveryconfcontents
static IncludeWal includewal
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6691
static bool verify_checksums
static int bgpipe[2]
uint32 TimeLineID
Definition: xlogdefs.h:52
static bool found_tablespace_dirs
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3163
const char * PQparameterStatus(const PGconn *conn, const char *paramName)
Definition: fe-connect.c:6656
#define write(a, b, c)
Definition: win32.h:14
#define pg_log_error(...)
Definition: logging.h:79
static bool manifest_force_encode
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static int tablespacecount
void _dosmaperr(unsigned long)
Definition: win32error.c:171
bool RunIdentifySystem(PGconn *conn, char **sysid, TimeLineID *starttli, XLogRecPtr *startpos, char **db_name)
Definition: streamutil.c:409
static bool writerecoveryconf
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4189
static bool checksum_failure
#define MemSet(start, val, len)
Definition: c.h:971
static void ReceiveBackupManifest(PGconn *conn)
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:6681
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2769
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57
#define fprintf
Definition: port.h:197
char * wait_result_to_str(int exitstatus)
Definition: wait_error.c:32
static char * basedir
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2692
void fsync_pgdata(const char *pg_data, int serverVersion)
Definition: file_utils.c:61
int PQsendQuery(PGconn *conn, const char *query)
Definition: fe-exec.c:1234
void destroyPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:116
void fsync_dir_recurse(const char *dir)
Definition: file_utils.c:125
PGconn * conn
Definition: streamutil.c:54
#define MAXPGPATH
static uint64 totaldone
static bool estimatesize
static int32 maxrate
static int has_xlogendptr
size_t PQescapeStringConn(PGconn *conn, char *to, const char *from, size_t length, int *error)
Definition: fe-exec.c:3410
unsigned int uint32
Definition: c.h:367
static char * manifest_checksums
static const char * get_tablespace_mapping(const char *dir)
static void progress_report(int tablespacenum, const char *filename, bool force)
int durable_rename(const char *oldfile, const char *newfile, int elevel)
Definition: fd.c:658
PQExpBuffer GenerateRecoveryConfig(PGconn *pgconn, char *replication_slot)
Definition: recovery_gen.c:23
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:45
static int verbose
#define unconstify(underlying_type, expr)
Definition: c.h:1205
static bool showprogress
static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
static char * label
static void StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier)
void PQclear(PGresult *res)
Definition: fe-exec.c:694
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:2754
#define Assert(condition)
Definition: c.h:738
static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
static bool manifest
static XLogRecPtr xlogendptr
static bool fastcheckpoint
static bool made_tablespace_dirs
static char * filename
Definition: pg_dumpall.c:90
static pid_t bgchild
static uint64 totalsize_kb
int i
static bool do_sync
static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
static char format
static char * replication_slot
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3188
#define snprintf
Definition: port.h:193
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:1778
#define pg_log_info(...)
Definition: logging.h:87
bool CheckServerVersionForStreaming(PGconn *conn)
Definition: receivelog.c:358

◆ cleanup_directories_atexit()

static void cleanup_directories_atexit ( void  )
static

Definition at line 214 of file pg_basebackup.c.

References basedir, checksum_failure, found_existing_pgdata, found_existing_xlogdir, found_tablespace_dirs, in_log_streamer, made_new_pgdata, made_new_xlogdir, made_tablespace_dirs, noclean, pg_log_error, pg_log_info, rmtree(), success, and xlog_dir.

Referenced by main().

215 {
216  if (success || in_log_streamer)
217  return;
218 
219  if (!noclean && !checksum_failure)
220  {
221  if (made_new_pgdata)
222  {
223  pg_log_info("removing data directory \"%s\"", basedir);
224  if (!rmtree(basedir, true))
225  pg_log_error("failed to remove data directory");
226  }
227  else if (found_existing_pgdata)
228  {
229  pg_log_info("removing contents of data directory \"%s\"", basedir);
230  if (!rmtree(basedir, false))
231  pg_log_error("failed to remove contents of data directory");
232  }
233 
234  if (made_new_xlogdir)
235  {
236  pg_log_info("removing WAL directory \"%s\"", xlog_dir);
237  if (!rmtree(xlog_dir, true))
238  pg_log_error("failed to remove WAL directory");
239  }
240  else if (found_existing_xlogdir)
241  {
242  pg_log_info("removing contents of WAL directory \"%s\"", xlog_dir);
243  if (!rmtree(xlog_dir, false))
244  pg_log_error("failed to remove contents of WAL directory");
245  }
246  }
247  else
248  {
250  pg_log_info("data directory \"%s\" not removed at user's request", basedir);
251 
253  pg_log_info("WAL directory \"%s\" not removed at user's request", xlog_dir);
254  }
255 
257  pg_log_info("changes to tablespace directories will not be undone");
258 }
static bool found_existing_pgdata
static bool found_tablespace_dirs
#define pg_log_error(...)
Definition: logging.h:79
static bool checksum_failure
static char * basedir
static bool found_existing_xlogdir
static bool success
static bool made_new_pgdata
bool rmtree(const char *path, bool rmtopdir)
Definition: rmtree.c:42
static bool in_log_streamer
static char * xlog_dir
static bool made_new_xlogdir
static bool made_tablespace_dirs
#define pg_log_info(...)
Definition: logging.h:87
static bool noclean

◆ disconnect_atexit()

static void disconnect_atexit ( void  )
static

Definition at line 261 of file pg_basebackup.c.

References conn, and PQfinish().

Referenced by main().

262 {
263  if (conn != NULL)
264  PQfinish(conn);
265 }
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4189
PGconn * conn
Definition: streamutil.c:54

◆ get_tablespace_mapping()

static const char * get_tablespace_mapping ( const char *  dir)
static

Definition at line 1482 of file pg_basebackup.c.

References canonicalize_path(), TablespaceList::head, MAXPGPATH, TablespaceListCell::new_dir, TablespaceListCell::next, TablespaceListCell::old_dir, and strlcpy().

Referenced by BaseBackup(), ReceiveAndUnpackTarFile(), and ReceiveTarAndUnpackCopyChunk().

1483 {
1484  TablespaceListCell *cell;
1485  char canon_dir[MAXPGPATH];
1486 
1487  /* Canonicalize path for comparison consistency */
1488  strlcpy(canon_dir, dir, sizeof(canon_dir));
1489  canonicalize_path(canon_dir);
1490 
1491  for (cell = tablespace_dirs.head; cell; cell = cell->next)
1492  if (strcmp(canon_dir, cell->old_dir) == 0)
1493  return cell->new_dir;
1494 
1495  return dir;
1496 }
static TablespaceList tablespace_dirs
char old_dir[MAXPGPATH]
Definition: pg_basebackup.c:50
void canonicalize_path(char *path)
Definition: path.c:254
char new_dir[MAXPGPATH]
Definition: pg_basebackup.c:51
#define MAXPGPATH
struct TablespaceListCell * next
Definition: pg_basebackup.c:49
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
TablespaceListCell * head
Definition: pg_basebackup.c:56

◆ kill_bgchild_atexit()

static void kill_bgchild_atexit ( void  )
static

Definition at line 274 of file pg_basebackup.c.

References bgchild, and kill.

Referenced by StartLogStreamer().

275 {
276  if (bgchild > 0)
277  kill(bgchild, SIGTERM);
278 }
#define kill(pid, sig)
Definition: win32_port.h:426
static pid_t bgchild

◆ LogStreamerMain()

static int LogStreamerMain ( logstreamer_param param)
static

Definition at line 530 of file pg_basebackup.c.

References logstreamer_param::bgconn, bgpipe, compresslevel, CreateWalDirectoryMethod(), CreateWalTarMethod(), StreamCtl::do_sync, WalWriteMethod::finish, format, FreeWalDirectoryMethod(), FreeWalTarMethod(), in_log_streamer, StreamCtl::mark_done, MemSet, StreamCtl::partial_suffix, pg_free(), pg_log_error, PGINVALID_SOCKET, PQfinish(), reached_end_position(), ReceiveXlogStream(), StreamCtl::replication_slot, replication_slot, StreamCtl::standby_message_timeout, standby_message_timeout, StreamCtl::startpos, logstreamer_param::startptr, StreamCtl::stop_socket, StreamCtl::stream_stop, StreamCtl::synchronous, StreamCtl::sysidentifier, logstreamer_param::sysidentifier, StreamCtl::timeline, logstreamer_param::timeline, StreamCtl::walmethod, and logstreamer_param::xlog.

Referenced by StartLogStreamer().

531 {
532  StreamCtl stream;
533 
534  in_log_streamer = true;
535 
536  MemSet(&stream, 0, sizeof(stream));
537  stream.startpos = param->startptr;
538  stream.timeline = param->timeline;
539  stream.sysidentifier = param->sysidentifier;
541 #ifndef WIN32
542  stream.stop_socket = bgpipe[0];
543 #else
544  stream.stop_socket = PGINVALID_SOCKET;
545 #endif
547  stream.synchronous = false;
548  /* fsync happens at the end of pg_basebackup for all data */
549  stream.do_sync = false;
550  stream.mark_done = true;
551  stream.partial_suffix = NULL;
553 
554  if (format == 'p')
555  stream.walmethod = CreateWalDirectoryMethod(param->xlog, 0,
556  stream.do_sync);
557  else
559  stream.do_sync);
560 
561  if (!ReceiveXlogStream(param->bgconn, &stream))
562 
563  /*
564  * Any errors will already have been reported in the function process,
565  * but we need to tell the parent that we didn't shutdown in a nice
566  * way.
567  */
568  return 1;
569 
570  if (!stream.walmethod->finish())
571  {
572  pg_log_error("could not finish writing WAL files: %m");
573  return 1;
574  }
575 
576  PQfinish(param->bgconn);
577 
578  if (format == 'p')
580  else
582  pg_free(stream.walmethod);
583 
584  return 0;
585 }
static int bgpipe[2]
bool do_sync
Definition: receivelog.h:38
#define pg_log_error(...)
Definition: logging.h:79
char * sysidentifier
Definition: receivelog.h:33
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4189
static int compresslevel
#define MemSet(start, val, len)
Definition: c.h:971
XLogRecPtr startpos
Definition: receivelog.h:31
char * partial_suffix
Definition: receivelog.h:47
static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline, bool segment_finished)
TimeLineID timeline
Definition: receivelog.h:32
WalWriteMethod * CreateWalDirectoryMethod(const char *basedir, int compression, bool sync)
Definition: walmethods.c:349
char * replication_slot
Definition: receivelog.h:48
bool mark_done
Definition: receivelog.h:37
XLogRecPtr startptr
stream_stop_callback stream_stop
Definition: receivelog.h:41
WalWriteMethod * walmethod
Definition: receivelog.h:46
static int standby_message_timeout
void FreeWalTarMethod(void)
Definition: walmethods.c:1018
#define PGINVALID_SOCKET
Definition: port.h:33
static bool in_log_streamer
WalWriteMethod * CreateWalTarMethod(const char *tarbase, int compression, bool sync)
Definition: walmethods.c:987
bool ReceiveXlogStream(PGconn *conn, StreamCtl *stream)
Definition: receivelog.c:436
bool synchronous
Definition: receivelog.h:36
void pg_free(void *ptr)
Definition: fe_memutils.c:105
bool(* finish)(void)
Definition: walmethods.h:75
pgsocket stop_socket
Definition: receivelog.h:43
int standby_message_timeout
Definition: receivelog.h:35
static char format
static char * replication_slot
void FreeWalDirectoryMethod(void)
Definition: walmethods.c:373
char xlog[MAXPGPATH]

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 2223 of file pg_basebackup.c.

References _, BaseBackup(), basedir, canonicalize_path(), cleanup_directories_atexit(), compresslevel, conn, connection_string, create_slot, dbgetpassword, dbhost, dbport, dbuser, disconnect_atexit(), do_sync, estimatesize, fastcheckpoint, FETCH_WAL, format, found_existing_pgdata, found_existing_xlogdir, fprintf, free, get_progname(), GetConnection(), getopt_long(), includewal, is_absolute_path, label, made_new_pgdata, made_new_xlogdir, manifest, manifest_checksums, manifest_force_encode, maxrate, MINIMUM_VERSION_FOR_MANIFESTS, MINIMUM_VERSION_FOR_PG_WAL, no_argument, no_slot, NO_WAL, noclean, optarg, optind, parse_max_rate(), pg_log_error, pg_logging_init(), pg_mode_mask, pg_strcasecmp(), pg_strdup(), PG_TEXTDOMAIN, PQserverVersion(), progname, psprintf(), replication_slot, required_argument, RetrieveWalSegSize(), set_pglocale_pgservice(), showprogress, standby_message_timeout, STREAM_WAL, success, symlink, tablespace_list_append(), temp_replication_slot, usage(), verbose, verify_checksums, verify_dir_is_empty_or_create(), writerecoveryconf, xlog_dir, and Z_DEFAULT_COMPRESSION.

2224 {
2225  static struct option long_options[] = {
2226  {"help", no_argument, NULL, '?'},
2227  {"version", no_argument, NULL, 'V'},
2228  {"pgdata", required_argument, NULL, 'D'},
2229  {"format", required_argument, NULL, 'F'},
2230  {"checkpoint", required_argument, NULL, 'c'},
2231  {"create-slot", no_argument, NULL, 'C'},
2232  {"max-rate", required_argument, NULL, 'r'},
2233  {"write-recovery-conf", no_argument, NULL, 'R'},
2234  {"slot", required_argument, NULL, 'S'},
2235  {"tablespace-mapping", required_argument, NULL, 'T'},
2236  {"wal-method", required_argument, NULL, 'X'},
2237  {"gzip", no_argument, NULL, 'z'},
2238  {"compress", required_argument, NULL, 'Z'},
2239  {"label", required_argument, NULL, 'l'},
2240  {"no-clean", no_argument, NULL, 'n'},
2241  {"no-sync", no_argument, NULL, 'N'},
2242  {"dbname", required_argument, NULL, 'd'},
2243  {"host", required_argument, NULL, 'h'},
2244  {"port", required_argument, NULL, 'p'},
2245  {"username", required_argument, NULL, 'U'},
2246  {"no-password", no_argument, NULL, 'w'},
2247  {"password", no_argument, NULL, 'W'},
2248  {"status-interval", required_argument, NULL, 's'},
2249  {"verbose", no_argument, NULL, 'v'},
2250  {"progress", no_argument, NULL, 'P'},
2251  {"waldir", required_argument, NULL, 1},
2252  {"no-slot", no_argument, NULL, 2},
2253  {"no-verify-checksums", no_argument, NULL, 3},
2254  {"no-estimate-size", no_argument, NULL, 4},
2255  {"no-manifest", no_argument, NULL, 5},
2256  {"manifest-force-encode", no_argument, NULL, 6},
2257  {"manifest-checksums", required_argument, NULL, 7},
2258  {NULL, 0, NULL, 0}
2259  };
2260  int c;
2261 
2262  int option_index;
2263 
2264  pg_logging_init(argv[0]);
2265  progname = get_progname(argv[0]);
2266  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_basebackup"));
2267 
2268  if (argc > 1)
2269  {
2270  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
2271  {
2272  usage();
2273  exit(0);
2274  }
2275  else if (strcmp(argv[1], "-V") == 0
2276  || strcmp(argv[1], "--version") == 0)
2277  {
2278  puts("pg_basebackup (PostgreSQL) " PG_VERSION);
2279  exit(0);
2280  }
2281  }
2282 
2284 
2285  while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
2286  long_options, &option_index)) != -1)
2287  {
2288  switch (c)
2289  {
2290  case 'C':
2291  create_slot = true;
2292  break;
2293  case 'D':
2295  break;
2296  case 'F':
2297  if (strcmp(optarg, "p") == 0 || strcmp(optarg, "plain") == 0)
2298  format = 'p';
2299  else if (strcmp(optarg, "t") == 0 || strcmp(optarg, "tar") == 0)
2300  format = 't';
2301  else
2302  {
2303  pg_log_error("invalid output format \"%s\", must be \"plain\" or \"tar\"",
2304  optarg);
2305  exit(1);
2306  }
2307  break;
2308  case 'r':
2310  break;
2311  case 'R':
2312  writerecoveryconf = true;
2313  break;
2314  case 'S':
2315 
2316  /*
2317  * When specifying replication slot name, use a permanent
2318  * slot.
2319  */
2321  temp_replication_slot = false;
2322  break;
2323  case 2:
2324  no_slot = true;
2325  break;
2326  case 'T':
2328  break;
2329  case 'X':
2330  if (strcmp(optarg, "n") == 0 ||
2331  strcmp(optarg, "none") == 0)
2332  {
2333  includewal = NO_WAL;
2334  }
2335  else if (strcmp(optarg, "f") == 0 ||
2336  strcmp(optarg, "fetch") == 0)
2337  {
2339  }
2340  else if (strcmp(optarg, "s") == 0 ||
2341  strcmp(optarg, "stream") == 0)
2342  {
2344  }
2345  else
2346  {
2347  pg_log_error("invalid wal-method option \"%s\", must be \"fetch\", \"stream\", or \"none\"",
2348  optarg);
2349  exit(1);
2350  }
2351  break;
2352  case 1:
2354  break;
2355  case 'l':
2356  label = pg_strdup(optarg);
2357  break;
2358  case 'n':
2359  noclean = true;
2360  break;
2361  case 'N':
2362  do_sync = false;
2363  break;
2364  case 'z':
2365 #ifdef HAVE_LIBZ
2367 #else
2368  compresslevel = 1; /* will be rejected below */
2369 #endif
2370  break;
2371  case 'Z':
2372  compresslevel = atoi(optarg);
2373  if (compresslevel < 0 || compresslevel > 9)
2374  {
2375  pg_log_error("invalid compression level \"%s\"", optarg);
2376  exit(1);
2377  }
2378  break;
2379  case 'c':
2380  if (pg_strcasecmp(optarg, "fast") == 0)
2381  fastcheckpoint = true;
2382  else if (pg_strcasecmp(optarg, "spread") == 0)
2383  fastcheckpoint = false;
2384  else
2385  {
2386  pg_log_error("invalid checkpoint argument \"%s\", must be \"fast\" or \"spread\"",
2387  optarg);
2388  exit(1);
2389  }
2390  break;
2391  case 'd':
2393  break;
2394  case 'h':
2395  dbhost = pg_strdup(optarg);
2396  break;
2397  case 'p':
2398  dbport = pg_strdup(optarg);
2399  break;
2400  case 'U':
2401  dbuser = pg_strdup(optarg);
2402  break;
2403  case 'w':
2404  dbgetpassword = -1;
2405  break;
2406  case 'W':
2407  dbgetpassword = 1;
2408  break;
2409  case 's':
2410  standby_message_timeout = atoi(optarg) * 1000;
2411  if (standby_message_timeout < 0)
2412  {
2413  pg_log_error("invalid status interval \"%s\"", optarg);
2414  exit(1);
2415  }
2416  break;
2417  case 'v':
2418  verbose++;
2419  break;
2420  case 'P':
2421  showprogress = true;
2422  break;
2423  case 3:
2424  verify_checksums = false;
2425  break;
2426  case 4:
2427  estimatesize = false;
2428  break;
2429  case 5:
2430  manifest = false;
2431  break;
2432  case 6:
2433  manifest_force_encode = true;
2434  break;
2435  case 7:
2437  break;
2438  default:
2439 
2440  /*
2441  * getopt_long already emitted a complaint
2442  */
2443  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2444  progname);
2445  exit(1);
2446  }
2447  }
2448 
2449  /*
2450  * Any non-option arguments?
2451  */
2452  if (optind < argc)
2453  {
2454  pg_log_error("too many command-line arguments (first is \"%s\")",
2455  argv[optind]);
2456  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2457  progname);
2458  exit(1);
2459  }
2460 
2461  /*
2462  * Required arguments
2463  */
2464  if (basedir == NULL)
2465  {
2466  pg_log_error("no target directory specified");
2467  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2468  progname);
2469  exit(1);
2470  }
2471 
2472  /*
2473  * Mutually exclusive arguments
2474  */
2475  if (format == 'p' && compresslevel != 0)
2476  {
2477  pg_log_error("only tar mode backups can be compressed");
2478  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2479  progname);
2480  exit(1);
2481  }
2482 
2483  if (format == 't' && includewal == STREAM_WAL && strcmp(basedir, "-") == 0)
2484  {
2485  pg_log_error("cannot stream write-ahead logs in tar mode to stdout");
2486  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2487  progname);
2488  exit(1);
2489  }
2490 
2492  {
2493  pg_log_error("replication slots can only be used with WAL streaming");
2494  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2495  progname);
2496  exit(1);
2497  }
2498 
2499  if (no_slot)
2500  {
2501  if (replication_slot)
2502  {
2503  pg_log_error("--no-slot cannot be used with slot name");
2504  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2505  progname);
2506  exit(1);
2507  }
2508  temp_replication_slot = false;
2509  }
2510 
2511  if (create_slot)
2512  {
2513  if (!replication_slot)
2514  {
2515  pg_log_error("%s needs a slot to be specified using --slot",
2516  "--create-slot");
2517  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2518  progname);
2519  exit(1);
2520  }
2521 
2522  if (no_slot)
2523  {
2524  pg_log_error("%s and %s are incompatible options",
2525  "--create-slot", "--no-slot");
2526  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2527  progname);
2528  exit(1);
2529  }
2530  }
2531 
2532  if (xlog_dir)
2533  {
2534  if (format != 'p')
2535  {
2536  pg_log_error("WAL directory location can only be specified in plain mode");
2537  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2538  progname);
2539  exit(1);
2540  }
2541 
2542  /* clean up xlog directory name, check it's absolute */
2544  if (!is_absolute_path(xlog_dir))
2545  {
2546  pg_log_error("WAL directory location must be an absolute path");
2547  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2548  progname);
2549  exit(1);
2550  }
2551  }
2552 
2553 #ifndef HAVE_LIBZ
2554  if (compresslevel != 0)
2555  {
2556  pg_log_error("this build does not support compression");
2557  exit(1);
2558  }
2559 #endif
2560 
2561  if (showprogress && !estimatesize)
2562  {
2563  pg_log_error("%s and %s are incompatible options",
2564  "--progress", "--no-estimate-size");
2565  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2566  progname);
2567  exit(1);
2568  }
2569 
2570  if (!manifest && manifest_checksums != NULL)
2571  {
2572  pg_log_error("%s and %s are incompatible options",
2573  "--no-manifest", "--manifest-checksums");
2574  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2575  progname);
2576  exit(1);
2577  }
2578 
2580  {
2581  pg_log_error("%s and %s are incompatible options",
2582  "--no-manifest", "--manifest-force-encode");
2583  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2584  progname);
2585  exit(1);
2586  }
2587 
2588  /* connection in replication mode to server */
2589  conn = GetConnection();
2590  if (!conn)
2591  {
2592  /* Error message already written in GetConnection() */
2593  exit(1);
2594  }
2595  atexit(disconnect_atexit);
2596 
2597  /*
2598  * Set umask so that directories/files are created with the same
2599  * permissions as directories/files in the source data directory.
2600  *
2601  * pg_mode_mask is set to owner-only by default and then updated in
2602  * GetConnection() where we get the mode from the server-side with
2603  * RetrieveDataDirCreatePerm() and then call SetDataDirectoryCreatePerm().
2604  */
2605  umask(pg_mode_mask);
2606 
2607  /* Backup manifests are supported in 13 and newer versions */
2609  manifest = false;
2610 
2611  /*
2612  * Verify that the target directory exists, or create it. For plaintext
2613  * backups, always require the directory. For tar backups, require it
2614  * unless we are writing to stdout.
2615  */
2616  if (format == 'p' || strcmp(basedir, "-") != 0)
2618 
2619  /* determine remote server's xlog segment size */
2620  if (!RetrieveWalSegSize(conn))
2621  exit(1);
2622 
2623  /* Create pg_wal symlink, if required */
2624  if (xlog_dir)
2625  {
2626  char *linkloc;
2627 
2629 
2630  /*
2631  * Form name of the place where the symlink must go. pg_xlog has been
2632  * renamed to pg_wal in post-10 clusters.
2633  */
2634  linkloc = psprintf("%s/%s", basedir,
2636  "pg_xlog" : "pg_wal");
2637 
2638 #ifdef HAVE_SYMLINK
2639  if (symlink(xlog_dir, linkloc) != 0)
2640  {
2641  pg_log_error("could not create symbolic link \"%s\": %m", linkloc);
2642  exit(1);
2643  }
2644 #else
2645  pg_log_error("symlinks are not supported on this platform");
2646  exit(1);
2647 #endif
2648  free(linkloc);
2649  }
2650 
2651  BaseBackup();
2652 
2653  success = true;
2654  return 0;
2655 }
static IncludeWal includewal
#define Z_DEFAULT_COMPRESSION
static bool verify_checksums
static bool found_existing_pgdata
static void usage(void)
const char * get_progname(const char *argv0)
Definition: path.c:453
#define pg_log_error(...)
Definition: logging.h:79
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:57
static int32 parse_max_rate(char *src)
static bool manifest_force_encode
void pg_logging_init(const char *argv0)
Definition: logging.c:81
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
void canonicalize_path(char *path)
Definition: path.c:254
static bool writerecoveryconf
static bool create_slot
static int compresslevel
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:6681
const char * progname
Definition: pg_standby.c:36
#define fprintf
Definition: port.h:197
static char * basedir
static void BaseBackup(void)
#define required_argument
Definition: getopt_long.h:25
int optind
Definition: getopt.c:50
char * connection_string
Definition: streamutil.c:46
bool RetrieveWalSegSize(PGconn *conn)
Definition: streamutil.c:277
PGconn * conn
Definition: streamutil.c:54
#define MINIMUM_VERSION_FOR_PG_WAL
static bool found_existing_xlogdir
static bool estimatesize
static bool success
static int32 maxrate
char * c
#define symlink(oldpath, newpath)
Definition: win32_port.h:221
static bool made_new_pgdata
#define is_absolute_path(filename)
Definition: port.h:86
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
static char * manifest_checksums
static int verbose
static int standby_message_timeout
static bool showprogress
int dbgetpassword
Definition: streamutil.c:51
#define no_argument
Definition: getopt_long.h:24
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1177
static bool temp_replication_slot
static char * label
static void disconnect_atexit(void)
char * dbport
Definition: streamutil.c:49
static void cleanup_directories_atexit(void)
#define free(a)
Definition: header.h:65
#define MINIMUM_VERSION_FOR_MANIFESTS
PGconn * GetConnection(UserMapping *user, bool will_prep_stmt)
Definition: connection.c:107
char * dbhost
Definition: streamutil.c:47
static char * xlog_dir
static bool manifest
static bool no_slot
static bool made_new_xlogdir
static bool fastcheckpoint
static void tablespace_list_append(const char *arg)
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:434
char * dbuser
Definition: streamutil.c:48
char * optarg
Definition: getopt.c:52
static bool do_sync
static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
static char format
static char * replication_slot
#define _(x)
Definition: elog.c:88
int pg_mode_mask
Definition: file_perm.c:25
static bool noclean

◆ parse_max_rate()

static int32 parse_max_rate ( char *  src)
static

Definition at line 861 of file pg_basebackup.c.

References MAX_RATE_UPPER, and pg_log_error.

Referenced by main().

862 {
863  double result;
864  char *after_num;
865  char *suffix = NULL;
866 
867  errno = 0;
868  result = strtod(src, &after_num);
869  if (src == after_num)
870  {
871  pg_log_error("transfer rate \"%s\" is not a valid value", src);
872  exit(1);
873  }
874  if (errno != 0)
875  {
876  pg_log_error("invalid transfer rate \"%s\": %m", src);
877  exit(1);
878  }
879 
880  if (result <= 0)
881  {
882  /*
883  * Reject obviously wrong values here.
884  */
885  pg_log_error("transfer rate must be greater than zero");
886  exit(1);
887  }
888 
889  /*
890  * Evaluate suffix, after skipping over possible whitespace. Lack of
891  * suffix means kilobytes.
892  */
893  while (*after_num != '\0' && isspace((unsigned char) *after_num))
894  after_num++;
895 
896  if (*after_num != '\0')
897  {
898  suffix = after_num;
899  if (*after_num == 'k')
900  {
901  /* kilobyte is the expected unit. */
902  after_num++;
903  }
904  else if (*after_num == 'M')
905  {
906  after_num++;
907  result *= 1024.0;
908  }
909  }
910 
911  /* The rest can only consist of white space. */
912  while (*after_num != '\0' && isspace((unsigned char) *after_num))
913  after_num++;
914 
915  if (*after_num != '\0')
916  {
917  pg_log_error("invalid --max-rate unit: \"%s\"", suffix);
918  exit(1);
919  }
920 
921  /* Valid integer? */
922  if ((uint64) result != (uint64) ((uint32) result))
923  {
924  pg_log_error("transfer rate \"%s\" exceeds integer range", src);
925  exit(1);
926  }
927 
928  /*
929  * The range is checked on the server side too, but avoid the server
930  * connection if a nonsensical value was passed.
931  */
932  if (result < MAX_RATE_LOWER || result > MAX_RATE_UPPER)
933  {
934  pg_log_error("transfer rate \"%s\" is out of range", src);
935  exit(1);
936  }
937 
938  return (int32) result;
939 }
#define pg_log_error(...)
Definition: logging.h:79
signed int int32
Definition: c.h:355
#define MAX_RATE_UPPER
Definition: basebackup.h:21
unsigned int uint32
Definition: c.h:367

◆ progress_report()

static void progress_report ( int  tablespacenum,
const char *  filename,
bool  force 
)
static

Definition at line 772 of file pg_basebackup.c.

References fprintf, INT64_FORMAT, last_progress_report, ngettext, now(), showprogress, snprintf, tablespacecount, totaldone, totalsize_kb, verbose, and VERBOSE_FILENAME_LENGTH.

Referenced by BaseBackup(), ReceiveAndUnpackTarFile(), ReceiveTarAndUnpackCopyChunk(), ReceiveTarCopyChunk(), ReceiveTarFile(), and write_target_range().

773 {
774  int percent;
775  char totaldone_str[32];
776  char totalsize_str[32];
777  pg_time_t now;
778 
779  if (!showprogress)
780  return;
781 
782  now = time(NULL);
783  if (now == last_progress_report && !force)
784  return; /* Max once per second */
785 
787  percent = totalsize_kb ? (int) ((totaldone / 1024) * 100 / totalsize_kb) : 0;
788 
789  /*
790  * Avoid overflowing past 100% or the full size. This may make the total
791  * size number change as we approach the end of the backup (the estimate
792  * will always be wrong if WAL is included), but that's better than having
793  * the done column be bigger than the total.
794  */
795  if (percent > 100)
796  percent = 100;
797  if (totaldone / 1024 > totalsize_kb)
798  totalsize_kb = totaldone / 1024;
799 
800  /*
801  * Separate step to keep platform-dependent format code out of
802  * translatable strings. And we only test for INT64_FORMAT availability
803  * in snprintf, not fprintf.
804  */
805  snprintf(totaldone_str, sizeof(totaldone_str), INT64_FORMAT,
806  totaldone / 1024);
807  snprintf(totalsize_str, sizeof(totalsize_str), INT64_FORMAT, totalsize_kb);
808 
809 #define VERBOSE_FILENAME_LENGTH 35
810  if (verbose)
811  {
812  if (!filename)
813 
814  /*
815  * No filename given, so clear the status line (used for last
816  * call)
817  */
818  fprintf(stderr,
819  ngettext("%*s/%s kB (100%%), %d/%d tablespace %*s",
820  "%*s/%s kB (100%%), %d/%d tablespaces %*s",
822  (int) strlen(totalsize_str),
823  totaldone_str, totalsize_str,
824  tablespacenum, tablespacecount,
825  VERBOSE_FILENAME_LENGTH + 5, "");
826  else
827  {
828  bool truncate = (strlen(filename) > VERBOSE_FILENAME_LENGTH);
829 
830  fprintf(stderr,
831  ngettext("%*s/%s kB (%d%%), %d/%d tablespace (%s%-*.*s)",
832  "%*s/%s kB (%d%%), %d/%d tablespaces (%s%-*.*s)",
834  (int) strlen(totalsize_str),
835  totaldone_str, totalsize_str, percent,
836  tablespacenum, tablespacecount,
837  /* Prefix with "..." if we do leading truncation */
838  truncate ? "..." : "",
841  /* Truncate filename at beginning if it's too long */
842  truncate ? filename + strlen(filename) - VERBOSE_FILENAME_LENGTH + 3 : filename);
843  }
844  }
845  else
846  fprintf(stderr,
847  ngettext("%*s/%s kB (%d%%), %d/%d tablespace",
848  "%*s/%s kB (%d%%), %d/%d tablespaces",
850  (int) strlen(totalsize_str),
851  totaldone_str, totalsize_str, percent,
852  tablespacenum, tablespacecount);
853 
854  if (isatty(fileno(stderr)))
855  fprintf(stderr, "\r");
856  else
857  fprintf(stderr, "\n");
858 }
int64 pg_time_t
Definition: pgtime.h:23
static pg_time_t last_progress_report
static int tablespacecount
#define VERBOSE_FILENAME_LENGTH
#define fprintf
Definition: port.h:197
static uint64 totaldone
static int verbose
static bool showprogress
#define ngettext(s, p, n)
Definition: c.h:1145
#define INT64_FORMAT
Definition: c.h:409
static char * filename
Definition: pg_dumpall.c:90
static uint64 totalsize_kb
#define snprintf
Definition: port.h:193
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1538

◆ reached_end_position()

static bool reached_end_position ( XLogRecPtr  segendpos,
uint32  timeline,
bool  segment_finished 
)
static

Definition at line 440 of file pg_basebackup.c.

References bgpipe, has_xlogendptr, MemSet, pg_log_error, read, select, and xlogendptr.

Referenced by LogStreamerMain().

442 {
443  if (!has_xlogendptr)
444  {
445 #ifndef WIN32
446  fd_set fds;
447  struct timeval tv;
448  int r;
449 
450  /*
451  * Don't have the end pointer yet - check our pipe to see if it has
452  * been sent yet.
453  */
454  FD_ZERO(&fds);
455  FD_SET(bgpipe[0], &fds);
456 
457  MemSet(&tv, 0, sizeof(tv));
458 
459  r = select(bgpipe[0] + 1, &fds, NULL, NULL, &tv);
460  if (r == 1)
461  {
462  char xlogend[64];
463  uint32 hi,
464  lo;
465 
466  MemSet(xlogend, 0, sizeof(xlogend));
467  r = read(bgpipe[0], xlogend, sizeof(xlogend) - 1);
468  if (r < 0)
469  {
470  pg_log_error("could not read from ready pipe: %m");
471  exit(1);
472  }
473 
474  if (sscanf(xlogend, "%X/%X", &hi, &lo) != 2)
475  {
476  pg_log_error("could not parse write-ahead log location \"%s\"",
477  xlogend);
478  exit(1);
479  }
480  xlogendptr = ((uint64) hi) << 32 | lo;
481  has_xlogendptr = 1;
482 
483  /*
484  * Fall through to check if we've reached the point further
485  * already.
486  */
487  }
488  else
489  {
490  /*
491  * No data received on the pipe means we don't know the end
492  * position yet - so just say it's not time to stop yet.
493  */
494  return false;
495  }
496 #else
497 
498  /*
499  * On win32, has_xlogendptr is set by the main thread, so if it's not
500  * set here, we just go back and wait until it shows up.
501  */
502  return false;
503 #endif
504  }
505 
506  /*
507  * At this point we have an end pointer, so compare it to the current
508  * position to figure out if it's time to stop.
509  */
510  if (segendpos >= xlogendptr)
511  return true;
512 
513  /*
514  * Have end pointer, but haven't reached it yet - so tell the caller to
515  * keep streaming.
516  */
517  return false;
518 }
static int bgpipe[2]
#define pg_log_error(...)
Definition: logging.h:79
#define MemSet(start, val, len)
Definition: c.h:971
static int has_xlogendptr
#define select(n, r, w, e, timeout)
Definition: win32_port.h:436
unsigned int uint32
Definition: c.h:367
static XLogRecPtr xlogendptr
#define read(a, b, c)
Definition: win32.h:13

◆ ReceiveAndUnpackTarFile()

static void ReceiveAndUnpackTarFile ( PGconn conn,
PGresult res,
int  rownum 
)
static

Definition at line 1509 of file pg_basebackup.c.

References basedir, UnpackTarState::current_path, UnpackTarState::file, UnpackTarState::filename, get_tablespace_mapping(), pg_log_error, PQgetisnull(), PQgetvalue(), progress_report(), ReceiveCopyData(), ReceiveTarAndUnpackCopyChunk(), strlcpy(), UnpackTarState::tablespacenum, writerecoveryconf, and WriteRecoveryConfig().

Referenced by BaseBackup().

1510 {
1512  bool basetablespace;
1513 
1514  memset(&state, 0, sizeof(state));
1515  state.tablespacenum = rownum;
1516 
1517  basetablespace = PQgetisnull(res, rownum, 0);
1518  if (basetablespace)
1519  strlcpy(state.current_path, basedir, sizeof(state.current_path));
1520  else
1521  strlcpy(state.current_path,
1522  get_tablespace_mapping(PQgetvalue(res, rownum, 1)),
1523  sizeof(state.current_path));
1524 
1526 
1527 
1528  if (state.file)
1529  fclose(state.file);
1530 
1531  progress_report(rownum, state.filename, true);
1532 
1533  if (state.file != NULL)
1534  {
1535  pg_log_error("COPY stream ended before last file was finished");
1536  exit(1);
1537  }
1538 
1539  if (basetablespace && writerecoveryconf)
1541 
1542  /*
1543  * No data is synced here, everything is done for all tablespaces at the
1544  * end.
1545  */
1546 }
char current_path[MAXPGPATH]
Definition: pg_basebackup.c:83
static PQExpBuffer recoveryconfcontents
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3163
#define pg_log_error(...)
Definition: logging.h:79
void WriteRecoveryConfig(PGconn *pgconn, char *target_dir, PQExpBuffer contents)
Definition: recovery_gen.c:117
static bool writerecoveryconf
char filename[MAXPGPATH]
Definition: pg_basebackup.c:84
static char * basedir
static void ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf, void *callback_data)
static void ReceiveCopyData(PGconn *conn, WriteDataCallback callback, void *callback_data)
static const char * get_tablespace_mapping(const char *dir)
static void progress_report(int tablespacenum, const char *filename, bool force)
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
Definition: regguts.h:298
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3188

◆ ReceiveBackupManifest()

static void ReceiveBackupManifest ( PGconn conn)
static

Definition at line 1732 of file pg_basebackup.c.

References basedir, WriteManifestState::file, WriteManifestState::filename, pg_log_error, ReceiveBackupManifestChunk(), ReceiveCopyData(), and snprintf.

Referenced by BaseBackup().

1733 {
1735 
1736  snprintf(state.filename, sizeof(state.filename),
1737  "%s/backup_manifest.tmp", basedir);
1738  state.file = fopen(state.filename, "wb");
1739  if (state.file == NULL)
1740  {
1741  pg_log_error("could not create file \"%s\": %m", state.filename);
1742  exit(1);
1743  }
1744 
1746 
1747  fclose(state.file);
1748 }
#define pg_log_error(...)
Definition: logging.h:79
static char * basedir
static void ReceiveCopyData(PGconn *conn, WriteDataCallback callback, void *callback_data)
static void ReceiveBackupManifestChunk(size_t r, char *copybuf, void *callback_data)
Definition: regguts.h:298
char filename[MAXPGPATH]
Definition: pg_basebackup.c:93
#define snprintf
Definition: port.h:193

◆ ReceiveBackupManifestChunk()

static void ReceiveBackupManifestChunk ( size_t  r,
char *  copybuf,
void *  callback_data 
)
static

Definition at line 1754 of file pg_basebackup.c.

References WriteManifestState::file, WriteManifestState::filename, and pg_log_error.

Referenced by ReceiveBackupManifest().

1755 {
1756  WriteManifestState *state = callback_data;
1757 
1758  errno = 0;
1759  if (fwrite(copybuf, r, 1, state->file) != 1)
1760  {
1761  /* if write didn't set errno, assume problem is no disk space */
1762  if (errno == 0)
1763  errno = ENOSPC;
1764  pg_log_error("could not write to file \"%s\": %m", state->filename);
1765  exit(1);
1766  }
1767 }
#define pg_log_error(...)
Definition: logging.h:79
StringInfo copybuf
Definition: tablesync.c:108
Definition: regguts.h:298
char filename[MAXPGPATH]
Definition: pg_basebackup.c:93

◆ ReceiveBackupManifestInMemory()

static void ReceiveBackupManifestInMemory ( PGconn conn,
PQExpBuffer  buf 
)
static

Definition at line 1773 of file pg_basebackup.c.

References ReceiveBackupManifestInMemoryChunk(), and ReceiveCopyData().

Referenced by ReceiveTarFile().

1774 {
1776 }
static void ReceiveCopyData(PGconn *conn, WriteDataCallback callback, void *callback_data)
static void ReceiveBackupManifestInMemoryChunk(size_t r, char *copybuf, void *callback_data)

◆ ReceiveBackupManifestInMemoryChunk()

static void ReceiveBackupManifestInMemoryChunk ( size_t  r,
char *  copybuf,
void *  callback_data 
)
static

Definition at line 1782 of file pg_basebackup.c.

References appendPQExpBuffer(), and buf.

Referenced by ReceiveBackupManifestInMemory().

1784 {
1785  PQExpBuffer buf = callback_data;
1786 
1787  appendPQExpBuffer(buf, copybuf, r);
1788 }
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:67
StringInfo copybuf
Definition: tablesync.c:108

◆ ReceiveCopyData()

static void ReceiveCopyData ( PGconn conn,
WriteDataCallback  callback,
void *  callback_data 
)
static

Definition at line 946 of file pg_basebackup.c.

References copybuf, pg_log_error, PGRES_COPY_OUT, PQclear(), PQerrorMessage(), PQfreemem(), PQgetCopyData(), PQgetResult(), and PQresultStatus().

Referenced by ReceiveAndUnpackTarFile(), ReceiveBackupManifest(), ReceiveBackupManifestInMemory(), and ReceiveTarFile().

948 {
949  PGresult *res;
950 
951  /* Get the COPY data stream. */
952  res = PQgetResult(conn);
953  if (PQresultStatus(res) != PGRES_COPY_OUT)
954  {
955  pg_log_error("could not get COPY data stream: %s",
956  PQerrorMessage(conn));
957  exit(1);
958  }
959  PQclear(res);
960 
961  /* Loop over chunks until done. */
962  while (1)
963  {
964  int r;
965  char *copybuf;
966 
967  r = PQgetCopyData(conn, &copybuf, 0);
968  if (r == -1)
969  {
970  /* End of chunk. */
971  break;
972  }
973  else if (r == -2)
974  {
975  pg_log_error("could not read COPY data: %s",
976  PQerrorMessage(conn));
977  exit(1);
978  }
979 
980  (*callback) (r, copybuf, callback_data);
981 
982  PQfreemem(copybuf);
983  }
984 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6691
#define pg_log_error(...)
Definition: logging.h:79
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2692
int PQgetCopyData(PGconn *conn, char **buffer, int async)
Definition: fe-exec.c:2473
StringInfo copybuf
Definition: tablesync.c:108
void PQclear(PGresult *res)
Definition: fe-exec.c:694
void PQfreemem(void *ptr)
Definition: fe-exec.c:3296
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:1778

◆ ReceiveTarAndUnpackCopyChunk()

static void ReceiveTarAndUnpackCopyChunk ( size_t  r,
char *  copybuf,
void *  callback_data 
)
static

Definition at line 1549 of file pg_basebackup.c.

References UnpackTarState::current_len_left, UnpackTarState::current_padding, UnpackTarState::current_path, UnpackTarState::file, UnpackTarState::filename, get_tablespace_mapping(), UnpackTarState::mapped_tblspc_path, mkdir, pg_dir_create_mode, pg_log_error, pg_str_endswith(), progress_report(), read_tar_number(), snprintf, symlink, UnpackTarState::tablespacenum, TAR_BLOCK_SIZE, tarPaddingBytesRequired(), and totaldone.

Referenced by ReceiveAndUnpackTarFile().

1550 {
1551  UnpackTarState *state = callback_data;
1552 
1553  if (state->file == NULL)
1554  {
1555 #ifndef WIN32
1556  int filemode;
1557 #endif
1558 
1559  /*
1560  * No current file, so this must be the header for a new file
1561  */
1562  if (r != TAR_BLOCK_SIZE)
1563  {
1564  pg_log_error("invalid tar block header size: %zu", r);
1565  exit(1);
1566  }
1568 
1569  state->current_len_left = read_tar_number(&copybuf[124], 12);
1570 
1571 #ifndef WIN32
1572  /* Set permissions on the file */
1573  filemode = read_tar_number(&copybuf[100], 8);
1574 #endif
1575 
1576  /*
1577  * All files are padded up to a multiple of TAR_BLOCK_SIZE
1578  */
1579  state->current_padding =
1581 
1582  /*
1583  * First part of header is zero terminated filename
1584  */
1585  snprintf(state->filename, sizeof(state->filename),
1586  "%s/%s", state->current_path, copybuf);
1587  if (state->filename[strlen(state->filename) - 1] == '/')
1588  {
1589  /*
1590  * Ends in a slash means directory or symlink to directory
1591  */
1592  if (copybuf[156] == '5')
1593  {
1594  /*
1595  * Directory. Remove trailing slash first.
1596  */
1597  state->filename[strlen(state->filename) - 1] = '\0';
1598  if (mkdir(state->filename, pg_dir_create_mode) != 0)
1599  {
1600  /*
1601  * When streaming WAL, pg_wal (or pg_xlog for pre-9.6
1602  * clusters) will have been created by the wal receiver
1603  * process. Also, when the WAL directory location was
1604  * specified, pg_wal (or pg_xlog) has already been created
1605  * as a symbolic link before starting the actual backup.
1606  * So just ignore creation failures on related
1607  * directories.
1608  */
1609  if (!((pg_str_endswith(state->filename, "/pg_wal") ||
1610  pg_str_endswith(state->filename, "/pg_xlog") ||
1611  pg_str_endswith(state->filename, "/archive_status")) &&
1612  errno == EEXIST))
1613  {
1614  pg_log_error("could not create directory \"%s\": %m",
1615  state->filename);
1616  exit(1);
1617  }
1618  }
1619 #ifndef WIN32
1620  if (chmod(state->filename, (mode_t) filemode))
1621  pg_log_error("could not set permissions on directory \"%s\": %m",
1622  state->filename);
1623 #endif
1624  }
1625  else if (copybuf[156] == '2')
1626  {
1627  /*
1628  * Symbolic link
1629  *
1630  * It's most likely a link in pg_tblspc directory, to the
1631  * location of a tablespace. Apply any tablespace mapping
1632  * given on the command line (--tablespace-mapping). (We
1633  * blindly apply the mapping without checking that the link
1634  * really is inside pg_tblspc. We don't expect there to be
1635  * other symlinks in a data directory, but if there are, you
1636  * can call it an undocumented feature that you can map them
1637  * too.)
1638  */
1639  state->filename[strlen(state->filename) - 1] = '\0'; /* Remove trailing slash */
1640 
1641  state->mapped_tblspc_path =
1643  if (symlink(state->mapped_tblspc_path, state->filename) != 0)
1644  {
1645  pg_log_error("could not create symbolic link from \"%s\" to \"%s\": %m",
1646  state->filename, state->mapped_tblspc_path);
1647  exit(1);
1648  }
1649  }
1650  else
1651  {
1652  pg_log_error("unrecognized link indicator \"%c\"",
1653  copybuf[156]);
1654  exit(1);
1655  }
1656  return; /* directory or link handled */
1657  }
1658 
1659  /*
1660  * regular file
1661  */
1662  state->file = fopen(state->filename, "wb");
1663  if (!state->file)
1664  {
1665  pg_log_error("could not create file \"%s\": %m", state->filename);
1666  exit(1);
1667  }
1668 
1669 #ifndef WIN32
1670  if (chmod(state->filename, (mode_t) filemode))
1671  pg_log_error("could not set permissions on file \"%s\": %m",
1672  state->filename);
1673 #endif
1674 
1675  if (state->current_len_left == 0)
1676  {
1677  /*
1678  * Done with this file, next one will be a new tar header
1679  */
1680  fclose(state->file);
1681  state->file = NULL;
1682  return;
1683  }
1684  } /* new file */
1685  else
1686  {
1687  /*
1688  * Continuing blocks in existing file
1689  */
1690  if (state->current_len_left == 0 && r == state->current_padding)
1691  {
1692  /*
1693  * Received the padding block for this file, ignore it and close
1694  * the file, then move on to the next tar header.
1695  */
1696  fclose(state->file);
1697  state->file = NULL;
1698  totaldone += r;
1699  return;
1700  }
1701 
1702  errno = 0;
1703  if (fwrite(copybuf, r, 1, state->file) != 1)
1704  {
1705  /* if write didn't set errno, assume problem is no disk space */
1706  if (errno == 0)
1707  errno = ENOSPC;
1708  pg_log_error("could not write to file \"%s\": %m", state->filename);
1709  exit(1);
1710  }
1711  totaldone += r;
1712  progress_report(state->tablespacenum, state->filename, false);
1713 
1714  state->current_len_left -= r;
1715  if (state->current_len_left == 0 && state->current_padding == 0)
1716  {
1717  /*
1718  * Received the last block, and there is no padding to be
1719  * expected. Close the file and move on to the next tar header.
1720  */
1721  fclose(state->file);
1722  state->file = NULL;
1723  return;
1724  }
1725  } /* continuing data in existing file */
1726 }
char current_path[MAXPGPATH]
Definition: pg_basebackup.c:83
const char * mapped_tblspc_path
Definition: pg_basebackup.c:85
bool pg_str_endswith(const char *str, const char *end)
Definition: string.c:31
uint64 read_tar_number(const char *s, int len)
Definition: tar.c:58
#define pg_log_error(...)
Definition: logging.h:79
char filename[MAXPGPATH]
Definition: pg_basebackup.c:84
static uint64 totaldone
#define TAR_BLOCK_SIZE
Definition: pgtar.h:17
#define symlink(oldpath, newpath)
Definition: win32_port.h:221
static const char * get_tablespace_mapping(const char *dir)
static void progress_report(int tablespacenum, const char *filename, bool force)
int pg_dir_create_mode
Definition: file_perm.c:18
StringInfo copybuf
Definition: tablesync.c:108
static size_t tarPaddingBytesRequired(size_t len)
Definition: pgtar.h:40
Definition: regguts.h:298
#define mkdir(a, b)
Definition: win32_port.h:57
#define snprintf
Definition: port.h:193
pgoff_t current_len_left
Definition: pg_basebackup.c:86

◆ ReceiveTarCopyChunk()

static void ReceiveTarCopyChunk ( size_t  r,
char *  copybuf,
void *  callback_data 
)
static

Definition at line 1292 of file pg_basebackup.c.

References WriteTarState::basetablespace, PQExpBufferData::data, WriteTarState::file_padding_len, WriteTarState::filename, WriteTarState::filesz, WriteTarState::found_postgresql_auto_conf, header(), WriteTarState::in_tarhdr, WriteTarState::is_postgresql_auto_conf, WriteTarState::is_recovery_guc_supported, PQExpBufferData::len, MemSet, pg_file_create_mode, progress_report(), read_tar_number(), WriteTarState::skip_file, WriteTarState::tablespacenum, TAR_BLOCK_SIZE, tarCreateHeader(), WriteTarState::tarhdr, WriteTarState::tarhdrsz, tarPaddingBytesRequired(), totaldone, writerecoveryconf, and writeTarData().

Referenced by ReceiveTarFile().

1293 {
1294  WriteTarState *state = callback_data;
1295 
1296  if (!writerecoveryconf || !state->basetablespace)
1297  {
1298  /*
1299  * When not writing config file, or when not working on the base
1300  * tablespace, we never have to look for an existing configuration
1301  * file in the stream.
1302  */
1303  writeTarData(state, copybuf, r);
1304  }
1305  else
1306  {
1307  /*
1308  * Look for a config file in the existing tar stream. If it's there,
1309  * we must skip it so we can later overwrite it with our own version
1310  * of the file.
1311  *
1312  * To do this, we have to process the individual files inside the TAR
1313  * stream. The stream consists of a header and zero or more chunks,
1314  * each with a length equal to TAR_BLOCK_SIZE. The stream from the
1315  * server is broken up into smaller pieces, so we have to track the
1316  * size of the files to find the next header structure.
1317  */
1318  int rr = r;
1319  int pos = 0;
1320 
1321  while (rr > 0)
1322  {
1323  if (state->in_tarhdr)
1324  {
1325  /*
1326  * We're currently reading a header structure inside the TAR
1327  * stream, i.e. the file metadata.
1328  */
1329  if (state->tarhdrsz < TAR_BLOCK_SIZE)
1330  {
1331  /*
1332  * Copy the header structure into tarhdr in case the
1333  * header is not aligned properly or it's not returned in
1334  * whole by the last PQgetCopyData call.
1335  */
1336  int hdrleft;
1337  int bytes2copy;
1338 
1339  hdrleft = TAR_BLOCK_SIZE - state->tarhdrsz;
1340  bytes2copy = (rr > hdrleft ? hdrleft : rr);
1341 
1342  memcpy(&state->tarhdr[state->tarhdrsz], copybuf + pos,
1343  bytes2copy);
1344 
1345  rr -= bytes2copy;
1346  pos += bytes2copy;
1347  state->tarhdrsz += bytes2copy;
1348  }
1349  else
1350  {
1351  /*
1352  * We have the complete header structure in tarhdr, look
1353  * at the file metadata: we may want append recovery info
1354  * into postgresql.auto.conf and skip standby.signal file
1355  * if recovery parameters are integrated as GUCs, and
1356  * recovery.conf otherwise. In both cases we must
1357  * calculate tar padding.
1358  */
1359  if (state->is_recovery_guc_supported)
1360  {
1361  state->skip_file =
1362  (strcmp(&state->tarhdr[0], "standby.signal") == 0);
1363  state->is_postgresql_auto_conf =
1364  (strcmp(&state->tarhdr[0], "postgresql.auto.conf") == 0);
1365  }
1366  else
1367  state->skip_file =
1368  (strcmp(&state->tarhdr[0], "recovery.conf") == 0);
1369 
1370  state->filesz = read_tar_number(&state->tarhdr[124], 12);
1371  state->file_padding_len =
1373 
1374  if (state->is_recovery_guc_supported &&
1375  state->is_postgresql_auto_conf &&
1377  {
1378  /* replace tar header */
1379  char header[TAR_BLOCK_SIZE];
1380 
1381  tarCreateHeader(header, "postgresql.auto.conf", NULL,
1382  state->filesz + recoveryconfcontents->len,
1383  pg_file_create_mode, 04000, 02000,
1384  time(NULL));
1385 
1386  writeTarData(state, header, sizeof(header));
1387  }
1388  else
1389  {
1390  /* copy stream with padding */
1391  state->filesz += state->file_padding_len;
1392 
1393  if (!state->skip_file)
1394  {
1395  /*
1396  * If we're not skipping the file, write the tar
1397  * header unmodified.
1398  */
1399  writeTarData(state, state->tarhdr, TAR_BLOCK_SIZE);
1400  }
1401  }
1402 
1403  /* Next part is the file, not the header */
1404  state->in_tarhdr = false;
1405  }
1406  }
1407  else
1408  {
1409  /*
1410  * We're processing a file's contents.
1411  */
1412  if (state->filesz > 0)
1413  {
1414  /*
1415  * We still have data to read (and possibly write).
1416  */
1417  int bytes2write;
1418 
1419  bytes2write = (state->filesz > rr ? rr : state->filesz);
1420 
1421  if (!state->skip_file)
1422  writeTarData(state, copybuf + pos, bytes2write);
1423 
1424  rr -= bytes2write;
1425  pos += bytes2write;
1426  state->filesz -= bytes2write;
1427  }
1428  else if (state->is_recovery_guc_supported &&
1429  state->is_postgresql_auto_conf &&
1431  {
1432  /* append recovery config to postgresql.auto.conf */
1433  int padding;
1434  int tailsize;
1435 
1436  tailsize = (TAR_BLOCK_SIZE - state->file_padding_len) + recoveryconfcontents->len;
1437  padding = tarPaddingBytesRequired(tailsize);
1438 
1441 
1442  if (padding)
1443  {
1444  char zerobuf[TAR_BLOCK_SIZE];
1445 
1446  MemSet(zerobuf, 0, sizeof(zerobuf));
1447  writeTarData(state, zerobuf, padding);
1448  }
1449 
1450  /* skip original file padding */
1451  state->is_postgresql_auto_conf = false;
1452  state->skip_file = true;
1453  state->filesz += state->file_padding_len;
1454 
1455  state->found_postgresql_auto_conf = true;
1456  }
1457  else
1458  {
1459  /*
1460  * No more data in the current file, the next piece of
1461  * data (if any) will be a new file header structure.
1462  */
1463  state->in_tarhdr = true;
1464  state->skip_file = false;
1465  state->is_postgresql_auto_conf = false;
1466  state->tarhdrsz = 0;
1467  state->filesz = 0;
1468  }
1469  }
1470  }
1471  }
1472  totaldone += r;
1473  progress_report(state->tablespacenum, state->filename, false);
1474 }
bool found_postgresql_auto_conf
Definition: pg_basebackup.c:71
static PQExpBuffer recoveryconfcontents
int pg_file_create_mode
Definition: file_perm.c:19
bool is_recovery_guc_supported
Definition: pg_basebackup.c:69
uint64 read_tar_number(const char *s, int len)
Definition: tar.c:58
char tarhdr[TAR_BLOCK_SIZE]
Definition: pg_basebackup.c:65
static void writeTarData(WriteTarState *state, char *buf, int r)
static bool writerecoveryconf
#define MemSet(start, val, len)
Definition: c.h:971
pgoff_t filesz
Definition: pg_basebackup.c:74
bool is_postgresql_auto_conf
Definition: pg_basebackup.c:70
static uint64 totaldone
#define TAR_BLOCK_SIZE
Definition: pgtar.h:17
static void progress_report(int tablespacenum, const char *filename, bool force)
enum tarError tarCreateHeader(char *h, const char *filename, const char *linktarget, pgoff_t size, mode_t mode, uid_t uid, gid_t gid, time_t mtime)
Definition: tar.c:114
StringInfo copybuf
Definition: tablesync.c:108
static size_t tarPaddingBytesRequired(size_t len)
Definition: pgtar.h:40
Definition: regguts.h:298
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:208
char filename[MAXPGPATH]
Definition: pg_basebackup.c:63

◆ ReceiveTarFile()

static void ReceiveTarFile ( PGconn conn,
PGresult res,
int  rownum 
)
static

Definition at line 1033 of file pg_basebackup.c.

References basedir, WriteTarState::basetablespace, buf, compresslevel, PQExpBufferData::data, fd(), WriteTarState::filename, WriteTarState::found_postgresql_auto_conf, header(), WriteTarState::in_tarhdr, initPQExpBuffer(), WriteTarState::is_recovery_guc_supported, PQExpBufferData::len, manifest, MemSet, MINIMUM_VERSION_FOR_RECOVERY_GUC, pg_file_create_mode, pg_log_error, PQExpBufferDataBroken, PQgetisnull(), PQgetvalue(), PQserverVersion(), progress_report(), ReceiveBackupManifestInMemory(), ReceiveCopyData(), ReceiveTarCopyChunk(), snprintf, generate_unaccent_rules::stdout, WriteTarState::tablespacenum, TAR_BLOCK_SIZE, tarCreateHeader(), WriteTarState::tarfile, tarPaddingBytesRequired(), termPQExpBuffer(), writerecoveryconf, and writeTarData().

Referenced by BaseBackup().

1034 {
1035  char zerobuf[TAR_BLOCK_SIZE * 2];
1037 
1038  memset(&state, 0, sizeof(state));
1039  state.tablespacenum = rownum;
1040  state.basetablespace = PQgetisnull(res, rownum, 0);
1041  state.in_tarhdr = true;
1042 
1043  /* recovery.conf is integrated into postgresql.conf in 12 and newer */
1045  state.is_recovery_guc_supported = true;
1046 
1047  if (state.basetablespace)
1048  {
1049  /*
1050  * Base tablespaces
1051  */
1052  if (strcmp(basedir, "-") == 0)
1053  {
1054 #ifdef WIN32
1055  _setmode(fileno(stdout), _O_BINARY);
1056 #endif
1057 
1058 #ifdef HAVE_LIBZ
1059  if (compresslevel != 0)
1060  {
1061  int fd = dup(fileno(stdout));
1062 
1063  if (fd < 0)
1064  {
1065  pg_log_error("could not duplicate stdout: %m");
1066  exit(1);
1067  }
1068 
1069  state.ztarfile = gzdopen(fd, "wb");
1070  if (state.ztarfile == NULL)
1071  {
1072  pg_log_error("could not open output file: %m");
1073  exit(1);
1074  }
1075 
1076  if (gzsetparams(state.ztarfile, compresslevel,
1077  Z_DEFAULT_STRATEGY) != Z_OK)
1078  {
1079  pg_log_error("could not set compression level %d: %s",
1080  compresslevel, get_gz_error(state.ztarfile));
1081  exit(1);
1082  }
1083  }
1084  else
1085 #endif
1086  state.tarfile = stdout;
1087  strcpy(state.filename, "-");
1088  }
1089  else
1090  {
1091 #ifdef HAVE_LIBZ
1092  if (compresslevel != 0)
1093  {
1094  snprintf(state.filename, sizeof(state.filename),
1095  "%s/base.tar.gz", basedir);
1096  state.ztarfile = gzopen(state.filename, "wb");
1097  if (gzsetparams(state.ztarfile, compresslevel,
1098  Z_DEFAULT_STRATEGY) != Z_OK)
1099  {
1100  pg_log_error("could not set compression level %d: %s",
1101  compresslevel, get_gz_error(state.ztarfile));
1102  exit(1);
1103  }
1104  }
1105  else
1106 #endif
1107  {
1108  snprintf(state.filename, sizeof(state.filename),
1109  "%s/base.tar", basedir);
1110  state.tarfile = fopen(state.filename, "wb");
1111  }
1112  }
1113  }
1114  else
1115  {
1116  /*
1117  * Specific tablespace
1118  */
1119 #ifdef HAVE_LIBZ
1120  if (compresslevel != 0)
1121  {
1122  snprintf(state.filename, sizeof(state.filename),
1123  "%s/%s.tar.gz",
1124  basedir, PQgetvalue(res, rownum, 0));
1125  state.ztarfile = gzopen(state.filename, "wb");
1126  if (gzsetparams(state.ztarfile, compresslevel,
1127  Z_DEFAULT_STRATEGY) != Z_OK)
1128  {
1129  pg_log_error("could not set compression level %d: %s",
1130  compresslevel, get_gz_error(state.ztarfile));
1131  exit(1);
1132  }
1133  }
1134  else
1135 #endif
1136  {
1137  snprintf(state.filename, sizeof(state.filename), "%s/%s.tar",
1138  basedir, PQgetvalue(res, rownum, 0));
1139  state.tarfile = fopen(state.filename, "wb");
1140  }
1141  }
1142 
1143 #ifdef HAVE_LIBZ
1144  if (compresslevel != 0)
1145  {
1146  if (!state.ztarfile)
1147  {
1148  /* Compression is in use */
1149  pg_log_error("could not create compressed file \"%s\": %s",
1150  state.filename, get_gz_error(state.ztarfile));
1151  exit(1);
1152  }
1153  }
1154  else
1155 #endif
1156  {
1157  /* Either no zlib support, or zlib support but compresslevel = 0 */
1158  if (!state.tarfile)
1159  {
1160  pg_log_error("could not create file \"%s\": %m", state.filename);
1161  exit(1);
1162  }
1163  }
1164 
1165  ReceiveCopyData(conn, ReceiveTarCopyChunk, &state);
1166 
1167  /*
1168  * End of copy data. If requested, and this is the base tablespace, write
1169  * configuration file into the tarfile. When done, close the file (but not
1170  * stdout).
1171  *
1172  * Also, write two completely empty blocks at the end of the tar file, as
1173  * required by some tar programs.
1174  */
1175 
1176  MemSet(zerobuf, 0, sizeof(zerobuf));
1177 
1178  if (state.basetablespace && writerecoveryconf)
1179  {
1180  char header[TAR_BLOCK_SIZE];
1181 
1182  /*
1183  * If postgresql.auto.conf has not been found in the streamed data,
1184  * add recovery configuration to postgresql.auto.conf if recovery
1185  * parameters are GUCs. If the instance connected to is older than
1186  * 12, create recovery.conf with this data otherwise.
1187  */
1189  {
1190  int padding;
1191 
1192  tarCreateHeader(header,
1193  state.is_recovery_guc_supported ? "postgresql.auto.conf" : "recovery.conf",
1194  NULL,
1196  pg_file_create_mode, 04000, 02000,
1197  time(NULL));
1198 
1200 
1201  writeTarData(&state, header, sizeof(header));
1204  if (padding)
1205  writeTarData(&state, zerobuf, padding);
1206  }
1207 
1208  /*
1209  * standby.signal is supported only if recovery parameters are GUCs.
1210  */
1211  if (state.is_recovery_guc_supported)
1212  {
1213  tarCreateHeader(header, "standby.signal", NULL,
1214  0, /* zero-length file */
1215  pg_file_create_mode, 04000, 02000,
1216  time(NULL));
1217 
1218  writeTarData(&state, header, sizeof(header));
1219 
1220  /*
1221  * we don't need to pad out to a multiple of the tar block size
1222  * here, because the file is zero length, which is a multiple of
1223  * any block size.
1224  */
1225  }
1226  }
1227 
1228  /*
1229  * Normally, we emit the backup manifest as a separate file, but when
1230  * we're writing a tarfile to stdout, we don't have that option, so
1231  * include it in the one tarfile we've got.
1232  */
1233  if (strcmp(basedir, "-") == 0 && manifest)
1234  {
1235  char header[TAR_BLOCK_SIZE];
1237 
1238  initPQExpBuffer(&buf);
1239  ReceiveBackupManifestInMemory(conn, &buf);
1240  if (PQExpBufferDataBroken(buf))
1241  {
1242  pg_log_error("out of memory");
1243  exit(1);
1244  }
1245  tarCreateHeader(header, "backup_manifest", NULL, buf.len,
1246  pg_file_create_mode, 04000, 02000,
1247  time(NULL));
1248  writeTarData(&state, header, sizeof(header));
1249  writeTarData(&state, buf.data, buf.len);
1250  termPQExpBuffer(&buf);
1251  }
1252 
1253  /* 2 * TAR_BLOCK_SIZE bytes empty data at end of file */
1254  writeTarData(&state, zerobuf, sizeof(zerobuf));
1255 
1256 #ifdef HAVE_LIBZ
1257  if (state.ztarfile != NULL)
1258  {
1259  if (gzclose(state.ztarfile) != 0)
1260  {
1261  pg_log_error("could not close compressed file \"%s\": %s",
1262  state.filename, get_gz_error(state.ztarfile));
1263  exit(1);
1264  }
1265  }
1266  else
1267 #endif
1268  {
1269  if (strcmp(basedir, "-") != 0)
1270  {
1271  if (fclose(state.tarfile) != 0)
1272  {
1273  pg_log_error("could not close file \"%s\": %m",
1274  state.filename);
1275  exit(1);
1276  }
1277  }
1278  }
1279 
1280  progress_report(rownum, state.filename, true);
1281 
1282  /*
1283  * Do not sync the resulting tar file yet, all files are synced once at
1284  * the end.
1285  */
1286 }
bool found_postgresql_auto_conf
Definition: pg_basebackup.c:71
static PQExpBuffer recoveryconfcontents
int pg_file_create_mode
Definition: file_perm.c:19
bool is_recovery_guc_supported
Definition: pg_basebackup.c:69
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3163
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
#define pg_log_error(...)
Definition: logging.h:79
static void writeTarData(WriteTarState *state, char *buf, int r)
static bool writerecoveryconf
static int compresslevel
#define MemSet(start, val, len)
Definition: c.h:971
#define MINIMUM_VERSION_FOR_RECOVERY_GUC
Definition: recovery_gen.h:21
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:6681
static int fd(const char *x, int i)
Definition: preproc-init.c:105
static char * basedir
static void ReceiveBackupManifestInMemory(PGconn *conn, PQExpBuffer buf)
static void ReceiveCopyData(PGconn *conn, WriteDataCallback callback, void *callback_data)
#define TAR_BLOCK_SIZE
Definition: pgtar.h:17
static char * buf
Definition: pg_test_fsync.c:67
static void progress_report(int tablespacenum, const char *filename, bool force)
enum tarError tarCreateHeader(char *h, const char *filename, const char *linktarget, pgoff_t size, mode_t mode, uid_t uid, gid_t gid, time_t mtime)
Definition: tar.c:114
static size_t tarPaddingBytesRequired(size_t len)
Definition: pgtar.h:40
#define PQExpBufferDataBroken(buf)
Definition: pqexpbuffer.h:67
static void ReceiveTarCopyChunk(size_t r, char *copybuf, void *callback_data)
Definition: regguts.h:298
static bool manifest
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:208
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3188
#define snprintf
Definition: port.h:193
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
char filename[MAXPGPATH]
Definition: pg_basebackup.c:63

◆ StartLogStreamer()

static void StartLogStreamer ( char *  startpos,
uint32  timeline,
char *  sysidentifier 
)
static

Definition at line 593 of file pg_basebackup.c.

References basedir, bgchild, logstreamer_param::bgconn, bgpipe, conn, create_slot, CreateReplicationSlot(), format, GetConnection(), kill_bgchild_atexit(), LogStreamerMain(), MAXPGPATH, MINIMUM_VERSION_FOR_PG_WAL, MINIMUM_VERSION_FOR_TEMP_SLOTS, pg_dir_create_mode, pg_log_error, pg_log_info, pg_malloc0(), pg_mkdir_p(), PQbackendPID(), PQserverVersion(), psprintf(), replication_slot, snprintf, logstreamer_param::startptr, logstreamer_param::sysidentifier, temp_replication_slot, logstreamer_param::timeline, verbose, WalSegSz, logstreamer_param::xlog, and XLogSegmentOffset.

Referenced by BaseBackup().

594 {
595  logstreamer_param *param;
596  uint32 hi,
597  lo;
598  char statusdir[MAXPGPATH];
599 
600  param = pg_malloc0(sizeof(logstreamer_param));
601  param->timeline = timeline;
602  param->sysidentifier = sysidentifier;
603 
604  /* Convert the starting position */
605  if (sscanf(startpos, "%X/%X", &hi, &lo) != 2)
606  {
607  pg_log_error("could not parse write-ahead log location \"%s\"",
608  startpos);
609  exit(1);
610  }
611  param->startptr = ((uint64) hi) << 32 | lo;
612  /* Round off to even segment position */
613  param->startptr -= XLogSegmentOffset(param->startptr, WalSegSz);
614 
615 #ifndef WIN32
616  /* Create our background pipe */
617  if (pipe(bgpipe) < 0)
618  {
619  pg_log_error("could not create pipe for background process: %m");
620  exit(1);
621  }
622 #endif
623 
624  /* Get a second connection */
625  param->bgconn = GetConnection();
626  if (!param->bgconn)
627  /* Error message already written in GetConnection() */
628  exit(1);
629 
630  /* In post-10 cluster, pg_xlog has been renamed to pg_wal */
631  snprintf(param->xlog, sizeof(param->xlog), "%s/%s",
632  basedir,
634  "pg_xlog" : "pg_wal");
635 
636  /* Temporary replication slots are only supported in 10 and newer */
638  temp_replication_slot = false;
639 
640  /*
641  * Create replication slot if requested
642  */
644  replication_slot = psprintf("pg_basebackup_%d", (int) PQbackendPID(param->bgconn));
646  {
647  if (!CreateReplicationSlot(param->bgconn, replication_slot, NULL,
648  temp_replication_slot, true, true, false))
649  exit(1);
650 
651  if (verbose)
652  {
654  pg_log_info("created temporary replication slot \"%s\"",
656  else
657  pg_log_info("created replication slot \"%s\"",
659  }
660  }
661 
662  if (format == 'p')
663  {
664  /*
665  * Create pg_wal/archive_status or pg_xlog/archive_status (and thus
666  * pg_wal or pg_xlog) depending on the target server so we can write
667  * to basedir/pg_wal or basedir/pg_xlog as the directory entry in the
668  * tar file may arrive later.
669  */
670  snprintf(statusdir, sizeof(statusdir), "%s/%s/archive_status",
671  basedir,
673  "pg_xlog" : "pg_wal");
674 
675  if (pg_mkdir_p(statusdir, pg_dir_create_mode) != 0 && errno != EEXIST)
676  {
677  pg_log_error("could not create directory \"%s\": %m", statusdir);
678  exit(1);
679  }
680  }
681 
682  /*
683  * Start a child process and tell it to start streaming. On Unix, this is
684  * a fork(). On Windows, we create a thread.
685  */
686 #ifndef WIN32
687  bgchild = fork();
688  if (bgchild == 0)
689  {
690  /* in child process */
691  exit(LogStreamerMain(param));
692  }
693  else if (bgchild < 0)
694  {
695  pg_log_error("could not create background process: %m");
696  exit(1);
697  }
698 
699  /*
700  * Else we are in the parent process and all is well.
701  */
702  atexit(kill_bgchild_atexit);
703 #else /* WIN32 */
704  bgchild = _beginthreadex(NULL, 0, (void *) LogStreamerMain, param, 0, NULL);
705  if (bgchild == 0)
706  {
707  pg_log_error("could not create background thread: %m");
708  exit(1);
709  }
710 #endif
711 }
static int bgpipe[2]
int pg_mkdir_p(char *path, int omode)
Definition: pgmkdirp.c:57
#define pg_log_error(...)
Definition: logging.h:79
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static bool create_slot
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:6681
static char * basedir
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
PGconn * conn
Definition: streamutil.c:54
#define MAXPGPATH
#define MINIMUM_VERSION_FOR_PG_WAL
unsigned int uint32
Definition: c.h:367
XLogRecPtr startptr
static int verbose
int pg_dir_create_mode
Definition: file_perm.c:18
static bool temp_replication_slot
int PQbackendPID(const PGconn *conn)
Definition: fe-connect.c:6717
#define XLogSegmentOffset(xlogptr, wal_segsz_bytes)
PGconn * GetConnection(UserMapping *user, bool will_prep_stmt)
Definition: connection.c:107
static void kill_bgchild_atexit(void)
static XLogRecPtr startpos
static void CreateReplicationSlot(CreateReplicationSlotCmd *cmd)
Definition: walsender.c:922
int WalSegSz
Definition: pg_standby.c:38
static pid_t bgchild
static char format
static char * replication_slot
static int LogStreamerMain(logstreamer_param *param)
#define snprintf
Definition: port.h:193
#define MINIMUM_VERSION_FOR_TEMP_SLOTS
#define pg_log_info(...)
Definition: logging.h:87
char xlog[MAXPGPATH]

◆ tablespace_list_append()

static void tablespace_list_append ( const char *  arg)
static

Definition at line 286 of file pg_basebackup.c.

References canonicalize_path(), errmsg(), TablespaceList::head, is_absolute_path, MAXPGPATH, TablespaceListCell::new_dir, TablespaceListCell::next, TablespaceListCell::old_dir, pg_log_error, pg_malloc0(), strerror, and TablespaceList::tail.

Referenced by main().

287 {
289  char *dst;
290  char *dst_ptr;
291  const char *arg_ptr;
292 
293  dst_ptr = dst = cell->old_dir;
294  for (arg_ptr = arg; *arg_ptr; arg_ptr++)
295  {
296  if (dst_ptr - dst >= MAXPGPATH)
297  {
298  pg_log_error("directory name too long");
299  exit(1);
300  }
301 
302  if (*arg_ptr == '\\' && *(arg_ptr + 1) == '=')
303  ; /* skip backslash escaping = */
304  else if (*arg_ptr == '=' && (arg_ptr == arg || *(arg_ptr - 1) != '\\'))
305  {
306  if (*cell->new_dir)
307  {
308  pg_log_error("multiple \"=\" signs in tablespace mapping");
309  exit(1);
310  }
311  else
312  dst = dst_ptr = cell->new_dir;
313  }
314  else
315  *dst_ptr++ = *arg_ptr;
316  }
317 
318  if (!*cell->old_dir || !*cell->new_dir)
319  {
320  pg_log_error("invalid tablespace mapping format \"%s\", must be \"OLDDIR=NEWDIR\"", arg);
321  exit(1);
322  }
323 
324  /*
325  * This check isn't absolutely necessary. But all tablespaces are created
326  * with absolute directories, so specifying a non-absolute path here would
327  * just never match, possibly confusing users. It's also good to be
328  * consistent with the new_dir check.
329  */
330  if (!is_absolute_path(cell->old_dir))
331  {
332  pg_log_error("old directory is not an absolute path in tablespace mapping: %s",
333  cell->old_dir);
334  exit(1);
335  }
336 
337  if (!is_absolute_path(cell->new_dir))
338  {
339  pg_log_error("new directory is not an absolute path in tablespace mapping: %s",
340  cell->new_dir);
341  exit(1);
342  }
343 
344  /*
345  * Comparisons done with these values should involve similarly
346  * canonicalized path values. This is particularly sensitive on Windows
347  * where path values may not necessarily use Unix slashes.
348  */
349  canonicalize_path(cell->old_dir);
350  canonicalize_path(cell->new_dir);
351 
352  if (tablespace_dirs.tail)
353  tablespace_dirs.tail->next = cell;
354  else
355  tablespace_dirs.head = cell;
356  tablespace_dirs.tail = cell;
357 }
static TablespaceList tablespace_dirs
#define pg_log_error(...)
Definition: logging.h:79
char old_dir[MAXPGPATH]
Definition: pg_basebackup.c:50
void canonicalize_path(char *path)
Definition: path.c:254
char new_dir[MAXPGPATH]
Definition: pg_basebackup.c:51
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
#define MAXPGPATH
#define is_absolute_path(filename)
Definition: port.h:86
struct TablespaceListCell * next
Definition: pg_basebackup.c:49
TablespaceListCell * tail
Definition: pg_basebackup.c:57
TablespaceListCell * head
Definition: pg_basebackup.c:56
void * arg

◆ usage()

static void usage ( void  )
static

Definition at line 376 of file pg_basebackup.c.

References _, printf, and progname.

Referenced by main().

377 {
378  printf(_("%s takes a base backup of a running PostgreSQL server.\n\n"),
379  progname);
380  printf(_("Usage:\n"));
381  printf(_(" %s [OPTION]...\n"), progname);
382  printf(_("\nOptions controlling the output:\n"));
383  printf(_(" -D, --pgdata=DIRECTORY receive base backup into directory\n"));
384  printf(_(" -F, --format=p|t output format (plain (default), tar)\n"));
385  printf(_(" -r, --max-rate=RATE maximum transfer rate to transfer data directory\n"
386  " (in kB/s, or use suffix \"k\" or \"M\")\n"));
387  printf(_(" -R, --write-recovery-conf\n"
388  " write configuration for replication\n"));
389  printf(_(" -T, --tablespace-mapping=OLDDIR=NEWDIR\n"
390  " relocate tablespace in OLDDIR to NEWDIR\n"));
391  printf(_(" --waldir=WALDIR location for the write-ahead log directory\n"));
392  printf(_(" -X, --wal-method=none|fetch|stream\n"
393  " include required WAL files with specified method\n"));
394  printf(_(" -z, --gzip compress tar output\n"));
395  printf(_(" -Z, --compress=0-9 compress tar output with given compression level\n"));
396  printf(_("\nGeneral options:\n"));
397  printf(_(" -c, --checkpoint=fast|spread\n"
398  " set fast or spread checkpointing\n"));
399  printf(_(" -C, --create-slot create replication slot\n"));
400  printf(_(" -l, --label=LABEL set backup label\n"));
401  printf(_(" -n, --no-clean do not clean up after errors\n"));
402  printf(_(" -N, --no-sync do not wait for changes to be written safely to disk\n"));
403  printf(_(" -P, --progress show progress information\n"));
404  printf(_(" -S, --slot=SLOTNAME replication slot to use\n"));
405  printf(_(" -v, --verbose output verbose messages\n"));
406  printf(_(" -V, --version output version information, then exit\n"));
407  printf(_(" --manifest-checksums=SHA{224,256,384,512}|CRC32C|NONE\n"
408  " use algorithm for manifest checksums\n"));
409  printf(_(" --manifest-force-encode\n"
410  " hex encode all file names in manifest\n"));
411  printf(_(" --no-estimate-size do not estimate backup size in server side\n"));
412  printf(_(" --no-manifest suppress generation of backup manifest\n"));
413  printf(_(" --no-slot prevent creation of temporary replication slot\n"));
414  printf(_(" --no-verify-checksums\n"
415  " do not verify checksums\n"));
416  printf(_(" -?, --help show this help, then exit\n"));
417  printf(_("\nConnection options:\n"));
418  printf(_(" -d, --dbname=CONNSTR connection string\n"));
419  printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
420  printf(_(" -p, --port=PORT database server port number\n"));
421  printf(_(" -s, --status-interval=INTERVAL\n"
422  " time between status packets sent to server (in seconds)\n"));
423  printf(_(" -U, --username=NAME connect as specified database user\n"));
424  printf(_(" -w, --no-password never prompt for password\n"));
425  printf(_(" -W, --password force password prompt (should happen automatically)\n"));
426  printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
427  printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
428 }
#define printf(...)
Definition: port.h:199
const char * progname
Definition: pg_standby.c:36
#define _(x)
Definition: elog.c:88

◆ verify_dir_is_empty_or_create()

static void verify_dir_is_empty_or_create ( char *  dirname,
bool created,
bool found 
)
static

Definition at line 719 of file pg_basebackup.c.

References pg_check_dir(), pg_dir_create_mode, pg_log_error, and pg_mkdir_p().

Referenced by BaseBackup(), and main().

720 {
721  switch (pg_check_dir(dirname))
722  {
723  case 0:
724 
725  /*
726  * Does not exist, so create
727  */
728  if (pg_mkdir_p(dirname, pg_dir_create_mode) == -1)
729  {
730  pg_log_error("could not create directory \"%s\": %m", dirname);
731  exit(1);
732  }
733  if (created)
734  *created = true;
735  return;
736  case 1:
737 
738  /*
739  * Exists, empty
740  */
741  if (found)
742  *found = true;
743  return;
744  case 2:
745  case 3:
746  case 4:
747 
748  /*
749  * Exists, not empty
750  */
751  pg_log_error("directory \"%s\" exists but is not empty", dirname);
752  exit(1);
753  case -1:
754 
755  /*
756  * Access problem
757  */
758  pg_log_error("could not access directory \"%s\": %m", dirname);
759  exit(1);
760  }
761 }
int pg_mkdir_p(char *path, int omode)
Definition: pgmkdirp.c:57
#define pg_log_error(...)
Definition: logging.h:79
int pg_dir_create_mode
Definition: file_perm.c:18
int pg_check_dir(const char *dir)
Definition: pgcheckdir.c:31

◆ writeTarData()

static void writeTarData ( WriteTarState state,
char *  buf,
int  r 
)
static

Definition at line 990 of file pg_basebackup.c.

References WriteTarState::filename, pg_log_error, and WriteTarState::tarfile.

Referenced by ReceiveTarCopyChunk(), and ReceiveTarFile().

991 {
992 #ifdef HAVE_LIBZ
993  if (state->ztarfile != NULL)
994  {
995  errno = 0;
996  if (gzwrite(state->ztarfile, buf, r) != r)
997  {
998  /* if write didn't set errno, assume problem is no disk space */
999  if (errno == 0)
1000  errno = ENOSPC;
1001  pg_log_error("could not write to compressed file \"%s\": %s",
1002  state->filename, get_gz_error(state->ztarfile));
1003  exit(1);
1004  }
1005  }
1006  else
1007 #endif
1008  {
1009  errno = 0;
1010  if (fwrite(buf, r, 1, state->tarfile) != 1)
1011  {
1012  /* if write didn't set errno, assume problem is no disk space */
1013  if (errno == 0)
1014  errno = ENOSPC;
1015  pg_log_error("could not write to file \"%s\": %m",
1016  state->filename);
1017  exit(1);
1018  }
1019  }
1020 }
#define pg_log_error(...)
Definition: logging.h:79
static char * buf
Definition: pg_test_fsync.c:67
char filename[MAXPGPATH]
Definition: pg_basebackup.c:63

Variable Documentation

◆ basedir

◆ bgchild

pid_t bgchild = -1
static

Definition at line 173 of file pg_basebackup.c.

Referenced by BaseBackup(), kill_bgchild_atexit(), and StartLogStreamer().

◆ bgpipe

int bgpipe[2] = {-1, -1}
static

◆ checksum_failure

bool checksum_failure = false
static

Definition at line 133 of file pg_basebackup.c.

Referenced by BaseBackup(), cleanup_directories_atexit(), and PageIsVerified().

◆ compresslevel

int compresslevel = 0
static

Definition at line 137 of file pg_basebackup.c.

Referenced by LogStreamerMain(), main(), and ReceiveTarFile().

◆ create_slot

bool create_slot = false
static

Definition at line 147 of file pg_basebackup.c.

Referenced by CreateSubscription(), main(), and StartLogStreamer().

◆ do_sync

bool do_sync = true
static

Definition at line 141 of file pg_basebackup.c.

Referenced by BaseBackup(), and main().

◆ estimatesize

bool estimatesize = true
static

Definition at line 135 of file pg_basebackup.c.

Referenced by BaseBackup(), and main().

◆ fastcheckpoint

bool fastcheckpoint = false
static

Definition at line 139 of file pg_basebackup.c.

Referenced by BaseBackup(), and main().

◆ format

◆ found_existing_pgdata

bool found_existing_pgdata = false
static

Definition at line 156 of file pg_basebackup.c.

Referenced by cleanup_directories_atexit(), and main().

◆ found_existing_xlogdir

bool found_existing_xlogdir = false
static

Definition at line 158 of file pg_basebackup.c.

Referenced by cleanup_directories_atexit(), and main().

◆ found_tablespace_dirs

bool found_tablespace_dirs = false
static

Definition at line 160 of file pg_basebackup.c.

Referenced by BaseBackup(), and cleanup_directories_atexit().

◆ has_xlogendptr

int has_xlogendptr = 0
static

Definition at line 180 of file pg_basebackup.c.

Referenced by BaseBackup(), and reached_end_position().

◆ in_log_streamer

bool in_log_streamer = false
static

Definition at line 174 of file pg_basebackup.c.

Referenced by cleanup_directories_atexit(), and LogStreamerMain().

◆ includewal

IncludeWal includewal = STREAM_WAL
static

Definition at line 138 of file pg_basebackup.c.

Referenced by BaseBackup(), and main().

◆ label

◆ last_progress_report

pg_time_t last_progress_report = 0
static

Definition at line 143 of file pg_basebackup.c.

Referenced by progress_report().

◆ made_new_pgdata

bool made_new_pgdata = false
static

Definition at line 155 of file pg_basebackup.c.

Referenced by cleanup_directories_atexit(), and main().

◆ made_new_xlogdir

bool made_new_xlogdir = false
static

Definition at line 157 of file pg_basebackup.c.

Referenced by cleanup_directories_atexit(), and main().

◆ made_tablespace_dirs

bool made_tablespace_dirs = false
static

Definition at line 159 of file pg_basebackup.c.

Referenced by BaseBackup(), and cleanup_directories_atexit().

◆ manifest

bool manifest = true
static

Definition at line 150 of file pg_basebackup.c.

Referenced by BaseBackup(), main(), perform_base_backup(), and ReceiveTarFile().

◆ manifest_checksums

char* manifest_checksums = NULL
static

Definition at line 152 of file pg_basebackup.c.

Referenced by BaseBackup(), and main().

◆ manifest_force_encode

bool manifest_force_encode = false
static

Definition at line 151 of file pg_basebackup.c.

Referenced by BaseBackup(), and main().

◆ maxrate

int32 maxrate = 0
static

Definition at line 144 of file pg_basebackup.c.

Referenced by BaseBackup(), main(), and parse_basebackup_options().

◆ no_slot

bool no_slot = false
static

Definition at line 148 of file pg_basebackup.c.

Referenced by main().

◆ noclean

bool noclean = false
static

Definition at line 132 of file pg_basebackup.c.

Referenced by cleanup_directories_atexit(), and main().

◆ recoveryconfcontents

PQExpBuffer recoveryconfcontents = NULL
static

Definition at line 186 of file pg_basebackup.c.

◆ replication_slot

char* replication_slot = NULL
static

Definition at line 145 of file pg_basebackup.c.

Referenced by BaseBackup(), LogStreamerMain(), main(), and StartLogStreamer().

◆ showprogress

bool showprogress = false
static

Definition at line 134 of file pg_basebackup.c.

Referenced by BaseBackup(), libpqConnect(), main(), and progress_report().

◆ standby_message_timeout

int standby_message_timeout = 10 * 1000
static

Definition at line 142 of file pg_basebackup.c.

Referenced by LogStreamerMain(), and main().

◆ success

bool success = false
static

Definition at line 154 of file pg_basebackup.c.

Referenced by cleanup_directories_atexit(), and main().

◆ tablespace_dirs

TablespaceList tablespace_dirs = {NULL, NULL}
static

Definition at line 128 of file pg_basebackup.c.

◆ tablespacecount

int tablespacecount
static

Definition at line 165 of file pg_basebackup.c.

Referenced by BaseBackup(), and progress_report().

◆ temp_replication_slot

bool temp_replication_slot = true
static

Definition at line 146 of file pg_basebackup.c.

Referenced by main(), and StartLogStreamer().

◆ totaldone

uint64 totaldone
static

◆ totalsize_kb

uint64 totalsize_kb
static

Definition at line 163 of file pg_basebackup.c.

Referenced by BaseBackup(), and progress_report().

◆ verbose

int verbose = 0
static

◆ verify_checksums

bool verify_checksums = true
static

Definition at line 149 of file pg_basebackup.c.

Referenced by BaseBackup(), and main().

◆ writerecoveryconf

bool writerecoveryconf = false
static

◆ xlog_dir

char* xlog_dir = NULL
static

Definition at line 129 of file pg_basebackup.c.

Referenced by cleanup_directories_atexit(), and main().

◆ xlogendptr

XLogRecPtr xlogendptr
static

Definition at line 177 of file pg_basebackup.c.

Referenced by BaseBackup(), and reached_end_position().