|
| 1 | +/*------------------------------------------------------------------------- |
| 2 | + * |
| 3 | + * pg_probackup.c: Backup/Recovery manager for PostgreSQL. |
| 4 | + * |
| 5 | + * Copyright (c) 2009-2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION |
| 6 | + * |
| 7 | + *------------------------------------------------------------------------- |
| 8 | + */ |
| 9 | + |
| 10 | +#include "pg_probackup.h" |
| 11 | +#include "streamutil.h" |
| 12 | + |
| 13 | +#include <stdio.h> |
| 14 | +#include <stdlib.h> |
| 15 | +#include <time.h> |
| 16 | +#include <sys/stat.h> |
| 17 | + |
| 18 | +const char *PROGRAM_VERSION = "1.0"; |
| 19 | +const char *PROGRAM_URL = "https://github.com/postgrespro/pg_probackup"; |
| 20 | +const char *PROGRAM_EMAIL = "https://github.com/postgrespro/pg_probackup/issues"; |
| 21 | + |
| 22 | +/* path configuration */ |
| 23 | +char *backup_path; |
| 24 | +char *pgdata; |
| 25 | +char arclog_path[MAXPGPATH]; |
| 26 | + |
| 27 | +/* common configuration */ |
| 28 | +bool check = false; |
| 29 | + |
| 30 | +/* directory configuration */ |
| 31 | +pgBackup current; |
| 32 | + |
| 33 | +/* backup configuration */ |
| 34 | +static bool smooth_checkpoint; |
| 35 | +static int keep_data_generations = KEEP_INFINITE; |
| 36 | +static int keep_data_days = KEEP_INFINITE; |
| 37 | +int num_threads = 1; |
| 38 | +bool stream_wal = false; |
| 39 | +bool from_replica = false; |
| 40 | +static bool backup_logs = false; |
| 41 | +bool progress = false; |
| 42 | +bool delete_wal = false; |
| 43 | + |
| 44 | +/* restore configuration */ |
| 45 | +static char *target_time; |
| 46 | +static char *target_xid; |
| 47 | +static char *target_inclusive; |
| 48 | +static TimeLineID target_tli; |
| 49 | + |
| 50 | +/* show configuration */ |
| 51 | +static bool show_all = false; |
| 52 | + |
| 53 | +static void opt_backup_mode(pgut_option *opt, const char *arg); |
| 54 | + |
| 55 | +static pgut_option options[] = |
| 56 | +{ |
| 57 | + /* directory options */ |
| 58 | + { 's', 'D', "pgdata", &pgdata, SOURCE_ENV }, |
| 59 | + { 's', 'B', "backup-path", &backup_path, SOURCE_ENV }, |
| 60 | + /* common options */ |
| 61 | +/* { 'b', 'c', "check", &check },*/ |
| 62 | + { 'i', 'j', "threads", &num_threads }, |
| 63 | + { 'b', 8, "stream", &stream_wal }, |
| 64 | + { 'b', 11, "progress", &progress }, |
| 65 | + /* backup options */ |
| 66 | + { 'b', 10, "backup-pg-log", &backup_logs }, |
| 67 | + { 'f', 'b', "backup-mode", opt_backup_mode, SOURCE_ENV }, |
| 68 | + { 'b', 'C', "smooth-checkpoint", &smooth_checkpoint, SOURCE_ENV }, |
| 69 | + { 's', 'S', "slot", &replication_slot, SOURCE_ENV }, |
| 70 | + /* options with only long name (keep-xxx) */ |
| 71 | +/* { 'i', 1, "keep-data-generations", &keep_data_generations, SOURCE_ENV }, |
| 72 | + { 'i', 2, "keep-data-days", &keep_data_days, SOURCE_ENV },*/ |
| 73 | + /* restore options */ |
| 74 | + { 's', 3, "time", &target_time, SOURCE_ENV }, |
| 75 | + { 's', 4, "xid", &target_xid, SOURCE_ENV }, |
| 76 | + { 's', 5, "inclusive", &target_inclusive, SOURCE_ENV }, |
| 77 | + { 'u', 6, "timeline", &target_tli, SOURCE_ENV }, |
| 78 | + /* catalog options */ |
| 79 | + { 'b', 'a', "show-all", &show_all }, |
| 80 | + /* delete options */ |
| 81 | + { 'b', 12, "wal", &delete_wal }, |
| 82 | + { 0 } |
| 83 | +}; |
| 84 | + |
| 85 | +/* |
| 86 | + * Entry point of pg_probackup command. |
| 87 | + */ |
| 88 | +int |
| 89 | +main(int argc, char *argv[]) |
| 90 | +{ |
| 91 | + const char *cmd = NULL; |
| 92 | + const char *backup_id_string = NULL; |
| 93 | + time_t backup_id = 0; |
| 94 | + int i; |
| 95 | + |
| 96 | + /* do not buffer progress messages */ |
| 97 | + setvbuf(stdout, 0, _IONBF, 0); /* TODO: remove this */ |
| 98 | + |
| 99 | + /* initialize configuration */ |
| 100 | + catalog_init_config(¤t); |
| 101 | + |
| 102 | + /* overwrite configuration with command line arguments */ |
| 103 | + i = pgut_getopt(argc, argv, options); |
| 104 | + |
| 105 | + for (; i < argc; i++) |
| 106 | + { |
| 107 | + if (cmd == NULL) |
| 108 | + { |
| 109 | + cmd = argv[i]; |
| 110 | + if(strcmp(cmd, "show") != 0 && |
| 111 | + strcmp(cmd, "validate") != 0 && |
| 112 | + strcmp(cmd, "delete") != 0 && |
| 113 | + strcmp(cmd, "restore") != 0 && |
| 114 | + strcmp(cmd, "delwal") != 0) |
| 115 | + break; |
| 116 | + } else if (backup_id_string == NULL) |
| 117 | + backup_id_string = argv[i]; |
| 118 | + else |
| 119 | + elog(ERROR, "too many arguments"); |
| 120 | + } |
| 121 | + |
| 122 | + /* command argument (backup/restore/show/...) is required. */ |
| 123 | + if (cmd == NULL) |
| 124 | + { |
| 125 | + help(false); |
| 126 | + return 1; |
| 127 | + } |
| 128 | + |
| 129 | + if (backup_id_string != NULL) |
| 130 | + { |
| 131 | + backup_id = base36dec(backup_id_string); |
| 132 | + if (backup_id == 0) { |
| 133 | + elog(ERROR, "wrong ID"); |
| 134 | + } |
| 135 | + } |
| 136 | + |
| 137 | + /* Read default configuration from file. */ |
| 138 | + if (backup_path) |
| 139 | + { |
| 140 | + char path[MAXPGPATH]; |
| 141 | + /* Check if backup_path is directory. */ |
| 142 | + struct stat stat_buf; |
| 143 | + int rc = stat(backup_path, &stat_buf); |
| 144 | + |
| 145 | + /* If rc == -1, there is no file or directory. So it's OK. */ |
| 146 | + if (rc != -1 && !S_ISDIR(stat_buf.st_mode)) |
| 147 | + elog(ERROR, "-B, --backup-path must be a path to directory"); |
| 148 | + |
| 149 | + join_path_components(path, backup_path, PG_RMAN_INI_FILE); |
| 150 | + pgut_readopt(path, options, ERROR); |
| 151 | + |
| 152 | + /* setup stream options */ |
| 153 | + if (pgut_dbname != NULL) |
| 154 | + dbname = pstrdup(pgut_dbname); |
| 155 | + if (host != NULL) |
| 156 | + dbhost = pstrdup(host); |
| 157 | + if (port != NULL) |
| 158 | + dbport = pstrdup(port); |
| 159 | + if (username != NULL) |
| 160 | + dbuser = pstrdup(username); |
| 161 | + } |
| 162 | + |
| 163 | + /* BACKUP_PATH is always required */ |
| 164 | + if (backup_path == NULL) |
| 165 | + elog(ERROR, "required parameter not specified: BACKUP_PATH (-B, --backup-path)"); |
| 166 | + |
| 167 | + /* path must be absolute */ |
| 168 | + if (backup_path != NULL && !is_absolute_path(backup_path)) |
| 169 | + elog(ERROR, "-B, --backup-path must be an absolute path"); |
| 170 | + if (pgdata != NULL && !is_absolute_path(pgdata)) |
| 171 | + elog(ERROR, "-D, --pgdata must be an absolute path"); |
| 172 | + |
| 173 | + join_path_components(arclog_path, backup_path, "wal"); |
| 174 | + |
| 175 | + /* setup exclusion list for file search */ |
| 176 | + for (i = 0; pgdata_exclude[i]; i++); /* find first empty slot */ |
| 177 | + |
| 178 | + pgdata_exclude[i++] = arclog_path; |
| 179 | + |
| 180 | + if(!backup_logs) |
| 181 | + pgdata_exclude[i++] = "pg_log"; |
| 182 | + |
| 183 | + if (target_time != NULL && target_xid != NULL) |
| 184 | + elog(ERROR, "You can't specify recovery-target-time and recovery-target-xid at the same time"); |
| 185 | + |
| 186 | + /* do actual operation */ |
| 187 | + if (pg_strcasecmp(cmd, "init") == 0) |
| 188 | + return do_init(); |
| 189 | + else if (pg_strcasecmp(cmd, "backup") == 0) |
| 190 | + { |
| 191 | + pgBackupOption bkupopt; |
| 192 | + int res; |
| 193 | + bkupopt.smooth_checkpoint = smooth_checkpoint; |
| 194 | + bkupopt.keep_data_generations = keep_data_generations; |
| 195 | + bkupopt.keep_data_days = keep_data_days; |
| 196 | + |
| 197 | + /* Do the backup */ |
| 198 | + res = do_backup(bkupopt); |
| 199 | + if (res != 0) |
| 200 | + return res; |
| 201 | + |
| 202 | + do_validate(current.start_time); |
| 203 | + } |
| 204 | + else if (pg_strcasecmp(cmd, "restore") == 0) |
| 205 | + return do_restore(backup_id, target_time, target_xid, |
| 206 | + target_inclusive, target_tli); |
| 207 | + else if (pg_strcasecmp(cmd, "show") == 0) |
| 208 | + return do_show(backup_id, show_all); |
| 209 | + else if (pg_strcasecmp(cmd, "validate") == 0) |
| 210 | + return do_validate(backup_id); |
| 211 | + else if (pg_strcasecmp(cmd, "delete") == 0) |
| 212 | + return do_delete(backup_id); |
| 213 | + else if (pg_strcasecmp(cmd, "delwal") == 0) |
| 214 | + return do_deletewal(backup_id, true); |
| 215 | + else |
| 216 | + elog(ERROR, "invalid command \"%s\"", cmd); |
| 217 | + |
| 218 | + return 0; |
| 219 | +} |
| 220 | + |
| 221 | +void |
| 222 | +pgut_help(bool details) |
| 223 | +{ |
| 224 | + printf(_("%s manage backup/recovery of PostgreSQL database.\n\n"), PROGRAM_NAME); |
| 225 | + printf(_("Usage:\n")); |
| 226 | + printf(_(" %s OPTION init\n"), PROGRAM_NAME); |
| 227 | + printf(_(" %s OPTION backup\n"), PROGRAM_NAME); |
| 228 | + printf(_(" %s OPTION restore\n"), PROGRAM_NAME); |
| 229 | + printf(_(" %s OPTION show [ID]\n"), PROGRAM_NAME); |
| 230 | + printf(_(" %s OPTION validate [ID]\n"), PROGRAM_NAME); |
| 231 | + printf(_(" %s OPTION delete ID\n"), PROGRAM_NAME); |
| 232 | + printf(_(" %s OPTION delwal [ID]\n"), PROGRAM_NAME); |
| 233 | + |
| 234 | + if (!details) |
| 235 | + return; |
| 236 | + |
| 237 | + printf(_("\nCommon Options:\n")); |
| 238 | + printf(_(" -D, --pgdata=PATH location of the database storage area\n")); |
| 239 | + printf(_(" -B, --backup-path=PATH location of the backup storage area\n")); |
| 240 | + /*printf(_(" -c, --check show what would have been done\n"));*/ |
| 241 | + printf(_(" -j, --threads=NUM num threads for backup and restore\n")); |
| 242 | + printf(_(" --progress show progress copy files\n")); |
| 243 | + printf(_("\nBackup options:\n")); |
| 244 | + printf(_(" -b, --backup-mode=MODE full,page,ptrack\n")); |
| 245 | + printf(_(" -C, --smooth-checkpoint do smooth checkpoint before backup\n")); |
| 246 | + printf(_(" --stream use stream for save/restore WAL during backup\n")); |
| 247 | + /*printf(_(" --keep-data-generations=N keep GENERATION of full data backup\n")); |
| 248 | + printf(_(" --keep-data-days=DAY keep enough data backup to recover to DAY days age\n"));*/ |
| 249 | + printf(_(" --backup-pg-log start backup pg_log directory\n")); |
| 250 | + printf(_(" -S, --slot=SLOTNAME replication slot to use\n")); |
| 251 | + printf(_("\nRestore options:\n")); |
| 252 | + printf(_(" --time time stamp up to which recovery will proceed\n")); |
| 253 | + printf(_(" --xid transaction ID up to which recovery will proceed\n")); |
| 254 | + printf(_(" --inclusive whether we stop just after the recovery target\n")); |
| 255 | + printf(_(" --timeline recovering into a particular timeline\n")); |
| 256 | + printf(_("\nCatalog options:\n")); |
| 257 | + printf(_(" -a, --show-all show deleted backup too\n")); |
| 258 | + printf(_("\nDelete options:\n")); |
| 259 | + printf(_(" --wal remove unnecessary wal archives also\n")); |
| 260 | +} |
| 261 | + |
| 262 | +static void |
| 263 | +opt_backup_mode(pgut_option *opt, const char *arg) |
| 264 | +{ |
| 265 | + current.backup_mode = parse_backup_mode(arg); |
| 266 | +} |
0 commit comments