#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;
} needed_tape_t;
/* local functions */
-tapelist_t *list_needed_tapes(GSList *dumpspecs, int only_one);
+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";
+
+ return strcmp(a_ds, b_ds);
+}
+
/*
* 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,
- int only_one)
+ int only_one,
+ disklist_t *diskqp)
{
- needed_tape_t *needed_tapes = NULL, *curtape = NULL;
- 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 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);
+ 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 */
matches = dumps_match_dumpspecs(alldumps, dumpspecs, 1);
- sort_find_result("Dhklp", &matches);
+ sort_find_result("Dhklpw", &matches);
for(curmatch = matches; curmatch; curmatch = curmatch->next) {
int havetape = 0;
- int have_part = 0;
/* keep only first dump if only_one */
if (only_one &&
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) &&
- !strcmp(rsttemp->hostname, curmatch->hostname) &&
- !strcmp(rsttemp->diskname, curmatch->diskname) &&
- !strcmp(rsttemp->timestamp, curmatch->timestamp) &&
- rsttemp->level == curmatch->level) {
- have_part = 1;
- }
- }
- }
- if (have_part)
- continue;
- for(curtape = needed_tapes; curtape; curtape = curtape->next) {
+ for(iter = needed_tapes; iter; iter = iter->next) {
+ needed_tape_t *curtape = iter->data;
if (!strcmp(curtape->label, curmatch->label)) {
- find_result_t *rsttemp = NULL;
- find_result_t *rstfile;
int keep = 1;
havetape = 1;
- for(rsttemp = curtape->files;
- rsttemp;
- rsttemp=rsttemp->next){
+ 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"),
break;
}
- rstfile = alloc(SIZEOF(find_result_t));
- memcpy(rstfile, curmatch, SIZEOF(find_result_t));
- rstfile->next = curtape->files;
-
- if (curmatch->filenum < 1)
- curtape->isafile = 1;
- else curtape->isafile = 0;
- curtape->files = rstfile;
+ 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;
+ needed_tape_t *newtape = g_new0(needed_tape_t, 1);
+ newtape->files = g_slist_prepend(newtape->files, curmatch);
+ newtape->isafile = (curmatch->filenum < 1);
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++;
+ needed_tapes = g_slist_prepend(needed_tapes, newtape);
} /* if(!havetape) */
} /* for(curmatch = matches ... */
- if(numtapes == 0){
+ 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,
- rst_flags->pipe_to_fd == STDOUT_FILENO);
+ 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);
+ }
}
}