📄 restore.c
字号:
changer_find(&data, scan_init, loadlabel_slot, desired_tape->label); return LOAD_CHANGER; } else { amfree(curslot); changer_loadslot("next", &curslot, cur_tapedev); return LOAD_NEXT; } } else { assert(!flags->amidxtaped); amfree(curslot); changer_loadslot("next", &curslot, cur_tapedev); return LOAD_NEXT; } g_assert_not_reached();}/* will never return LOAD_CHANGER. */LoadStatusload_manual_tape( char **tapedev_ptr, FILE *prompt_out, FILE *prompt_in, rst_flags_t *flags, am_feature_t *their_features, tapelist_t *desired_tape){ char *input = NULL; if (flags->amidxtaped) { if (their_features && am_has_feature(their_features, fe_amrecover_FEEDME)) { g_fprintf(prompt_out, "FEEDME %s\r\n", desired_tape->label); fflush(prompt_out); input = agets(prompt_in);/* Strips \n but not \r */ if(!input) { error(_("Connection lost with amrecover")); /*NOTREACHED*/ } else if (strcmp("OK\r", input) == 0) { } else if (strncmp("TAPE ", input, 5) == 0) { amfree(*tapedev_ptr); *tapedev_ptr = alloc(1025); if (sscanf(input, "TAPE %1024s\r", *tapedev_ptr) != 1) { error(_("Got bad response from amrecover: %s"), input); /*NOTREACHED*/ } } else { send_message(prompt_out, flags, their_features, _("Got bad response from amrecover: %s"), input); error(_("Got bad response from amrecover: %s"), input); /*NOTREACHED*/ } } else { send_message(prompt_out, flags, their_features, _("Client doesn't support fe_amrecover_FEEDME")); error(_("Client doesn't support fe_amrecover_FEEDME")); /*NOTREACHED*/ } } else { if (desired_tape) { g_fprintf(prompt_out, _("Insert tape labeled %s in device %s \n" "and press enter, ^D to finish reading tapes\n"), desired_tape->label, *tapedev_ptr); } else { g_fprintf(prompt_out,_("Insert a tape to search and press " "enter, ^D to finish reading tapes\n")); } fflush(prompt_out); if((input = agets(prompt_in)) == NULL) return LOAD_STOP; } amfree(input); return LOAD_NEXT;}/* Search a seen-tapes list for a particular name, to see if we've already * processed this tape. Returns TRUE if this label has already been seen. */static gboolean check_volume_seen(seentapes_t * list, char * label) { seentapes_t * cur_tape; for (cur_tape = list; cur_tape != NULL; cur_tape = cur_tape->next) { if (strcmp(cur_tape->label, label) == 0) { return TRUE; } } return FALSE;}/* Add a volume to the seen tapes list. */static void record_seen_volume(seentapes_t ** list, char * label, char * slotstr) { seentapes_t * new_entry; if (list == NULL) return; new_entry = malloc(sizeof(seentapes_t)); new_entry->label = stralloc(label); if (slotstr == NULL) { new_entry->slotstr = NULL; } else { new_entry->slotstr = stralloc(slotstr); } new_entry->files = NULL; new_entry->next = *list; *list = new_entry;}/* Record a specific dump on a volume. */static void record_seen_dump(seentapes_t * volume, dumpfile_t * header) { dumplist_t * this_dump; if (volume == NULL) return; this_dump = malloc(sizeof(*this_dump)); this_dump->file = g_memdup(header, sizeof(*header)); this_dump->next = NULL; if (volume->files) { dumplist_t * tmp_dump = volume->files; while (tmp_dump->next != NULL) { tmp_dump = tmp_dump->next; } tmp_dump->next = this_dump; } else { volume->files = this_dump; }}static void print_tape_inventory(FILE * logstream, seentapes_t * tape_seen, char * timestamp, char * label, int tape_count) { char * logline; dumplist_t * fileentry; logline = log_genstring(L_START, "taper", "datestamp %s label %s tape %d", timestamp, label, tape_count); fputs(logline, logstream); amfree(logline); for(fileentry=tape_seen->files; fileentry; fileentry=fileentry->next){ switch (fileentry->file->type) { case F_DUMPFILE: logline = log_genstring(L_SUCCESS, "taper", "%s %s %s %d [faked log entry]", fileentry->file->name, fileentry->file->disk, fileentry->file->datestamp, fileentry->file->dumplevel); break; case F_SPLIT_DUMPFILE: logline = log_genstring(L_CHUNK, "taper", "%s %s %s %d %d [faked log entry]", fileentry->file->name, fileentry->file->disk, fileentry->file->datestamp, fileentry->file->partnum, fileentry->file->dumplevel); break; default: break; } if(logline != NULL){ fputs(logline, logstream); amfree(logline); fflush(logstream); } }}/* Check if the given header matches the given dumpspecs. Returns TRUE if dumpspecs is NULL and false if the header is NULL. Returns true if the header matches the match list. */static gboolean run_dumpspecs(GSList * dumpspecs, dumpfile_t * header) { dumpspec_t *ds; if (dumpspecs == NULL) return TRUE; if (header == NULL) return FALSE; while (dumpspecs) { ds = (dumpspec_t *)dumpspecs->data; if (disk_match(header, ds->datestamp, ds->host, ds->disk, ds->level) != 0) { return TRUE; } dumpspecs = dumpspecs->next; } return FALSE;}/* A wrapper around restore() above. This function does some extra checking to seek to the file in question and ensure that we really, really want to use it. The next_file argument provides instruction on what to do if the requested file does not exist on the volume: If next_file is NULL then if the requested file is missing the function will return RESTORE_STATUS_NEXT_FILE. If next_file is not NULL then the first extant file whose number is equal to or greater than file_num will be attempted. *next_file will be filled in with the number of the file following the one that was attempted. */static RestoreFileStatustry_restore_single_file(Device * device, int file_num, int* next_file, FILE * prompt_out, rst_flags_t * flags, am_feature_t * their_features, dumpfile_t * first_restored_file, GSList * dumpspecs, seentapes_t * tape_seen) { RestoreSource source; source.u.device = device; source.restore_mode = DEVICE_MODE; source.header = device_seek_file(device, file_num); if (source.header == NULL) { /* This definitely indicates an error. */ send_message(prompt_out, flags, their_features, "Could not seek device %s to file %d.", device->device_name, file_num); return RESTORE_STATUS_NEXT_TAPE; } else if (source.header->type == F_TAPEEND) { amfree(source.header); return RESTORE_STATUS_NEXT_TAPE; } else if (device->file != file_num) { if (next_file == NULL) { send_message(prompt_out, flags, their_features, "Requested file %d does not exist.", file_num); return RESTORE_STATUS_NEXT_FILE; } else { send_message(prompt_out, flags, their_features, "Skipped from file %d to file %d.", file_num, device->file); file_num = device->file; } } if (next_file != NULL) { *next_file = file_num + 1; } g_return_val_if_fail(source.header->type == F_DUMPFILE || source.header->type == F_CONT_DUMPFILE || source.header->type == F_SPLIT_DUMPFILE, RESTORE_STATUS_NEXT_FILE); if (!run_dumpspecs(dumpspecs, source.header)) { if(!flags->amidxtaped) { g_fprintf(prompt_out, "%s: %d: skipping ", get_pname(), file_num); print_header(prompt_out, source.header); } return RESTORE_STATUS_NEXT_FILE; } if (first_restored_file != NULL && first_restored_file->type != F_UNKNOWN && !headers_equal(first_restored_file, source.header, 1) && (flags->pipe_to_fd == fileno(stdout))) { return RESTORE_STATUS_STOP; } if (!flags->amidxtaped) { g_fprintf(stderr, "%s: %d: restoring ", get_pname(), file_num); print_header(stderr, source.header); } record_seen_dump(tape_seen, source.header); restore(&source, flags); if (first_restored_file) { memcpy(first_restored_file, source.header, sizeof(dumpfile_t)); } return RESTORE_STATUS_NEXT_FILE;}/* This function handles processing of a particular tape or holding disk file. It returns TRUE if it is useful to load another tape.*/gbooleansearch_a_tape(Device * device, FILE *prompt_out, /* Where to send any prompts */ rst_flags_t *flags, /* Restore options. */ am_feature_t *their_features, tapelist_t *desired_tape, /* A list of desired tape files */ GSList *dumpspecs, /* What disks to restore. */ seentapes_t **tape_seen, /* Where to record data on this tape. */ /* May be NULL. If zeroed, will be filled in with the first restored file. If already filled in, then we may only restore other files from the same dump. */ dumpfile_t * first_restored_file, int tape_count, FILE * logstream) { seentapes_t * tape_seen_head = NULL; RestoreSource source; off_t filenum; int tapefile_idx = -1; int i; RestoreFileStatus restore_status = RESTORE_STATUS_NEXT_TAPE; source.restore_mode = DEVICE_MODE; source.u.device = device; filenum = (off_t)0; if(desired_tape && desired_tape->numfiles > 0) tapefile_idx = 0; if (desired_tape) { dbprintf(_("search_a_tape: desired_tape=%p label=%s\n"), desired_tape, desired_tape->label); dbprintf(_("tape: numfiles = %d\n"), desired_tape->numfiles); for (i=0; i < desired_tape->numfiles; i++) { dbprintf(_("tape: files[%d] = %lld\n"), i, (long long)desired_tape->files[i]); } } else { dbprintf(_("search_a_tape: no desired_tape\n")); } dbprintf(_("current tapefile_idx = %d\n"), tapefile_idx); if (tape_seen) { if (check_volume_seen(*tape_seen, device->volume_label)) { send_message(prompt_out, flags, their_features, "Skipping repeat tape %s in slot %s", device->volume_label, curslot); return TRUE; } record_seen_volume(tape_seen, device->volume_label, curslot); tape_seen_head = *tape_seen; } if (desired_tape && desired_tape->numfiles > 0) { /* Iterate the tape list, handle each file in order. */ int file_index; for (file_index = 0; file_index < desired_tape->numfiles; file_index ++) { int file_num = desired_tape->files[file_index]; restore_status = try_restore_single_file(device, file_num, NULL, prompt_out, flags, their_features, first_restored_file, NULL, tape_seen_head); if (restore_status != RESTORE_STATUS_NEXT_FILE) break; } } else if(flags->fsf && flags->amidxtaped) { /* Restore a single file, then quit. */ restore_status = try_restore_single_file(device, flags->fsf, NULL, prompt_out, flags, their_features, first_restored_file, dumpspecs, tape_seen_head); } else { /* Search the tape from beginning to end. */ int file_num; if (flags->fsf > 0) { file_num = flags->fsf; } else { file_num = 1; } if (!flags->amidxtaped) { g_fprintf(prompt_out, "Restoring from tape %s starting with file %d.\n", device->volume_label, file_num); fflush(prompt_out); } for (;;) { restore_status = try_restore_single_file(device, file_num, &file_num, prompt_out, flags, their_features, first_restored_file, dumpspecs, tape_seen_head); if (restore_status != RESTORE_STATUS_NEXT_FILE) break; } } /* spit out our accumulated list of dumps, if we're inventorying */ if (logstream != NULL) { print_tape_inventory(logstream, tape_seen_head, device->volume_time, device->volume_label, tape_count); } return (restore_status != RESTORE_STATUS_STOP);}static void free_seen_tapes(seentapes_t * seentapes) { while (seentapes != NULL) { seentapes_t *tape_seen = seentapes; seentapes = seentapes->next; while(tape_seen->files != NULL) { dumplist_t *temp_dump = tape_seen->files; tape_seen->files = temp_dump->next; amfree(temp_dump->file); amfree(temp_dump); } amfree(tape_seen->label); amfree(tape_seen->slotstr); amfree(tape_seen); }}/* Spit out a list of expected tapes, so people with manual changers know
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -