Imported Upstream version 2.6.1
[debian/amanda] / restore-src / amfetchdump.c
index bdeb114c50fe28e21c3311d84a8babb9b9efeda6..927149da4e94b6f93adbfcbb88784147926a6f32 100644 (file)
@@ -39,6 +39,7 @@
 #include "changer.h"
 #include "logfile.h"
 #include "cmdline.h"
+#include "server_util.h"
 
 #define CREAT_MODE     0640
 
@@ -49,14 +50,12 @@ int get_lock = 0;
 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);
 
@@ -91,6 +90,21 @@ usage(void)
     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
@@ -99,25 +113,19 @@ usage(void)
 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);
@@ -126,20 +134,19 @@ list_needed_tapes(
     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;
 
+       g_fprintf(stderr, "Examining %s %s on %s\n", curmatch->hostname, curmatch->diskname, curmatch->label);
        /* keep only first dump if only_one */
        if (only_one &&
            curmatch != matches &&
@@ -147,6 +154,7 @@ list_needed_tapes(
             strcmp(curmatch->diskname, matches->diskname) ||
             strcmp(curmatch->timestamp, matches->timestamp) ||
             curmatch->level != matches->level)) {
+           g_fprintf(stderr, "only_one matched\n");
            continue;
        }
        if(strcmp("OK", curmatch->status)){
@@ -154,37 +162,19 @@ list_needed_tapes(
                             curmatch->timestamp, curmatch->hostname,
                             curmatch->diskname, curmatch->level,
                             curmatch->status);
+           g_fprintf(stderr, "!OK\n");
            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"),
@@ -197,56 +187,77 @@ list_needed_tapes(
                    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);
 }
 
@@ -270,6 +281,8 @@ main(
     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:
@@ -378,12 +391,23 @@ main(
        /*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 |
@@ -404,14 +428,17 @@ main(
 
     /* 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();
@@ -422,6 +449,7 @@ main(
        flush_open_outputs(1, NULL);
     else flush_open_outputs(0, NULL);
 
+    free_disklist(&diskq);
     free_rst_flags(rst_flags);
 
     return(0);
@@ -430,7 +458,10 @@ main(
 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);
+       }
     }
 }