00001
00002
00003
00004
00005
00006
00007
00008
00009
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"
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
00064 static bool backup_started_in_recovery = false;
00065
00066
00067
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
00081
00082
00083 static void
00084 base_backup_cleanup(int code, Datum arg)
00085 {
00086 do_pg_abort_backup();
00087 }
00088
00089
00090
00091
00092
00093
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
00118 while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
00119 {
00120 char fullpath[MAXPGPATH];
00121 char linkpath[MAXPGPATH];
00122 int rllen;
00123
00124
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
00157
00158
00159
00160 ereport(WARNING,
00161 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00162 errmsg("tablespaces are not supported on this platform")));
00163 #endif
00164 }
00165
00166
00167 ti = palloc0(sizeof(tablespaceinfo));
00168 ti->size = opt->progress ? sendDir(".", 1, true) : -1;
00169 tablespaces = lappend(tablespaces, ti);
00170
00171
00172 SendBackupHeader(tablespaces);
00173
00174
00175 foreach(lc, tablespaces)
00176 {
00177 tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
00178 StringInfoData buf;
00179
00180
00181 pq_beginmessage(&buf, 'H');
00182 pq_sendbyte(&buf, 0);
00183 pq_sendint(&buf, 0, 2);
00184 pq_endmessage(&buf);
00185
00186 if (ti->path == NULL)
00187 {
00188 struct stat statbuf;
00189
00190
00191 sendFileWithContent(BACKUP_LABEL_FILE, labelfile);
00192
00193
00194 sendDir(".", 1, false);
00195
00196
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
00209
00210
00211
00212
00213 if (opt->includewal && ti->path == NULL)
00214 {
00215 Assert(lnext(lc) == NULL);
00216 }
00217 else
00218 pq_putemptymessage('c');
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
00229
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
00250
00251
00252
00253
00254
00255
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
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
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
00288
00289
00290 CheckXLogRemoved(startsegno, ThisTimeLineID);
00291
00292
00293
00294
00295
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
00308
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
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
00356
00357
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
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
00403 FreeFile(fp);
00404 }
00405
00406
00407
00408
00409
00410
00411
00412
00413
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
00429 pq_putemptymessage('c');
00430 }
00431 SendXlogRecPtrResult(endptr, endtli);
00432 }
00433
00434
00435
00436
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
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
00521
00522
00523
00524
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
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
00573 pq_beginmessage(&buf, 'T');
00574 pq_sendint(&buf, 3, 2);
00575
00576
00577 pq_sendstring(&buf, "spcoid");
00578 pq_sendint(&buf, 0, 4);
00579 pq_sendint(&buf, 0, 2);
00580 pq_sendint(&buf, OIDOID, 4);
00581 pq_sendint(&buf, 4, 2);
00582 pq_sendint(&buf, 0, 4);
00583 pq_sendint(&buf, 0, 2);
00584
00585
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
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
00609 pq_beginmessage(&buf, 'D');
00610 pq_sendint(&buf, 3, 2);
00611 if (ti->path == NULL)
00612 {
00613 pq_sendint(&buf, -1, 4);
00614 pq_sendint(&buf, -1, 4);
00615 }
00616 else
00617 {
00618 pq_sendint(&buf, strlen(ti->oid), 4);
00619 pq_sendbytes(&buf, ti->oid, strlen(ti->oid));
00620 pq_sendint(&buf, strlen(ti->path), 4);
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);
00627
00628 pq_endmessage(&buf);
00629 }
00630
00631
00632 pq_puttextmessage('C', "SELECT");
00633 }
00634
00635
00636
00637
00638
00639 static void
00640 SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
00641 {
00642 StringInfoData buf;
00643 char str[MAXFNAMELEN];
00644
00645 pq_beginmessage(&buf, 'T');
00646 pq_sendint(&buf, 2, 2);
00647
00648
00649 pq_sendstring(&buf, "recptr");
00650 pq_sendint(&buf, 0, 4);
00651 pq_sendint(&buf, 0, 2);
00652 pq_sendint(&buf, TEXTOID, 4);
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);
00659 pq_sendint(&buf, 0, 2);
00660
00661
00662
00663
00664 pq_sendint(&buf, INT8OID, 4);
00665 pq_sendint(&buf, -1, 2);
00666 pq_sendint(&buf, 0, 4);
00667 pq_sendint(&buf, 0, 2);
00668 pq_endmessage(&buf);
00669
00670
00671 pq_beginmessage(&buf, 'D');
00672 pq_sendint(&buf, 2, 2);
00673
00674 snprintf(str, sizeof(str), "%X/%X", (uint32) (ptr >> 32), (uint32) ptr);
00675 pq_sendint(&buf, strlen(str), 4);
00676 pq_sendbytes(&buf, str, strlen(str));
00677
00678 snprintf(str, sizeof(str), "%u", tli);
00679 pq_sendint(&buf, strlen(str), 4);
00680 pq_sendbytes(&buf, str, strlen(str));
00681 pq_endmessage(&buf);
00682
00683
00684 pq_puttextmessage('C', "SELECT");
00685 }
00686
00687
00688
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
00701
00702
00703
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
00717 pq_putmessage('d', content, len);
00718
00719
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
00732
00733
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
00744
00745
00746 snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path,
00747 TABLESPACE_VERSION_DIRECTORY);
00748
00749
00750
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
00761 return 0;
00762 }
00763 if (!sizeonly)
00764 _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf);
00765 size = 512;
00766
00767
00768 size += sendDir(pathbuf, strlen(path), sizeonly);
00769
00770 return size;
00771 }
00772
00773
00774
00775
00776
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
00791 if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
00792 continue;
00793
00794
00795 if (strncmp(de->d_name,
00796 PG_TEMP_FILE_PREFIX,
00797 strlen(PG_TEMP_FILE_PREFIX)) == 0)
00798 continue;
00799
00800
00801
00802
00803
00804
00805 if (strcmp(de->d_name, BACKUP_LABEL_FILE) == 0)
00806 continue;
00807
00808
00809
00810
00811
00812
00813
00814
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
00828 if (strcmp(pathbuf, "./postmaster.pid") == 0 ||
00829 strcmp(pathbuf, "./postmaster.opts") == 0)
00830 continue;
00831
00832
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
00845 continue;
00846 }
00847
00848
00849
00850
00851
00852
00853 if (strcmp(pathbuf, "./pg_xlog") == 0)
00854 {
00855 if (!sizeonly)
00856 {
00857
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;
00867 continue;
00868 }
00869
00870
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;
00898 #else
00899
00900
00901
00902
00903
00904
00905 ereport(WARNING,
00906 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00907 errmsg("tablespaces are not supported on this platform")));
00908 continue;
00909 #endif
00910 }
00911 else if (S_ISDIR(statbuf.st_mode))
00912 {
00913
00914
00915
00916
00917 if (!sizeonly)
00918 _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf);
00919 size += 512;
00920
00921
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
00935 size += ((statbuf.st_size + 511) & ~511);
00936 size += 512;
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
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959 #define MAX_TAR_MEMBER_FILELEN (((int64) 1 << Min(33, sizeof(pgoff_t)*8 - 1)) - 1)
00960
00961
00962
00963
00964
00965
00966
00967
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
00991
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
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
01013
01014
01015
01016 break;
01017 }
01018 }
01019
01020
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
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 }