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, ©buf, 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, ©buf, 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(©buf[124], 12);
1402
1403 /* Set permissions on the file */
1404 filemode = read_tar_number(©buf[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(©buf[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