static void update_tapelist( taper_state_t *state) { char *tapelist_name = NULL; char *tapelist_name_old = NULL; tape_t *tp; char *comment = NULL; tapelist_name = config_dir_relative(getconf_str(CNF_TAPELIST)); if (state->cur_tape == 0) { tapelist_name_old = stralloc2(tapelist_name, ".yesterday"); } else { char cur_str[NUM_STR_SIZE]; g_snprintf(cur_str, SIZEOF(cur_str), "%d", state->cur_tape - 1); tapelist_name_old = vstralloc(tapelist_name, ".today.", cur_str, NULL); } if (read_tapelist(tapelist_name) != 0) { log_add(L_INFO, "pid-done %ld", (long)getpid()); error("could not load tapelist \"%s\"", tapelist_name); /*NOTREACHED*/ } /* make a copy of the tapelist file */ if (write_tapelist(tapelist_name_old)) { log_add(L_INFO, "pid-done %ld", (long)getpid()); error("could not write tapelist: %s", strerror(errno)); /*NOTREACHED*/ } amfree(tapelist_name_old); /* get a copy of the comment, before freeing the old record */ tp = lookup_tapelabel(state->device->volume_label); if (tp && tp->comment) comment = stralloc(tp->comment); /* edit the tapelist and rewrite it */ remove_tapelabel(state->device->volume_label); add_tapelabel(state->driver_start_time, state->device->volume_label, comment); if (write_tapelist(tapelist_name)) { error("could not write tapelist: %s", strerror(errno)); /*NOTREACHED*/ } amfree(tapelist_name); amfree(comment); }
int main( int argc, char ** argv) { GList *dlist; GList *dlist1; disk_t *diskp; disklist_t diskl; size_t i; char *conf_diskfile; char *conf_tapelist; char *conf_indexdir; find_result_t *output_find; time_t tmp_time; int amtrmidx_debug = 0; config_overrides_t *cfg_ovr = NULL; gboolean compress_index; gboolean sort_index; char *lock_file; file_lock *lock_index; if (argc > 1 && argv[1] && g_str_equal(argv[1], "--version")) { printf("amtrmidx-%s\n", VERSION); return (0); } /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); safe_cd(); set_pname("amtrmidx"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); dbopen(DBG_SUBDIR_SERVER); dbprintf(_("%s: version %s\n"), argv[0], VERSION); cfg_ovr = extract_commandline_config_overrides(&argc, &argv); if (argc > 1 && g_str_equal(argv[1], "-t")) { amtrmidx_debug = 1; argc--; argv++; } if (argc < 2) { g_fprintf(stderr, _("Usage: %s [-t] <config> [-o configoption]*\n"), argv[0]); return 1; } set_config_overrides(cfg_ovr); config_init_with_global(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, argv[1]); conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE)); read_diskfile(conf_diskfile, &diskl); amfree(conf_diskfile); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } check_running_as(RUNNING_AS_DUMPUSER); dbrename(get_config_name(), DBG_SUBDIR_SERVER); conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST)); if(read_tapelist(conf_tapelist)) { error(_("could not load tapelist \"%s\""), conf_tapelist); /*NOTREACHED*/ } amfree(conf_tapelist); compress_index = getconf_boolean(CNF_COMPRESS_INDEX); sort_index = getconf_boolean(CNF_SORT_INDEX); output_find = find_dump(&diskl); conf_indexdir = config_dir_relative(getconf_str(CNF_INDEXDIR)); /* take a lock file to prevent concurent trim */ lock_file = g_strdup_printf("%s/%s", conf_indexdir, "lock"); lock_index = file_lock_new(lock_file); if (file_lock_lock_wr(lock_index) != 0) goto lock_failed; /* now go through the list of disks and find which have indexes */ time(&tmp_time); tmp_time -= 7*24*60*60; /* back one week */ for (dlist = diskl.head; dlist != NULL; dlist = dlist->next) { diskp = dlist->data; if (diskp->index) { char *indexdir, *qindexdir; DIR *d; struct dirent *f; char **names; size_t name_length; size_t name_count; char *host; char *disk, *qdisk; size_t len_date; disk_t *dp; GSList *matching_dp = NULL; /* get listing of indices, newest first */ host = sanitise_filename(diskp->host->hostname); disk = sanitise_filename(diskp->name); qdisk = quote_string(diskp->name); indexdir = g_strjoin(NULL, conf_indexdir, "/", host, "/", disk, "/", NULL); qindexdir = quote_string(indexdir); /* find all dles that use the same indexdir */ for (dlist1 = diskl.head; dlist1 != NULL; dlist1 = dlist1->next) { char *dp_host, *dp_disk; dp = dlist1->data; dp_host = sanitise_filename(dp->host->hostname); dp_disk = sanitise_filename(dp->name); if (g_str_equal(host, dp_host) && g_str_equal(disk, dp_disk)) { matching_dp = g_slist_append(matching_dp, dp); } amfree(dp_host); amfree(dp_disk); } dbprintf("%s %s -> %s\n", diskp->host->hostname, qdisk, qindexdir); amfree(qdisk); if ((d = opendir(indexdir)) == NULL) { dbprintf(_("could not open index directory %s\n"), qindexdir); amfree(host); amfree(disk); amfree(indexdir); amfree(qindexdir); g_slist_free(matching_dp); continue; } name_length = 100; names = (char **)g_malloc(name_length * sizeof(char *)); name_count = 0; while ((f = readdir(d)) != NULL) { size_t l; if(is_dot_or_dotdot(f->d_name)) { continue; } for(i = 0; i < sizeof("YYYYMMDDHHMMSS")-1; i++) { if(! isdigit((int)(f->d_name[i]))) { break; } } len_date = i; /* len_date=8 for YYYYMMDD */ /* len_date=14 for YYYYMMDDHHMMSS */ if((len_date != 8 && len_date != 14) || f->d_name[len_date] != '_' || ! isdigit((int)(f->d_name[len_date+1]))) { continue; /* not an index file */ } /* * Clear out old index temp files. */ l = strlen(f->d_name) - (sizeof(".tmp")-1); if ((l > (len_date + 1)) && (g_str_equal(f->d_name + l, ".tmp"))) { struct stat sbuf; char *path, *qpath; path = g_strconcat(indexdir, f->d_name, NULL); qpath = quote_string(path); if(lstat(path, &sbuf) != -1 && ((sbuf.st_mode & S_IFMT) == S_IFREG) && ((time_t)sbuf.st_mtime < tmp_time)) { dbprintf("rm %s\n", qpath); if(amtrmidx_debug == 0 && unlink(path) == -1) { dbprintf(_("Error removing %s: %s\n"), qpath, strerror(errno)); } } amfree(qpath); amfree(path); continue; } if(name_count >= name_length) { char **new_names; new_names = g_malloc((name_length * 2) * sizeof(char *)); memcpy(new_names, names, name_length * sizeof(char *)); amfree(names); names = new_names; name_length *= 2; } names[name_count++] = g_strdup(f->d_name); } closedir(d); qsort(names, name_count, sizeof(char *), sort_by_name_reversed); /* * Search for the first full dump past the minimum number * of index files to keep. */ for(i = 0; i < name_count; i++) { char *datestamp; int level; size_t len_date; int matching = 0; GSList *mdp; for(len_date = 0; len_date < sizeof("YYYYMMDDHHMMSS")-1; len_date++) { if(! isdigit((int)(names[i][len_date]))) { break; } } datestamp = g_strdup(names[i]); datestamp[len_date] = '\0'; if (sscanf(&names[i][len_date+1], "%d", &level) != 1) level = 0; for (mdp = matching_dp; mdp != NULL; mdp = mdp->next) { dp = mdp->data; if (dump_exist(output_find, dp->host->hostname, dp->name, datestamp, level)) { matching = 1; } } if (!matching) { struct stat sbuf; char *path, *qpath; path = g_strconcat(indexdir, names[i], NULL); qpath = quote_string(path); if(lstat(path, &sbuf) != -1 && ((sbuf.st_mode & S_IFMT) == S_IFREG) && ((time_t)sbuf.st_mtime < tmp_time)) { dbprintf("rm %s\n", qpath); if(amtrmidx_debug == 0 && unlink(path) == -1) { dbprintf(_("Error removing %s: %s\n"), qpath, strerror(errno)); } } amfree(qpath); amfree(path); } /* Did it require un/compression and/or sorting */ { char *orig_name = getindexfname(host, disk, datestamp, level); char *sorted_name = getindex_sorted_fname(host, disk, datestamp, level); char *sorted_gz_name = getindex_sorted_gz_fname(host, disk, datestamp, level); char *unsorted_name = getindex_unsorted_fname(host, disk, datestamp, level); char *unsorted_gz_name = getindex_unsorted_gz_fname(host, disk, datestamp, level); gboolean orig_exist = FALSE; gboolean sorted_exist = FALSE; gboolean sorted_gz_exist = FALSE; gboolean unsorted_exist = FALSE; gboolean unsorted_gz_exist = FALSE; int fd; int uncompress_err_fd = -1; int sort_err_fd = -1; int compress_err_fd = -1; pid_t uncompress_pid = -1; pid_t sort_pid = -1; pid_t compress_pid = -1; orig_exist = file_exists(orig_name); sorted_exist = file_exists(sorted_name); sorted_gz_exist = file_exists(sorted_gz_name); unsorted_exist = file_exists(unsorted_name); unsorted_gz_exist = file_exists(unsorted_gz_name); if (sort_index && compress_index) { if (!sorted_gz_exist) { if (sorted_exist) { // COMPRESS compress_pid = run_compress(-1, NULL, &compress_err_fd, sorted_name, sorted_gz_name); unlink(sorted_name); } else if (unsorted_exist) { // SORT AND COMPRESS sort_pid = run_sort(-1, &fd, &sort_err_fd, unsorted_name, NULL); compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name); unlink(unsorted_name); } else if (unsorted_gz_exist) { // UNCOMPRESS SORT AND COMPRESS uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, unsorted_gz_name, NULL); sort_pid = run_sort(fd, &fd, &sort_err_fd, NULL, NULL); compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name); unlink(unsorted_gz_name); } else if (orig_exist) { // UNCOMPRESS SORT AND COMPRESS uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, orig_name, NULL); sort_pid = run_sort(fd, &fd, &sort_err_fd, NULL, NULL); compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name); unlink(orig_name); } } else { if (sorted_exist) { unlink(sorted_name); } if (unsorted_exist) { unlink(unsorted_name); } if (unsorted_gz_exist) { unlink(unsorted_gz_name); } } } else if (sort_index && !compress_index) { if (!sorted_exist) { if (sorted_gz_exist) { // UNCOMPRESS uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, sorted_gz_name, sorted_name); unlink(sorted_gz_name); } else if (unsorted_exist) { // SORT sort_pid = run_sort(-1, NULL, &sort_err_fd, unsorted_name, sorted_name); unlink(unsorted_name); } else if (unsorted_gz_exist) { // UNCOMPRESS AND SORT uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, unsorted_gz_name, NULL); sort_pid = run_sort(fd, NULL, &sort_err_fd, NULL, sorted_name); unlink(unsorted_gz_name); } else if (orig_exist) { // UNCOMPRESS AND SORT uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, orig_name, NULL); sort_pid = run_sort(fd, NULL, &sort_err_fd, NULL, sorted_name); unlink(orig_name); } } else { if (sorted_gz_exist) { unlink(sorted_gz_name); } if (unsorted_exist) { unlink(unsorted_name); } if (unsorted_gz_exist) { unlink(unsorted_gz_name); } } } else if (!sort_index && compress_index) { if (!sorted_gz_exist && !unsorted_gz_exist) { if (sorted_exist) { // COMPRESS sorted compress_pid = run_compress(-1, NULL, &compress_err_fd, sorted_name, sorted_gz_name); unlink(sorted_name); } else if (unsorted_exist) { // COMPRESS unsorted compress_pid = run_compress(-1, NULL, &compress_err_fd, unsorted_name, unsorted_gz_name); unlink(unsorted_name); } else if (orig_exist) { // RENAME orig rename(orig_name, unsorted_gz_name); } } else { if (sorted_exist) { unlink(sorted_name); } if (unsorted_exist) { unlink(unsorted_name); } if (sorted_gz_exist && unsorted_gz_exist) { unlink(unsorted_gz_name); } } } else if (!sort_index && !compress_index) { if (!sorted_exist && !unsorted_exist) { if (sorted_gz_exist) { // UNCOMPRESS sorted uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, sorted_gz_name, sorted_name); unlink(sorted_gz_name); } else if (unsorted_gz_exist) { // UNCOMPRESS unsorted uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, unsorted_gz_name, unsorted_name); unlink(unsorted_gz_name); } else if (orig_exist) { // UNCOMPRESS orig uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, orig_name, unsorted_name); unlink(orig_name); } } else { if (sorted_gz_exist) { unlink(sorted_gz_name); } if (unsorted_gz_exist) { unlink(unsorted_gz_name); } if (sorted_exist && unsorted_exist) { unlink(unsorted_name); } } } if (uncompress_pid != -1) wait_process(uncompress_pid, uncompress_err_fd, "uncompress"); if (sort_pid != -1) wait_process(sort_pid, sort_err_fd, "sort"); if (compress_pid != -1) wait_process(compress_pid, compress_err_fd, "compress"); g_free(orig_name); g_free(sorted_name); g_free(sorted_gz_name); g_free(unsorted_name); g_free(unsorted_gz_name); } amfree(datestamp); amfree(names[i]); } g_slist_free(matching_dp); amfree(names); amfree(host); amfree(disk); amfree(indexdir); amfree(qindexdir); } } file_lock_unlock(lock_index); lock_failed: file_lock_free(lock_index); amfree(conf_indexdir); amfree(lock_file); free_find_result(&output_find); clear_tapelist(); free_disklist(&diskl); unload_disklist(); dbclose(); return 0; }
int main(int argc, char ** argv) { char * tapelist_name; taper_state_t state; config_overwrites_t *cfg_ovr = NULL; char *cfg_opt = NULL; /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); set_pname("taper"); dbopen("server"); device_api_init(); init_taper_state(&state); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); g_fprintf(stderr, _("%s: pid %ld executable %s version %s\n"), get_pname(), (long) getpid(), argv[0], version()); dbprintf(_("%s: pid %ld executable %s version %s\n"), get_pname(), (long) getpid(), argv[0], version()); /* Process options */ cfg_ovr = extract_commandline_config_overwrites(&argc, &argv); if(argc > 2) { error("Too many arguments!\n"); g_assert_not_reached(); } if (argc > 1) cfg_opt = argv[1]; config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt); apply_config_overwrites(cfg_ovr); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } safe_cd(); add_amanda_log_handler(amanda_log_stderr); add_amanda_log_handler(amanda_log_trace_log); check_running_as(RUNNING_AS_DUMPUSER); dbrename(get_config_name(), DBG_SUBDIR_SERVER); log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid()); tapelist_name = config_dir_relative(getconf_str(CNF_TAPELIST)); if (read_tapelist(tapelist_name) != 0) { log_add(L_INFO, "pid-done %ld", (long)getpid()); error("could not load tapelist \"%s\"", tapelist_name); g_assert_not_reached(); } amfree(tapelist_name); state.have_changer = changer_init(); if (state.have_changer < 0) { log_add(L_INFO, "pid-done %ld", (long)getpid()); error("changer initialization failed: %s", strerror(errno)); g_assert_not_reached(); } state.next_tape_label = NULL; state.next_tape_device = NULL; state.cur_tape = 0; if (!find_first_tape(&state)) { log_add(L_INFO, "pid-done %ld", (long)getpid()); return EXIT_SUCCESS; } while (process_driver_command(&state)); log_add(L_INFO, "pid-done %ld", (long)getpid()); return EXIT_SUCCESS; }
int main( int argc, char ** argv) { int foreground; int batch; int redirect; char **datearg = NULL; int nb_datearg = 0; char *conf_diskfile; char *conf_tapelist; char *conf_logfile; int conf_usetimestamps; disklist_t diskq; disk_t *dp; pid_t pid; pid_t driver_pid, reporter_pid; amwait_t exitcode; int opt; GSList *holding_list=NULL, *holding_file; int driver_pipe[2]; char date_string[100]; char date_string_standard[100]; time_t today; char *errstr; struct tm *tm; char *tapedev; char *tpchanger; char *qdisk, *qhname; GSList *datestamp_list = NULL; config_overrides_t *cfg_ovr; char **config_options; find_result_t *holding_files; disklist_t holding_disklist = { NULL, NULL }; /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); safe_cd(); set_pname("amflush"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); dbopen(DBG_SUBDIR_SERVER); add_amanda_log_handler(amanda_log_stderr); foreground = 0; batch = 0; redirect = 1; /* process arguments */ cfg_ovr = new_config_overrides(argc/2); while((opt = getopt(argc, argv, "bfso:D:")) != EOF) { switch(opt) { case 'b': batch = 1; break; case 'f': foreground = 1; break; case 's': redirect = 0; break; case 'o': add_config_override_opt(cfg_ovr, optarg); break; case 'D': if (datearg == NULL) datearg = g_malloc(21*sizeof(char *)); if(nb_datearg == 20) { g_fprintf(stderr,_("maximum of 20 -D arguments.\n")); exit(1); } datearg[nb_datearg++] = g_strdup(optarg); datearg[nb_datearg] = NULL; break; } } argc -= optind, argv += optind; if(!foreground && !redirect) { g_fprintf(stderr,_("Can't redirect to stdout/stderr if not in forground.\n")); exit(1); } if(argc < 1) { error(_("Usage: amflush [-b] [-f] [-s] [-D date]* [-o configoption]* <confdir> [host [disk]* ]*")); /*NOTREACHED*/ } set_config_overrides(cfg_ovr); config_init(CONFIG_INIT_EXPLICIT_NAME, argv[0]); conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE)); read_diskfile(conf_diskfile, &diskq); amfree(conf_diskfile); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } check_running_as(RUNNING_AS_DUMPUSER); dbrename(get_config_name(), DBG_SUBDIR_SERVER); /* load DLEs from the holding disk, in case there's anything to flush there */ search_holding_disk(&holding_files, &holding_disklist); /* note that the dumps are added to the global disklist, so we need not * consult holding_files or holding_disklist after this. The holding-only * dumps will be filtered properly by match_disklist, setting the dp->todo * flag appropriately. */ errstr = match_disklist(&diskq, argc-1, argv+1); if (errstr) { g_printf(_("%s"),errstr); amfree(errstr); } conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST)); if(read_tapelist(conf_tapelist)) { error(_("could not load tapelist \"%s\""), conf_tapelist); /*NOTREACHED*/ } amfree(conf_tapelist); conf_usetimestamps = getconf_boolean(CNF_USETIMESTAMPS); amflush_datestamp = get_datestamp_from_time(0); if(conf_usetimestamps == 0) { amflush_timestamp = g_strdup(amflush_datestamp); } else { amflush_timestamp = get_timestamp_from_time(0); } conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR)); conf_logfile = g_strjoin(NULL, conf_logdir, "/log", NULL); if (access(conf_logfile, F_OK) == 0) { run_amcleanup(get_config_name()); } if (access(conf_logfile, F_OK) == 0) { char *process_name = get_master_process(conf_logfile); error(_("%s exists: %s is already running, or you must run amcleanup"), conf_logfile, process_name); /*NOTREACHED*/ } driver_program = g_strjoin(NULL, amlibexecdir, "/", "driver", NULL); reporter_program = g_strjoin(NULL, sbindir, "/", "amreport", NULL); logroll_program = g_strjoin(NULL, amlibexecdir, "/", "amlogroll", NULL); tapedev = getconf_str(CNF_TAPEDEV); tpchanger = getconf_str(CNF_TPCHANGER); if (tapedev == NULL && tpchanger == NULL) { error(_("No tapedev or tpchanger specified")); } /* if dates were specified (-D), then use match_datestamp * against the list of all datestamps to turn that list * into a set of existing datestamps (basically, evaluate the * expressions into actual datestamps) */ if(datearg) { GSList *all_datestamps; GSList *datestamp; int i, ok; all_datestamps = holding_get_all_datestamps(); for(datestamp = all_datestamps; datestamp != NULL; datestamp = datestamp->next) { ok = 0; for(i=0; i<nb_datearg && ok==0; i++) { ok = match_datestamp(datearg[i], (char *)datestamp->data); } if (ok) datestamp_list = g_slist_insert_sorted(datestamp_list, g_strdup((char *)datestamp->data), g_compare_strings); } slist_free_full(all_datestamps, g_free); } else { /* otherwise, in batch mode, use all datestamps */ if(batch) { datestamp_list = holding_get_all_datestamps(); } /* or allow the user to pick datestamps */ else { datestamp_list = pick_datestamp(); } } if(!datestamp_list) { g_printf(_("Could not find any Amanda directories to flush.\n")); exit(1); } holding_list = holding_get_files_for_flush(datestamp_list); if (holding_list == NULL) { g_printf(_("Could not find any valid dump image, check directory.\n")); exit(1); } if (access(conf_logfile, F_OK) == 0) { char *process_name = get_master_process(conf_logfile); error(_("%s exists: someone started %s"), conf_logfile, process_name); /*NOTREACHED*/ } log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid()); if(!batch) confirm(datestamp_list); for(dp = diskq.head; dp != NULL; dp = dp->next) { if(dp->todo) { char *qname; qname = quote_string(dp->name); log_add(L_DISK, "%s %s", dp->host->hostname, qname); amfree(qname); } } if(!foreground) { /* write it before redirecting stdout */ puts(_("Running in background, you can log off now.")); puts(_("You'll get mail when amflush is finished.")); } if(redirect) redirect_stderr(); if(!foreground) detach(); add_amanda_log_handler(amanda_log_stderr); add_amanda_log_handler(amanda_log_trace_log); today = time(NULL); tm = localtime(&today); if (tm) { strftime(date_string, 100, "%a %b %e %H:%M:%S %Z %Y", tm); strftime(date_string_standard, 100, "%Y-%m-%d %H:%M:%S %Z", tm); } else { error(_("BAD DATE")); /* should never happen */ } g_fprintf(stderr, _("amflush: start at %s\n"), date_string); g_fprintf(stderr, _("amflush: datestamp %s\n"), amflush_timestamp); g_fprintf(stderr, _("amflush: starttime %s\n"), amflush_timestamp); g_fprintf(stderr, _("amflush: starttime-locale-independent %s\n"), date_string_standard); log_add(L_START, _("date %s"), amflush_timestamp); /* START DRIVER */ if(pipe(driver_pipe) == -1) { error(_("error [opening pipe to driver: %s]"), strerror(errno)); /*NOTREACHED*/ } if((driver_pid = fork()) == 0) { /* * This is the child process. */ dup2(driver_pipe[0], 0); close(driver_pipe[1]); config_options = get_config_options(3); config_options[0] = "driver"; config_options[1] = get_config_name(); config_options[2] = "nodump"; safe_fd(-1, 0); execve(driver_program, config_options, safe_env()); error(_("cannot exec %s: %s"), driver_program, strerror(errno)); /*NOTREACHED*/ } else if(driver_pid == -1) { error(_("cannot fork for %s: %s"), driver_program, strerror(errno)); /*NOTREACHED*/ } driver_stream = fdopen(driver_pipe[1], "w"); if (!driver_stream) { error(_("Can't fdopen: %s"), strerror(errno)); /*NOTREACHED*/ } g_fprintf(driver_stream, "DATE %s\n", amflush_timestamp); for(holding_file=holding_list; holding_file != NULL; holding_file = holding_file->next) { dumpfile_t file; holding_file_get_dumpfile((char *)holding_file->data, &file); if (holding_file_size((char *)holding_file->data, 1) <= 0) { g_debug("%s is empty - ignoring", (char *)holding_file->data); log_add(L_INFO, "%s: removing file with no data.", (char *)holding_file->data); holding_file_unlink((char *)holding_file->data); dumpfile_free_data(&file); continue; } /* search_holding_disk should have already ensured that every * holding dumpfile has an entry in the dynamic disklist */ dp = lookup_disk(file.name, file.disk); assert(dp != NULL); /* but match_disklist may have indicated we should not flush it */ if (dp->todo == 0) continue; qdisk = quote_string(file.disk); qhname = quote_string((char *)holding_file->data); g_fprintf(stderr, "FLUSH %s %s %s %d %s\n", file.name, qdisk, file.datestamp, file.dumplevel, qhname); g_debug("flushing '%s'", (char *)holding_file->data); g_fprintf(driver_stream, "FLUSH %s %s %s %d %s\n", file.name, qdisk, file.datestamp, file.dumplevel, qhname); amfree(qdisk); amfree(qhname); dumpfile_free_data(&file); } g_fprintf(stderr, "ENDFLUSH\n"); fflush(stderr); g_fprintf(driver_stream, "ENDFLUSH\n"); fflush(driver_stream); fclose(driver_stream); /* WAIT DRIVER */ while(1) { if((pid = wait(&exitcode)) == -1) { if(errno == EINTR) { continue; } else { error(_("wait for %s: %s"), driver_program, strerror(errno)); /*NOTREACHED*/ } } else if (pid == driver_pid) { break; } } slist_free_full(datestamp_list, g_free); datestamp_list = NULL; slist_free_full(holding_list, g_free); holding_list = NULL; if(redirect) { /* rename errfile */ char *errfile, *errfilex, *nerrfilex, number[100]; int tapecycle; int maxdays, days; struct stat stat_buf; errfile = g_strjoin(NULL, conf_logdir, "/amflush", NULL); errfilex = NULL; nerrfilex = NULL; tapecycle = getconf_int(CNF_TAPECYCLE); maxdays = tapecycle + 2; days = 1; /* First, find out the last existing errfile, */ /* to avoid ``infinite'' loops if tapecycle is infinite */ g_snprintf(number,100,"%d",days); errfilex = newvstralloc(errfilex, errfile, ".", number, NULL); while ( days < maxdays && stat(errfilex,&stat_buf)==0) { days++; g_snprintf(number,100,"%d",days); errfilex = newvstralloc(errfilex, errfile, ".", number, NULL); } g_snprintf(number,100,"%d",days); errfilex = newvstralloc(errfilex, errfile, ".", number, NULL); nerrfilex = NULL; while (days > 1) { amfree(nerrfilex); nerrfilex = errfilex; days--; g_snprintf(number,100,"%d",days); errfilex = g_strjoin(NULL, errfile, ".", number, NULL); if (rename(errfilex, nerrfilex) != 0) { error(_("cannot rename \"%s\" to \"%s\": %s"), errfilex, nerrfilex, strerror(errno)); /*NOTREACHED*/ } } errfilex = newvstralloc(errfilex, errfile, ".1", NULL); if (rename(errfile,errfilex) != 0) { error(_("cannot rename \"%s\" to \"%s\": %s"), errfilex, nerrfilex, strerror(errno)); /*NOTREACHED*/ } amfree(errfile); amfree(errfilex); amfree(nerrfilex); } /* * Have amreport generate report and send mail. Note that we do * not bother checking the exit status. If it does not work, it * can be rerun. */ if((reporter_pid = fork()) == 0) { /* * This is the child process. */ config_options = get_config_options(3); config_options[0] = "amreport"; config_options[1] = get_config_name(); config_options[2] = "--from-amdump"; safe_fd(-1, 0); execve(reporter_program, config_options, safe_env()); error(_("cannot exec %s: %s"), reporter_program, strerror(errno)); /*NOTREACHED*/ } else if(reporter_pid == -1) { error(_("cannot fork for %s: %s"), reporter_program, strerror(errno)); /*NOTREACHED*/ } while(1) { if((pid = wait(&exitcode)) == -1) { if(errno == EINTR) { continue; } else { error(_("wait for %s: %s"), reporter_program, strerror(errno)); /*NOTREACHED*/ } } else if (pid == reporter_pid) { break; } } log_add(L_INFO, "pid-done %ld", (long)getpid()); /* * Call amlogroll to rename the log file to its datestamped version. * Since we exec at this point, our exit code will be that of amlogroll. */ config_options = get_config_options(2); config_options[0] = "amlogroll"; config_options[1] = get_config_name(); safe_fd(-1, 0); execve(logroll_program, config_options, safe_env()); error(_("cannot exec %s: %s"), logroll_program, strerror(errno)); /*NOTREACHED*/ return 0; /* keep the compiler happy */ }
int main( int argc, char ** argv) { disklist_t diskl; int no_keep; /* files per system to keep */ char **output_find_log; DIR *dir; struct dirent *adir; char **name; int useful; char *olddir; char *oldfile = NULL, *newfile = NULL; time_t today, date_keep; char *logname = NULL; struct stat stat_log; struct stat stat_old; char *conf_diskfile; char *conf_tapelist; char *conf_logdir; int dumpcycle; config_overwrites_t *cfg_ovr = NULL; /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); safe_cd(); set_pname("amtrmlog"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); cfg_ovr = extract_commandline_config_overwrites(&argc, &argv); if (argc > 1 && strcmp(argv[1], "-t") == 0) { amtrmidx_debug = 1; argc--; argv++; } if (argc < 2) { g_fprintf(stderr, _("Usage: %s [-t] <config> [-o configoption]*\n"), argv[0]); return 1; } dbopen(DBG_SUBDIR_SERVER); dbprintf(_("%s: version %s\n"), argv[0], version()); config_init(CONFIG_INIT_EXPLICIT_NAME, argv[1]); apply_config_overwrites(cfg_ovr); conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE)); read_diskfile(conf_diskfile, &diskl); amfree(conf_diskfile); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } check_running_as(RUNNING_AS_DUMPUSER); dbrename(get_config_name(), DBG_SUBDIR_SERVER); conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST)); if (read_tapelist(conf_tapelist)) { error(_("could not load tapelist \"%s\""), conf_tapelist); /*NOTREACHED*/ } amfree(conf_tapelist); today = time((time_t *)NULL); dumpcycle = getconf_int(CNF_DUMPCYCLE); if(dumpcycle > 5000) dumpcycle = 5000; date_keep = today - (dumpcycle * 86400); output_find_log = find_log(); /* determine how many log to keep */ no_keep = getconf_int(CNF_TAPECYCLE) * 2; dbprintf(plural(_("Keeping %d log file\n"), _("Keeping %d log files\n"), no_keep), no_keep); conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR)); olddir = vstralloc(conf_logdir, "/oldlog", NULL); if (mkpdir(olddir, 0700, (uid_t)-1, (gid_t)-1) != 0) { error(_("could not create parents of %s: %s"), olddir, strerror(errno)); /*NOTREACHED*/ } if (mkdir(olddir, 0700) != 0 && errno != EEXIST) { error(_("could not create %s: %s"), olddir, strerror(errno)); /*NOTREACHED*/ } if (stat(olddir,&stat_old) == -1) { error(_("can't stat oldlog directory \"%s\": %s"), olddir, strerror(errno)); /*NOTREACHED*/ } if (!S_ISDIR(stat_old.st_mode)) { error(_("Oldlog directory \"%s\" is not a directory"), olddir); /*NOTREACHED*/ } if ((dir = opendir(conf_logdir)) == NULL) { error(_("could not open log directory \"%s\": %s"), conf_logdir,strerror(errno)); /*NOTREACHED*/ } while ((adir=readdir(dir)) != NULL) { if(strncmp(adir->d_name,"log.",4)==0) { useful=0; for (name=output_find_log;*name !=NULL; name++) { if((strlen(adir->d_name) >= 13 && strlen(*name) >= 13 && adir->d_name[12] == '.' && (*name)[12] == '.' && strncmp(adir->d_name,*name,12)==0) || strncmp(adir->d_name,*name,18)==0) { useful=1; break; } } logname=newvstralloc(logname, conf_logdir, "/" ,adir->d_name, NULL); if(stat(logname,&stat_log)==0) { if((time_t)stat_log.st_mtime > date_keep) { useful = 1; } } if(useful == 0) { oldfile = newvstralloc(oldfile, conf_logdir, "/", adir->d_name, NULL); newfile = newvstralloc(newfile, olddir, "/", adir->d_name, NULL); if (rename(oldfile,newfile) != 0) { error(_("could not rename \"%s\" to \"%s\": %s"), oldfile, newfile, strerror(errno)); /*NOTREACHED*/ } } } } closedir(dir); for (name = output_find_log; *name != NULL; name++) { amfree(*name); } amfree(output_find_log); amfree(logname); amfree(oldfile); amfree(newfile); amfree(olddir); amfree(conf_logdir); clear_tapelist(); free_disklist(&diskl); dbclose(); return 0; }
/* * Build the list of tapes we'll be wanting, and include data about the * files we want from said tapes while we're at it (the whole find_result * should do fine) */ tapelist_t * list_needed_tapes( GSList * dumpspecs, int only_one, disklist_t *diskqp) { GSList *needed_tapes = NULL; GSList *seen_dumps = NULL; GSList *iter, *iter2; find_result_t *alldumps = NULL; find_result_t *curmatch = NULL; find_result_t *matches = NULL; tapelist_t *tapes = NULL; int usage_order_counter = 0; char *conf_tapelist; /* Load the tape list */ conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST)); if(read_tapelist(conf_tapelist)) { error(_("could not load tapelist \"%s\""), conf_tapelist); /*NOTREACHED*/ } amfree(conf_tapelist); /* Grab a find_output_t of all logged dumps */ alldumps = find_dump(diskqp); if(alldumps == NULL){ g_fprintf(stderr, _("No dump records found\n")); dbclose(); exit(1); } /* Compare all known dumps to our match list, note what we'll need */ matches = dumps_match_dumpspecs(alldumps, dumpspecs, 1); /* D = dump_timestamp, newest first * h = hostname * k = diskname * l = level * p = partnum * w = write_timestamp */ sort_find_result("Dhklpw", &matches); for(curmatch = matches; curmatch; curmatch = curmatch->next) { int havetape = 0; /* keep only first dump if only_one */ if (only_one && curmatch != matches && (strcmp(curmatch->hostname, matches->hostname) || strcmp(curmatch->diskname, matches->diskname) || strcmp(curmatch->timestamp, matches->timestamp) || curmatch->level != matches->level)) { continue; } if(strcmp("OK", curmatch->status)){ g_fprintf(stderr,_("Dump %s %s %s %d had status '%s', skipping\n"), curmatch->timestamp, curmatch->hostname, curmatch->diskname, curmatch->level, curmatch->status); continue; } for(iter = needed_tapes; iter; iter = iter->next) { needed_tape_t *curtape = iter->data; if (!strcmp(curtape->label, curmatch->label)) { int keep = 1; havetape = 1; for(iter2 = curtape->files; iter2; iter2 = iter2->next){ find_result_t *rsttemp = iter2->data; if(curmatch->filenum == rsttemp->filenum){ g_fprintf(stderr, _("Seeing multiple entries for tape " "%s file %lld, using most recent\n"), curtape->label, (long long)curmatch->filenum); keep = 0; } } if(!keep){ break; } curtape->isafile = (curmatch->filenum < 1); curtape->files = g_slist_prepend(curtape->files, curmatch); break; } } if (!havetape) { needed_tape_t *newtape = g_new0(needed_tape_t, 1); newtape->usage_order = usage_order_counter++; newtape->files = g_slist_prepend(newtape->files, curmatch); newtape->isafile = (curmatch->filenum < 1); newtape->label = curmatch->label; needed_tapes = g_slist_prepend(needed_tapes, newtape); } /* if(!havetape) */ } /* for(curmatch = matches ... */ if(g_slist_length(needed_tapes) == 0){ g_fprintf(stderr, _("No matching dumps found\n")); exit(1); /* NOTREACHED */ } /* sort the tapelist by tape write_timestamp */ needed_tapes = g_slist_sort(needed_tapes, sort_needed_tapes_by_write_timestamp); /* stick that list in a structure that librestore will understand, removing * files we have already seen in the process; this prefers the earliest written * copy of any dumps which are available on multiple tapes */ seen_dumps = NULL; for(iter = needed_tapes; iter; iter = iter->next) { needed_tape_t *curtape = iter->data; for(iter2 = curtape->files; iter2; iter2 = iter2->next) { find_result_t *curfind = iter2->data; find_result_t *prev; GSList *iter; int have_part; /* have we already seen this? */ have_part = 0; for (iter = seen_dumps; iter; iter = iter->next) { prev = iter->data; if (!strcmp(prev->partnum, curfind->partnum) && !strcmp(prev->hostname, curfind->hostname) && !strcmp(prev->diskname, curfind->diskname) && !strcmp(prev->timestamp, curfind->timestamp) && prev->level == curfind->level) { have_part = 1; break; } } if (!have_part) { seen_dumps = g_slist_prepend(seen_dumps, curfind); tapes = append_to_tapelist(tapes, curtape->label, curfind->filenum, -1, curtape->isafile); } } } /* free our resources */ for (iter = needed_tapes; iter; iter = iter->next) { needed_tape_t *curtape = iter->data; g_slist_free(curtape->files); g_free(curtape); } g_slist_free(seen_dumps); g_slist_free(needed_tapes); free_find_result(&matches); /* and we're done */ g_fprintf(stderr, _("%d tape(s) needed for restoration\n"), num_entries(tapes)); return(tapes); }