00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "postgres_fe.h"
00015 #include "libpq-fe.h"
00016 #include "pqexpbuffer.h"
00017 #include "pgtar.h"
00018
00019 #include <unistd.h>
00020 #include <dirent.h>
00021 #include <sys/stat.h>
00022 #include <sys/types.h>
00023 #include <sys/wait.h>
00024 #include <time.h>
00025
00026 #ifdef HAVE_LIBZ
00027 #include <zlib.h>
00028 #endif
00029
00030 #include "getopt_long.h"
00031
00032 #include "receivelog.h"
00033 #include "streamutil.h"
00034
00035
00036
00037 char *basedir = NULL;
00038 char format = 'p';
00039 char *label = "pg_basebackup base backup";
00040 bool showprogress = false;
00041 int verbose = 0;
00042 int compresslevel = 0;
00043 bool includewal = false;
00044 bool streamwal = false;
00045 bool fastcheckpoint = false;
00046 bool writerecoveryconf = false;
00047 int standby_message_timeout = 10 * 1000;
00048
00049
00050 static uint64 totalsize;
00051 static uint64 totaldone;
00052 static int tablespacecount;
00053
00054
00055 #ifndef WIN32
00056 static int bgpipe[2] = {-1, -1};
00057 #endif
00058
00059
00060 static pid_t bgchild = -1;
00061
00062
00063 static XLogRecPtr xlogendptr;
00064
00065 #ifndef WIN32
00066 static int has_xlogendptr = 0;
00067 #else
00068 static volatile LONG has_xlogendptr = 0;
00069 #endif
00070
00071
00072 static PQExpBuffer recoveryconfcontents = NULL;
00073
00074
00075 static void usage(void);
00076 static void verify_dir_is_empty_or_create(char *dirname);
00077 static void progress_report(int tablespacenum, const char *filename);
00078
00079 static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
00080 static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
00081 static void GenerateRecoveryConf(PGconn *conn);
00082 static void WriteRecoveryConf(void);
00083 static void BaseBackup(void);
00084
00085 static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
00086 bool segment_finished);
00087
00088 #ifdef HAVE_LIBZ
00089 static const char *
00090 get_gz_error(gzFile gzf)
00091 {
00092 int errnum;
00093 const char *errmsg;
00094
00095 errmsg = gzerror(gzf, &errnum);
00096 if (errnum == Z_ERRNO)
00097 return strerror(errno);
00098 else
00099 return errmsg;
00100 }
00101 #endif
00102
00103 static void
00104 usage(void)
00105 {
00106 printf(_("%s takes a base backup of a running PostgreSQL server.\n\n"),
00107 progname);
00108 printf(_("Usage:\n"));
00109 printf(_(" %s [OPTION]...\n"), progname);
00110 printf(_("\nOptions controlling the output:\n"));
00111 printf(_(" -D, --pgdata=DIRECTORY receive base backup into directory\n"));
00112 printf(_(" -F, --format=p|t output format (plain (default), tar)\n"));
00113 printf(_(" -R, --write-recovery-conf\n"
00114 " write recovery.conf after backup\n"));
00115 printf(_(" -x, --xlog include required WAL files in backup (fetch mode)\n"));
00116 printf(_(" -X, --xlog-method=fetch|stream\n"
00117 " include required WAL files with specified method\n"));
00118 printf(_(" -z, --gzip compress tar output\n"));
00119 printf(_(" -Z, --compress=0-9 compress tar output with given compression level\n"));
00120 printf(_("\nGeneral options:\n"));
00121 printf(_(" -c, --checkpoint=fast|spread\n"
00122 " set fast or spread checkpointing\n"));
00123 printf(_(" -l, --label=LABEL set backup label\n"));
00124 printf(_(" -P, --progress show progress information\n"));
00125 printf(_(" -v, --verbose output verbose messages\n"));
00126 printf(_(" -V, --version output version information, then exit\n"));
00127 printf(_(" -?, --help show this help, then exit\n"));
00128 printf(_("\nConnection options:\n"));
00129 printf(_(" -d, --dbname=CONNSTR connection string\n"));
00130 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
00131 printf(_(" -p, --port=PORT database server port number\n"));
00132 printf(_(" -s, --status-interval=INTERVAL\n"
00133 " time between status packets sent to server (in seconds)\n"));
00134 printf(_(" -U, --username=NAME connect as specified database user\n"));
00135 printf(_(" -w, --no-password never prompt for password\n"));
00136 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
00137 printf(_("\nReport bugs to <[email protected]>.\n"));
00138 }
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 static bool
00150 reached_end_position(XLogRecPtr segendpos, uint32 timeline,
00151 bool segment_finished)
00152 {
00153 if (!has_xlogendptr)
00154 {
00155 #ifndef WIN32
00156 fd_set fds;
00157 struct timeval tv;
00158 int r;
00159
00160
00161
00162
00163
00164 FD_ZERO(&fds);
00165 FD_SET(bgpipe[0], &fds);
00166
00167 MemSet(&tv, 0, sizeof(tv));
00168
00169 r = select(bgpipe[0] + 1, &fds, NULL, NULL, &tv);
00170 if (r == 1)
00171 {
00172 char xlogend[64];
00173 uint32 hi,
00174 lo;
00175
00176 MemSet(xlogend, 0, sizeof(xlogend));
00177 r = read(bgpipe[0], xlogend, sizeof(xlogend));
00178 if (r < 0)
00179 {
00180 fprintf(stderr, _("%s: could not read from ready pipe: %s\n"),
00181 progname, strerror(errno));
00182 exit(1);
00183 }
00184
00185 if (sscanf(xlogend, "%X/%X", &hi, &lo) != 2)
00186 {
00187 fprintf(stderr,
00188 _("%s: could not parse transaction log location \"%s\"\n"),
00189 progname, xlogend);
00190 exit(1);
00191 }
00192 xlogendptr = ((uint64) hi) << 32 | lo;
00193 has_xlogendptr = 1;
00194
00195
00196
00197
00198
00199 }
00200 else
00201 {
00202
00203
00204
00205
00206 return false;
00207 }
00208 #else
00209
00210
00211
00212
00213
00214 return false;
00215 #endif
00216 }
00217
00218
00219
00220
00221
00222 if (segendpos >= xlogendptr)
00223 return true;
00224
00225
00226
00227
00228
00229 return false;
00230 }
00231
00232 typedef struct
00233 {
00234 PGconn *bgconn;
00235 XLogRecPtr startptr;
00236 char xlogdir[MAXPGPATH];
00237 char *sysidentifier;
00238 int timeline;
00239 } logstreamer_param;
00240
00241 static int
00242 LogStreamerMain(logstreamer_param *param)
00243 {
00244 if (!ReceiveXlogStream(param->bgconn, param->startptr, param->timeline,
00245 param->sysidentifier, param->xlogdir,
00246 reached_end_position, standby_message_timeout,
00247 NULL))
00248
00249
00250
00251
00252
00253
00254 return 1;
00255
00256 PQfinish(param->bgconn);
00257 return 0;
00258 }
00259
00260
00261
00262
00263
00264
00265 static void
00266 StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier)
00267 {
00268 logstreamer_param *param;
00269 uint32 hi,
00270 lo;
00271
00272 param = pg_malloc0(sizeof(logstreamer_param));
00273 param->timeline = timeline;
00274 param->sysidentifier = sysidentifier;
00275
00276
00277 if (sscanf(startpos, "%X/%X", &hi, &lo) != 2)
00278 {
00279 fprintf(stderr,
00280 _("%s: could not parse transaction log location \"%s\"\n"),
00281 progname, startpos);
00282 disconnect_and_exit(1);
00283 }
00284 param->startptr = ((uint64) hi) << 32 | lo;
00285
00286 param->startptr -= param->startptr % XLOG_SEG_SIZE;
00287
00288 #ifndef WIN32
00289
00290 if (pipe(bgpipe) < 0)
00291 {
00292 fprintf(stderr,
00293 _("%s: could not create pipe for background process: %s\n"),
00294 progname, strerror(errno));
00295 disconnect_and_exit(1);
00296 }
00297 #endif
00298
00299
00300 param->bgconn = GetConnection();
00301 if (!param->bgconn)
00302
00303 exit(1);
00304
00305
00306
00307
00308
00309
00310 snprintf(param->xlogdir, sizeof(param->xlogdir), "%s/pg_xlog", basedir);
00311 verify_dir_is_empty_or_create(param->xlogdir);
00312
00313
00314
00315
00316
00317 #ifndef WIN32
00318 bgchild = fork();
00319 if (bgchild == 0)
00320 {
00321
00322 exit(LogStreamerMain(param));
00323 }
00324 else if (bgchild < 0)
00325 {
00326 fprintf(stderr, _("%s: could not create background process: %s\n"),
00327 progname, strerror(errno));
00328 disconnect_and_exit(1);
00329 }
00330
00331
00332
00333
00334 #else
00335 bgchild = _beginthreadex(NULL, 0, (void *) LogStreamerMain, param, 0, NULL);
00336 if (bgchild == 0)
00337 {
00338 fprintf(stderr, _("%s: could not create background thread: %s\n"),
00339 progname, strerror(errno));
00340 disconnect_and_exit(1);
00341 }
00342 #endif
00343 }
00344
00345
00346
00347
00348
00349
00350 static void
00351 verify_dir_is_empty_or_create(char *dirname)
00352 {
00353 switch (pg_check_dir(dirname))
00354 {
00355 case 0:
00356
00357
00358
00359
00360 if (pg_mkdir_p(dirname, S_IRWXU) == -1)
00361 {
00362 fprintf(stderr,
00363 _("%s: could not create directory \"%s\": %s\n"),
00364 progname, dirname, strerror(errno));
00365 disconnect_and_exit(1);
00366 }
00367 return;
00368 case 1:
00369
00370
00371
00372
00373 return;
00374 case 2:
00375 case 3:
00376 case 4:
00377
00378
00379
00380
00381 fprintf(stderr,
00382 _("%s: directory \"%s\" exists but is not empty\n"),
00383 progname, dirname);
00384 disconnect_and_exit(1);
00385 case -1:
00386
00387
00388
00389
00390 fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
00391 progname, dirname, strerror(errno));
00392 disconnect_and_exit(1);
00393 }
00394 }
00395
00396
00397
00398
00399
00400
00401 static void
00402 progress_report(int tablespacenum, const char *filename)
00403 {
00404 int percent = (int) ((totaldone / 1024) * 100 / totalsize);
00405 char totaldone_str[32];
00406 char totalsize_str[32];
00407
00408
00409
00410
00411
00412
00413
00414 if (percent > 100)
00415 percent = 100;
00416 if (totaldone / 1024 > totalsize)
00417 totalsize = totaldone / 1024;
00418
00419
00420
00421
00422
00423
00424 snprintf(totaldone_str, sizeof(totaldone_str), INT64_FORMAT,
00425 totaldone / 1024);
00426 snprintf(totalsize_str, sizeof(totalsize_str), INT64_FORMAT, totalsize);
00427
00428 #define VERBOSE_FILENAME_LENGTH 35
00429 if (verbose)
00430 {
00431 if (!filename)
00432
00433
00434
00435
00436
00437 fprintf(stderr,
00438 ngettext("%*s/%s kB (100%%), %d/%d tablespace %*s",
00439 "%*s/%s kB (100%%), %d/%d tablespaces %*s",
00440 tablespacecount),
00441 (int) strlen(totalsize_str),
00442 totaldone_str, totalsize_str,
00443 tablespacenum, tablespacecount,
00444 VERBOSE_FILENAME_LENGTH + 5, "");
00445 else
00446 {
00447 bool truncate = (strlen(filename) > VERBOSE_FILENAME_LENGTH);
00448
00449 fprintf(stderr,
00450 ngettext("%*s/%s kB (%d%%), %d/%d tablespace (%s%-*.*s)",
00451 "%*s/%s kB (%d%%), %d/%d tablespaces (%s%-*.*s)",
00452 tablespacecount),
00453 (int) strlen(totalsize_str),
00454 totaldone_str, totalsize_str, percent,
00455 tablespacenum, tablespacecount,
00456
00457 truncate ? "..." : "",
00458 truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
00459 truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
00460
00461 truncate ? filename + strlen(filename) - VERBOSE_FILENAME_LENGTH + 3 : filename);
00462 }
00463 }
00464 else
00465 fprintf(stderr,
00466 ngettext("%*s/%s kB (%d%%), %d/%d tablespace",
00467 "%*s/%s kB (%d%%), %d/%d tablespaces",
00468 tablespacecount),
00469 (int) strlen(totalsize_str),
00470 totaldone_str, totalsize_str, percent,
00471 tablespacenum, tablespacecount);
00472
00473 fprintf(stderr, "\r");
00474 }
00475
00476
00477
00478
00479
00480 static void
00481 writeTarData(
00482 #ifdef HAVE_LIBZ
00483 gzFile ztarfile,
00484 #endif
00485 FILE *tarfile, char *buf, int r, char *current_file)
00486 {
00487 #ifdef HAVE_LIBZ
00488 if (ztarfile != NULL)
00489 {
00490 if (gzwrite(ztarfile, buf, r) != r)
00491 {
00492 fprintf(stderr,
00493 _("%s: could not write to compressed file \"%s\": %s\n"),
00494 progname, current_file, get_gz_error(ztarfile));
00495 disconnect_and_exit(1);
00496 }
00497 }
00498 else
00499 #endif
00500 {
00501 if (fwrite(buf, r, 1, tarfile) != 1)
00502 {
00503 fprintf(stderr, _("%s: could not write to file \"%s\": %s\n"),
00504 progname, current_file, strerror(errno));
00505 disconnect_and_exit(1);
00506 }
00507 }
00508 }
00509
00510 #ifdef HAVE_LIBZ
00511 #define WRITE_TAR_DATA(buf, sz) writeTarData(ztarfile, tarfile, buf, sz, filename)
00512 #else
00513 #define WRITE_TAR_DATA(buf, sz) writeTarData(tarfile, buf, sz, filename)
00514 #endif
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526 static void
00527 ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
00528 {
00529 char filename[MAXPGPATH];
00530 char *copybuf = NULL;
00531 FILE *tarfile = NULL;
00532 char tarhdr[512];
00533 bool basetablespace = PQgetisnull(res, rownum, 0);
00534 bool in_tarhdr = true;
00535 bool skip_file = false;
00536 size_t tarhdrsz = 0;
00537 size_t filesz = 0;
00538
00539 #ifdef HAVE_LIBZ
00540 gzFile ztarfile = NULL;
00541 #endif
00542
00543 if (basetablespace)
00544 {
00545
00546
00547
00548 if (strcmp(basedir, "-") == 0)
00549 {
00550 #ifdef HAVE_LIBZ
00551 if (compresslevel != 0)
00552 {
00553 ztarfile = gzdopen(dup(fileno(stdout)), "wb");
00554 if (gzsetparams(ztarfile, compresslevel,
00555 Z_DEFAULT_STRATEGY) != Z_OK)
00556 {
00557 fprintf(stderr,
00558 _("%s: could not set compression level %d: %s\n"),
00559 progname, compresslevel, get_gz_error(ztarfile));
00560 disconnect_and_exit(1);
00561 }
00562 }
00563 else
00564 #endif
00565 tarfile = stdout;
00566 }
00567 else
00568 {
00569 #ifdef HAVE_LIBZ
00570 if (compresslevel != 0)
00571 {
00572 snprintf(filename, sizeof(filename), "%s/base.tar.gz", basedir);
00573 ztarfile = gzopen(filename, "wb");
00574 if (gzsetparams(ztarfile, compresslevel,
00575 Z_DEFAULT_STRATEGY) != Z_OK)
00576 {
00577 fprintf(stderr,
00578 _("%s: could not set compression level %d: %s\n"),
00579 progname, compresslevel, get_gz_error(ztarfile));
00580 disconnect_and_exit(1);
00581 }
00582 }
00583 else
00584 #endif
00585 {
00586 snprintf(filename, sizeof(filename), "%s/base.tar", basedir);
00587 tarfile = fopen(filename, "wb");
00588 }
00589 }
00590 }
00591 else
00592 {
00593
00594
00595
00596 #ifdef HAVE_LIBZ
00597 if (compresslevel != 0)
00598 {
00599 snprintf(filename, sizeof(filename), "%s/%s.tar.gz", basedir,
00600 PQgetvalue(res, rownum, 0));
00601 ztarfile = gzopen(filename, "wb");
00602 if (gzsetparams(ztarfile, compresslevel,
00603 Z_DEFAULT_STRATEGY) != Z_OK)
00604 {
00605 fprintf(stderr,
00606 _("%s: could not set compression level %d: %s\n"),
00607 progname, compresslevel, get_gz_error(ztarfile));
00608 disconnect_and_exit(1);
00609 }
00610 }
00611 else
00612 #endif
00613 {
00614 snprintf(filename, sizeof(filename), "%s/%s.tar", basedir,
00615 PQgetvalue(res, rownum, 0));
00616 tarfile = fopen(filename, "wb");
00617 }
00618 }
00619
00620 #ifdef HAVE_LIBZ
00621 if (compresslevel != 0)
00622 {
00623 if (!ztarfile)
00624 {
00625
00626 fprintf(stderr,
00627 _("%s: could not create compressed file \"%s\": %s\n"),
00628 progname, filename, get_gz_error(ztarfile));
00629 disconnect_and_exit(1);
00630 }
00631 }
00632 else
00633 #endif
00634 {
00635
00636 if (!tarfile)
00637 {
00638 fprintf(stderr, _("%s: could not create file \"%s\": %s\n"),
00639 progname, filename, strerror(errno));
00640 disconnect_and_exit(1);
00641 }
00642 }
00643
00644
00645
00646
00647 res = PQgetResult(conn);
00648 if (PQresultStatus(res) != PGRES_COPY_OUT)
00649 {
00650 fprintf(stderr, _("%s: could not get COPY data stream: %s"),
00651 progname, PQerrorMessage(conn));
00652 disconnect_and_exit(1);
00653 }
00654
00655 while (1)
00656 {
00657 int r;
00658
00659 if (copybuf != NULL)
00660 {
00661 PQfreemem(copybuf);
00662 copybuf = NULL;
00663 }
00664
00665 r = PQgetCopyData(conn, ©buf, 0);
00666 if (r == -1)
00667 {
00668
00669
00670
00671
00672
00673
00674
00675
00676 char zerobuf[1024];
00677
00678 MemSet(zerobuf, 0, sizeof(zerobuf));
00679
00680 if (basetablespace && writerecoveryconf)
00681 {
00682 char header[512];
00683 int padding;
00684
00685 tarCreateHeader(header, "recovery.conf", NULL,
00686 recoveryconfcontents->len,
00687 0600, 04000, 02000,
00688 time(NULL));
00689
00690 padding = ((recoveryconfcontents->len + 511) & ~511) - recoveryconfcontents->len;
00691
00692 WRITE_TAR_DATA(header, sizeof(header));
00693 WRITE_TAR_DATA(recoveryconfcontents->data, recoveryconfcontents->len);
00694 if (padding)
00695 WRITE_TAR_DATA(zerobuf, padding);
00696 }
00697
00698
00699 WRITE_TAR_DATA(zerobuf, sizeof(zerobuf));
00700
00701 #ifdef HAVE_LIBZ
00702 if (ztarfile != NULL)
00703 {
00704 if (gzclose(ztarfile) != 0)
00705 {
00706 fprintf(stderr,
00707 _("%s: could not close compressed file \"%s\": %s\n"),
00708 progname, filename, get_gz_error(ztarfile));
00709 disconnect_and_exit(1);
00710 }
00711 }
00712 else
00713 #endif
00714 {
00715 if (strcmp(basedir, "-") != 0)
00716 {
00717 if (fclose(tarfile) != 0)
00718 {
00719 fprintf(stderr,
00720 _("%s: could not close file \"%s\": %s\n"),
00721 progname, filename, strerror(errno));
00722 disconnect_and_exit(1);
00723 }
00724 }
00725 }
00726
00727 break;
00728 }
00729 else if (r == -2)
00730 {
00731 fprintf(stderr, _("%s: could not read COPY data: %s"),
00732 progname, PQerrorMessage(conn));
00733 disconnect_and_exit(1);
00734 }
00735
00736 if (!writerecoveryconf || !basetablespace)
00737 {
00738
00739
00740
00741
00742
00743 WRITE_TAR_DATA(copybuf, r);
00744 }
00745 else
00746 {
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758 int rr = r;
00759 int pos = 0;
00760
00761 while (rr > 0)
00762 {
00763 if (in_tarhdr)
00764 {
00765
00766
00767
00768
00769 if (tarhdrsz < 512)
00770 {
00771
00772
00773
00774
00775
00776 int hdrleft;
00777 int bytes2copy;
00778
00779 hdrleft = 512 - tarhdrsz;
00780 bytes2copy = (rr > hdrleft ? hdrleft : rr);
00781
00782 memcpy(&tarhdr[tarhdrsz], copybuf + pos, bytes2copy);
00783
00784 rr -= bytes2copy;
00785 pos += bytes2copy;
00786 tarhdrsz += bytes2copy;
00787 }
00788 else
00789 {
00790
00791
00792
00793
00794
00795
00796
00797 int padding;
00798
00799 skip_file = (strcmp(&tarhdr[0], "recovery.conf") == 0);
00800
00801 sscanf(&tarhdr[124], "%11o", (unsigned int *) &filesz);
00802
00803 padding = ((filesz + 511) & ~511) - filesz;
00804 filesz += padding;
00805
00806
00807 in_tarhdr = false;
00808
00809
00810
00811
00812
00813 if (!skip_file)
00814 WRITE_TAR_DATA(tarhdr, 512);
00815 }
00816 }
00817 else
00818 {
00819
00820
00821
00822 if (filesz > 0)
00823 {
00824
00825
00826
00827 int bytes2write;
00828
00829 bytes2write = (filesz > rr ? rr : filesz);
00830
00831 if (!skip_file)
00832 WRITE_TAR_DATA(copybuf + pos, bytes2write);
00833
00834 rr -= bytes2write;
00835 pos += bytes2write;
00836 filesz -= bytes2write;
00837 }
00838 else
00839 {
00840
00841
00842
00843
00844 in_tarhdr = true;
00845 skip_file = false;
00846 tarhdrsz = 0;
00847 filesz = 0;
00848 }
00849 }
00850 }
00851 }
00852 totaldone += r;
00853 if (showprogress)
00854 progress_report(rownum, filename);
00855 }
00856
00857 if (copybuf != NULL)
00858 PQfreemem(copybuf);
00859 }
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871 static void
00872 ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
00873 {
00874 char current_path[MAXPGPATH];
00875 char filename[MAXPGPATH];
00876 int current_len_left;
00877 int current_padding = 0;
00878 bool basetablespace = PQgetisnull(res, rownum, 0);
00879 char *copybuf = NULL;
00880 FILE *file = NULL;
00881
00882 if (basetablespace)
00883 strcpy(current_path, basedir);
00884 else
00885 strcpy(current_path, PQgetvalue(res, rownum, 1));
00886
00887
00888
00889
00890 res = PQgetResult(conn);
00891 if (PQresultStatus(res) != PGRES_COPY_OUT)
00892 {
00893 fprintf(stderr, _("%s: could not get COPY data stream: %s"),
00894 progname, PQerrorMessage(conn));
00895 disconnect_and_exit(1);
00896 }
00897
00898 while (1)
00899 {
00900 int r;
00901
00902 if (copybuf != NULL)
00903 {
00904 PQfreemem(copybuf);
00905 copybuf = NULL;
00906 }
00907
00908 r = PQgetCopyData(conn, ©buf, 0);
00909
00910 if (r == -1)
00911 {
00912
00913
00914
00915 if (file)
00916 fclose(file);
00917
00918 break;
00919 }
00920 else if (r == -2)
00921 {
00922 fprintf(stderr, _("%s: could not read COPY data: %s"),
00923 progname, PQerrorMessage(conn));
00924 disconnect_and_exit(1);
00925 }
00926
00927 if (file == NULL)
00928 {
00929 int filemode;
00930
00931
00932
00933
00934 if (r != 512)
00935 {
00936 fprintf(stderr, _("%s: invalid tar block header size: %d\n"),
00937 progname, r);
00938 disconnect_and_exit(1);
00939 }
00940 totaldone += 512;
00941
00942 if (sscanf(copybuf + 124, "%11o", ¤t_len_left) != 1)
00943 {
00944 fprintf(stderr, _("%s: could not parse file size\n"),
00945 progname);
00946 disconnect_and_exit(1);
00947 }
00948
00949
00950 if (sscanf(©buf[100], "%07o ", &filemode) != 1)
00951 {
00952 fprintf(stderr, _("%s: could not parse file mode\n"),
00953 progname);
00954 disconnect_and_exit(1);
00955 }
00956
00957
00958
00959
00960 current_padding =
00961 ((current_len_left + 511) & ~511) - current_len_left;
00962
00963
00964
00965
00966 snprintf(filename, sizeof(filename), "%s/%s", current_path,
00967 copybuf);
00968 if (filename[strlen(filename) - 1] == '/')
00969 {
00970
00971
00972
00973 if (copybuf[156] == '5')
00974 {
00975
00976
00977
00978 filename[strlen(filename) - 1] = '\0';
00979 if (mkdir(filename, S_IRWXU) != 0)
00980 {
00981
00982
00983
00984
00985
00986 if (!streamwal || strcmp(filename + strlen(filename) - 8, "/pg_xlog") != 0)
00987 {
00988 fprintf(stderr,
00989 _("%s: could not create directory \"%s\": %s\n"),
00990 progname, filename, strerror(errno));
00991 disconnect_and_exit(1);
00992 }
00993 }
00994 #ifndef WIN32
00995 if (chmod(filename, (mode_t) filemode))
00996 fprintf(stderr,
00997 _("%s: could not set permissions on directory \"%s\": %s\n"),
00998 progname, filename, strerror(errno));
00999 #endif
01000 }
01001 else if (copybuf[156] == '2')
01002 {
01003
01004
01005
01006 filename[strlen(filename) - 1] = '\0';
01007 if (symlink(©buf[157], filename) != 0)
01008 {
01009 fprintf(stderr,
01010 _("%s: could not create symbolic link from \"%s\" to \"%s\": %s\n"),
01011 progname, filename, ©buf[157], strerror(errno));
01012 disconnect_and_exit(1);
01013 }
01014 }
01015 else
01016 {
01017 fprintf(stderr,
01018 _("%s: unrecognized link indicator \"%c\"\n"),
01019 progname, copybuf[156]);
01020 disconnect_and_exit(1);
01021 }
01022 continue;
01023 }
01024
01025
01026
01027
01028 file = fopen(filename, "wb");
01029 if (!file)
01030 {
01031 fprintf(stderr, _("%s: could not create file \"%s\": %s\n"),
01032 progname, filename, strerror(errno));
01033 disconnect_and_exit(1);
01034 }
01035
01036 #ifndef WIN32
01037 if (chmod(filename, (mode_t) filemode))
01038 fprintf(stderr, _("%s: could not set permissions on file \"%s\": %s\n"),
01039 progname, filename, strerror(errno));
01040 #endif
01041
01042 if (current_len_left == 0)
01043 {
01044
01045
01046
01047 fclose(file);
01048 file = NULL;
01049 continue;
01050 }
01051 }
01052 else
01053 {
01054
01055
01056
01057 if (current_len_left == 0 && r == current_padding)
01058 {
01059
01060
01061
01062
01063 fclose(file);
01064 file = NULL;
01065 totaldone += r;
01066 continue;
01067 }
01068
01069 if (fwrite(copybuf, r, 1, file) != 1)
01070 {
01071 fprintf(stderr, _("%s: could not write to file \"%s\": %s\n"),
01072 progname, filename, strerror(errno));
01073 disconnect_and_exit(1);
01074 }
01075 totaldone += r;
01076 if (showprogress)
01077 progress_report(rownum, filename);
01078
01079 current_len_left -= r;
01080 if (current_len_left == 0 && current_padding == 0)
01081 {
01082
01083
01084
01085
01086
01087 fclose(file);
01088 file = NULL;
01089 continue;
01090 }
01091 }
01092 }
01093
01094 if (file != NULL)
01095 {
01096 fprintf(stderr,
01097 _("%s: COPY stream ended before last file was finished\n"),
01098 progname);
01099 disconnect_and_exit(1);
01100 }
01101
01102 if (copybuf != NULL)
01103 PQfreemem(copybuf);
01104
01105 if (basetablespace && writerecoveryconf)
01106 WriteRecoveryConf();
01107 }
01108
01109
01110
01111
01112 static char *
01113 escape_quotes(const char *src)
01114 {
01115 char *result = escape_single_quotes_ascii(src);
01116
01117 if (!result)
01118 {
01119 fprintf(stderr, _("%s: out of memory\n"), progname);
01120 exit(1);
01121 }
01122 return result;
01123 }
01124
01125
01126
01127
01128 static void
01129 GenerateRecoveryConf(PGconn *conn)
01130 {
01131 PQconninfoOption *connOptions;
01132 PQconninfoOption *option;
01133
01134 recoveryconfcontents = createPQExpBuffer();
01135 if (!recoveryconfcontents)
01136 {
01137 fprintf(stderr, _("%s: out of memory\n"), progname);
01138 disconnect_and_exit(1);
01139 }
01140
01141 connOptions = PQconninfo(conn);
01142 if (connOptions == NULL)
01143 {
01144 fprintf(stderr, _("%s: out of memory\n"), progname);
01145 disconnect_and_exit(1);
01146 }
01147
01148 appendPQExpBufferStr(recoveryconfcontents, "standby_mode = 'on'\n");
01149 appendPQExpBufferStr(recoveryconfcontents, "primary_conninfo = '");
01150
01151 for (option = connOptions; option && option->keyword; option++)
01152 {
01153 char *escaped;
01154
01155
01156
01157
01158
01159
01160
01161 if (strcmp(option->keyword, "replication") == 0 ||
01162 strcmp(option->keyword, "dbname") == 0 ||
01163 strcmp(option->keyword, "fallback_application_name") == 0 ||
01164 (option->val == NULL) ||
01165 (option->val != NULL && option->val[0] == '\0'))
01166 continue;
01167
01168
01169
01170
01171
01172 escaped = escape_quotes(option->val);
01173
01174 appendPQExpBuffer(recoveryconfcontents, "%s=''%s'' ", option->keyword, escaped);
01175
01176 free(escaped);
01177 }
01178
01179 appendPQExpBufferStr(recoveryconfcontents, "'\n");
01180 if (PQExpBufferBroken(recoveryconfcontents))
01181 {
01182 fprintf(stderr, _("%s: out of memory\n"), progname);
01183 disconnect_and_exit(1);
01184 }
01185
01186 PQconninfoFree(connOptions);
01187 }
01188
01189
01190
01191
01192
01193
01194 static void
01195 WriteRecoveryConf(void)
01196 {
01197 char filename[MAXPGPATH];
01198 FILE *cf;
01199
01200 sprintf(filename, "%s/recovery.conf", basedir);
01201
01202 cf = fopen(filename, "w");
01203 if (cf == NULL)
01204 {
01205 fprintf(stderr, _("%s: could not create file \"%s\": %s\n"), progname, filename, strerror(errno));
01206 disconnect_and_exit(1);
01207 }
01208
01209 if (fwrite(recoveryconfcontents->data, recoveryconfcontents->len, 1, cf) != 1)
01210 {
01211 fprintf(stderr,
01212 _("%s: could not write to file \"%s\": %s\n"),
01213 progname, filename, strerror(errno));
01214 disconnect_and_exit(1);
01215 }
01216
01217 fclose(cf);
01218 }
01219
01220
01221 static void
01222 BaseBackup(void)
01223 {
01224 PGresult *res;
01225 char *sysidentifier;
01226 uint32 latesttli;
01227 uint32 starttli;
01228 char current_path[MAXPGPATH];
01229 char escaped_label[MAXPGPATH];
01230 int i;
01231 char xlogstart[64];
01232 char xlogend[64];
01233 int minServerMajor,
01234 maxServerMajor;
01235 int serverMajor;
01236
01237
01238
01239
01240 conn = GetConnection();
01241 if (!conn)
01242
01243 exit(1);
01244
01245
01246
01247
01248
01249 minServerMajor = 901;
01250 maxServerMajor = PG_VERSION_NUM / 100;
01251 serverMajor = PQserverVersion(conn) / 100;
01252 if (serverMajor < minServerMajor || serverMajor > maxServerMajor)
01253 {
01254 const char *serverver = PQparameterStatus(conn, "server_version");
01255 fprintf(stderr, _("%s: incompatible server version %s\n"),
01256 progname, serverver ? serverver : "'unknown'");
01257 disconnect_and_exit(1);
01258 }
01259
01260
01261
01262
01263
01264 if (streamwal && !CheckServerVersionForStreaming(conn))
01265 {
01266
01267 disconnect_and_exit(1);
01268 }
01269
01270
01271
01272
01273 if (writerecoveryconf)
01274 GenerateRecoveryConf(conn);
01275
01276
01277
01278
01279 res = PQexec(conn, "IDENTIFY_SYSTEM");
01280 if (PQresultStatus(res) != PGRES_TUPLES_OK)
01281 {
01282 fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
01283 progname, "IDENTIFY_SYSTEM", PQerrorMessage(conn));
01284 disconnect_and_exit(1);
01285 }
01286 if (PQntuples(res) != 1 || PQnfields(res) != 3)
01287 {
01288 fprintf(stderr,
01289 _("%s: could not identify system: got %d rows and %d fields, expected %d rows and %d fields\n"),
01290 progname, PQntuples(res), PQnfields(res), 1, 3);
01291 disconnect_and_exit(1);
01292 }
01293 sysidentifier = pg_strdup(PQgetvalue(res, 0, 0));
01294 latesttli = atoi(PQgetvalue(res, 0, 1));
01295 PQclear(res);
01296
01297
01298
01299
01300 PQescapeStringConn(conn, escaped_label, label, sizeof(escaped_label), &i);
01301 snprintf(current_path, sizeof(current_path),
01302 "BASE_BACKUP LABEL '%s' %s %s %s %s",
01303 escaped_label,
01304 showprogress ? "PROGRESS" : "",
01305 includewal && !streamwal ? "WAL" : "",
01306 fastcheckpoint ? "FAST" : "",
01307 includewal ? "NOWAIT" : "");
01308
01309 if (PQsendQuery(conn, current_path) == 0)
01310 {
01311 fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
01312 progname, "BASE_BACKUP", PQerrorMessage(conn));
01313 disconnect_and_exit(1);
01314 }
01315
01316
01317
01318
01319 res = PQgetResult(conn);
01320 if (PQresultStatus(res) != PGRES_TUPLES_OK)
01321 {
01322 fprintf(stderr, _("%s: could not initiate base backup: %s"),
01323 progname, PQerrorMessage(conn));
01324 disconnect_and_exit(1);
01325 }
01326 if (PQntuples(res) != 1)
01327 {
01328 fprintf(stderr,
01329 _("%s: server returned unexpected response to BASE_BACKUP command; got %d rows and %d fields, expected %d rows and %d fields\n"),
01330 progname, PQntuples(res), PQnfields(res), 1, 2);
01331 disconnect_and_exit(1);
01332 }
01333
01334 strcpy(xlogstart, PQgetvalue(res, 0, 0));
01335
01336
01337
01338
01339 if (PQnfields(res) >= 2)
01340 starttli = atoi(PQgetvalue(res, 0, 1));
01341 else
01342 starttli = latesttli;
01343 PQclear(res);
01344 MemSet(xlogend, 0, sizeof(xlogend));
01345
01346 if (verbose && includewal)
01347 fprintf(stderr, _("transaction log start point: %s on timeline %u\n"),
01348 xlogstart, starttli);
01349
01350
01351
01352
01353 res = PQgetResult(conn);
01354 if (PQresultStatus(res) != PGRES_TUPLES_OK)
01355 {
01356 fprintf(stderr, _("%s: could not get backup header: %s"),
01357 progname, PQerrorMessage(conn));
01358 disconnect_and_exit(1);
01359 }
01360 if (PQntuples(res) < 1)
01361 {
01362 fprintf(stderr, _("%s: no data returned from server\n"), progname);
01363 disconnect_and_exit(1);
01364 }
01365
01366
01367
01368
01369 totalsize = totaldone = 0;
01370 tablespacecount = PQntuples(res);
01371 for (i = 0; i < PQntuples(res); i++)
01372 {
01373 if (showprogress)
01374 totalsize += atol(PQgetvalue(res, i, 2));
01375
01376
01377
01378
01379
01380
01381 if (format == 'p' && !PQgetisnull(res, i, 1))
01382 verify_dir_is_empty_or_create(PQgetvalue(res, i, 1));
01383 }
01384
01385
01386
01387
01388 if (format == 't' && strcmp(basedir, "-") == 0 && PQntuples(res) > 1)
01389 {
01390 fprintf(stderr,
01391 _("%s: can only write single tablespace to stdout, database has %d\n"),
01392 progname, PQntuples(res));
01393 disconnect_and_exit(1);
01394 }
01395
01396
01397
01398
01399
01400 if (streamwal)
01401 {
01402 if (verbose)
01403 fprintf(stderr, _("%s: starting background WAL receiver\n"),
01404 progname);
01405 StartLogStreamer(xlogstart, starttli, sysidentifier);
01406 }
01407
01408
01409
01410
01411 for (i = 0; i < PQntuples(res); i++)
01412 {
01413 if (format == 't')
01414 ReceiveTarFile(conn, res, i);
01415 else
01416 ReceiveAndUnpackTarFile(conn, res, i);
01417 }
01418
01419 if (showprogress)
01420 {
01421 progress_report(PQntuples(res), NULL);
01422 fprintf(stderr, "\n");
01423 }
01424 PQclear(res);
01425
01426
01427
01428
01429 res = PQgetResult(conn);
01430 if (PQresultStatus(res) != PGRES_TUPLES_OK)
01431 {
01432 fprintf(stderr,
01433 _("%s: could not get transaction log end position from server: %s"),
01434 progname, PQerrorMessage(conn));
01435 disconnect_and_exit(1);
01436 }
01437 if (PQntuples(res) != 1)
01438 {
01439 fprintf(stderr,
01440 _("%s: no transaction log end position returned from server\n"),
01441 progname);
01442 disconnect_and_exit(1);
01443 }
01444 strcpy(xlogend, PQgetvalue(res, 0, 0));
01445 if (verbose && includewal)
01446 fprintf(stderr, "transaction log end point: %s\n", xlogend);
01447 PQclear(res);
01448
01449 res = PQgetResult(conn);
01450 if (PQresultStatus(res) != PGRES_COMMAND_OK)
01451 {
01452 fprintf(stderr, _("%s: final receive failed: %s"),
01453 progname, PQerrorMessage(conn));
01454 disconnect_and_exit(1);
01455 }
01456
01457 if (bgchild > 0)
01458 {
01459 #ifndef WIN32
01460 int status;
01461 int r;
01462 #else
01463 DWORD status;
01464 uint32 hi,
01465 lo;
01466 #endif
01467
01468 if (verbose)
01469 fprintf(stderr,
01470 _("%s: waiting for background process to finish streaming ...\n"), progname);
01471
01472 #ifndef WIN32
01473 if (write(bgpipe[1], xlogend, strlen(xlogend)) != strlen(xlogend))
01474 {
01475 fprintf(stderr,
01476 _("%s: could not send command to background pipe: %s\n"),
01477 progname, strerror(errno));
01478 disconnect_and_exit(1);
01479 }
01480
01481
01482 r = waitpid(bgchild, &status, 0);
01483 if (r == -1)
01484 {
01485 fprintf(stderr, _("%s: could not wait for child process: %s\n"),
01486 progname, strerror(errno));
01487 disconnect_and_exit(1);
01488 }
01489 if (r != bgchild)
01490 {
01491 fprintf(stderr, _("%s: child %d died, expected %d\n"),
01492 progname, r, (int) bgchild);
01493 disconnect_and_exit(1);
01494 }
01495 if (!WIFEXITED(status))
01496 {
01497 fprintf(stderr, _("%s: child process did not exit normally\n"),
01498 progname);
01499 disconnect_and_exit(1);
01500 }
01501 if (WEXITSTATUS(status) != 0)
01502 {
01503 fprintf(stderr, _("%s: child process exited with error %d\n"),
01504 progname, WEXITSTATUS(status));
01505 disconnect_and_exit(1);
01506 }
01507
01508 #else
01509
01510
01511
01512
01513
01514
01515 if (sscanf(xlogend, "%X/%X", &hi, &lo) != 2)
01516 {
01517 fprintf(stderr,
01518 _("%s: could not parse transaction log location \"%s\"\n"),
01519 progname, xlogend);
01520 disconnect_and_exit(1);
01521 }
01522 xlogendptr = ((uint64) hi) << 32 | lo;
01523 InterlockedIncrement(&has_xlogendptr);
01524
01525
01526 if (WaitForSingleObjectEx((HANDLE) bgchild, INFINITE, FALSE) !=
01527 WAIT_OBJECT_0)
01528 {
01529 _dosmaperr(GetLastError());
01530 fprintf(stderr, _("%s: could not wait for child thread: %s\n"),
01531 progname, strerror(errno));
01532 disconnect_and_exit(1);
01533 }
01534 if (GetExitCodeThread((HANDLE) bgchild, &status) == 0)
01535 {
01536 _dosmaperr(GetLastError());
01537 fprintf(stderr, _("%s: could not get child thread exit status: %s\n"),
01538 progname, strerror(errno));
01539 disconnect_and_exit(1);
01540 }
01541 if (status != 0)
01542 {
01543 fprintf(stderr, _("%s: child thread exited with error %u\n"),
01544 progname, (unsigned int) status);
01545 disconnect_and_exit(1);
01546 }
01547
01548 #endif
01549 }
01550
01551
01552 destroyPQExpBuffer(recoveryconfcontents);
01553
01554
01555
01556
01557 PQclear(res);
01558 PQfinish(conn);
01559
01560 if (verbose)
01561 fprintf(stderr, "%s: base backup completed\n", progname);
01562 }
01563
01564
01565 int
01566 main(int argc, char **argv)
01567 {
01568 static struct option long_options[] = {
01569 {"help", no_argument, NULL, '?'},
01570 {"version", no_argument, NULL, 'V'},
01571 {"pgdata", required_argument, NULL, 'D'},
01572 {"format", required_argument, NULL, 'F'},
01573 {"checkpoint", required_argument, NULL, 'c'},
01574 {"write-recovery-conf", no_argument, NULL, 'R'},
01575 {"xlog", no_argument, NULL, 'x'},
01576 {"xlog-method", required_argument, NULL, 'X'},
01577 {"gzip", no_argument, NULL, 'z'},
01578 {"compress", required_argument, NULL, 'Z'},
01579 {"label", required_argument, NULL, 'l'},
01580 {"dbname", required_argument, NULL, 'd'},
01581 {"host", required_argument, NULL, 'h'},
01582 {"port", required_argument, NULL, 'p'},
01583 {"username", required_argument, NULL, 'U'},
01584 {"no-password", no_argument, NULL, 'w'},
01585 {"password", no_argument, NULL, 'W'},
01586 {"status-interval", required_argument, NULL, 's'},
01587 {"verbose", no_argument, NULL, 'v'},
01588 {"progress", no_argument, NULL, 'P'},
01589 {NULL, 0, NULL, 0}
01590 };
01591 int c;
01592
01593 int option_index;
01594
01595 progname = get_progname(argv[0]);
01596 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_basebackup"));
01597
01598 if (argc > 1)
01599 {
01600 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
01601 {
01602 usage();
01603 exit(0);
01604 }
01605 else if (strcmp(argv[1], "-V") == 0
01606 || strcmp(argv[1], "--version") == 0)
01607 {
01608 puts("pg_basebackup (PostgreSQL) " PG_VERSION);
01609 exit(0);
01610 }
01611 }
01612
01613 while ((c = getopt_long(argc, argv, "D:F:RxX:l:zZ:d:c:h:p:U:s:wWvP",
01614 long_options, &option_index)) != -1)
01615 {
01616 switch (c)
01617 {
01618 case 'D':
01619 basedir = pg_strdup(optarg);
01620 break;
01621 case 'F':
01622 if (strcmp(optarg, "p") == 0 || strcmp(optarg, "plain") == 0)
01623 format = 'p';
01624 else if (strcmp(optarg, "t") == 0 || strcmp(optarg, "tar") == 0)
01625 format = 't';
01626 else
01627 {
01628 fprintf(stderr,
01629 _("%s: invalid output format \"%s\", must be \"plain\" or \"tar\"\n"),
01630 progname, optarg);
01631 exit(1);
01632 }
01633 break;
01634 case 'R':
01635 writerecoveryconf = true;
01636 break;
01637 case 'x':
01638 if (includewal)
01639 {
01640 fprintf(stderr,
01641 _("%s: cannot specify both --xlog and --xlog-method\n"),
01642 progname);
01643 exit(1);
01644 }
01645
01646 includewal = true;
01647 streamwal = false;
01648 break;
01649 case 'X':
01650 if (includewal)
01651 {
01652 fprintf(stderr,
01653 _("%s: cannot specify both --xlog and --xlog-method\n"),
01654 progname);
01655 exit(1);
01656 }
01657
01658 includewal = true;
01659 if (strcmp(optarg, "f") == 0 ||
01660 strcmp(optarg, "fetch") == 0)
01661 streamwal = false;
01662 else if (strcmp(optarg, "s") == 0 ||
01663 strcmp(optarg, "stream") == 0)
01664 streamwal = true;
01665 else
01666 {
01667 fprintf(stderr,
01668 _("%s: invalid xlog-method option \"%s\", must be \"fetch\" or \"stream\"\n"),
01669 progname, optarg);
01670 exit(1);
01671 }
01672 break;
01673 case 'l':
01674 label = pg_strdup(optarg);
01675 break;
01676 case 'z':
01677 #ifdef HAVE_LIBZ
01678 compresslevel = Z_DEFAULT_COMPRESSION;
01679 #else
01680 compresslevel = 1;
01681 #endif
01682 break;
01683 case 'Z':
01684 compresslevel = atoi(optarg);
01685 if (compresslevel <= 0 || compresslevel > 9)
01686 {
01687 fprintf(stderr, _("%s: invalid compression level \"%s\"\n"),
01688 progname, optarg);
01689 exit(1);
01690 }
01691 break;
01692 case 'c':
01693 if (pg_strcasecmp(optarg, "fast") == 0)
01694 fastcheckpoint = true;
01695 else if (pg_strcasecmp(optarg, "spread") == 0)
01696 fastcheckpoint = false;
01697 else
01698 {
01699 fprintf(stderr, _("%s: invalid checkpoint argument \"%s\", must be \"fast\" or \"spread\"\n"),
01700 progname, optarg);
01701 exit(1);
01702 }
01703 break;
01704 case 'd':
01705 connection_string = pg_strdup(optarg);
01706 break;
01707 case 'h':
01708 dbhost = pg_strdup(optarg);
01709 break;
01710 case 'p':
01711 dbport = pg_strdup(optarg);
01712 break;
01713 case 'U':
01714 dbuser = pg_strdup(optarg);
01715 break;
01716 case 'w':
01717 dbgetpassword = -1;
01718 break;
01719 case 'W':
01720 dbgetpassword = 1;
01721 break;
01722 case 's':
01723 standby_message_timeout = atoi(optarg) * 1000;
01724 if (standby_message_timeout < 0)
01725 {
01726 fprintf(stderr, _("%s: invalid status interval \"%s\"\n"),
01727 progname, optarg);
01728 exit(1);
01729 }
01730 break;
01731 case 'v':
01732 verbose++;
01733 break;
01734 case 'P':
01735 showprogress = true;
01736 break;
01737 default:
01738
01739
01740
01741
01742 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
01743 progname);
01744 exit(1);
01745 }
01746 }
01747
01748
01749
01750
01751 if (optind < argc)
01752 {
01753 fprintf(stderr,
01754 _("%s: too many command-line arguments (first is \"%s\")\n"),
01755 progname, argv[optind]);
01756 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
01757 progname);
01758 exit(1);
01759 }
01760
01761
01762
01763
01764 if (basedir == NULL)
01765 {
01766 fprintf(stderr, _("%s: no target directory specified\n"), progname);
01767 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
01768 progname);
01769 exit(1);
01770 }
01771
01772
01773
01774
01775 if (format == 'p' && compresslevel != 0)
01776 {
01777 fprintf(stderr,
01778 _("%s: only tar mode backups can be compressed\n"),
01779 progname);
01780 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
01781 progname);
01782 exit(1);
01783 }
01784
01785 if (format != 'p' && streamwal)
01786 {
01787 fprintf(stderr,
01788 _("%s: WAL streaming can only be used in plain mode\n"),
01789 progname);
01790 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
01791 progname);
01792 exit(1);
01793 }
01794
01795 #ifndef HAVE_LIBZ
01796 if (compresslevel != 0)
01797 {
01798 fprintf(stderr,
01799 _("%s: this build does not support compression\n"),
01800 progname);
01801 exit(1);
01802 }
01803 #endif
01804
01805
01806
01807
01808
01809
01810 if (format == 'p' || strcmp(basedir, "-") != 0)
01811 verify_dir_is_empty_or_create(basedir);
01812
01813 BaseBackup();
01814
01815 return 0;
01816 }