45#define INCREMENTAL_PREFIX "INCREMENTAL."
46#define INCREMENTAL_PREFIX_LENGTH (sizeof(INCREMENTAL_PREFIX) - 1)
113 char *input_directory,
114 char *output_directory,
117 char **prior_backup_dirs,
133 static struct option long_options[] = {
150 char *last_input_dir;
158 char **prior_backup_dirs;
172 memset(&opt, 0,
sizeof(opt));
179 long_options, &optindex)) != -1)
205 pg_fatal(
"unrecognized checksum algorithm: \"%s\"",
239 pg_fatal(
"no output directory specified");
247 "The target directory will not be modified.");
252#if (defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE)) || \
253 (defined(__linux__) && defined(FICLONE))
261 pg_fatal(
"file cloning not supported on this platform");
266#if defined(HAVE_COPY_FILE_RANGE)
269 pg_log_debug(
"would use copy_file_range to copy blocks");
271 pg_log_debug(
"will use copy_file_range to copy blocks");
274 pg_fatal(
"copy_file_range not supported on this platform");
279 pgdata = argv[argc - 1];
283 pg_log_debug(
"read server version %u from file \"%s/%s\"",
287 n_backups = argc -
optind;
297 n_prior_backups = argc -
optind - 1;
298 prior_backup_dirs = argv +
optind;
307 for (
i = 0;
i < n_backups;
i++)
310 manifests[
i]->system_identifier != system_identifier)
316 pg_fatal(
"%s: manifest system identifier is %" PRIu64
", but control file has %" PRIu64,
318 manifests[
i]->system_identifier,
324 last_input_dir = argv[argc - 1];
341 for (ts = tablespaces; ts != NULL; ts = ts->
next)
354 if (manifests[n_prior_backups] == NULL)
355 pg_fatal(
"cannot generate a manifest because no manifest is available for the final input backup");
366 last_backup_label->
cursor = 0;
372 pg_log_debug(
"processing backup directory \"%s\"", last_input_dir);
374 NULL, n_prior_backups, prior_backup_dirs,
375 manifests, mwriter, &opt);
378 for (ts = tablespaces; ts != NULL; ts = ts->
next)
395 pg_log_debug(
"would create symbolic link from \"%s\" to \"%s\"",
399 pg_log_debug(
"creating symbolic link from \"%s\" to \"%s\"",
402 pg_fatal(
"could not create symbolic link from \"%s\" to \"%s\": %m",
414 pg_fatal(
"could not create directory \"%s\": %m",
421 NULL, n_prior_backups, prior_backup_dirs,
422 manifests, mwriter, &opt);
428 manifests[n_prior_backups]->first_wal_range);
444 pg_log_warning(
"--link mode was used; any modifications to the output "
445 "directory might destructively modify input directories");
470 dst_ptr = dst = tsmap->
old_dir;
471 for (arg_ptr =
arg; *arg_ptr !=
'\0'; arg_ptr++)
474 pg_fatal(
"directory name too long");
476 if (*arg_ptr ==
'\\' && *(arg_ptr + 1) ==
'=')
478 else if (*arg_ptr ==
'=' && (arg_ptr ==
arg || *(arg_ptr - 1) !=
'\\'))
481 pg_fatal(
"multiple \"=\" signs in tablespace mapping");
483 dst = dst_ptr = tsmap->
new_dir;
486 *dst_ptr++ = *arg_ptr;
489 pg_fatal(
"invalid tablespace mapping format \"%s\", must be \"OLDDIR=NEWDIR\"",
arg);
500 pg_fatal(
"old directory is not an absolute path in tablespace mapping: %s",
504 pg_fatal(
"old directory is not an absolute path in tablespace mapping: %s",
530 for (
i = n_backups - 1;
i >= 0; --
i)
542 if ((
fd = open(pathbuf, O_RDONLY, 0)) < 0)
543 pg_fatal(
"could not open file \"%s\": %m", pathbuf);
558 pg_fatal(
"could not close file \"%s\": %m", pathbuf);
562 &previous_tli, &previous_lsn);
572 if (
i > 0 && previous_tli == 0)
573 pg_fatal(
"backup at \"%s\" is a full backup, but only the first backup should be a full backup",
575 if (
i == 0 && previous_tli != 0)
576 pg_fatal(
"backup at \"%s\" is an incremental backup, but the first backup should be a full backup",
578 if (
i < n_backups - 1 && start_tli != check_tli)
579 pg_fatal(
"backup at \"%s\" starts on timeline %u, but expected %u",
580 backup_dirs[
i], start_tli, check_tli);
581 if (
i < n_backups - 1 && start_lsn != check_lsn)
582 pg_fatal(
"backup at \"%s\" starts at LSN %X/%08X, but expected %X/%08X",
586 check_tli = previous_tli;
587 check_lsn = previous_lsn;
617 uint64 system_identifier = 0;
618 uint32 data_checksum_version = 0;
619 bool data_checksum_mismatch =
false;
622 for (
i = n_backups - 1;
i >= 0; --
i)
634 pg_fatal(
"%s: CRC is incorrect", controlpath);
638 pg_fatal(
"%s: unexpected control file version",
642 if (
i == n_backups - 1)
645 pg_fatal(
"%s: expected system identifier %" PRIu64
", but found %" PRIu64,
646 controlpath, system_identifier,
653 if (
i == n_backups - 1)
655 else if (data_checksum_version != 0 &&
657 data_checksum_mismatch =
true;
668 pg_log_debug(
"system identifier is %" PRIu64, system_identifier);
674 if (data_checksum_mismatch)
677 pg_log_warning_hint(
"Disable, and optionally reenable, checksums on the output directory to avoid failures.");
680 return system_identifier;
694 if (
stat(dir, &st) != 0)
695 pg_fatal(
"could not stat file \"%s\": %m", dir);
718 pg_log_info(
"removing contents of output directory \"%s\"",
721 pg_log_error(
"failed to remove contents of output directory");
749 pg_fatal(
"could not create directory \"%s\": %m", dirname);
754 pg_log_debug(
"using existing directory \"%s\"", dirname);
761 pg_fatal(
"directory \"%s\" exists but is not empty", dirname);
764 pg_fatal(
"could not access directory \"%s\": %m", dirname);
778 printf(
_(
"%s reconstructs full backups from incrementals.\n\n"),
progname);
782 printf(
_(
" -d, --debug generate lots of debugging output\n"));
783 printf(
_(
" -k, --link link files instead of copying\n"));
784 printf(
_(
" -n, --dry-run do not actually do anything\n"));
785 printf(
_(
" -N, --no-sync do not wait for changes to be written safely to disk\n"));
786 printf(
_(
" -o, --output=DIRECTORY output directory\n"));
787 printf(
_(
" -T, --tablespace-mapping=OLDDIR=NEWDIR\n"
788 " relocate tablespace in OLDDIR to NEWDIR\n"));
789 printf(
_(
" --clone clone (reflink) files instead of copying\n"));
790 printf(
_(
" --copy copy files (default)\n"));
791 printf(
_(
" --copy-file-range copy using copy_file_range() system call\n"));
792 printf(
_(
" --manifest-checksums=SHA{224,256,384,512}|CRC32C|NONE\n"
793 " use algorithm for manifest checksums\n"));
794 printf(
_(
" --no-manifest suppress generation of backup manifest\n"));
795 printf(
_(
" --sync-method=METHOD set method for syncing files to disk\n"));
796 printf(
_(
" -V, --version output version information, then exit\n"));
797 printf(
_(
" -?, --help show this help, then exit\n"));
799 printf(
_(
"\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
800 printf(
_(
"%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
815 oid = strtoul(s, &ep, 10);
816 if (errno != 0 || *ep !=
'\0' || oid < 1 || oid >
PG_UINT32_MAX)
844 char *input_directory,
845 char *output_directory,
848 char **prior_backup_dirs,
858 bool is_pg_tblspc =
false;
859 bool is_pg_wal =
false;
860 bool is_incremental_dir =
false;
887 is_incremental_dir =
true;
888 else if (relative_path != NULL)
891 is_pg_wal = (strcmp(relative_path,
"pg_wal") == 0 ||
892 strncmp(relative_path,
"pg_wal/", 7) == 0);
893 is_incremental_dir = strncmp(relative_path,
"base/", 5) == 0 ||
894 strcmp(relative_path,
"global") == 0 ||
913 if (relative_path == NULL)
920 manifest_prefix[0] =
'\0';
939 if (relative_path != NULL)
942 pg_log_debug(
"would create directory \"%s\"", ofulldir);
947 pg_fatal(
"could not create directory \"%s\": %m", ofulldir);
952 if ((dir =
opendir(ifulldir)) == NULL)
953 pg_fatal(
"could not open directory \"%s\": %m", ifulldir);
954 while (errno = 0, (de =
readdir(dir)) != NULL)
961 int checksum_length = 0;
962 uint8 *checksum_payload = NULL;
966 if (strcmp(de->
d_name,
".") == 0 ||
967 strcmp(de->
d_name,
"..") == 0)
996 if (relative_path == NULL)
1004 input_directory, output_directory,
1006 n_prior_backups, prior_backup_dirs,
1007 manifests, mwriter, opt);
1025 if (relative_path == NULL &&
1026 (strcmp(de->
d_name,
"backup_label") == 0 ||
1027 strcmp(de->
d_name,
"backup_manifest") == 0))
1034 if (is_incremental_dir &&
1077 latest_manifest != NULL)
1081 mfile = manifest_files_lookup(latest_manifest->
files,
1091 bmpath =
psprintf(
"%s/%s", input_directory,
1093 pg_log_warning(
"manifest file \"%s\" contains no entry for file \"%s\"",
1094 bmpath, manifest_path);
1109 if (checksum_length != 0)
1116 copy_file(ifullpath, ofullpath, &checksum_ctx,
1133 if (mwriter != NULL)
1150 if (
stat(ofullpath, &sb) < 0)
1151 pg_fatal(
"could not stat file \"%s\": %m", ofullpath);
1156 checksum_type, checksum_length,
1161 if (checksum_payload != NULL)
1162 pfree(checksum_payload);
1222 if ((dir =
opendir(pg_tblspc)) == NULL)
1223 pg_fatal(
"could not open directory \"%s\": %m", pg_tblspc);
1225 while (errno = 0, (de =
readdir(dir)) != NULL)
1236 if (strcmp(de->
d_name,
".") == 0 || strcmp(de->
d_name,
"..") == 0)
1245 pg_log_debug(
"skipping \"%s\" because the filename is not a legal tablespace OID",
1256 pg_log_debug(
"skipping \"%s\" because it is neither a symbolic link nor a directory",
1274 link_length =
readlink(tblspcdir, link_target,
sizeof(link_target));
1275 if (link_length < 0)
1276 pg_fatal(
"could not read symbolic link \"%s\": %m",
1278 if (link_length >=
sizeof(link_target))
1279 pg_fatal(
"target of symbolic link \"%s\" is too long", tblspcdir);
1280 link_target[link_length] =
'\0';
1282 pg_fatal(
"target of symbolic link \"%s\" is relative", tblspcdir);
1291 for (tsmap = opt->
tsmappings; tsmap != NULL; tsmap = tsmap->
next)
1293 if (strcmp(tsmap->
old_dir, link_target) == 0)
1304 pg_fatal(
"tablespace at \"%s\" has no tablespace mapping",
1320 for (otherts = tslist; otherts != NULL; otherts = otherts->
next)
1322 pg_fatal(
"tablespaces with OIDs %u and %u both point at directory \"%s\"",
1331 pg_fatal(
"could not close directory \"%s\": %m", pg_tblspc);
1369 pg_fatal(
"could not read file \"%s\": read %zd of %lld",
1375 buf->data[
buf->len] =
'\0';
void parse_backup_label(char *filename, StringInfo buf, TimeLineID *start_tli, XLogRecPtr *start_lsn, TimeLineID *previous_tli, XLogRecPtr *previous_lsn)
void write_backup_label(char *output_directory, StringInfo buf, pg_checksum_type checksum_type, manifest_writer *mwriter)
#define PG_TEXTDOMAIN(domain)
#define OidIsValid(objectId)
bool pg_checksum_parse_type(char *name, pg_checksum_type *type)
int pg_checksum_final(pg_checksum_context *context, uint8 *output)
int pg_checksum_init(pg_checksum_context *context, pg_checksum_type type)
#define PG_CHECKSUM_MAX_LENGTH
void set_pglocale_pgservice(const char *argv0, const char *app)
ControlFileData * get_controlfile_by_exact_path(const char *ControlFilePath, bool *crc_ok_p)
@ COPY_METHOD_COPY_FILE_RANGE
void copy_file(const char *fromfile, const char *tofile)
struct dirent * readdir(DIR *)
DIR * opendir(const char *)
void * pg_malloc(size_t size)
void * pg_malloc0(size_t size)
uint32 get_pg_version(const char *datadir, char **version_str)
void SetDataDirectoryCreatePerm(int dataDirMode)
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
@ DATA_DIR_SYNC_METHOD_FSYNC
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
#define required_argument
static pg_noreturn void manifest_data ** load_backup_manifests(int n_backups, char **backup_directories)
void pg_logging_increase_verbosity(void)
void pg_logging_init(const char *argv0)
#define pg_log_error(...)
#define pg_log_error_hint(...)
#define pg_log_warning_hint(...)
#define pg_log_debug(...)
void pfree(void *pointer)
void handle_help_version_opts(int argc, char *argv[], const char *fixed_progname, help_handler hlp)
bool parse_sync_method(const char *optarg, DataDirSyncMethod *sync_method)
static cb_tablespace * scan_for_existing_tablespaces(char *pathname, cb_options *opt)
int main(int argc, char *argv[])
struct cb_cleanup_dir cb_cleanup_dir
static void remember_to_cleanup_directory(char *target_path, bool rmtopdir)
static void help(const char *progname)
static void process_directory_recursively(Oid tsoid, char *input_directory, char *output_directory, char *relative_path, int n_prior_backups, char **prior_backup_dirs, manifest_data **manifests, manifest_writer *mwriter, cb_options *opt)
static void create_output_directory(char *dirname, cb_options *opt)
static void check_input_dir_permissions(char *dir)
static uint64 check_control_files(int n_backups, char **backup_dirs)
static cb_cleanup_dir * cleanup_dir_list
struct cb_tablespace cb_tablespace
#define INCREMENTAL_PREFIX_LENGTH
static void cleanup_directories_atexit(void)
static StringInfo check_backup_label_files(int n_backups, char **backup_dirs)
static void add_tablespace_mapping(cb_options *opt, char *arg)
#define INCREMENTAL_PREFIX
struct cb_tablespace_mapping cb_tablespace_mapping
static void slurp_file(int fd, char *filename, StringInfo buf, int maxlen)
struct cb_options cb_options
static bool parse_oid(char *s, Oid *result)
static void reset_directory_cleanup_list(void)
#define PG_CONTROL_VERSION
PGDLLIMPORT char * optarg
#define pg_log_warning(...)
int pg_mkdir_p(char *path, int omode)
#define is_absolute_path(filename)
void canonicalize_path(char *path)
int pg_check_dir(const char *dir)
const char * get_progname(const char *argv0)
size_t strlcpy(char *dst, const char *src, size_t siz)
static int fd(const char *x, int i)
char * psprintf(const char *fmt,...)
void reconstruct_from_incremental_file(char *input_filename, char *output_filename, char *relative_path, char *bare_file_name, int n_prior_backups, char **prior_backup_dirs, manifest_data **manifests, char *manifest_path, pg_checksum_type checksum_type, int *checksum_length, uint8 **checksum_payload, CopyMethod copy_method, bool debug, bool dry_run)
#define PG_TBLSPC_DIR_SLASH
bool rmtree(const char *path, bool rmtopdir)
void destroyStringInfo(StringInfo str)
StringInfo makeStringInfo(void)
void resetStringInfo(StringInfo str)
void enlargeStringInfo(StringInfo str, int needed)
uint32 pg_control_version
uint32 data_checksum_version
struct cb_cleanup_dir * next
cb_tablespace_mapping * tsmappings
DataDirSyncMethod sync_method
pg_checksum_type manifest_checksums
struct cb_tablespace_mapping * next
struct cb_tablespace * next
manifest_files_hash * files
pg_checksum_type checksum_type
#define GET_PG_MAJORVERSION_NUM(v)
#define symlink(oldpath, newpath)
#define readlink(path, buf, size)
manifest_writer * create_manifest_writer(char *directory, uint64 system_identifier)
void add_file_to_manifest(manifest_writer *mwriter, const char *manifest_path, uint64 size, time_t mtime, pg_checksum_type checksum_type, int checksum_length, uint8 *checksum_payload)
void finalize_manifest(manifest_writer *mwriter, manifest_wal_range *first_wal_range)
#define XLOG_CONTROL_FILE
#define LSN_FORMAT_ARGS(lsn)
#define InvalidXLogRecPtr