int reload(struct conf **confs, const char *conffile, bool firsttime) { if(!firsttime) logp("Reloading config\n"); if(confs_init(confs)) return -1; if(conf_load_global_only(conffile, confs)) return -1; umask(get_mode_t(confs[OPT_UMASK])); // This will turn on syslogging which could not be turned on before // conf_load. log_fzp_set(NULL, confs); #ifndef HAVE_WIN32 if(get_e_burp_mode(confs[OPT_BURP_MODE])==BURP_MODE_SERVER) setup_signals(); #endif // Do not try to change user or group after the first time. if(firsttime && chuser_and_or_chgrp( get_string(confs[OPT_USER]), get_string(confs[OPT_GROUP]))) return -1; return 0; }
static int conf_finalise_global_only(const char *conf_path, struct conf **confs) { int r=0; if(!get_string(confs[OPT_PORT])) conf_problem(conf_path, "port unset", &r); // Let the caller check the 'keep' value. if(!get_string(confs[OPT_SSL_KEY_PASSWORD]) && set_string(confs[OPT_SSL_KEY_PASSWORD], "")) r--; if(general_conf_checks(confs, conf_path, &r)) r--; switch(get_e_burp_mode(confs[OPT_BURP_MODE])) { case BURP_MODE_SERVER: if(server_conf_checks(confs, conf_path, &r)) r--; break; case BURP_MODE_CLIENT: if(client_conf_checks(confs, conf_path, &r)) r--; break; case BURP_MODE_UNSET: default: logp("%s: mode unset - need 'server' or 'client'\n", conf_path); r--; break; } return r; }
static int conf_set_from_global(struct conf **globalc, struct conf **cc) { int i=0; for(i=0; i<OPT_MAX; i++) { if(!(cc[i]->flags & CONF_FLAG_CC_OVERRIDE)) continue; switch(cc[i]->conf_type) { case CT_STRING: set_string(cc[i], get_string(globalc[i])); break; case CT_UINT: set_int(cc[i], get_int(globalc[i])); break; case CT_FLOAT: set_float(cc[i], get_float(globalc[i])); break; case CT_MODE_T: set_mode_t(cc[i], get_mode_t(globalc[i])); break; case CT_SSIZE_T: set_uint64_t(cc[i], get_uint64_t(globalc[i])); break; case CT_E_BURP_MODE: set_e_burp_mode(cc[i], get_e_burp_mode(globalc[i])); break; case CT_E_PROTOCOL: set_e_protocol(cc[i], get_e_protocol(globalc[i])); break; case CT_E_RECOVERY_METHOD: set_e_recovery_method(cc[i], get_e_recovery_method(globalc[i])); break; case CT_E_RSHASH: set_e_rshash(cc[i], get_e_rshash(globalc[i])); break; case CT_STRLIST: // Done later. break; case CT_CNTR: break; // No default so that there are warnings if anything // was missed. } } // If ssl_peer_cn is not set, default it to the client name. if(!get_string(globalc[OPT_SSL_PEER_CN]) && set_string(cc[OPT_SSL_PEER_CN], get_string(cc[OPT_CNAME]))) return -1; return 0; }
static #endif int conf_finalise(struct conf **c) { int s_script_notify=0; if(finalise_fstypes(c)) return -1; strlist_compile_regexes(get_strlist(c[OPT_INCREG])); strlist_compile_regexes(get_strlist(c[OPT_EXCREG])); set_max_ext(get_strlist(c[OPT_INCEXT])); set_max_ext(get_strlist(c[OPT_EXCEXT])); set_max_ext(get_strlist(c[OPT_EXCOM])); if(get_e_burp_mode(c[OPT_BURP_MODE])==BURP_MODE_CLIENT && finalise_glob(c)) return -1; if(finalise_incexc_dirs(c) || finalise_start_dirs(c)) return -1; if(finalise_keep_args(c)) return -1; if((s_script_notify=get_int(c[OPT_S_SCRIPT_NOTIFY]))) { set_int(c[OPT_S_SCRIPT_PRE_NOTIFY], s_script_notify); set_int(c[OPT_S_SCRIPT_POST_NOTIFY], s_script_notify); } // These override the specific pre/post script paths with the general // one. For example, if 'server_script' is set, its value is used for // 'server_script_pre' and 'server_script_post'. if(pre_post_override(c[OPT_B_SCRIPT], c[OPT_B_SCRIPT_PRE], c[OPT_B_SCRIPT_POST]) || pre_post_override(c[OPT_R_SCRIPT], c[OPT_R_SCRIPT_PRE], c[OPT_R_SCRIPT_POST]) || pre_post_override(c[OPT_S_SCRIPT], c[OPT_S_SCRIPT_PRE], c[OPT_S_SCRIPT_POST]) // And these do the same for the script arguments. || setup_script_arg_overrides(c[OPT_B_SCRIPT_ARG], c[OPT_B_SCRIPT_PRE_ARG], c[OPT_B_SCRIPT_POST_ARG]) || setup_script_arg_overrides(c[OPT_R_SCRIPT_ARG], c[OPT_R_SCRIPT_PRE_ARG], c[OPT_R_SCRIPT_POST_ARG]) || setup_script_arg_overrides(c[OPT_S_SCRIPT_ARG], c[OPT_S_SCRIPT_PRE_ARG], c[OPT_S_SCRIPT_POST_ARG])) return -1; // We are now done with these. Clear them, otherwise they interfere. set_string(c[OPT_S_SCRIPT], NULL); set_strlist(c[OPT_S_SCRIPT_ARG], NULL); return 0; }
static void check_default(struct conf **c, enum conf_opt o) { switch(o) { case OPT_BURP_MODE: fail_unless(get_e_burp_mode(c[o])==BURP_MODE_UNSET); break; case OPT_LOCKFILE: case OPT_PIDFILE: case OPT_ADDRESS: case OPT_PORT: case OPT_STATUS_ADDRESS: case OPT_STATUS_PORT: case OPT_SSL_CERT_CA: case OPT_SSL_CERT: case OPT_SSL_KEY: case OPT_SSL_KEY_PASSWORD: case OPT_SSL_PEER_CN: case OPT_SSL_CIPHERS: case OPT_SSL_DHFILE: case OPT_CA_CONF: case OPT_CA_NAME: case OPT_CA_SERVER_NAME: case OPT_CA_BURP_CA: case OPT_CA_CSR_DIR: case OPT_CA_CRL: case OPT_PEER_VERSION: case OPT_CLIENT_LOCKDIR: case OPT_MONITOR_LOGFILE: case OPT_CNAME: case OPT_PASSWORD: case OPT_PASSWD: case OPT_SERVER: case OPT_ENCRYPTION_PASSWORD: case OPT_AUTOUPGRADE_OS: case OPT_AUTOUPGRADE_DIR: case OPT_BACKUP: case OPT_BACKUP2: case OPT_RESTOREPREFIX: case OPT_RESTORE_SPOOL: case OPT_BROWSEFILE: case OPT_BROWSEDIR: case OPT_B_SCRIPT_PRE: case OPT_B_SCRIPT_POST: case OPT_R_SCRIPT_PRE: case OPT_R_SCRIPT_POST: case OPT_B_SCRIPT: case OPT_R_SCRIPT: case OPT_RESTORE_PATH: case OPT_ORIG_CLIENT: case OPT_CONFFILE: case OPT_USER: case OPT_GROUP: case OPT_DIRECTORY: case OPT_TIMESTAMP_FORMAT: case OPT_CLIENTCONFDIR: case OPT_S_SCRIPT_PRE: case OPT_S_SCRIPT_POST: case OPT_MANUAL_DELETE: case OPT_S_SCRIPT: case OPT_TIMER_SCRIPT: case OPT_N_SUCCESS_SCRIPT: case OPT_N_FAILURE_SCRIPT: case OPT_DEDUP_GROUP: case OPT_VSS_DRIVES: case OPT_REGEX: case OPT_RESTORE_CLIENT: fail_unless(get_string(c[o])==NULL); break; case OPT_RATELIMIT: fail_unless(get_float(c[o])==0); break; case OPT_CLIENT_IS_WINDOWS: case OPT_RANDOMISE: case OPT_B_SCRIPT_POST_RUN_ON_FAIL: case OPT_R_SCRIPT_POST_RUN_ON_FAIL: case OPT_SEND_CLIENT_CNTR: case OPT_BREAKPOINT: case OPT_SYSLOG: case OPT_PROGRESS_COUNTER: case OPT_MONITOR_BROWSE_CACHE: case OPT_S_SCRIPT_PRE_NOTIFY: case OPT_S_SCRIPT_POST_RUN_ON_FAIL: case OPT_S_SCRIPT_POST_NOTIFY: case OPT_S_SCRIPT_NOTIFY: case OPT_HARDLINKED_ARCHIVE: case OPT_N_SUCCESS_WARNINGS_ONLY: case OPT_N_SUCCESS_CHANGES_ONLY: case OPT_CROSS_ALL_FILESYSTEMS: case OPT_READ_ALL_FIFOS: case OPT_READ_ALL_BLOCKDEVS: case OPT_SPLIT_VSS: case OPT_STRIP_VSS: case OPT_ATIME: case OPT_SCAN_PROBLEM_RAISES_ERROR: case OPT_OVERWRITE: case OPT_STRIP: case OPT_MESSAGE: case OPT_CA_CRL_CHECK: fail_unless(get_int(c[o])==0); break; case OPT_DAEMON: case OPT_STDOUT: case OPT_FORK: case OPT_ENABLED: case OPT_DIRECTORY_TREE: case OPT_PASSWORD_CHECK: case OPT_LIBRSYNC: case OPT_VERSION_WARN: case OPT_PATH_LENGTH_WARN: case OPT_CLIENT_CAN_DELETE: case OPT_CLIENT_CAN_DIFF: case OPT_CLIENT_CAN_FORCE_BACKUP: case OPT_CLIENT_CAN_LIST: case OPT_CLIENT_CAN_RESTORE: case OPT_CLIENT_CAN_VERIFY: case OPT_SERVER_CAN_RESTORE: case OPT_SERVER_CAN_OVERRIDE_INCLUDES: case OPT_B_SCRIPT_RESERVED_ARGS: case OPT_R_SCRIPT_RESERVED_ARGS: case OPT_GLOB_AFTER_SCRIPT_PRE: case OPT_ACL: case OPT_XATTR: fail_unless(get_int(c[o])==1); break; case OPT_NETWORK_TIMEOUT: fail_unless(get_int(c[o])==60*60*2); break; case OPT_SSL_COMPRESSION: case OPT_MAX_CHILDREN: case OPT_MAX_STATUS_CHILDREN: fail_unless(get_int(c[o])==5); break; case OPT_COMPRESSION: fail_unless(get_int(c[o])==9); break; case OPT_MAX_STORAGE_SUBDIRS: fail_unless(get_int(c[o])==30000); break; case OPT_MAX_HARDLINKS: fail_unless(get_int(c[o])==10000); break; case OPT_UMASK: fail_unless(get_mode_t(c[o])==0022); break; case OPT_STARTDIR: case OPT_B_SCRIPT_PRE_ARG: case OPT_B_SCRIPT_POST_ARG: case OPT_R_SCRIPT_PRE_ARG: case OPT_R_SCRIPT_POST_ARG: case OPT_B_SCRIPT_ARG: case OPT_R_SCRIPT_ARG: case OPT_S_SCRIPT_PRE_ARG: case OPT_S_SCRIPT_POST_ARG: case OPT_S_SCRIPT_ARG: case OPT_TIMER_ARG: case OPT_N_SUCCESS_ARG: case OPT_N_FAILURE_ARG: case OPT_RESTORE_CLIENTS: case OPT_KEEP: case OPT_INCEXCDIR: case OPT_INCLUDE: case OPT_EXCLUDE: case OPT_FSCHGDIR: case OPT_NOBACKUP: case OPT_INCEXT: case OPT_EXCEXT: case OPT_INCREG: case OPT_EXCREG: case OPT_EXCFS: case OPT_EXCOM: case OPT_INCGLOB: case OPT_FIFOS: case OPT_BLOCKDEVS: case OPT_LABEL: fail_unless(get_strlist(c[o])==NULL); break; case OPT_PROTOCOL: fail_unless(get_e_protocol(c[o])==PROTO_AUTO); break; case OPT_HARD_QUOTA: case OPT_SOFT_QUOTA: case OPT_MIN_FILE_SIZE: case OPT_MAX_FILE_SIZE: fail_unless(get_uint64_t(c[o])==0); break; case OPT_WORKING_DIR_RECOVERY_METHOD: fail_unless(get_e_recovery_method(c[o])== RECOVERY_METHOD_DELETE); break; case OPT_RSHASH: fail_unless(get_e_rshash(c[o])==RSHASH_UNSET); break; case OPT_CNTR: fail_unless(get_cntr(c)==NULL); break; case OPT_MAX: break; // No default, so we get compiler warnings if something was // missed. } }
int run_bedup(int argc, char *argv[]) { int i=1; int ret=0; int option=0; int nonburp=0; unsigned int maxlinks=DEF_MAX_LINKS; char *groups=NULL; char ext[16]=""; int givenconfigfile=0; const char *configfile=NULL; configfile=get_config_path(); snprintf(ext, sizeof(ext), ".bedup.%d", getpid()); while((option=getopt(argc, argv, "c:dg:hlm:nvV?"))!=-1) { switch(option) { case 'c': configfile=optarg; givenconfigfile=1; break; case 'd': deletedups=1; break; case 'g': groups=optarg; break; case 'l': makelinks=1; break; case 'm': maxlinks=atoi(optarg); break; case 'n': nonburp=1; break; case 'V': printf("%s-%s\n", prog, VERSION); return 0; case 'v': verbose=1; break; case 'h': case '?': return usage(); } } if(nonburp && givenconfigfile) { logp("-n and -c options are mutually exclusive\n"); return 1; } if(nonburp && groups) { logp("-n and -g options are mutually exclusive\n"); return 1; } if(!nonburp && maxlinks!=DEF_MAX_LINKS) { logp("-m option is specified via the configuration file in burp mode (max_hardlinks=)\n"); return 1; } if(deletedups && makelinks) { logp("-d and -l options are mutually exclusive\n"); return 1; } if(deletedups && !nonburp) { logp("-d option requires -n option\n"); return 1; } if(optind>=argc) { if(nonburp) { logp("No directories found after options\n"); return 1; } } else { if(!nonburp) { logp("Do not specify extra arguments.\n"); return 1; } } if(maxlinks<2) { logp("The argument to -m needs to be greater than 1.\n"); return 1; } if(nonburp) { // Read directories from command line. for(i=optind; i<argc; i++) { // Strip trailing slashes, for tidiness. if(argv[i][strlen(argv[i])-1]=='/') argv[i][strlen(argv[i])-1]='\0'; if(process_dir("", argv[i], ext, maxlinks, 0 /* not burp mode */, 0 /* level */)) { ret=1; break; } } } else { struct conf **globalcs=NULL; struct strlist *grouplist=NULL; struct lock *globallock=NULL; if(groups) { char *tok=NULL; if((tok=strtok(groups, ",\n"))) { do { if(strlist_add(&grouplist, tok, 1)) { log_out_of_memory(__func__); return -1; } } while((tok=strtok(NULL, ",\n"))); } if(!grouplist) { logp("unable to read list of groups\n"); return -1; } } // Read directories from config files, and get locks. if(!(globalcs=confs_alloc())) return -1; if(confs_init(globalcs)) return -1; if(conf_load_global_only(configfile, globalcs)) return 1; if(get_e_burp_mode(globalcs[OPT_BURP_MODE])!=BURP_MODE_SERVER) { logp("%s is not a server config file\n", configfile); confs_free(&globalcs); return 1; } logp("Dedup clients from %s\n", get_string(globalcs[OPT_CLIENTCONFDIR])); maxlinks=get_int(globalcs[OPT_MAX_HARDLINKS]); if(grouplist) { struct strlist *g=NULL; logp("in dedup groups:\n"); for(g=grouplist; g; g=g->next) logp("%s\n", g->path); } else { char *lockpath=NULL; // Only get the global lock when doing a global run. // If you are doing individual groups, you are likely // to want to do many different dedup jobs and a // global lock would get in the way. if(!(lockpath=prepend( get_string(globalcs[OPT_LOCKFILE]), ".bedup", "")) || !(globallock=lock_alloc_and_init(lockpath))) return 1; lock_get(globallock); if(globallock->status!=GET_LOCK_GOT) { logp("Could not get lock %s (%d)\n", lockpath, globallock->status); free_w(&lockpath); return 1; } logp("Got %s\n", lockpath); } ret=iterate_over_clients(globalcs, grouplist, ext, maxlinks); confs_free(&globalcs); lock_release(globallock); lock_free(&globallock); strlists_free(&grouplist); } if(!nonburp) { logp("%d client storages scanned\n", ccount); } logp("%llu duplicate %s found\n", count, count==1?"file":"files"); logp("%llu bytes %s%s\n", savedbytes, (makelinks || deletedups)?"saved":"saveable", bytes_to_human(savedbytes)); return ret; }
static #endif int real_main(int argc, char *argv[]) { int ret=1; int option=0; int daemon=1; int forking=1; int strip=0; int randomise=0; struct lock *lock=NULL; struct conf **confs=NULL; int forceoverwrite=0; enum action act=ACTION_LIST; const char *backup=NULL; const char *backup2=NULL; char *restoreprefix=NULL; char *stripfrompath=NULL; const char *regex=NULL; const char *browsefile=NULL; char *browsedir=NULL; const char *conffile=get_conf_path(); const char *orig_client=NULL; const char *logfile=NULL; // The orig_client is the original client that the normal client // would like to restore from. #ifndef HAVE_WIN32 int generate_ca_only=0; #endif int vss_restore=1; int test_confs=0; enum burp_mode mode; log_init(argv[0]); #ifndef HAVE_WIN32 if(!strcmp(prog, "bedup")) return run_bedup(argc, argv); if(!strcmp(prog, "bsigs")) return run_bsigs(argc, argv); #endif while((option=getopt(argc, argv, "a:b:c:C:d:fFghil:nq:Qr:s:tvxjz:?"))!=-1) { switch(option) { case 'a': if(parse_action(&act, optarg)) goto end; break; case 'b': // The diff command may have two backups // specified. if(!backup2 && backup) backup2=optarg; if(!backup) backup=optarg; break; case 'c': conffile=optarg; break; case 'C': orig_client=optarg; break; case 'd': restoreprefix=optarg; // for restores browsedir=optarg; // for lists break; case 'f': forceoverwrite=1; break; case 'F': daemon=0; break; case 'g': #ifndef HAVE_WIN32 generate_ca_only=1; #endif break; case 'i': cmd_print_all(); ret=0; goto end; case 'l': logfile=optarg; break; case 'n': forking=0; break; case 'q': randomise=atoi(optarg); break; case 'Q': log_force_quiet(); break; case 'r': regex=optarg; break; case 's': strip=atoi(optarg); break; case 'v': printf("%s-%s\n", progname(), VERSION); ret=0; goto end; case 'x': vss_restore=0; break; case 't': test_confs=1; break; case 'z': browsefile=optarg; break; case 'h': case '?': default: usage(); goto end; } } if(optind<argc) { usage(); goto end; } if(act==ACTION_MONITOR) { // Try to output everything in JSON. log_set_json(1); #ifndef HAVE_WIN32 // Need to do this so that processes reading stdout get the // result of the printfs of logp straight away. setlinebuf(stdout); #endif } if(!(confs=confs_alloc())) goto end; if(reload(confs, conffile, 1)) goto end; // Dry run to test config file syntax. if(test_confs) { ret=run_test_confs(confs, orig_client); goto end; } if(!backup) switch(act) { case ACTION_DELETE: logp("No backup specified for deletion.\n"); goto end; case ACTION_RESTORE: case ACTION_VERIFY: case ACTION_DIFF: case ACTION_DIFF_LONG: logp("No backup specified. Using the most recent.\n"); backup="0"; default: break; } if(!backup2) switch(act) { case ACTION_DIFF: case ACTION_DIFF_LONG: logp("No second backup specified. Using file system scan.\n"); backup2="n"; // For 'next'. default: break; } // The logfile option is only used for the status client stuff. if(logfile && (act!=ACTION_STATUS && act!=ACTION_STATUS_SNAPSHOT)) logp("-l <logfile> option obsoleted\n"); if(orig_client && *orig_client && set_string(confs[OPT_ORIG_CLIENT], orig_client)) goto end; // The random delay needs to happen before the lock is got, otherwise // you would never be able to use burp by hand. if(randomise) set_int(confs[OPT_RANDOMISE], randomise); mode=get_e_burp_mode(confs[OPT_BURP_MODE]); if(mode==BURP_MODE_CLIENT && (act==ACTION_BACKUP_TIMED || act==ACTION_TIMER_CHECK)) random_delay(confs); if(mode==BURP_MODE_SERVER && act==ACTION_CHAMP_CHOOSER) { // These server modes need to run without getting the lock. } else if(mode==BURP_MODE_CLIENT && (act==ACTION_LIST || act==ACTION_LIST_LONG || act==ACTION_DIFF || act==ACTION_DIFF_LONG || act==ACTION_STATUS || act==ACTION_STATUS_SNAPSHOT || act==ACTION_MONITOR)) { // These client modes need to run without getting the lock. } else { const char *lockfile=confs_get_lockfile(confs); if(!(lock=lock_alloc_and_init(lockfile))) goto end; lock_get(lock); switch(lock->status) { case GET_LOCK_GOT: break; case GET_LOCK_NOT_GOT: logp("Could not get lockfile.\n"); logp("Another process is probably running,\n"); goto end; case GET_LOCK_ERROR: default: logp("Could not get lockfile.\n"); logp("Maybe you do not have permissions to write to %s.\n", lockfile); goto end; } } set_int(confs[OPT_OVERWRITE], forceoverwrite); set_int(confs[OPT_STRIP], strip); set_int(confs[OPT_FORK], forking); set_int(confs[OPT_DAEMON], daemon); strip_trailing_slashes(&restoreprefix); strip_trailing_slashes(&browsedir); if(replace_conf_str(confs[OPT_BACKUP], backup) || replace_conf_str(confs[OPT_BACKUP2], backup2) || replace_conf_str(confs[OPT_RESTOREPREFIX], restoreprefix) || replace_conf_str(confs[OPT_STRIP_FROM_PATH], stripfrompath) || replace_conf_str(confs[OPT_REGEX], regex) || replace_conf_str(confs[OPT_BROWSEFILE], browsefile) || replace_conf_str(confs[OPT_BROWSEDIR], browsedir) || replace_conf_str(confs[OPT_MONITOR_LOGFILE], logfile)) goto end; base64_init(); hexmap_init(); if(mode==BURP_MODE_SERVER) { #ifdef HAVE_WIN32 logp("Sorry, server mode is not implemented for Windows.\n"); #else ret=server_modes(act, conffile, lock, generate_ca_only, confs); #endif } else { ret=client(confs, act, vss_restore); } end: lock_release(lock); lock_free(&lock); confs_free(&confs); return ret; }