static char *xlog_dir = "";
static char format = 'p'; /* p(lain)/t(ar) */
static char *label = "pg_basebackup base backup";
+static bool noclean = false;
static bool showprogress = false;
static int verbose = 0;
static int compresslevel = 0;
static pg_time_t last_progress_report = 0;
static int32 maxrate = 0; /* no limit by default */
+static bool success = false;
+static bool made_new_pgdata = false;
+static bool found_existing_pgdata = false;
+static bool made_new_xlogdir = false;
+static bool found_existing_xlogdir = false;
+static bool made_tablespace_dirs = false;
+static bool found_tablespace_dirs = false;
/* Progress counters */
static uint64 totalsize;
/* Handle to child process */
static pid_t bgchild = -1;
+static bool in_log_streamer = false;
/* End position for xlog streaming, empty string if unknown yet */
static XLogRecPtr xlogendptr;
/* Function headers */
static void usage(void);
static void disconnect_and_exit(int code);
-static void verify_dir_is_empty_or_create(char *dirname);
+static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found);
static void progress_report(int tablespacenum, const char *filename, bool force);
static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
static void tablespace_list_append(const char *arg);
+static void
+cleanup_directories_atexit(void)
+{
+ if (success || in_log_streamer)
+ return;
+
+ if (!noclean)
+ {
+ if (made_new_pgdata)
+ {
+ fprintf(stderr, _("%s: removing data directory \"%s\"\n"),
+ progname, basedir);
+ if (!rmtree(basedir, true))
+ fprintf(stderr, _("%s: failed to remove data directory\n"),
+ progname);
+ }
+ else if (found_existing_pgdata)
+ {
+ fprintf(stderr,
+ _("%s: removing contents of data directory \"%s\"\n"),
+ progname, basedir);
+ if (!rmtree(basedir, false))
+ fprintf(stderr, _("%s: failed to remove contents of data directory\n"),
+ progname);
+ }
+
+ if (made_new_xlogdir)
+ {
+ fprintf(stderr, _("%s: removing transaction log directory \"%s\"\n"),
+ progname, xlog_dir);
+ if (!rmtree(xlog_dir, true))
+ fprintf(stderr, _("%s: failed to remove transaction log directory\n"),
+ progname);
+ }
+ else if (found_existing_xlogdir)
+ {
+ fprintf(stderr,
+ _("%s: removing contents of transaction log directory \"%s\"\n"),
+ progname, xlog_dir);
+ if (!rmtree(xlog_dir, false))
+ fprintf(stderr, _("%s: failed to remove contents of transaction log directory\n"),
+ progname);
+ }
+ }
+ else
+ {
+ if (made_new_pgdata || found_existing_pgdata)
+ fprintf(stderr,
+ _("%s: data directory \"%s\" not removed at user's request\n"),
+ progname, basedir);
+
+ if (made_new_xlogdir || found_existing_xlogdir)
+ fprintf(stderr,
+ _("%s: transaction log directory \"%s\" not removed at user's request\n"),
+ progname, xlog_dir);
+ }
+
+ if (made_tablespace_dirs || found_tablespace_dirs)
+ fprintf(stderr,
+ _("%s: changes to tablespace directories will not be undone"),
+ progname);
+}
+
static void
disconnect_and_exit(int code)
{
printf(_(" -c, --checkpoint=fast|spread\n"
" set fast or spread checkpointing\n"));
printf(_(" -l, --label=LABEL set backup label\n"));
+ printf(_(" -n, --noclean do not clean up after errors\n"));
printf(_(" -P, --progress show progress information\n"));
printf(_(" -v, --verbose output verbose messages\n"));
printf(_(" -V, --version output version information, then exit\n"));
{
StreamCtl stream;
+ in_log_streamer = true;
+
MemSet(&stream, 0, sizeof(stream));
stream.startpos = param->startptr;
stream.timeline = param->timeline;
* be give and the process ended.
*/
static void
-verify_dir_is_empty_or_create(char *dirname)
+verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
{
switch (pg_check_dir(dirname))
{
progname, dirname, strerror(errno));
disconnect_and_exit(1);
}
+ if (created)
+ *created = true;
return;
case 1:
/*
* Exists, empty
*/
+ if (found)
+ *found = true;
return;
case 2:
case 3:
{
char *path = (char *) get_tablespace_mapping(PQgetvalue(res, i, 1));
- verify_dir_is_empty_or_create(path);
+ verify_dir_is_empty_or_create(path, &made_tablespace_dirs, &found_tablespace_dirs);
}
}
{"gzip", no_argument, NULL, 'z'},
{"compress", required_argument, NULL, 'Z'},
{"label", required_argument, NULL, 'l'},
+ {"noclean", no_argument, NULL, 'n'},
{"dbname", required_argument, NULL, 'd'},
{"host", required_argument, NULL, 'h'},
{"port", required_argument, NULL, 'p'},
}
}
- while ((c = getopt_long(argc, argv, "D:F:r:RT:xX:l:zZ:d:c:h:p:U:s:S:wWvP",
+ atexit(cleanup_directories_atexit);
+
+ while ((c = getopt_long(argc, argv, "D:F:r:RT:xX:l:nzZ:d:c:h:p:U:s:S:wWvP",
long_options, &option_index)) != -1)
{
switch (c)
case 'l':
label = pg_strdup(optarg);
break;
+ case 'n':
+ noclean = true;
+ break;
case 'z':
#ifdef HAVE_LIBZ
compresslevel = Z_DEFAULT_COMPRESSION;
* unless we are writing to stdout.
*/
if (format == 'p' || strcmp(basedir, "-") != 0)
- verify_dir_is_empty_or_create(basedir);
+ verify_dir_is_empty_or_create(basedir, &made_new_pgdata, &found_existing_pgdata);
/* Create transaction log symlink, if required */
if (strcmp(xlog_dir, "") != 0)
{
char *linkloc;
- verify_dir_is_empty_or_create(xlog_dir);
+ verify_dir_is_empty_or_create(xlog_dir, &made_new_xlogdir, &found_existing_xlogdir);
/* form name of the place where the symlink must go */
linkloc = psprintf("%s/pg_xlog", basedir);
BaseBackup();
+ success = true;
return 0;
}