|
| 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 | +constchar*PROGRAM_VERSION="1.0"; |
| 19 | +constchar*PROGRAM_URL="https://github.com/postgrespro/pg_probackup"; |
| 20 | +constchar*PROGRAM_EMAIL="https://github.com/postgrespro/pg_probackup/issues"; |
| 21 | + |
| 22 | +/* path configuration */ |
| 23 | +char*backup_path; |
| 24 | +char*pgdata; |
| 25 | +chararclog_path[MAXPGPATH]; |
| 26 | + |
| 27 | +/* common configuration */ |
| 28 | +boolcheck= false; |
| 29 | + |
| 30 | +/* directory configuration */ |
| 31 | +pgBackupcurrent; |
| 32 | + |
| 33 | +/* backup configuration */ |
| 34 | +staticboolsmooth_checkpoint; |
| 35 | +staticintkeep_data_generations=KEEP_INFINITE; |
| 36 | +staticintkeep_data_days=KEEP_INFINITE; |
| 37 | +intnum_threads=1; |
| 38 | +boolstream_wal= false; |
| 39 | +boolfrom_replica= false; |
| 40 | +staticboolbackup_logs= false; |
| 41 | +boolprogress= false; |
| 42 | +booldelete_wal= false; |
| 43 | + |
| 44 | +/* restore configuration */ |
| 45 | +staticchar*target_time; |
| 46 | +staticchar*target_xid; |
| 47 | +staticchar*target_inclusive; |
| 48 | +staticTimeLineIDtarget_tli; |
| 49 | + |
| 50 | +/* show configuration */ |
| 51 | +staticboolshow_all= false; |
| 52 | + |
| 53 | +staticvoidopt_backup_mode(pgut_option*opt,constchar*arg); |
| 54 | + |
| 55 | +staticpgut_optionoptions[]= |
| 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(intargc,char*argv[]) |
| 90 | +{ |
| 91 | +constchar*cmd=NULL; |
| 92 | +constchar*backup_id_string=NULL; |
| 93 | +time_tbackup_id=0; |
| 94 | +inti; |
| 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 | +}elseif (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 | +return1; |
| 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 | +charpath[MAXPGPATH]; |
| 141 | +/* Check if backup_path is directory. */ |
| 142 | +structstatstat_buf; |
| 143 | +intrc=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 | +returndo_init(); |
| 189 | +elseif (pg_strcasecmp(cmd,"backup")==0) |
| 190 | +{ |
| 191 | +pgBackupOptionbkupopt; |
| 192 | +intres; |
| 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 | +returnres; |
| 201 | + |
| 202 | +do_validate(current.start_time); |
| 203 | +} |
| 204 | +elseif (pg_strcasecmp(cmd,"restore")==0) |
| 205 | +returndo_restore(backup_id,target_time,target_xid, |
| 206 | +target_inclusive,target_tli); |
| 207 | +elseif (pg_strcasecmp(cmd,"show")==0) |
| 208 | +returndo_show(backup_id,show_all); |
| 209 | +elseif (pg_strcasecmp(cmd,"validate")==0) |
| 210 | +returndo_validate(backup_id); |
| 211 | +elseif (pg_strcasecmp(cmd,"delete")==0) |
| 212 | +returndo_delete(backup_id); |
| 213 | +elseif (pg_strcasecmp(cmd,"delwal")==0) |
| 214 | +returndo_deletewal(backup_id, true); |
| 215 | +else |
| 216 | +elog(ERROR,"invalid command \"%s\"",cmd); |
| 217 | + |
| 218 | +return0; |
| 219 | +} |
| 220 | + |
| 221 | +void |
| 222 | +pgut_help(booldetails) |
| 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 | +staticvoid |
| 263 | +opt_backup_mode(pgut_option*opt,constchar*arg) |
| 264 | +{ |
| 265 | +current.backup_mode=parse_backup_mode(arg); |
| 266 | +} |