* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.2 2002/08/17 15:12:07 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.3 2002/08/29 22:19:03 petere Exp $
*
*-------------------------------------------------------------------------
*/
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
-#ifdef USE_LOCALE
#include <locale.h>
-#endif
#include "access/xlog.h"
#include "catalog/catversion.h"
/******************** end of stuff copied from xlog.c ********************/
+#define _(x) gettext((x))
-static char *DataDir; /* locations of important stuff */
static char XLogDir[MAXPGPATH];
static char ControlFilePath[MAXPGPATH];
static uint32 newXlogId,
newXlogSeg; /* ID/Segment of new XLOG segment */
static bool guessed = false; /* T if we had to guess at any values */
+static char *progname;
+
+static bool ReadControlFile(void);
+static void GuessControlValues(void);
+static void PrintControlValues(bool guessed);
+static void RewriteControlFile(void);
+static void KillExistingXLOG(void);
+static void WriteEmptyXLOG(void);
+static void usage(void);
+
+
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ bool force = false;
+ bool noupdate = false;
+ TransactionId set_xid = 0;
+ uint32 minXlogId = 0,
+ minXlogSeg = 0;
+ char *DataDir;
+ int fd;
+ char path[MAXPGPATH];
+
+ setlocale(LC_ALL, "");
+#ifdef ENABLE_NLS
+ bindtextdomain("pg_resetxlog", LOCALEDIR);
+ textdomain("pg_resetxlog");
+#endif
+
+ if (!strrchr(argv[0], '/'))
+ progname = argv[0];
+ else
+ progname = strrchr(argv[0], '/') + 1;
+
+ if (argc > 1)
+ {
+ if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
+ {
+ usage();
+ exit(0);
+ }
+ if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
+ {
+ puts("pg_resetxlog (PostgreSQL) " PG_VERSION);
+ exit(0);
+ }
+ }
+
+
+ while ((c = getopt(argc, argv, "fl:nx:")) != -1)
+ {
+ switch (c)
+ {
+ case 'f':
+ force = true;
+ break;
+
+ case 'n':
+ noupdate = true;
+ break;
+
+ case 'x':
+ set_xid = strtoul(optarg, NULL, 0);
+ if (set_xid == 0)
+ {
+ fprintf(stderr, _("%s: transaction ID (-x) must not be 0\n"), progname);
+ exit(1);
+ }
+ break;
+
+ case 'l':
+ if (sscanf(optarg, "%u,%u", &minXlogId, &minXlogSeg) != 2)
+ {
+ fprintf(stderr, _("%s: invalid argument for -l option\n"), progname);
+ fprintf(stderr, _("Try '%s --help' for more information.\n"), progname);
+ exit(1);
+ }
+ break;
+
+ default:
+ fprintf(stderr, _("Try '%s --help' for more information.\n"), progname);
+ exit(1);
+ }
+ }
+
+ if (optind == argc)
+ {
+ fprintf(stderr, _("%s: no data directory specified\n"), progname);
+ fprintf(stderr, _("Try '%s --help' for more information.\n"), progname);
+ exit(1);
+ }
+
+ DataDir = argv[optind];
+ snprintf(XLogDir, MAXPGPATH, "%s/pg_xlog", DataDir);
+ snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
+
+ /*
+ * Check for a postmaster lock file --- if there is one, refuse to
+ * proceed, on grounds we might be interfering with a live
+ * installation.
+ */
+ snprintf(path, MAXPGPATH, "%s/postmaster.pid", DataDir);
+
+ if ((fd = open(path, O_RDONLY)) < 0)
+ {
+ if (errno != ENOENT)
+ {
+ fprintf(stderr, _("%s: could not open %s for reading: %s\n"), progname, path, strerror(errno));
+ exit(1);
+ }
+ }
+ else
+ {
+ fprintf(stderr, _("%s: lock file %s exists\n"
+ "Is a server running? If not, delete the lock file and try again.\n"),
+ progname, path);
+ exit(1);
+ }
+
+ /*
+ * Attempt to read the existing pg_control file
+ */
+ if (!ReadControlFile())
+ GuessControlValues();
+
+ /*
+ * If we had to guess anything, and -f was not given, just print the
+ * guessed values and exit. Also print if -n is given.
+ */
+ if ((guessed && !force) || noupdate)
+ {
+ PrintControlValues(guessed);
+ if (!noupdate)
+ {
+ printf(_("\nIf these values seem acceptable, use -f to force reset.\n"));
+ exit(1);
+ }
+ else
+ exit(0);
+ }
+
+ /*
+ * Don't reset from a dirty pg_control without -f, either.
+ */
+ if (ControlFile.state != DB_SHUTDOWNED && !force)
+ {
+ printf(_("The database server was not shut down cleanly.\n"
+ "Resetting the transaction log may cause data to be lost.\n"
+ "If you want to proceed anyway, use -f to force reset.\n"));
+ exit(1);
+ }
+
+ /*
+ * Else, do the dirty deed.
+ *
+ * First adjust fields if required by switches.
+ */
+ if (set_xid != 0)
+ ControlFile.checkPointCopy.nextXid = set_xid;
+
+ if (minXlogId > ControlFile.logId ||
+ (minXlogId == ControlFile.logId && minXlogSeg > ControlFile.logSeg))
+ {
+ ControlFile.logId = minXlogId;
+ ControlFile.logSeg = minXlogSeg;
+ }
+
+ RewriteControlFile();
+ KillExistingXLOG();
+ WriteEmptyXLOG();
+
+ printf(_("Transaction log reset\n"));
+ return 0;
+}
/*
* odds are we've been handed a bad DataDir path, so give up. User
* can do "touch pg_control" to force us to proceed.
*/
- perror("Failed to open $PGDATA/global/pg_control for reading");
+ fprintf(stderr, _("%s: could not open %s for reading: %s\n"),
+ progname, ControlFilePath, strerror(errno));
if (errno == ENOENT)
- fprintf(stderr, "If you're sure the PGDATA path is correct, do\n"
- " touch %s\n"
- "and try again.\n", ControlFilePath);
+ fprintf(stderr, _("If you are sure the data directory path is correct, do\n"
+ " touch %s\n"
+ "and try again.\n"),
+ ControlFilePath);
exit(1);
}
len = read(fd, buffer, BLCKSZ);
if (len < 0)
{
- perror("Failed to read $PGDATA/global/pg_control");
+ fprintf(stderr, _("%s: could not read %s: %s\n"),
+ progname, ControlFilePath, strerror(errno));
exit(1);
}
close(fd);
return true;
}
- fprintf(stderr, "pg_control exists but has invalid CRC; proceed with caution.\n");
+ fprintf(stderr, _("%s: pg_control exists but has invalid CRC; proceed with caution\n"),
+ progname);
/* We will use the data anyway, but treat it as guessed. */
memcpy(&ControlFile, buffer, sizeof(ControlFile));
guessed = true;
}
/* Looks like it's a mess. */
- fprintf(stderr, "pg_control exists but is broken or unknown version; ignoring it.\n");
+ fprintf(stderr, _("%s: pg_control exists but is broken or unknown version; ignoring it\n"),
+ progname);
return false;
}
static void
GuessControlValues(void)
{
-#ifdef USE_LOCALE
char *localeptr;
-#endif
/*
* Set up a completely default set of pg_control values.
ControlFile.blcksz = BLCKSZ;
ControlFile.relseg_size = RELSEG_SIZE;
-#ifdef USE_LOCALE
localeptr = setlocale(LC_COLLATE, "");
if (!localeptr)
{
- fprintf(stderr, "Invalid LC_COLLATE setting\n");
+ fprintf(stderr, _("%s: invalid LC_COLLATE setting\n"), progname);
exit(1);
}
StrNCpy(ControlFile.lc_collate, localeptr, LOCALE_NAME_BUFLEN);
localeptr = setlocale(LC_CTYPE, "");
if (!localeptr)
{
- fprintf(stderr, "Invalid LC_CTYPE setting\n");
+ fprintf(stderr, _("%s: invalid LC_CTYPE setting\n"), progname);
exit(1);
}
StrNCpy(ControlFile.lc_ctype, localeptr, LOCALE_NAME_BUFLEN);
-#else
- strcpy(ControlFile.lc_collate, "C");
- strcpy(ControlFile.lc_ctype, "C");
-#endif
/*
* XXX eventually, should try to grovel through old XLOG to develop
static void
PrintControlValues(bool guessed)
{
- printf("%spg_control values:\n\n"
- "pg_control version number: %u\n"
- "Catalog version number: %u\n"
- "Current log file id: %u\n"
- "Next log file segment: %u\n"
- "Latest checkpoint's StartUpID: %u\n"
- "Latest checkpoint's NextXID: %u\n"
- "Latest checkpoint's NextOID: %u\n"
- "Database block size: %u\n"
- "Blocks per segment of large relation: %u\n"
- "LC_COLLATE: %s\n"
- "LC_CTYPE: %s\n",
-
- (guessed ? "Guessed-at " : ""),
- ControlFile.pg_control_version,
- ControlFile.catalog_version_no,
- ControlFile.logId,
- ControlFile.logSeg,
- ControlFile.checkPointCopy.ThisStartUpID,
- ControlFile.checkPointCopy.nextXid,
- ControlFile.checkPointCopy.nextOid,
- ControlFile.blcksz,
- ControlFile.relseg_size,
- ControlFile.lc_collate,
- ControlFile.lc_ctype);
+ if (guessed)
+ printf(_("Guessed pg_control values:\n\n"));
+ else
+ printf(_("pg_control values:\n\n"));
+
+ printf(_("pg_control version number: %u\n"), ControlFile.pg_control_version);
+ printf(_("Catalog version number: %u\n"), ControlFile.catalog_version_no);
+ printf(_("Current log file ID: %u\n"), ControlFile.logId);
+ printf(_("Next log file segment: %u\n"), ControlFile.logSeg);
+ printf(_("Latest checkpoint's StartUpID: %u\n"), ControlFile.checkPointCopy.ThisStartUpID);
+ printf(_("Latest checkpoint's NextXID: %u\n"), ControlFile.checkPointCopy.nextXid);
+ printf(_("Latest checkpoint's NextOID: %u\n"), ControlFile.checkPointCopy.nextOid);
+ printf(_("Database block size: %u\n"), ControlFile.blcksz);
+ printf(_("Blocks per segment of large relation: %u\n"), ControlFile.relseg_size);
+ printf(_("LC_COLLATE: %s\n"), ControlFile.lc_collate);
+ printf(_("LC_CTYPE: %s\n"), ControlFile.lc_ctype);
}
*/
if (sizeof(ControlFileData) > BLCKSZ)
{
- fprintf(stderr, "sizeof(ControlFileData) is too large ... fix xlog.c\n");
+ fprintf(stderr,
+ _("%s: internal error -- sizeof(ControlFileData) is too large ... fix xlog.c\n"),
+ progname);
exit(1);
}
fd = open(ControlFilePath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, S_IRUSR | S_IWUSR);
if (fd < 0)
{
- perror("RewriteControlFile failed to create pg_control file");
+ fprintf(stderr, _("%s: could not create pg_control file: %s\n"),
+ progname, strerror(errno));
exit(1);
}
/* if write didn't set errno, assume problem is no disk space */
if (errno == 0)
errno = ENOSPC;
- perror("RewriteControlFile failed to write pg_control file");
+ fprintf(stderr, _("%s: could not write pg_control file: %s\n"),
+ progname, strerror(errno));
exit(1);
}
if (fsync(fd) != 0)
{
- perror("fsync");
+ fprintf(stderr, _("%s: fsync error: %s\n"), progname, strerror(errno));
exit(1);
}
xldir = opendir(XLogDir);
if (xldir == NULL)
{
- perror("KillExistingXLOG: cannot open $PGDATA/pg_xlog directory");
+ fprintf(stderr, _("%s: could not open directory %s: %s\n"),
+ progname, XLogDir, strerror(errno));
exit(1);
}
snprintf(path, MAXPGPATH, "%s/%s", XLogDir, xlde->d_name);
if (unlink(path) < 0)
{
- perror(path);
+ fprintf(stderr, _("%s: could not delete file %s: %s\n"),
+ progname, path, strerror(errno));
exit(1);
}
}
errno = 0;
}
+
if (errno)
{
- perror("KillExistingXLOG: cannot read $PGDATA/pg_xlog directory");
+ fprintf(stderr, _("%s: could not read from directory %s: %s\n"),
+ progname, XLogDir, strerror(errno));
exit(1);
}
closedir(xldir);
S_IRUSR | S_IWUSR);
if (fd < 0)
{
- perror(path);
+ fprintf(stderr, _("%s: could not open %s: %s\n"),
+ progname, path, strerror(errno));
exit(1);
}
/* if write didn't set errno, assume problem is no disk space */
if (errno == 0)
errno = ENOSPC;
- perror("WriteEmptyXLOG: failed to write xlog file");
+ fprintf(stderr, _("%s: could not write %s: %s\n"),
+ progname, path, strerror(errno));
exit(1);
}
{
if (errno == 0)
errno = ENOSPC;
- perror("WriteEmptyXLOG: failed to write xlog file");
+ fprintf(stderr, _("%s: could not write %s: %s\n"),
+ progname, path, strerror(errno));
exit(1);
}
}
if (fsync(fd) != 0)
{
- perror("fsync");
+ fprintf(stderr, _("%s: fsync error: %s\n"), progname, strerror(errno));
exit(1);
}
static void
usage(void)
{
- fprintf(stderr, "Usage: pg_resetxlog [-f] [-n] [-x xid] [ -l fileid seg ] PGDataDirectory\n"
- " -f\t\tforce update to be done\n"
- " -n\t\tno update, just show extracted pg_control values (for testing)\n"
- " -x xid\tset next transaction ID\n"
- " -l fileid seg\tforce minimum WAL starting location for new xlog\n");
- exit(1);
-}
-
-
-int
-main(int argc, char **argv)
-{
- int argn;
- bool force = false;
- bool noupdate = false;
- TransactionId set_xid = 0;
- uint32 minXlogId = 0,
- minXlogSeg = 0;
- int fd;
- char path[MAXPGPATH];
-
- for (argn = 1; argn < argc; argn++)
- {
- if (argv[argn][0] != '-')
- break; /* end of switches */
- if (strcmp(argv[argn], "-f") == 0)
- force = true;
- else if (strcmp(argv[argn], "-n") == 0)
- noupdate = true;
- else if (strcmp(argv[argn], "-x") == 0)
- {
- argn++;
- if (argn == argc)
- usage();
- set_xid = strtoul(argv[argn], NULL, 0);
- if (set_xid == 0)
- {
- fprintf(stderr, "XID can not be 0.\n");
- exit(1);
- }
- }
- else if (strcmp(argv[argn], "-l") == 0)
- {
- argn++;
- if (argn == argc)
- usage();
- minXlogId = strtoul(argv[argn], NULL, 0);
- argn++;
- if (argn == argc)
- usage();
- minXlogSeg = strtoul(argv[argn], NULL, 0);
- }
- else
- usage();
- }
-
- if (argn != argc - 1) /* one required non-switch argument */
- usage();
-
- DataDir = argv[argn++];
-
- snprintf(XLogDir, MAXPGPATH, "%s/pg_xlog", DataDir);
-
- snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
-
- /*
- * Check for a postmaster lock file --- if there is one, refuse to
- * proceed, on grounds we might be interfering with a live
- * installation.
- */
- snprintf(path, MAXPGPATH, "%s/postmaster.pid", DataDir);
-
- if ((fd = open(path, O_RDONLY)) < 0)
- {
- if (errno != ENOENT)
- {
- perror("Failed to open $PGDATA/postmaster.pid for reading");
- exit(1);
- }
- }
- else
- {
- fprintf(stderr, "Lock file '%s' exists --- is a postmaster running?\n"
- "If not, delete the lock file and try again.\n",
- path);
- exit(1);
- }
-
- /*
- * Attempt to read the existing pg_control file
- */
- if (!ReadControlFile())
- GuessControlValues();
-
- /*
- * If we had to guess anything, and -f was not given, just print the
- * guessed values and exit. Also print if -n is given.
- */
- if ((guessed && !force) || noupdate)
- {
- PrintControlValues(guessed);
- if (!noupdate)
- {
- printf("\nIf these values seem acceptable, use -f to force reset.\n");
- exit(1);
- }
- else
- exit(0);
- }
-
- /*
- * Don't reset from a dirty pg_control without -f, either.
- */
- if (ControlFile.state != DB_SHUTDOWNED && !force)
- {
- printf("The database was not shut down cleanly.\n"
- "Resetting the xlog may cause data to be lost!\n"
- "If you want to proceed anyway, use -f to force reset.\n");
- exit(1);
- }
-
- /*
- * Else, do the dirty deed.
- *
- * First adjust fields if required by switches.
- */
- if (set_xid != 0)
- ControlFile.checkPointCopy.nextXid = set_xid;
-
- if (minXlogId > ControlFile.logId ||
- (minXlogId == ControlFile.logId && minXlogSeg > ControlFile.logSeg))
- {
- ControlFile.logId = minXlogId;
- ControlFile.logSeg = minXlogSeg;
- }
-
- RewriteControlFile();
- KillExistingXLOG();
- WriteEmptyXLOG();
-
- printf("XLOG reset.\n");
- return 0;
+ printf(_("%s resets the PostgreSQL transaction log.\n\n"), progname);
+ printf(_("Usage:\n %s [OPTIONS] DATADIR\n\n"), progname);
+ printf(_("Options:\n"));
+ printf(_(" -f force update to be done\n"));
+ printf(_(" -l FILEID,SEG force minimum WAL starting location for new transaction log\n"));
+ printf(_(" -n no update, just show extracted control values (for testing)\n"));
+ printf(_(" -x XID set next transaction ID\n"));
+ printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
}