Header And Logo

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

basebackup.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * basebackup.c
00004  *    code for taking a base backup and streaming it to a standby
00005  *
00006  * Portions Copyright (c) 2010-2013, PostgreSQL Global Development Group
00007  *
00008  * IDENTIFICATION
00009  *    src/backend/replication/basebackup.c
00010  *
00011  *-------------------------------------------------------------------------
00012  */
00013 #include "postgres.h"
00014 
00015 #include <sys/types.h>
00016 #include <sys/stat.h>
00017 #include <unistd.h>
00018 #include <time.h>
00019 
00020 #include "access/xlog_internal.h"       /* for pg_start/stop_backup */
00021 #include "catalog/pg_type.h"
00022 #include "common/relpath.h"
00023 #include "lib/stringinfo.h"
00024 #include "libpq/libpq.h"
00025 #include "libpq/pqformat.h"
00026 #include "miscadmin.h"
00027 #include "nodes/pg_list.h"
00028 #include "replication/basebackup.h"
00029 #include "replication/walsender.h"
00030 #include "replication/walsender_private.h"
00031 #include "storage/fd.h"
00032 #include "storage/ipc.h"
00033 #include "utils/builtins.h"
00034 #include "utils/elog.h"
00035 #include "utils/ps_status.h"
00036 #include "pgtar.h"
00037 
00038 typedef struct
00039 {
00040     const char *label;
00041     bool        progress;
00042     bool        fastcheckpoint;
00043     bool        nowait;
00044     bool        includewal;
00045 } basebackup_options;
00046 
00047 
00048 static int64 sendDir(char *path, int basepathlen, bool sizeonly);
00049 static int64 sendTablespace(char *path, bool sizeonly);
00050 static bool sendFile(char *readfilename, char *tarfilename,
00051          struct stat * statbuf, bool missing_ok);
00052 static void sendFileWithContent(const char *filename, const char *content);
00053 static void _tarWriteHeader(const char *filename, const char *linktarget,
00054                 struct stat * statbuf);
00055 static void send_int8_string(StringInfoData *buf, int64 intval);
00056 static void SendBackupHeader(List *tablespaces);
00057 static void base_backup_cleanup(int code, Datum arg);
00058 static void perform_base_backup(basebackup_options *opt, DIR *tblspcdir);
00059 static void parse_basebackup_options(List *options, basebackup_options *opt);
00060 static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
00061 static int compareWalFileNames(const void *a, const void *b);
00062 
00063 /* Was the backup currently in-progress initiated in recovery mode? */
00064 static bool backup_started_in_recovery = false;
00065 
00066 /*
00067  * Size of each block sent into the tar stream for larger files.
00068  */
00069 #define TAR_SEND_SIZE 32768
00070 
00071 typedef struct
00072 {
00073     char       *oid;
00074     char       *path;
00075     int64       size;
00076 } tablespaceinfo;
00077 
00078 
00079 /*
00080  * Called when ERROR or FATAL happens in perform_base_backup() after
00081  * we have started the backup - make sure we end it!
00082  */
00083 static void
00084 base_backup_cleanup(int code, Datum arg)
00085 {
00086     do_pg_abort_backup();
00087 }
00088 
00089 /*
00090  * Actually do a base backup for the specified tablespaces.
00091  *
00092  * This is split out mainly to avoid complaints about "variable might be
00093  * clobbered by longjmp" from stupider versions of gcc.
00094  */
00095 static void
00096 perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
00097 {
00098     XLogRecPtr  startptr;
00099     TimeLineID  starttli;
00100     XLogRecPtr  endptr;
00101     TimeLineID  endtli;
00102     char       *labelfile;
00103 
00104     backup_started_in_recovery = RecoveryInProgress();
00105 
00106     startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
00107                                   &labelfile);
00108     SendXlogRecPtrResult(startptr, starttli);
00109 
00110     PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
00111     {
00112         List       *tablespaces = NIL;
00113         ListCell   *lc;
00114         struct dirent *de;
00115         tablespaceinfo *ti;
00116 
00117         /* Collect information about all tablespaces */
00118         while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
00119         {
00120             char        fullpath[MAXPGPATH];
00121             char        linkpath[MAXPGPATH];
00122             int         rllen;
00123 
00124             /* Skip special stuff */
00125             if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
00126                 continue;
00127 
00128             snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
00129 
00130 #if defined(HAVE_READLINK) || defined(WIN32)
00131             rllen = readlink(fullpath, linkpath, sizeof(linkpath));
00132             if (rllen < 0)
00133             {
00134                 ereport(WARNING,
00135                         (errmsg("could not read symbolic link \"%s\": %m",
00136                                 fullpath)));
00137                 continue;
00138             }
00139             else if (rllen >= sizeof(linkpath))
00140             {
00141                 ereport(WARNING,
00142                         (errmsg("symbolic link \"%s\" target is too long",
00143                                 fullpath)));
00144                 continue;
00145             }
00146             linkpath[rllen] = '\0';
00147 
00148             ti = palloc(sizeof(tablespaceinfo));
00149             ti->oid = pstrdup(de->d_name);
00150             ti->path = pstrdup(linkpath);
00151             ti->size = opt->progress ? sendTablespace(fullpath, true) : -1;
00152             tablespaces = lappend(tablespaces, ti);
00153 #else
00154 
00155             /*
00156              * If the platform does not have symbolic links, it should not be
00157              * possible to have tablespaces - clearly somebody else created
00158              * them. Warn about it and ignore.
00159              */
00160             ereport(WARNING,
00161                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00162                   errmsg("tablespaces are not supported on this platform")));
00163 #endif
00164         }
00165 
00166         /* Add a node for the base directory at the end */
00167         ti = palloc0(sizeof(tablespaceinfo));
00168         ti->size = opt->progress ? sendDir(".", 1, true) : -1;
00169         tablespaces = lappend(tablespaces, ti);
00170 
00171         /* Send tablespace header */
00172         SendBackupHeader(tablespaces);
00173 
00174         /* Send off our tablespaces one by one */
00175         foreach(lc, tablespaces)
00176         {
00177             tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
00178             StringInfoData buf;
00179 
00180             /* Send CopyOutResponse message */
00181             pq_beginmessage(&buf, 'H');
00182             pq_sendbyte(&buf, 0);       /* overall format */
00183             pq_sendint(&buf, 0, 2);     /* natts */
00184             pq_endmessage(&buf);
00185 
00186             if (ti->path == NULL)
00187             {
00188                 struct stat statbuf;
00189 
00190                 /* In the main tar, include the backup_label first... */
00191                 sendFileWithContent(BACKUP_LABEL_FILE, labelfile);
00192 
00193                 /* ... then the bulk of the files ... */
00194                 sendDir(".", 1, false);
00195 
00196                 /* ... and pg_control after everything else. */
00197                 if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
00198                     ereport(ERROR,
00199                             (errcode_for_file_access(),
00200                              errmsg("could not stat control file \"%s\": %m",
00201                                     XLOG_CONTROL_FILE)));
00202                 sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false);
00203             }
00204             else
00205                 sendTablespace(ti->path, false);
00206 
00207             /*
00208              * If we're including WAL, and this is the main data directory we
00209              * don't terminate the tar stream here. Instead, we will append
00210              * the xlog files below and terminate it then. This is safe since
00211              * the main data directory is always sent *last*.
00212              */
00213             if (opt->includewal && ti->path == NULL)
00214             {
00215                 Assert(lnext(lc) == NULL);
00216             }
00217             else
00218                 pq_putemptymessage('c');        /* CopyDone */
00219         }
00220     }
00221     PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
00222 
00223     endptr = do_pg_stop_backup(labelfile, !opt->nowait, &endtli);
00224 
00225     if (opt->includewal)
00226     {
00227         /*
00228          * We've left the last tar file "open", so we can now append the
00229          * required WAL files to it.
00230          */
00231         char        pathbuf[MAXPGPATH];
00232         XLogSegNo   segno;
00233         XLogSegNo   startsegno;
00234         XLogSegNo   endsegno;
00235         struct stat statbuf;
00236         List       *historyFileList = NIL;
00237         List       *walFileList = NIL;
00238         char      **walFiles;
00239         int         nWalFiles;
00240         char        firstoff[MAXFNAMELEN];
00241         char        lastoff[MAXFNAMELEN];
00242         DIR        *dir;
00243         struct dirent *de;
00244         int         i;
00245         ListCell   *lc;
00246         TimeLineID  tli;
00247 
00248         /*
00249          * I'd rather not worry about timelines here, so scan pg_xlog and
00250          * include all WAL files in the range between 'startptr' and 'endptr',
00251          * regardless of the timeline the file is stamped with. If there are
00252          * some spurious WAL files belonging to timelines that don't belong
00253          * in this server's history, they will be included too. Normally there
00254          * shouldn't be such files, but if there are, there's little harm in
00255          * including them.
00256          */
00257         XLByteToSeg(startptr, startsegno);
00258         XLogFileName(firstoff, ThisTimeLineID, startsegno);
00259         XLByteToPrevSeg(endptr, endsegno);
00260         XLogFileName(lastoff, ThisTimeLineID, endsegno);
00261 
00262         dir = AllocateDir("pg_xlog");
00263         if (!dir)
00264             ereport(ERROR,
00265                     (errmsg("could not open directory \"%s\": %m", "pg_xlog")));
00266         while ((de = ReadDir(dir, "pg_xlog")) != NULL)
00267         {
00268             /* Does it look like a WAL segment, and is it in the range? */
00269             if (strlen(de->d_name) == 24 &&
00270                 strspn(de->d_name, "0123456789ABCDEF") == 24 &&
00271                 strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
00272                 strcmp(de->d_name + 8, lastoff + 8) <= 0)
00273             {
00274                 walFileList = lappend(walFileList, pstrdup(de->d_name));
00275             }
00276             /* Does it look like a timeline history file? */
00277             else if (strlen(de->d_name) == 8 + strlen(".history") &&
00278                      strspn(de->d_name, "0123456789ABCDEF") == 8 &&
00279                      strcmp(de->d_name + 8, ".history") == 0)
00280             {
00281                 historyFileList = lappend(historyFileList, pstrdup(de->d_name));
00282             }
00283         }
00284         FreeDir(dir);
00285 
00286         /*
00287          * Before we go any further, check that none of the WAL segments we
00288          * need were removed.
00289          */
00290         CheckXLogRemoved(startsegno, ThisTimeLineID);
00291 
00292         /*
00293          * Put the WAL filenames into an array, and sort. We send the files
00294          * in order from oldest to newest, to reduce the chance that a file
00295          * is recycled before we get a chance to send it over.
00296          */
00297         nWalFiles = list_length(walFileList);
00298         walFiles = palloc(nWalFiles * sizeof(char *));
00299         i = 0;
00300         foreach(lc, walFileList)
00301         {
00302             walFiles[i++] = lfirst(lc);
00303         }
00304         qsort(walFiles, nWalFiles, sizeof(char *), compareWalFileNames);
00305 
00306         /*
00307          * Sanity check: the first and last segment should cover startptr and
00308          * endptr, with no gaps in between.
00309          */
00310         XLogFromFileName(walFiles[0], &tli, &segno);
00311         if (segno != startsegno)
00312         {
00313             char startfname[MAXFNAMELEN];
00314             XLogFileName(startfname, ThisTimeLineID, startsegno);
00315             ereport(ERROR,
00316                     (errmsg("could not find WAL file \"%s\"", startfname)));
00317         }
00318         for (i = 0; i < nWalFiles; i++)
00319         {
00320             XLogSegNo currsegno = segno;
00321             XLogSegNo nextsegno = segno + 1;
00322 
00323             XLogFromFileName(walFiles[i], &tli, &segno);
00324             if (!(nextsegno == segno || currsegno == segno))
00325             {
00326                 char nextfname[MAXFNAMELEN];
00327                 XLogFileName(nextfname, ThisTimeLineID, nextsegno);
00328                 ereport(ERROR,
00329                         (errmsg("could not find WAL file \"%s\"", nextfname)));
00330             }
00331         }
00332         if (segno != endsegno)
00333         {
00334             char endfname[MAXFNAMELEN];
00335             XLogFileName(endfname, ThisTimeLineID, endsegno);
00336             ereport(ERROR,
00337                     (errmsg("could not find WAL file \"%s\"", endfname)));
00338         }
00339 
00340         /* Ok, we have everything we need. Send the WAL files. */
00341         for (i = 0; i < nWalFiles; i++)
00342         {
00343             FILE       *fp;
00344             char        buf[TAR_SEND_SIZE];
00345             size_t      cnt;
00346             pgoff_t     len = 0;
00347 
00348             snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFiles[i]);
00349             XLogFromFileName(walFiles[i], &tli, &segno);
00350 
00351             fp = AllocateFile(pathbuf, "rb");
00352             if (fp == NULL)
00353             {
00354                 /*
00355                  * Most likely reason for this is that the file was already
00356                  * removed by a checkpoint, so check for that to get a better
00357                  * error message.
00358                  */
00359                 CheckXLogRemoved(segno, tli);
00360 
00361                 ereport(ERROR,
00362                         (errcode_for_file_access(),
00363                          errmsg("could not open file \"%s\": %m", pathbuf)));
00364             }
00365 
00366             if (fstat(fileno(fp), &statbuf) != 0)
00367                 ereport(ERROR,
00368                         (errcode_for_file_access(),
00369                          errmsg("could not stat file \"%s\": %m",
00370                                 pathbuf)));
00371             if (statbuf.st_size != XLogSegSize)
00372             {
00373                 CheckXLogRemoved(segno, tli);
00374                 ereport(ERROR,
00375                         (errcode_for_file_access(),
00376                          errmsg("unexpected WAL file size \"%s\"", walFiles[i])));
00377             }
00378 
00379             _tarWriteHeader(pathbuf, NULL, &statbuf);
00380 
00381             while ((cnt = fread(buf, 1, Min(sizeof(buf), XLogSegSize - len), fp)) > 0)
00382             {
00383                 CheckXLogRemoved(segno, tli);
00384                 /* Send the chunk as a CopyData message */
00385                 if (pq_putmessage('d', buf, cnt))
00386                     ereport(ERROR,
00387                             (errmsg("base backup could not send data, aborting backup")));
00388 
00389                 len += cnt;
00390                 if (len == XLogSegSize)
00391                     break;
00392             }
00393 
00394             if (len != XLogSegSize)
00395             {
00396                 CheckXLogRemoved(segno, tli);
00397                 ereport(ERROR,
00398                         (errcode_for_file_access(),
00399                          errmsg("unexpected WAL file size \"%s\"", walFiles[i])));
00400             }
00401 
00402             /* XLogSegSize is a multiple of 512, so no need for padding */
00403             FreeFile(fp);
00404         }
00405 
00406         /*
00407          * Send timeline history files too. Only the latest timeline history
00408          * file is required for recovery, and even that only if there happens
00409          * to be a timeline switch in the first WAL segment that contains the
00410          * checkpoint record, or if we're taking a base backup from a standby
00411          * server and the target timeline changes while the backup is taken. 
00412          * But they are small and highly useful for debugging purposes, so
00413          * better include them all, always.
00414          */
00415         foreach(lc, historyFileList)
00416         {
00417             char *fname = lfirst(lc);
00418             snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
00419 
00420             if (lstat(pathbuf, &statbuf) != 0)
00421                 ereport(ERROR,
00422                         (errcode_for_file_access(),
00423                          errmsg("could not stat file \"%s\": %m", pathbuf)));
00424 
00425             sendFile(pathbuf, pathbuf, &statbuf, false);
00426         }
00427 
00428         /* Send CopyDone message for the last tar file */
00429         pq_putemptymessage('c');
00430     }
00431     SendXlogRecPtrResult(endptr, endtli);
00432 }
00433 
00434 /*
00435  * qsort comparison function, to compare log/seg portion of WAL segment
00436  * filenames, ignoring the timeline portion.
00437  */
00438 static int
00439 compareWalFileNames(const void *a, const void *b)
00440 {
00441     char *fna = *((char **) a);
00442     char *fnb = *((char **) b);
00443 
00444     return strcmp(fna + 8, fnb + 8);
00445 }
00446 
00447 /*
00448  * Parse the base backup options passed down by the parser
00449  */
00450 static void
00451 parse_basebackup_options(List *options, basebackup_options *opt)
00452 {
00453     ListCell   *lopt;
00454     bool        o_label = false;
00455     bool        o_progress = false;
00456     bool        o_fast = false;
00457     bool        o_nowait = false;
00458     bool        o_wal = false;
00459 
00460     MemSet(opt, 0, sizeof(*opt));
00461     foreach(lopt, options)
00462     {
00463         DefElem    *defel = (DefElem *) lfirst(lopt);
00464 
00465         if (strcmp(defel->defname, "label") == 0)
00466         {
00467             if (o_label)
00468                 ereport(ERROR,
00469                         (errcode(ERRCODE_SYNTAX_ERROR),
00470                          errmsg("duplicate option \"%s\"", defel->defname)));
00471             opt->label = strVal(defel->arg);
00472             o_label = true;
00473         }
00474         else if (strcmp(defel->defname, "progress") == 0)
00475         {
00476             if (o_progress)
00477                 ereport(ERROR,
00478                         (errcode(ERRCODE_SYNTAX_ERROR),
00479                          errmsg("duplicate option \"%s\"", defel->defname)));
00480             opt->progress = true;
00481             o_progress = true;
00482         }
00483         else if (strcmp(defel->defname, "fast") == 0)
00484         {
00485             if (o_fast)
00486                 ereport(ERROR,
00487                         (errcode(ERRCODE_SYNTAX_ERROR),
00488                          errmsg("duplicate option \"%s\"", defel->defname)));
00489             opt->fastcheckpoint = true;
00490             o_fast = true;
00491         }
00492         else if (strcmp(defel->defname, "nowait") == 0)
00493         {
00494             if (o_nowait)
00495                 ereport(ERROR,
00496                         (errcode(ERRCODE_SYNTAX_ERROR),
00497                          errmsg("duplicate option \"%s\"", defel->defname)));
00498             opt->nowait = true;
00499             o_nowait = true;
00500         }
00501         else if (strcmp(defel->defname, "wal") == 0)
00502         {
00503             if (o_wal)
00504                 ereport(ERROR,
00505                         (errcode(ERRCODE_SYNTAX_ERROR),
00506                          errmsg("duplicate option \"%s\"", defel->defname)));
00507             opt->includewal = true;
00508             o_wal = true;
00509         }
00510         else
00511             elog(ERROR, "option \"%s\" not recognized",
00512                  defel->defname);
00513     }
00514     if (opt->label == NULL)
00515         opt->label = "base backup";
00516 }
00517 
00518 
00519 /*
00520  * SendBaseBackup() - send a complete base backup.
00521  *
00522  * The function will put the system into backup mode like pg_start_backup()
00523  * does, so that the backup is consistent even though we read directly from
00524  * the filesystem, bypassing the buffer cache.
00525  */
00526 void
00527 SendBaseBackup(BaseBackupCmd *cmd)
00528 {
00529     DIR        *dir;
00530     basebackup_options opt;
00531 
00532     parse_basebackup_options(cmd->options, &opt);
00533 
00534     WalSndSetState(WALSNDSTATE_BACKUP);
00535 
00536     if (update_process_title)
00537     {
00538         char        activitymsg[50];
00539 
00540         snprintf(activitymsg, sizeof(activitymsg), "sending backup \"%s\"",
00541                  opt.label);
00542         set_ps_display(activitymsg, false);
00543     }
00544 
00545     /* Make sure we can open the directory with tablespaces in it */
00546     dir = AllocateDir("pg_tblspc");
00547     if (!dir)
00548         ereport(ERROR,
00549                 (errmsg("could not open directory \"%s\": %m", "pg_tblspc")));
00550 
00551     perform_base_backup(&opt, dir);
00552 
00553     FreeDir(dir);
00554 }
00555 
00556 static void
00557 send_int8_string(StringInfoData *buf, int64 intval)
00558 {
00559     char        is[32];
00560 
00561     sprintf(is, INT64_FORMAT, intval);
00562     pq_sendint(buf, strlen(is), 4);
00563     pq_sendbytes(buf, is, strlen(is));
00564 }
00565 
00566 static void
00567 SendBackupHeader(List *tablespaces)
00568 {
00569     StringInfoData buf;
00570     ListCell   *lc;
00571 
00572     /* Construct and send the directory information */
00573     pq_beginmessage(&buf, 'T'); /* RowDescription */
00574     pq_sendint(&buf, 3, 2);     /* 3 fields */
00575 
00576     /* First field - spcoid */
00577     pq_sendstring(&buf, "spcoid");
00578     pq_sendint(&buf, 0, 4);     /* table oid */
00579     pq_sendint(&buf, 0, 2);     /* attnum */
00580     pq_sendint(&buf, OIDOID, 4);    /* type oid */
00581     pq_sendint(&buf, 4, 2);     /* typlen */
00582     pq_sendint(&buf, 0, 4);     /* typmod */
00583     pq_sendint(&buf, 0, 2);     /* format code */
00584 
00585     /* Second field - spcpath */
00586     pq_sendstring(&buf, "spclocation");
00587     pq_sendint(&buf, 0, 4);
00588     pq_sendint(&buf, 0, 2);
00589     pq_sendint(&buf, TEXTOID, 4);
00590     pq_sendint(&buf, -1, 2);
00591     pq_sendint(&buf, 0, 4);
00592     pq_sendint(&buf, 0, 2);
00593 
00594     /* Third field - size */
00595     pq_sendstring(&buf, "size");
00596     pq_sendint(&buf, 0, 4);
00597     pq_sendint(&buf, 0, 2);
00598     pq_sendint(&buf, INT8OID, 4);
00599     pq_sendint(&buf, 8, 2);
00600     pq_sendint(&buf, 0, 4);
00601     pq_sendint(&buf, 0, 2);
00602     pq_endmessage(&buf);
00603 
00604     foreach(lc, tablespaces)
00605     {
00606         tablespaceinfo *ti = lfirst(lc);
00607 
00608         /* Send one datarow message */
00609         pq_beginmessage(&buf, 'D');
00610         pq_sendint(&buf, 3, 2); /* number of columns */
00611         if (ti->path == NULL)
00612         {
00613             pq_sendint(&buf, -1, 4);    /* Length = -1 ==> NULL */
00614             pq_sendint(&buf, -1, 4);
00615         }
00616         else
00617         {
00618             pq_sendint(&buf, strlen(ti->oid), 4);       /* length */
00619             pq_sendbytes(&buf, ti->oid, strlen(ti->oid));
00620             pq_sendint(&buf, strlen(ti->path), 4);      /* length */
00621             pq_sendbytes(&buf, ti->path, strlen(ti->path));
00622         }
00623         if (ti->size >= 0)
00624             send_int8_string(&buf, ti->size / 1024);
00625         else
00626             pq_sendint(&buf, -1, 4);    /* NULL */
00627 
00628         pq_endmessage(&buf);
00629     }
00630 
00631     /* Send a CommandComplete message */
00632     pq_puttextmessage('C', "SELECT");
00633 }
00634 
00635 /*
00636  * Send a single resultset containing just a single
00637  * XlogRecPtr record (in text format)
00638  */
00639 static void
00640 SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
00641 {
00642     StringInfoData buf;
00643     char        str[MAXFNAMELEN];
00644 
00645     pq_beginmessage(&buf, 'T'); /* RowDescription */
00646     pq_sendint(&buf, 2, 2);     /* 2 fields */
00647 
00648     /* Field headers */
00649     pq_sendstring(&buf, "recptr");
00650     pq_sendint(&buf, 0, 4);     /* table oid */
00651     pq_sendint(&buf, 0, 2);     /* attnum */
00652     pq_sendint(&buf, TEXTOID, 4);       /* type oid */
00653     pq_sendint(&buf, -1, 2);
00654     pq_sendint(&buf, 0, 4);
00655     pq_sendint(&buf, 0, 2);
00656 
00657     pq_sendstring(&buf, "tli");
00658     pq_sendint(&buf, 0, 4);     /* table oid */
00659     pq_sendint(&buf, 0, 2);     /* attnum */
00660     /*
00661      * int8 may seem like a surprising data type for this, but in thory int4
00662      * would not be wide enough for this, as TimeLineID is unsigned.
00663      */
00664     pq_sendint(&buf, INT8OID, 4);   /* type oid */
00665     pq_sendint(&buf, -1, 2);
00666     pq_sendint(&buf, 0, 4);
00667     pq_sendint(&buf, 0, 2);
00668     pq_endmessage(&buf);
00669 
00670     /* Data row */
00671     pq_beginmessage(&buf, 'D');
00672     pq_sendint(&buf, 2, 2);     /* number of columns */
00673 
00674     snprintf(str, sizeof(str), "%X/%X", (uint32) (ptr >> 32), (uint32) ptr);
00675     pq_sendint(&buf, strlen(str), 4);   /* length */
00676     pq_sendbytes(&buf, str, strlen(str));
00677 
00678     snprintf(str, sizeof(str), "%u", tli);
00679     pq_sendint(&buf, strlen(str), 4);   /* length */
00680     pq_sendbytes(&buf, str, strlen(str));
00681     pq_endmessage(&buf);
00682 
00683     /* Send a CommandComplete message */
00684     pq_puttextmessage('C', "SELECT");
00685 }
00686 
00687 /*
00688  * Inject a file with given name and content in the output tar stream.
00689  */
00690 static void
00691 sendFileWithContent(const char *filename, const char *content)
00692 {
00693     struct stat statbuf;
00694     int         pad,
00695                 len;
00696 
00697     len = strlen(content);
00698 
00699     /*
00700      * Construct a stat struct for the backup_label file we're injecting in
00701      * the tar.
00702      */
00703     /* Windows doesn't have the concept of uid and gid */
00704 #ifdef WIN32
00705     statbuf.st_uid = 0;
00706     statbuf.st_gid = 0;
00707 #else
00708     statbuf.st_uid = geteuid();
00709     statbuf.st_gid = getegid();
00710 #endif
00711     statbuf.st_mtime = time(NULL);
00712     statbuf.st_mode = S_IRUSR | S_IWUSR;
00713     statbuf.st_size = len;
00714 
00715     _tarWriteHeader(filename, NULL, &statbuf);
00716     /* Send the contents as a CopyData message */
00717     pq_putmessage('d', content, len);
00718 
00719     /* Pad to 512 byte boundary, per tar format requirements */
00720     pad = ((len + 511) & ~511) - len;
00721     if (pad > 0)
00722     {
00723         char        buf[512];
00724 
00725         MemSet(buf, 0, pad);
00726         pq_putmessage('d', buf, pad);
00727     }
00728 }
00729 
00730 /*
00731  * Include the tablespace directory pointed to by 'path' in the output tar
00732  * stream.  If 'sizeonly' is true, we just calculate a total length and return
00733  * it, without actually sending anything.
00734  */
00735 static int64
00736 sendTablespace(char *path, bool sizeonly)
00737 {
00738     int64       size;
00739     char        pathbuf[MAXPGPATH];
00740     struct stat statbuf;
00741 
00742     /*
00743      * 'path' points to the tablespace location, but we only want to include
00744      * the version directory in it that belongs to us.
00745      */
00746     snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path,
00747              TABLESPACE_VERSION_DIRECTORY);
00748 
00749     /*
00750      * Store a directory entry in the tar file so we get the permissions right.
00751      */
00752     if (lstat(pathbuf, &statbuf) != 0)
00753     {
00754         if (errno != ENOENT)
00755             ereport(ERROR,
00756                     (errcode_for_file_access(),
00757                      errmsg("could not stat file or directory \"%s\": %m",
00758                             pathbuf)));
00759 
00760         /* If the tablespace went away while scanning, it's no error. */
00761         return 0;
00762     }
00763     if (!sizeonly)
00764         _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf);
00765     size = 512;     /* Size of the header just added */
00766 
00767     /* Send all the files in the tablespace version directory */
00768     size += sendDir(pathbuf, strlen(path), sizeonly);
00769 
00770     return size;
00771 }
00772 
00773 /*
00774  * Include all files from the given directory in the output tar stream. If
00775  * 'sizeonly' is true, we just calculate a total length and return it, without
00776  * actually sending anything.
00777  */
00778 static int64
00779 sendDir(char *path, int basepathlen, bool sizeonly)
00780 {
00781     DIR        *dir;
00782     struct dirent *de;
00783     char        pathbuf[MAXPGPATH];
00784     struct stat statbuf;
00785     int64       size = 0;
00786 
00787     dir = AllocateDir(path);
00788     while ((de = ReadDir(dir, path)) != NULL)
00789     {
00790         /* Skip special stuff */
00791         if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
00792             continue;
00793 
00794         /* Skip temporary files */
00795         if (strncmp(de->d_name,
00796                     PG_TEMP_FILE_PREFIX,
00797                     strlen(PG_TEMP_FILE_PREFIX)) == 0)
00798             continue;
00799 
00800         /*
00801          * If there's a backup_label file, it belongs to a backup started by
00802          * the user with pg_start_backup(). It is *not* correct for this
00803          * backup, our backup_label is injected into the tar separately.
00804          */
00805         if (strcmp(de->d_name, BACKUP_LABEL_FILE) == 0)
00806             continue;
00807 
00808         /*
00809          * Check if the postmaster has signaled us to exit, and abort with an
00810          * error in that case. The error handler further up will call
00811          * do_pg_abort_backup() for us. Also check that if the backup was
00812          * started while still in recovery, the server wasn't promoted.
00813          * dp_pg_stop_backup() will check that too, but it's better to stop
00814          * the backup early than continue to the end and fail there.
00815          */
00816         CHECK_FOR_INTERRUPTS();
00817         if (RecoveryInProgress() != backup_started_in_recovery)
00818             ereport(ERROR,
00819                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00820                      errmsg("the standby was promoted during online backup"),
00821                      errhint("This means that the backup being taken is corrupt "
00822                              "and should not be used. "
00823                              "Try taking another online backup.")));
00824 
00825         snprintf(pathbuf, MAXPGPATH, "%s/%s", path, de->d_name);
00826 
00827         /* Skip postmaster.pid and postmaster.opts in the data directory */
00828         if (strcmp(pathbuf, "./postmaster.pid") == 0 ||
00829             strcmp(pathbuf, "./postmaster.opts") == 0)
00830             continue;
00831 
00832         /* Skip pg_control here to back up it last */
00833         if (strcmp(pathbuf, "./global/pg_control") == 0)
00834             continue;
00835 
00836         if (lstat(pathbuf, &statbuf) != 0)
00837         {
00838             if (errno != ENOENT)
00839                 ereport(ERROR,
00840                         (errcode_for_file_access(),
00841                          errmsg("could not stat file or directory \"%s\": %m",
00842                                 pathbuf)));
00843 
00844             /* If the file went away while scanning, it's no error. */
00845             continue;
00846         }
00847 
00848         /*
00849          * We can skip pg_xlog, the WAL segments need to be fetched from the
00850          * WAL archive anyway. But include it as an empty directory anyway, so
00851          * we get permissions right.
00852          */
00853         if (strcmp(pathbuf, "./pg_xlog") == 0)
00854         {
00855             if (!sizeonly)
00856             {
00857                 /* If pg_xlog is a symlink, write it as a directory anyway */
00858 #ifndef WIN32
00859                 if (S_ISLNK(statbuf.st_mode))
00860 #else
00861                 if (pgwin32_is_junction(pathbuf))
00862 #endif
00863                     statbuf.st_mode = S_IFDIR | S_IRWXU;
00864                 _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf);
00865             }
00866             size += 512;        /* Size of the header just added */
00867             continue;           /* don't recurse into pg_xlog */
00868         }
00869 
00870         /* Allow symbolic links in pg_tblspc only */
00871         if (strcmp(path, "./pg_tblspc") == 0 &&
00872 #ifndef WIN32
00873             S_ISLNK(statbuf.st_mode)
00874 #else
00875             pgwin32_is_junction(pathbuf)
00876 #endif
00877             )
00878         {
00879 #if defined(HAVE_READLINK) || defined(WIN32)
00880             char        linkpath[MAXPGPATH];
00881             int         rllen;
00882 
00883             rllen = readlink(pathbuf, linkpath, sizeof(linkpath));
00884             if (rllen < 0)
00885                 ereport(ERROR,
00886                         (errcode_for_file_access(),
00887                          errmsg("could not read symbolic link \"%s\": %m",
00888                                 pathbuf)));
00889             if (rllen >= sizeof(linkpath))
00890                 ereport(ERROR,
00891                         (errmsg("symbolic link \"%s\" target is too long",
00892                                 pathbuf)));
00893             linkpath[rllen] = '\0';
00894 
00895             if (!sizeonly)
00896                 _tarWriteHeader(pathbuf + basepathlen + 1, linkpath, &statbuf);
00897             size += 512;        /* Size of the header just added */
00898 #else
00899 
00900             /*
00901              * If the platform does not have symbolic links, it should not be
00902              * possible to have tablespaces - clearly somebody else created
00903              * them. Warn about it and ignore.
00904              */
00905             ereport(WARNING,
00906                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00907                   errmsg("tablespaces are not supported on this platform")));
00908             continue;
00909 #endif   /* HAVE_READLINK */
00910         }
00911         else if (S_ISDIR(statbuf.st_mode))
00912         {
00913             /*
00914              * Store a directory entry in the tar file so we can get the
00915              * permissions right.
00916              */
00917             if (!sizeonly)
00918                 _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf);
00919             size += 512;        /* Size of the header just added */
00920 
00921             /* call ourselves recursively for a directory */
00922             size += sendDir(pathbuf, basepathlen, sizeonly);
00923         }
00924         else if (S_ISREG(statbuf.st_mode))
00925         {
00926             bool sent = false;
00927 
00928             if (!sizeonly)
00929                 sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
00930                                 true);
00931 
00932             if (sent || sizeonly)
00933             {
00934                 /* Add size, rounded up to 512byte block */
00935                 size += ((statbuf.st_size + 511) & ~511);
00936                 size += 512;        /* Size of the header of the file */
00937             }
00938         }
00939         else
00940             ereport(WARNING,
00941                     (errmsg("skipping special file \"%s\"", pathbuf)));
00942     }
00943     FreeDir(dir);
00944     return size;
00945 }
00946 
00947 /*****
00948  * Functions for handling tar file format
00949  *
00950  * Copied from pg_dump, but modified to work with libpq for sending
00951  */
00952 
00953 
00954 /*
00955  * Maximum file size for a tar member: The limit inherent in the
00956  * format is 2^33-1 bytes (nearly 8 GB).  But we don't want to exceed
00957  * what we can represent in pgoff_t.
00958  */
00959 #define MAX_TAR_MEMBER_FILELEN (((int64) 1 << Min(33, sizeof(pgoff_t)*8 - 1)) - 1)
00960 
00961 /*
00962  * Given the member, write the TAR header & send the file.
00963  *
00964  * If 'missing_ok' is true, will not throw an error if the file is not found.
00965  *
00966  * Returns true if the file was successfully sent, false if 'missing_ok',
00967  * and the file did not exist.
00968  */
00969 static bool
00970 sendFile(char *readfilename, char *tarfilename, struct stat *statbuf,
00971          bool missing_ok)
00972 {
00973     FILE       *fp;
00974     char        buf[TAR_SEND_SIZE];
00975     size_t      cnt;
00976     pgoff_t     len = 0;
00977     size_t      pad;
00978 
00979     fp = AllocateFile(readfilename, "rb");
00980     if (fp == NULL)
00981     {
00982         if (errno == ENOENT && missing_ok)
00983             return false;
00984         ereport(ERROR,
00985                 (errcode_for_file_access(),
00986                  errmsg("could not open file \"%s\": %m", readfilename)));
00987     }
00988 
00989     /*
00990      * Some compilers will throw a warning knowing this test can never be true
00991      * because pgoff_t can't exceed the compared maximum on their platform.
00992      */
00993     if (statbuf->st_size > MAX_TAR_MEMBER_FILELEN)
00994         ereport(ERROR,
00995                 (errmsg("archive member \"%s\" too large for tar format",
00996                         tarfilename)));
00997 
00998     _tarWriteHeader(tarfilename, NULL, statbuf);
00999 
01000     while ((cnt = fread(buf, 1, Min(sizeof(buf), statbuf->st_size - len), fp)) > 0)
01001     {
01002         /* Send the chunk as a CopyData message */
01003         if (pq_putmessage('d', buf, cnt))
01004             ereport(ERROR,
01005                (errmsg("base backup could not send data, aborting backup")));
01006 
01007         len += cnt;
01008 
01009         if (len >= statbuf->st_size)
01010         {
01011             /*
01012              * Reached end of file. The file could be longer, if it was
01013              * extended while we were sending it, but for a base backup we can
01014              * ignore such extended data. It will be restored from WAL.
01015              */
01016             break;
01017         }
01018     }
01019 
01020     /* If the file was truncated while we were sending it, pad it with zeros */
01021     if (len < statbuf->st_size)
01022     {
01023         MemSet(buf, 0, sizeof(buf));
01024         while (len < statbuf->st_size)
01025         {
01026             cnt = Min(sizeof(buf), statbuf->st_size - len);
01027             pq_putmessage('d', buf, cnt);
01028             len += cnt;
01029         }
01030     }
01031 
01032     /* Pad to 512 byte boundary, per tar format requirements */
01033     pad = ((len + 511) & ~511) - len;
01034     if (pad > 0)
01035     {
01036         MemSet(buf, 0, pad);
01037         pq_putmessage('d', buf, pad);
01038     }
01039 
01040     FreeFile(fp);
01041 
01042     return true;
01043 }
01044 
01045 
01046 static void
01047 _tarWriteHeader(const char *filename, const char *linktarget,
01048                 struct stat * statbuf)
01049 {
01050     char        h[512];
01051 
01052     tarCreateHeader(h, filename, linktarget, statbuf->st_size,
01053                     statbuf->st_mode, statbuf->st_uid, statbuf->st_gid,
01054                     statbuf->st_mtime);
01055 
01056     pq_putmessage('d', h, 512);
01057 }