#include "changer.h"
#include "logfile.h"
#include "cmdline.h"
+#include "server_util.h"
#define CREAT_MODE 0640
typedef struct needed_tapes_s {
char *label;
int isafile;
- find_result_t *files;
- struct needed_tapes_s *next;
- struct needed_tapes_s *prev;
+ GSList *files;
+
+ /* usage_order helps to determine the order in which multiple tapes were
+ * used in a single run; it is set as the tapes are added, as sorted by
+ * dumpfile part number */
+ int usage_order;
} needed_tape_t;
/* local functions */
-tapelist_t *list_needed_tapes(GSList *dumpspecs);
+tapelist_t *list_needed_tapes(GSList *dumpspecs, int only_one, disklist_t *diskqp);
void usage(void);
int main(int argc, char **argv);
exit(1);
}
+static gint
+sort_needed_tapes_by_write_timestamp(
+ gconstpointer a,
+ gconstpointer b)
+{
+ needed_tape_t *a_nt = (needed_tape_t *)a;
+ needed_tape_t *b_nt = (needed_tape_t *)b;
+ tape_t *a_t = a_nt->isafile? NULL : lookup_tapelabel(a_nt->label);
+ tape_t *b_t = b_nt->isafile? NULL : lookup_tapelabel(b_nt->label);
+ char *a_ds = a_t? a_t->datestamp : "none";
+ char *b_ds = b_t? b_t->datestamp : "none";
+
+ /* if the tape timestamps match, sort them by usage_order, which is derived
+ * from the order the tapes were written in a single run */
+ int r = strcmp(a_ds, b_ds);
+ if (r != 0)
+ return r;
+ return (a_nt->usage_order > b_nt->usage_order)? 1 : -1;
+}
+
/*
* 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
*/
tapelist_t *
list_needed_tapes(
- GSList * dumpspecs)
+ GSList * dumpspecs,
+ int only_one,
+ disklist_t *diskqp)
{
- needed_tape_t *needed_tapes = NULL, *curtape = NULL;
- disklist_t diskqp;
- dumpspec_t *ds = NULL;
+ 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 numtapes = 0;
- char *conf_diskfile, *conf_tapelist;
-
- /* For disks and tape lists */
- conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE));
- if(read_diskfile(conf_diskfile, &diskqp) != 0) {
- error(_("could not load disklist \"%s\""), conf_diskfile);
- /*NOTREACHED*/
- }
- amfree(conf_diskfile);
+ 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);
amfree(conf_tapelist);
/* Grab a find_output_t of all logged dumps */
- alldumps = find_dump(&diskqp);
- free_disklist(&diskqp);
+ alldumps = find_dump(diskqp);
if(alldumps == NULL){
g_fprintf(stderr, _("No dump records found\n"));
exit(1);
}
/* Compare all known dumps to our match list, note what we'll need */
- while (dumpspecs) {
- find_result_t *curmatch = NULL;
- find_result_t *matches = NULL;
- ds = (dumpspec_t *)dumpspecs->data;
-
- matches = dumps_match(alldumps, ds->host, ds->disk,
- ds->datestamp, ds->level, 1);
- sort_find_result("Dhklp", &matches);
- for(curmatch = matches; curmatch; curmatch = curmatch->next){
- int havetape = 0;
- int have_part = 0;
- 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;
- }
- /* check if we already have that part */
- for(curtape = needed_tapes; curtape; curtape = curtape->next) {
- find_result_t *rsttemp = NULL;
- for(rsttemp = curtape->files;
- rsttemp;
- rsttemp=rsttemp->next) {
- if (strcmp(rsttemp->partnum, curmatch->partnum) == 0)
- have_part = 1;
- }
- }
- if (have_part)
- continue;
- for(curtape = needed_tapes; curtape; curtape = curtape->next) {
- if(!strcmp(curtape->label, curmatch->label)){
- find_result_t *rsttemp = NULL;
- find_result_t *rstfile = alloc(SIZEOF(find_result_t));
- int keep = 1;
-
- memcpy(rstfile, curmatch, SIZEOF(find_result_t));
-
- havetape = 1;
-
- for(rsttemp = curtape->files;
- rsttemp;
- rsttemp=rsttemp->next){
- if(rstfile->filenum == rsttemp->filenum){
- g_fprintf(stderr, _("Seeing multiple entries for tape "
+ 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)rstfile->filenum);
- keep = 0;
- }
+ (long long)curmatch->filenum);
+ keep = 0;
}
- if(!keep){
- amfree(rstfile);
- break;
- }
- rstfile->next = curtape->files;
-
- if(curmatch->filenum < 1) curtape->isafile = 1;
- else curtape->isafile = 0;
- curtape->files = rstfile;
+ }
+ if(!keep){
break;
}
+
+ curtape->isafile = (curmatch->filenum < 1);
+ curtape->files = g_slist_prepend(curtape->files, curmatch);
+ break;
}
- if(!havetape){
- find_result_t *rstfile = alloc(SIZEOF(find_result_t));
- needed_tape_t *newtape =
- alloc(SIZEOF(needed_tape_t));
- memcpy(rstfile, curmatch, SIZEOF(find_result_t));
- rstfile->next = NULL;
- newtape->files = rstfile;
- if(curmatch->filenum < 1) newtape->isafile = 1;
- else newtape->isafile = 0;
- newtape->label = curmatch->label;
- if(needed_tapes){
- needed_tapes->prev->next = newtape;
- newtape->prev = needed_tapes->prev;
- needed_tapes->prev = newtape;
- }
- else{
- needed_tapes = newtape;
- needed_tapes->prev = needed_tapes;
- }
- newtape->next = NULL;
- numtapes++;
-#if 0
-// free_find_result(rstfile);
-#endif
- } /* if(!havetape) */
-
- } /* for(curmatch = matches ... */
- dumpspecs = dumpspecs->next;
- } /* while (dumpspecs) */
-
- if(numtapes == 0){
+ }
+ 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 */
}
- /* stick that list in a structure that librestore will understand */
- for(curtape = needed_tapes; curtape; curtape = curtape->next) {
- find_result_t *curfind = NULL;
- for(curfind = curtape->files; curfind; curfind = curfind->next) {
- tapes = append_to_tapelist(tapes, curtape->label,
- curfind->filenum, -1, curtape->isafile);
+ /* 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);
+ }
}
}
- g_fprintf(stderr, _("%d tape(s) needed for restoration\n"), numtapes);
+ /* 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);
}
rst_flags_t *rst_flags;
int minimum_arguments;
config_overwrites_t *cfg_ovr = NULL;
+ disklist_t diskq;
+ char * conf_diskfile = NULL;
/*
* Configure program for internationalization:
/*NOTREACHED*/
}
- config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_FATAL, argv[optind++]);
+ config_init(CONFIG_INIT_EXPLICIT_NAME, argv[optind++]);
apply_config_overwrites(cfg_ovr);
+ 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(config_name, DBG_SUBDIR_SERVER);
+ dbrename(get_config_name(), DBG_SUBDIR_SERVER);
dumpspecs = cmdline_parse_dumpspecs(argc - optind, argv + optind,
CMDLINE_PARSE_DATESTAMP |
/* Decide what tapes we'll need */
- needed_tapes = list_needed_tapes(dumpspecs);
+ needed_tapes = list_needed_tapes(dumpspecs,
+ rst_flags->pipe_to_fd == STDOUT_FILENO,
+ &diskq);
parent_pid = getpid();
atexit(cleanup);
get_lock = lock_logfile(); /* config is loaded, should be ok here */
if(get_lock == 0) {
- error(_("%s exists: amdump or amflush is already running, or you must run amcleanup"), rst_conf_logfile);
+ char *process_name = get_master_process(rst_conf_logfile);
+ error(_("%s exists: %s is already running, or you must run amcleanup"), rst_conf_logfile, process_name);
}
+ log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
search_tapes(NULL, stdin, rst_flags->alt_tapedev == NULL,
needed_tapes, dumpspecs, rst_flags, NULL);
cleanup();
flush_open_outputs(1, NULL);
else flush_open_outputs(0, NULL);
+ free_disklist(&diskq);
free_rst_flags(rst_flags);
return(0);
static void
cleanup(void)
{
- if(parent_pid == getpid()) {
- if(get_lock) unlink(rst_conf_logfile);
+ if (parent_pid == getpid()) {
+ if (get_lock) {
+ log_add(L_INFO, "pid-done %ld\n", (long)getpid());
+ unlink(rst_conf_logfile);
+ }
}
}