/* * Convert a previously str-ified and escaped list of tapes back into a * tapelist structure. */ tapelist_t * unmarshal_tapelist_str( char * tapelist_str, int with_storage) { char *temp_storage, *temp_label, *temp_filenum; int l_idx, n_idx; size_t input_length; tapelist_t *tapelist = NULL; if(!tapelist_str) return(NULL); input_length = strlen(tapelist_str); temp_label = g_malloc(input_length+1); temp_storage = g_malloc(input_length+1); temp_filenum = g_malloc(input_length+1); do { /* first, read the storage part */ if (with_storage) { memset(temp_storage, '\0', input_length+1); l_idx = 0; while(*tapelist_str != ':' && *tapelist_str != '\0'){ if(*tapelist_str == '\\') tapelist_str++; /* skip escapes */ temp_storage[l_idx] = *tapelist_str; if(*tapelist_str == '\0') break; /* bad format, should kvetch */ tapelist_str++; l_idx++; } if(*tapelist_str != '\0') tapelist_str++; } /* then, read the label part */ memset(temp_label, '\0', input_length+1); l_idx = 0; while(*tapelist_str != ':' && *tapelist_str != '\0'){ if(*tapelist_str == '\\') tapelist_str++; /* skip escapes */ temp_label[l_idx] = *tapelist_str; if(*tapelist_str == '\0') break; /* bad format, should kvetch */ tapelist_str++; l_idx++; } if(*tapelist_str != '\0') tapelist_str++; tapelist = append_to_tapelist(tapelist, temp_storage, temp_label, (off_t)-1, -1, 0); /* now read the list of file numbers */ while(*tapelist_str != ';' && *tapelist_str != '\0'){ off_t filenum; memset(temp_filenum, '\0', input_length+1); n_idx = 0; while(*tapelist_str != ';' && *tapelist_str != ',' && *tapelist_str != '\0'){ temp_filenum[n_idx] = *tapelist_str; tapelist_str++; n_idx++; } filenum = OFF_T_ATOI(temp_filenum); tapelist = append_to_tapelist(tapelist, temp_storage, temp_label, filenum, -1, 0); if(*tapelist_str != '\0' && *tapelist_str != ';') tapelist_str++; } if(*tapelist_str != '\0') tapelist_str++; } while(*tapelist_str != '\0'); amfree(temp_label); amfree(temp_storage); amfree(temp_filenum); return(tapelist); }
/* * 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); }