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, bool finished)
 
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 1797 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, 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().

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

◆ cleanup_directories_atexit()

static void cleanup_directories_atexit ( void  )
static

Definition at line 215 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().

216 {
217  if (success || in_log_streamer)
218  return;
219 
220  if (!noclean && !checksum_failure)
221  {
222  if (made_new_pgdata)
223  {
224  pg_log_info("removing data directory \"%s\"", basedir);
225  if (!rmtree(basedir, true))
226  pg_log_error("failed to remove data directory");
227  }
228  else if (found_existing_pgdata)
229  {
230  pg_log_info("removing contents of data directory \"%s\"", basedir);
231  if (!rmtree(basedir, false))
232  pg_log_error("failed to remove contents of data directory");
233  }
234 
235  if (made_new_xlogdir)
236  {
237  pg_log_info("removing WAL directory \"%s\"", xlog_dir);
238  if (!rmtree(xlog_dir, true))
239  pg_log_error("failed to remove WAL directory");
240  }
241  else if (found_existing_xlogdir)
242  {
243  pg_log_info("removing contents of WAL directory \"%s\"", xlog_dir);
244  if (!rmtree(xlog_dir, false))
245  pg_log_error("failed to remove contents of WAL directory");
246  }
247  }
248  else
249  {
251  pg_log_info("data directory \"%s\" not removed at user's request", basedir);
252 
254  pg_log_info("WAL directory \"%s\" not removed at user's request", xlog_dir);
255  }
256 
258  pg_log_info("changes to tablespace directories will not be undone");
259 }
static bool found_existing_pgdata
static bool found_tablespace_dirs
#define pg_log_error(...)
Definition: logging.h:80
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:88
static bool noclean

◆ disconnect_atexit()

static void disconnect_atexit ( void  )
static

Definition at line 262 of file pg_basebackup.c.

References conn, and PQfinish().

Referenced by main().

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

◆ get_tablespace_mapping()

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

Definition at line 1488 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().

1489 {
1490  TablespaceListCell *cell;
1491  char canon_dir[MAXPGPATH];
1492 
1493  /* Canonicalize path for comparison consistency */
1494  strlcpy(canon_dir, dir, sizeof(canon_dir));
1495  canonicalize_path(canon_dir);
1496 
1497  for (cell = tablespace_dirs.head; cell; cell = cell->next)
1498  if (strcmp(canon_dir, cell->old_dir) == 0)
1499  return cell->new_dir;
1500 
1501  return dir;
1502 }
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 275 of file pg_basebackup.c.

References bgchild, and kill.

Referenced by StartLogStreamer().

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

◆ LogStreamerMain()

static int LogStreamerMain ( logstreamer_param param)
static

Definition at line 531 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().

532 {
533  StreamCtl stream;
534 
535  in_log_streamer = true;
536 
537  MemSet(&stream, 0, sizeof(stream));
538  stream.startpos = param->startptr;
539  stream.timeline = param->timeline;
540  stream.sysidentifier = param->sysidentifier;
542 #ifndef WIN32
543  stream.stop_socket = bgpipe[0];
544 #else
545  stream.stop_socket = PGINVALID_SOCKET;
546 #endif
548  stream.synchronous = false;
549  /* fsync happens at the end of pg_basebackup for all data */
550  stream.do_sync = false;
551  stream.mark_done = true;
552  stream.partial_suffix = NULL;
554 
555  if (format == 'p')
556  stream.walmethod = CreateWalDirectoryMethod(param->xlog, 0,
557  stream.do_sync);
558  else
560  stream.do_sync);
561 
562  if (!ReceiveXlogStream(param->bgconn, &stream))
563 
564  /*
565  * Any errors will already have been reported in the function process,
566  * but we need to tell the parent that we didn't shutdown in a nice
567  * way.
568  */
569  return 1;
570 
571  if (!stream.walmethod->finish())
572  {
573  pg_log_error("could not finish writing WAL files: %m");
574  return 1;
575  }
576 
577  PQfinish(param->bgconn);
578 
579  if (format == 'p')
581  else
583  pg_free(stream.walmethod);
584 
585  return 0;
586 }
static int bgpipe[2]
bool do_sync
Definition: receivelog.h:38
#define pg_log_error(...)
Definition: logging.h:80
char * sysidentifier
Definition: receivelog.h:33
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4171
static int compresslevel
#define MemSet(start, val, len)
Definition: c.h:949
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:435
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 2225 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.

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

References MAX_RATE_UPPER, and pg_log_error.

Referenced by main().

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

◆ progress_report()

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

Definition at line 776 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().

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

◆ reached_end_position()

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

Definition at line 441 of file pg_basebackup.c.

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

Referenced by LogStreamerMain().

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

