Header And Logo

PostgreSQL
| The world's most advanced open source database.

pg_basebackup.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * pg_basebackup.c - receive a base backup using streaming replication protocol
00004  *
00005  * Author: Magnus Hagander <[email protected]>
00006  *
00007  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00008  *
00009  * IDENTIFICATION
00010  *        src/bin/pg_basebackup/pg_basebackup.c
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 /* Global options */
00037 char       *basedir = NULL;
00038 char        format = 'p';       /* p(lain)/t(ar) */
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;        /* 10 sec = default */
00048 
00049 /* Progress counters */
00050 static uint64 totalsize;
00051 static uint64 totaldone;
00052 static int  tablespacecount;
00053 
00054 /* Pipe to communicate with background wal receiver process */
00055 #ifndef WIN32
00056 static int  bgpipe[2] = {-1, -1};
00057 #endif
00058 
00059 /* Handle to child process */
00060 static pid_t bgchild = -1;
00061 
00062 /* End position for xlog streaming, empty string if unknown yet */
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 /* Contents of recovery.conf to be generated */
00072 static PQExpBuffer recoveryconfcontents = NULL;
00073 
00074 /* Function headers */
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  * Called in the background process every time data is received.
00143  * On Unix, we check to see if there is any data on our pipe
00144  * (which would mean we have a stop position), and if it is, check if
00145  * it is time to stop.
00146  * On Windows, we are in a single process, so we can just check if it's
00147  * time to stop.
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          * Don't have the end pointer yet - check our pipe to see if it has
00162          * been sent yet.
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              * Fall through to check if we've reached the point further
00197              * already.
00198              */
00199         }
00200         else
00201         {
00202             /*
00203              * No data received on the pipe means we don't know the end
00204              * position yet - so just say it's not time to stop yet.
00205              */
00206             return false;
00207         }
00208 #else
00209 
00210         /*
00211          * On win32, has_xlogendptr is set by the main thread, so if it's not
00212          * set here, we just go back and wait until it shows up.
00213          */
00214         return false;
00215 #endif
00216     }
00217 
00218     /*
00219      * At this point we have an end pointer, so compare it to the current
00220      * position to figure out if it's time to stop.
00221      */
00222     if (segendpos >= xlogendptr)
00223         return true;
00224 
00225     /*
00226      * Have end pointer, but haven't reached it yet - so tell the caller to
00227      * keep streaming.
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          * Any errors will already have been reported in the function process,
00251          * but we need to tell the parent that we didn't shutdown in a nice
00252          * way.
00253          */
00254         return 1;
00255 
00256     PQfinish(param->bgconn);
00257     return 0;
00258 }
00259 
00260 /*
00261  * Initiate background process for receiving xlog during the backup.
00262  * The background stream will use its own database connection so we can
00263  * stream the logfile in parallel with the backups.
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     /* Convert the starting position */
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     /* Round off to even segment position */
00286     param->startptr -= param->startptr % XLOG_SEG_SIZE;
00287 
00288 #ifndef WIN32
00289     /* Create our background pipe */
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     /* Get a second connection */
00300     param->bgconn = GetConnection();
00301     if (!param->bgconn)
00302         /* Error message already written in GetConnection() */
00303         exit(1);
00304 
00305     /*
00306      * Always in plain format, so we can write to basedir/pg_xlog. But the
00307      * directory entry in the tar file may arrive later, so make sure it's
00308      * created before we start.
00309      */
00310     snprintf(param->xlogdir, sizeof(param->xlogdir), "%s/pg_xlog", basedir);
00311     verify_dir_is_empty_or_create(param->xlogdir);
00312 
00313     /*
00314      * Start a child process and tell it to start streaming. On Unix, this is
00315      * a fork(). On Windows, we create a thread.
00316      */
00317 #ifndef WIN32
00318     bgchild = fork();
00319     if (bgchild == 0)
00320     {
00321         /* in child process */
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      * Else we are in the parent process and all is well.
00333      */
00334 #else                           /* WIN32 */
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  * Verify that the given directory exists and is empty. If it does not
00347  * exist, it is created. If it exists but is not empty, an error will
00348  * be give and the process ended.
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              * Does not exist, so create
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              * Exists, empty
00372              */
00373             return;
00374         case 2:
00375         case 3:
00376         case 4:
00377 
00378             /*
00379              * Exists, not empty
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              * Access problem
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  * Print a progress report based on the global variables. If verbose output
00399  * is enabled, also print the current file name.
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      * Avoid overflowing past 100% or the full size. This may make the total
00410      * size number change as we approach the end of the backup (the estimate
00411      * will always be wrong if WAL is included), but that's better than having
00412      * the done column be bigger than the total.
00413      */
00414     if (percent > 100)
00415         percent = 100;
00416     if (totaldone / 1024 > totalsize)
00417         totalsize = totaldone / 1024;
00418 
00419     /*
00420      * Separate step to keep platform-dependent format code out of
00421      * translatable strings.  And we only test for INT64_FORMAT availability
00422      * in snprintf, not fprintf.
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              * No filename given, so clear the status line (used for last
00435              * call)
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                     /* Prefix with "..." if we do leading truncation */
00457                     truncate ? "..." : "",
00458                     truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
00459                     truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
00460                     /* Truncate filename at beginning if it's too long */
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  * Write a piece of tar data
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  * Receive a tar format file from the connection to the server, and write
00518  * the data from this file directly into a tar file. If compression is
00519  * enabled, the data will be compressed while written to the file.
00520  *
00521  * The file will be named base.tar[.gz] if it's for the main data directory
00522  * or <tablespaceoid>.tar[.gz] if it's for another tablespace.
00523  *
00524  * No attempt to inspect or validate the contents of the file is done.
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          * Base tablespaces
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          * Specific tablespace
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             /* Compression is in use */
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         /* Either no zlib support, or zlib support but compresslevel = 0 */
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      * Get the COPY data stream
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, &copybuf, 0);
00666         if (r == -1)
00667         {
00668             /*
00669              * End of chunk. If requested, and this is the base tablespace,
00670              * write recovery.conf into the tarfile. When done, close the file
00671              * (but not stdout).
00672              *
00673              * Also, write two completely empty blocks at the end of the tar
00674              * file, as required by some tar programs.
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             /* 2 * 512 bytes empty data at end of file */
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              * When not writing recovery.conf, or when not working on the base
00740              * tablespace, we never have to look for an existing recovery.conf
00741              * file in the stream.
00742              */
00743             WRITE_TAR_DATA(copybuf, r);
00744         }
00745         else
00746         {
00747             /*
00748              * Look for a recovery.conf in the existing tar stream. If it's
00749              * there, we must skip it so we can later overwrite it with our
00750              * own version of the file.
00751              *
00752              * To do this, we have to process the individual files inside the
00753              * TAR stream. The stream consists of a header and zero or more
00754              * chunks, all 512 bytes long. The stream from the server is
00755              * broken up into smaller pieces, so we have to track the size of
00756              * the files to find the next header structure.
00757              */
00758             int         rr = r;
00759             int         pos = 0;
00760 
00761             while (rr > 0)
00762             {
00763                 if (in_tarhdr)
00764                 {
00765                     /*
00766                      * We're currently reading a header structure inside the
00767                      * TAR stream, i.e. the file metadata.
00768                      */
00769                     if (tarhdrsz < 512)
00770                     {
00771                         /*
00772                          * Copy the header structure into tarhdr in case the
00773                          * header is not aligned to 512 bytes or it's not
00774                          * returned in whole by the last PQgetCopyData call.
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                          * We have the complete header structure in tarhdr,
00792                          * look at the file metadata: - the subsequent file
00793                          * contents have to be skipped if the filename is
00794                          * recovery.conf - find out the size of the file
00795                          * padded to the next multiple of 512
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                         /* Next part is the file, not the header */
00807                         in_tarhdr = false;
00808 
00809                         /*
00810                          * If we're not skipping the file, write the tar
00811                          * header unmodified.
00812                          */
00813                         if (!skip_file)
00814                             WRITE_TAR_DATA(tarhdr, 512);
00815                     }
00816                 }
00817                 else
00818                 {
00819                     /*
00820                      * We're processing a file's contents.
00821                      */
00822                     if (filesz > 0)
00823                     {
00824                         /*
00825                          * We still have data to read (and possibly write).
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                          * No more data in the current file, the next piece of
00842                          * data (if any) will be a new file header structure.
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     }                           /* while (1) */
00856 
00857     if (copybuf != NULL)
00858         PQfreemem(copybuf);
00859 }
00860 
00861 /*
00862  * Receive a tar format stream from the connection to the server, and unpack
00863  * the contents of it into a directory. Only files, directories and
00864  * symlinks are supported, no other kinds of special files.
00865  *
00866  * If the data is for the main data directory, it will be restored in the
00867  * specified directory. If it's for another tablespace, it will be restored
00868  * in the original directory, since relocation of tablespaces is not
00869  * supported.
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      * Get the COPY data
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, &copybuf, 0);
00909 
00910         if (r == -1)
00911         {
00912             /*
00913              * End of chunk
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              * No current file, so this must be the header for a new file
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", &current_len_left) != 1)
00943             {
00944                 fprintf(stderr, _("%s: could not parse file size\n"),
00945                         progname);
00946                 disconnect_and_exit(1);
00947             }
00948 
00949             /* Set permissions on the file */
00950             if (sscanf(&copybuf[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              * All files are padded up to 512 bytes
00959              */
00960             current_padding =
00961                 ((current_len_left + 511) & ~511) - current_len_left;
00962 
00963             /*
00964              * First part of header is zero terminated filename
00965              */
00966             snprintf(filename, sizeof(filename), "%s/%s", current_path,
00967                      copybuf);
00968             if (filename[strlen(filename) - 1] == '/')
00969             {
00970                 /*
00971                  * Ends in a slash means directory or symlink to directory
00972                  */
00973                 if (copybuf[156] == '5')
00974                 {
00975                     /*
00976                      * Directory
00977                      */
00978                     filename[strlen(filename) - 1] = '\0';      /* Remove trailing slash */
00979                     if (mkdir(filename, S_IRWXU) != 0)
00980                     {
00981                         /*
00982                          * When streaming WAL, pg_xlog will have been created
00983                          * by the wal receiver process, so just ignore failure
00984                          * on that.
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                      * Symbolic link
01005                      */
01006                     filename[strlen(filename) - 1] = '\0';      /* Remove trailing slash */
01007                     if (symlink(&copybuf[157], filename) != 0)
01008                     {
01009                         fprintf(stderr,
01010                                 _("%s: could not create symbolic link from \"%s\" to \"%s\": %s\n"),
01011                          progname, filename, &copybuf[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;       /* directory or link handled */
01023             }
01024 
01025             /*
01026              * regular file
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                  * Done with this file, next one will be a new tar header
01046                  */
01047                 fclose(file);
01048                 file = NULL;
01049                 continue;
01050             }
01051         }                       /* new file */
01052         else
01053         {
01054             /*
01055              * Continuing blocks in existing file
01056              */
01057             if (current_len_left == 0 && r == current_padding)
01058             {
01059                 /*
01060                  * Received the padding block for this file, ignore it and
01061                  * close the file, then move on to the next tar header.
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                  * Received the last block, and there is no padding to be
01084                  * expected. Close the file and move on to the next tar
01085                  * header.
01086                  */
01087                 fclose(file);
01088                 file = NULL;
01089                 continue;
01090             }
01091         }                       /* continuing data in existing file */
01092     }                           /* loop over all data blocks */
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  * Escape single quotes used in connection parameters
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  * Create a recovery.conf file in memory using a PQExpBuffer
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          * Do not emit this setting if: - the setting is "replication",
01157          * "dbname" or "fallback_application_name", since these would be
01158          * overridden by the libpqwalreceiver module anyway. - not set or
01159          * empty.
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          * Write "keyword='value'" pieces, the value string is escaped if
01170          * necessary and doubled single quotes around the value string.
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  * Write a recovery.conf file into the directory specified in basedir,
01192  * with the contents already collected in memory.
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      * Connect in replication mode to the server
01239      */
01240     conn = GetConnection();
01241     if (!conn)
01242         /* Error message already written in GetConnection() */
01243         exit(1);
01244 
01245     /*
01246      * Check server version. BASE_BACKUP command was introduced in 9.1, so
01247      * we can't work with servers older than 9.1.
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      * If WAL streaming was requested, also check that the server is new
01262      * enough for that.
01263      */
01264     if (streamwal && !CheckServerVersionForStreaming(conn))
01265     {
01266         /* Error message already written in CheckServerVersionForStreaming() */
01267         disconnect_and_exit(1);
01268     }
01269 
01270     /*
01271      * Build contents of recovery.conf if requested
01272      */
01273     if (writerecoveryconf)
01274         GenerateRecoveryConf(conn);
01275 
01276     /*
01277      * Run IDENTIFY_SYSTEM so we can get the timeline
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      * Start the actual backup
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      * Get the starting xlog position
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      * 9.3 and later sends the TLI of the starting point. With older servers,
01337      * assume it's the same as the latest timeline reported by IDENTIFY_SYSTEM.
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      * Get the header
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      * Sum up the total size, for progress reporting
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          * Verify tablespace directories are empty. Don't bother with the
01378          * first once since it can be relocated, and it will be checked before
01379          * we do anything anyway.
01380          */
01381         if (format == 'p' && !PQgetisnull(res, i, 1))
01382             verify_dir_is_empty_or_create(PQgetvalue(res, i, 1));
01383     }
01384 
01385     /*
01386      * When writing to stdout, require a single tablespace
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      * If we're streaming WAL, start the streaming session before we start
01398      * receiving the actual data chunks.
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      * Start receiving chunks
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     }                           /* Loop over all tablespaces */
01418 
01419     if (showprogress)
01420     {
01421         progress_report(PQntuples(res), NULL);
01422         fprintf(stderr, "\n");  /* Need to move to next line */
01423     }
01424     PQclear(res);
01425 
01426     /*
01427      * Get the stop position
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         /* Just wait for the background process to exit */
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         /* Exited normally, we're happy! */
01508 #else                           /* WIN32 */
01509 
01510         /*
01511          * On Windows, since we are in the same process, we can just store the
01512          * value directly in the variable, and then set the flag that says
01513          * it's there.
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         /* First wait for the thread to exit */
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         /* Exited normally, we're happy */
01548 #endif
01549     }
01550 
01551     /* Free the recovery.conf contents */
01552     destroyPQExpBuffer(recoveryconfcontents);
01553 
01554     /*
01555      * End of copy data. Final result is already checked inside the loop.
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;      /* will be rejected below */
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                  * getopt_long already emitted a complaint
01741                  */
01742                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
01743                         progname);
01744                 exit(1);
01745         }
01746     }
01747 
01748     /*
01749      * Any non-option arguments?
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      * Required arguments
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      * Mutually exclusive arguments
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      * Verify that the target directory exists, or create it. For plaintext
01807      * backups, always require the directory. For tar backups, require it
01808      * unless we are writing to stdout.
01809      */
01810     if (format == 'p' || strcmp(basedir, "-") != 0)
01811         verify_dir_is_empty_or_create(basedir);
01812 
01813     BaseBackup();
01814 
01815     return 0;
01816 }