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