1516 {
1518  bool basetablespace;
1519 
1520  memset(&state, 0, sizeof(state));
1521  state.tablespacenum = rownum;
1522 
1523  basetablespace = PQgetisnull(res, rownum, 0);
1524  if (basetablespace)
1525  strlcpy(state.current_path, basedir, sizeof(state.current_path));
1526  else
1527  strlcpy(state.current_path,
1528  get_tablespace_mapping(PQgetvalue(res, rownum, 1)),
1529  sizeof(state.current_path));
1530 
1532 
1533 
1534  if (state.file)
1535  fclose(state.file);
1536 
1537  progress_report(rownum, state.filename, true, false);
1538 
1539  if (state.file != NULL)
1540  {
1541  pg_log_error("COPY stream ended before last file was finished");
1542  exit(1);
1543  }
1544 
1545  if (basetablespace && writerecoveryconf)
1547 
1548  /*
1549  * No data is synced here, everything is done for all tablespaces at the
1550  * end.
1551  */
1552 }
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:80
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)
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
static void progress_report(int tablespacenum, const char *filename, bool force, bool finished)

◆ ReceiveBackupManifest()

static void ReceiveBackupManifest ( PGconn conn)
static

Definition at line 1738 of file pg_basebackup.c.

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

Referenced by BaseBackup().

1739 {
1741 
1742  snprintf(state.filename, sizeof(state.filename),
1743  "%s/backup_manifest.tmp", basedir);
1744  state.file = fopen(state.filename, "wb");
1745  if (state.file == NULL)
1746  {
1747  pg_log_error("could not create file \"%s\": %m", state.filename);
1748  exit(1);
1749  }
1750 
1752 
1753  fclose(state.file);
1754 }
#define pg_log_error(...)
Definition: logging.h:80
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 1760 of file pg_basebackup.c.

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

Referenced by ReceiveBackupManifest().

1761 {
1762  WriteManifestState *state = callback_data;
1763 
1764  errno = 0;
1765  if (fwrite(copybuf, r, 1, state->file) != 1)
1766  {
1767  /* if write didn't set errno, assume problem is no disk space */
1768  if (errno == 0)
1769  errno = ENOSPC;
1770  pg_log_error("could not write to file \"%s\": %m", state->filename);
1771  exit(1);
1772  }
1773 }
#define pg_log_error(...)
Definition: logging.h:80
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 1779 of file pg_basebackup.c.

References ReceiveBackupManifestInMemoryChunk(), and ReceiveCopyData().

Referenced by ReceiveTarFile().

1780 {
1782 }
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 1788 of file pg_basebackup.c.

References appendPQExpBuffer(), and buf.

Referenced by ReceiveBackupManifestInMemory().

1790 {
1791  PQExpBuffer buf = callback_data;
1792 
1793  appendPQExpBuffer(buf, copybuf, r);
1794 }
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
StringInfo copybuf
Definition: tablesync.c:108

◆ ReceiveCopyData()

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

Definition at line 952 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().

954 {
955  PGresult *res;
956 
957  /* Get the COPY data stream. */
958  res = PQgetResult(conn);
959  if (PQresultStatus(res) != PGRES_COPY_OUT)
960  {
961  pg_log_error("could not get COPY data stream: %s",
962  PQerrorMessage(conn));
963  exit(1);
964  }
965  PQclear(res);
966 
967  /* Loop over chunks until done. */
968  while (1)
969  {
970  int r;
971  char *copybuf;
972 
973  r = PQgetCopyData(conn, &copybuf, 0);
974  if (r == -1)
975  {
976  /* End of chunk. */
977  break;
978  }
979  else if (r == -2)
980  {
981  pg_log_error("could not read COPY data: %s",
982  PQerrorMessage(conn));
983  exit(1);
984  }
985 
986  (*callback) (r, copybuf, callback_data);
987 
988  PQfreemem(copybuf);
989  }
990 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6666
#define pg_log_error(...)
Definition: logging.h:80
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 1555 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().

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

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

◆ ReceiveTarFile()

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

Definition at line 1039 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().

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

◆ StartLogStreamer()

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

Definition at line 594 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().

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

◆ tablespace_list_append()

static void tablespace_list_append ( const char *  arg)
static

Definition at line 287 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().

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

References _, printf, and progname.

Referenced by main().

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

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

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

Referenced by ReceiveTarCopyChunk(), and ReceiveTarFile().

997 {
998 #ifdef HAVE_LIBZ
999  if (state->ztarfile != NULL)
1000  {
1001  errno = 0;
1002  if (gzwrite(state->ztarfile, buf, r) != r)
1003  {
1004  /* if write didn't set errno, assume problem is no disk space */
1005  if (errno == 0)
1006  errno = ENOSPC;
1007  pg_log_error("could not write to compressed file \"%s\": %s",
1008  state->filename, get_gz_error(state->ztarfile));
1009  exit(1);
1010  }
1011  }
1012  else
1013 #endif
1014  {
1015  errno = 0;
1016  if (fwrite(buf, r, 1, state->tarfile) != 1)
1017  {
1018  /* if write didn't set errno, assume problem is no disk space */
1019  if (errno == 0)
1020  errno = ENOSPC;
1021  pg_log_error("could not write to file \"%s\": %m",
1022  state->filename);
1023  exit(1);
1024  }
1025  }
1026 }
#define pg_log_error(...)
Definition: logging.h:80
static char * buf
Definition: pg_test_fsync.c:68
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().