diff --git a/src/bin/pg_resetwal/Makefile b/src/bin/pg_resetwal/Makefile index 2a38356..d3326b4 100644 --- a/src/bin/pg_resetwal/Makefile +++ b/src/bin/pg_resetwal/Makefile @@ -15,13 +15,21 @@ subdir = src/bin/pg_resetwal top_builddir = ../../.. include $(top_builddir)/src/Makefile.global -OBJS= pg_resetwal.o $(WIN32RES) +OBJS= pg_resetwal.o compat.o $(ENCRYPTIONOBJS) $(WIN32RES) + +override CPPFLAGS := -DFRONTEND $(CPPFLAGS) + +ENCRYPTIONSOURCES = $(sort $(notdir $(wildcard $(top_srcdir)/src/backend/storage/encryption/*.c))) +ENCRYPTIONOBJS = $(patsubst %.c,%.o,$(ENCRYPTIONSOURCES)) all: pg_resetwal pg_resetwal: $(OBJS) | submake-libpgport $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) +$(ENCRYPTIONSOURCES): % : $(top_srcdir)/src/backend/storage/encryption/% + rm -f $@ && $(LN_S) $< . + install: all installdirs $(INSTALL_PROGRAM) pg_resetwal$(X) '$(DESTDIR)$(bindir)/pg_resetwal$(X)' @@ -32,7 +40,7 @@ uninstall: rm -f '$(DESTDIR)$(bindir)/pg_resetwal$(X)' clean distclean maintainer-clean: - rm -f pg_resetwal$(X) $(OBJS) + rm -f pg_resetwal$(X) $(OBJS) $(ENCRYPTIONSOURCES) rm -rf tmp_check check: diff --git a/src/bin/pg_resetwal/compat.c b/src/bin/pg_resetwal/compat.c new file mode 100644 index 0000000..1555176 --- /dev/null +++ b/src/bin/pg_resetwal/compat.c @@ -0,0 +1,125 @@ +/*------------------------------------------------------------------------- + * + * compat.c + * Reimplementations of various backend functions. + * + * Portions Copyright (c) 2013-2019, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/bin/pg_waldump/compat.c + * + * This file contains client-side implementations for various backend + * functions that the rm_desc functions in *desc.c files rely on. + * + *------------------------------------------------------------------------- + */ + +/* ugly hack, same as in e.g pg_controldata */ +#define FRONTEND 1 +#include "postgres.h" + +#include + +#include "lib/stringinfo.h" +#include "utils/datetime.h" +#include "common/logging.h" + +/* copied from timestamp.c */ +pg_time_t +timestamptz_to_time_t(TimestampTz t) +{ + pg_time_t result; + + result = (pg_time_t) (t / USECS_PER_SEC + + ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY)); + return result; +} + +/* + * Stopgap implementation of timestamptz_to_str that doesn't depend on backend + * infrastructure. This will work for timestamps that are within the range + * of the platform time_t type. (pg_time_t is compatible except for possibly + * being wider.) + * + * XXX the return value points to a static buffer, so beware of using more + * than one result value concurrently. + * + * XXX: The backend timestamp infrastructure should instead be split out and + * moved into src/common. That's a large project though. + */ +const char * +timestamptz_to_str(TimestampTz dt) +{ + static char buf[MAXDATELEN + 1]; + char ts[MAXDATELEN + 1]; + char zone[MAXDATELEN + 1]; + time_t result = (time_t) timestamptz_to_time_t(dt); + struct tm *ltime = localtime(&result); + + strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", ltime); + strftime(zone, sizeof(zone), "%Z", ltime); + + snprintf(buf, sizeof(buf), "%s.%06d %s", + ts, (int) (dt % USECS_PER_SEC), zone); + + return buf; +} + +/* + * Provide a hacked up compat layer for StringInfos so xlog desc functions can + * be linked/called. + */ +void +initStringInfo(StringInfo str) +{ + int size = 1024; /* initial default buffer size */ + + str->data = (char *) palloc(size); + str->maxlen = size; + str->data[0] = '\0'; + str->len = 0; + str->cursor = 0; +} + +void +appendStringInfo(StringInfo str, const char *fmt,...) +{ + va_list args; + + va_start(args, fmt); + if (str) + { + int avail; + size_t nprinted; + + avail = str->maxlen - str->len; + nprinted = pvsnprintf(str->data + str->len, (size_t) avail, fmt, args); + + if (nprinted < (size_t) avail) + { + /* Success. Note nprinted does not include trailing null. */ + str->len += (int) nprinted; + } + else + { + pg_log_error("the string is too long"); + exit(1); + } + + } + else + vprintf(fmt, args); + va_end(args); +} + +void +appendStringInfoString(StringInfo str, const char *string) +{ + appendStringInfo(str, "%s", string); +} + +void +appendStringInfoChar(StringInfo str, char ch) +{ + appendStringInfo(str, "%c", ch); +} diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c index c4ee016..c6273e6 100644 --- a/src/bin/pg_resetwal/pg_resetwal.c +++ b/src/bin/pg_resetwal/pg_resetwal.c @@ -58,6 +58,8 @@ #include "getopt_long.h" #include "pg_getopt.h" #include "storage/large_object.h" +#include "catalog/pg_control.h" +#include "storage/encryption.h" static ControlFileData ControlFile; /* pg_control values */ static XLogSegNo newXlogSegNo; /* new XLOG segment # */ @@ -101,6 +103,7 @@ main(int argc, char *argv[]) {"dry-run", no_argument, NULL, 'n'}, {"next-oid", required_argument, NULL, 'o'}, {"multixact-offset", required_argument, NULL, 'O'}, + {"cluster-passphrase-command", required_argument, NULL, 'p'}, {"next-transaction-id", required_argument, NULL, 'x'}, {"wal-segsize", required_argument, NULL, 1}, {NULL, 0, NULL, 0} @@ -115,6 +118,7 @@ main(int argc, char *argv[]) char *DataDir = NULL; char *log_fname = NULL; int fd; + char *cluster_passphrase = NULL; pg_logging_init(argv[0]); set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_resetwal")); @@ -135,7 +139,7 @@ main(int argc, char *argv[]) } - while ((c = getopt_long(argc, argv, "c:D:e:fl:m:no:O:x:", long_options, NULL)) != -1) + while ((c = getopt_long(argc, argv, "c:D:e:fl:m:no:O:p:x:", long_options, NULL)) != -1) { switch (c) { @@ -277,6 +281,11 @@ main(int argc, char *argv[]) } break; + case 'p': + { + cluster_passphrase = pg_strdup(optarg); + break; + } case 'l': if (strspn(optarg, "01234567890ABCDEFabcdef") != XLOG_FNAME_LEN) { @@ -390,6 +399,9 @@ main(int argc, char *argv[]) exit(1); } + if (DataDir && cluster_passphrase) + getKmgr(DataDir, cluster_passphrase, progname); + /* * Attempt to read the existing pg_control file */ @@ -1122,6 +1134,7 @@ WriteEmptyXLOG(void) int fd; int nbytes; char *recptr; + char *buftowrite; memset(buffer.data, 0, XLOG_BLCKSZ); @@ -1157,6 +1170,13 @@ WriteEmptyXLOG(void) FIN_CRC32C(crc); record->xl_crc = crc; + if (DataEncryptionEnabled()) + { + buftowrite = EncryptXLog(buffer.data, XLOG_BLCKSZ, newXlogSegNo, 0); + } + else + buftowrite = buffer.data; + /* Write the first page */ XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID, newXlogSegNo, WalSegSz); @@ -1172,7 +1192,7 @@ WriteEmptyXLOG(void) } errno = 0; - if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ) + if (write(fd, buftowrite, XLOG_BLCKSZ) != XLOG_BLCKSZ) { /* if write didn't set errno, assume problem is no disk space */ if (errno == 0) @@ -1182,11 +1202,11 @@ WriteEmptyXLOG(void) } /* Fill the rest of the file with zeroes */ - memset(buffer.data, 0, XLOG_BLCKSZ); + memset(buftowrite, 0, XLOG_BLCKSZ); for (nbytes = XLOG_BLCKSZ; nbytes < WalSegSz; nbytes += XLOG_BLCKSZ) { errno = 0; - if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ) + if (write(fd, buftowrite, XLOG_BLCKSZ) != XLOG_BLCKSZ) { if (errno == 0) errno = ENOSPC; @@ -1222,6 +1242,8 @@ usage(void) printf(_(" -n, --dry-run no update, just show what would be done\n")); printf(_(" -o, --next-oid=OID set next OID\n")); printf(_(" -O, --multixact-offset=OFFSET set next multitransaction offset\n")); + printf(_(" -p --cluster-passphrase-command=COMMAND\n" + " set command to obtain passphrase for data encryption key\n")); printf(_(" -V, --version output version information, then exit\n")); printf(_(" -x, --next-transaction-id=XID set next transaction ID\n")); printf(_(" --wal-segsize=SIZE size of WAL segments, in megabytes\n"));