📄 restore.c
字号:
what to load */static void print_expected_tape_list(FILE* prompt_out, FILE* prompt_in, tapelist_t *tapelist, rst_flags_t * flags) { tapelist_t * cur_volume; g_fprintf(prompt_out, "The following tapes are needed:"); for(cur_volume = tapelist; cur_volume != NULL; cur_volume = cur_volume->next){ g_fprintf(prompt_out, " %s", cur_volume->label); } g_fprintf(prompt_out, "\n"); fflush(prompt_out); if(flags->wait_tape_prompt){ char *input = NULL; g_fprintf(prompt_out,"Press enter when ready\n"); fflush(prompt_out); input = agets(prompt_in); amfree(input); g_fprintf(prompt_out, "\n"); fflush(prompt_out); }}/* Restore a single holding-disk file. We will fill in this_header with the header from this restore (if it is not null), and in the stdout-pipe case, we abort according to last_header. Returns TRUE if the restore should continue, FALSE if we are done. */gboolean restore_holding_disk(FILE * prompt_out, rst_flags_t * flags, am_feature_t * features, tapelist_t * file, seentapes_t ** seen, GSList * dumpspecs, dumpfile_t * this_header, dumpfile_t * last_header) { RestoreSource source; gboolean read_result; dumpfile_t header; source.header = &header; source.restore_mode = HOLDING_MODE; source.u.holding_fd = robust_open(file->label, 0, 0); if (source.u.holding_fd < 0) { send_message(prompt_out, flags, features, "could not open %s: %s", file->label, strerror(errno)); return TRUE; } g_fprintf(stderr, "Reading %s from fd %d\n", file->label, source.u.holding_fd); read_result = read_holding_disk_header(source.header, source.u.holding_fd, flags); if (!read_result) { send_message(prompt_out, flags, features, "Invalid header reading %s.", file->label); aclose(source.u.holding_fd); return TRUE; } if (!run_dumpspecs(dumpspecs, source.header)) { return FALSE; } if (last_header != NULL && !flags->amidxtaped && flags->pipe_to_fd == STDOUT_FILENO && last_header->type != F_UNKNOWN && !headers_equal(last_header, source.header, 1)) { return FALSE; } else if (this_header != NULL) { memcpy(this_header, source.header, sizeof(*this_header)); } if (seen != NULL) { record_seen_volume(seen, file->label, "<none>"); record_seen_dump(*seen, source.header); } print_header(stderr, source.header); restore(&source, flags); aclose(source.u.holding_fd); return TRUE;}/* Ask for a specific manual tape. If we find the right one, then open it * and return a Device handle. If not, return NULL. Pass a device name, but * it might be overridden. */static Device* manual_find_tape(char ** cur_tapedev, tapelist_t * cur_volume, FILE * prompt_out, FILE * prompt_in, rst_flags_t * flags, am_feature_t * features) { LoadStatus status = LOAD_NEXT; Device * rval; for (;;) { status = load_manual_tape(cur_tapedev, prompt_out, prompt_in, flags, features, cur_volume); if (status == LOAD_STOP) return NULL; rval = conditional_device_open(*cur_tapedev, prompt_out, flags, features, cur_volume); if (rval != NULL) return rval; }}/* If we have a tapelist, then we mandate restoring in tapelist order. The logic is simple: Get the next tape, and deal with it, then move on to the next one. */static voidrestore_from_tapelist(FILE * prompt_out, FILE * prompt_in, tapelist_t * tapelist, GSList * dumpspecs, rst_flags_t * flags, am_feature_t * features, char * cur_tapedev, gboolean use_changer, FILE * logstream) { tapelist_t * cur_volume; dumpfile_t first_restored_file; seentapes_t * seentapes = NULL; fh_init(&first_restored_file); for(cur_volume = tapelist; cur_volume != NULL; cur_volume = cur_volume->next){ if (cur_volume->isafile) { /* Restore from holding disk; just go. */ if (first_restored_file.type == F_UNKNOWN) { if (!restore_holding_disk(prompt_out, flags, features, cur_volume, &seentapes, NULL, NULL, &first_restored_file)) { break; } } else { restore_holding_disk(prompt_out, flags, features, cur_volume, &seentapes, NULL, &first_restored_file, NULL); } if (flags->pipe_to_fd == fileno(stdout)) { break; } } else { Device * device = NULL; if (use_changer) { char * tapedev = NULL; loadlabel_data data; data.cur_tapedev = &tapedev; data.searchlabel = cur_volume->label; changer_find(&data, scan_init, loadlabel_slot, cur_volume->label); device = conditional_device_open(tapedev, prompt_out, flags, features, cur_volume); amfree(tapedev); } if (device == NULL) device = manual_find_tape(&cur_tapedev, cur_volume, prompt_out, prompt_in, flags, features); if (device == NULL) break; if (use_changer) { g_fprintf(stderr, "Scanning volume %s (slot %s)\n", device->volume_label, curslot); } else { g_fprintf(stderr, "Scanning volume %s\n", device->volume_label); } if (!search_a_tape(device, prompt_out, flags, features, cur_volume, dumpspecs, &seentapes, &first_restored_file, 0, logstream)) { g_object_unref(device); break; } g_object_unref(device); } } free_seen_tapes(seentapes);}/* This function works when we are operating without a tapelist (regardless of whether or not we have a changer). This only happens when we are using amfetchdump without dump logs, but in the future may include amrestore as well. The philosophy is to keep loading tapes until we run out. */static voidrestore_without_tapelist(FILE * prompt_out, FILE * prompt_in, GSList * dumpspecs, rst_flags_t * flags, am_feature_t * features, char * cur_tapedev, /* -1 if no changer. */ int slot_count, FILE * logstream) { int cur_slot = 1; seentapes_t * seentapes; int tape_count = 0; dumpfile_t first_restored_file; fh_init(&first_restored_file); /* This loop also aborts if we run out of manual tapes, or encounter a changer error. */ for (;;) { Device * device = NULL; if (slot_count > 0) { while (cur_slot < slot_count && device == NULL) { amfree(curslot); changer_loadslot("next", &curslot, &cur_tapedev); device = conditional_device_open(cur_tapedev, prompt_out, flags, features, NULL); amfree(cur_tapedev); cur_slot ++; } if (cur_slot >= slot_count) break; g_fprintf(stderr, "Scanning %s (slot %s)\n", device->volume_label, curslot); } else { device = manual_find_tape(&cur_tapedev, NULL, prompt_out, prompt_in, flags, features); } if (device == NULL) break;; if (!search_a_tape(device, prompt_out, flags, features, NULL, dumpspecs, &seentapes, &first_restored_file, tape_count, logstream)) { g_object_unref(device); break; } g_object_unref(device); tape_count ++; } free_seen_tapes(seentapes);}/* * Take a pattern of dumps and restore it blind, a la amrestore. In addition, * be smart enough to change tapes and continue with minimal operator * intervention, and write out a record of what was found on tapes in the * the regular logging format. Can take a tapelist with a specific set of * tapes to search (rather than "everything I can find"), which in turn can * optionally list specific files to restore. */ voidsearch_tapes( FILE * prompt_out, FILE * prompt_in, int use_changer, tapelist_t * tapelist, GSList * dumpspecs, rst_flags_t * flags, am_feature_t * their_features){ char *cur_tapedev; int slots = -1; FILE *logstream = NULL; tapelist_t *desired_tape = NULL; struct sigaction act, oact; device_api_init(); if(!prompt_out) prompt_out = stderr; /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); /* catch SIGINT with something that'll flush unmerged splits */ act.sa_handler = handle_sigint; sigemptyset(&act.sa_mask); act.sa_flags = 0; if(sigaction(SIGINT, &act, &oact) != 0){ error(_("error setting SIGINT handler: %s"), strerror(errno)); /*NOTREACHED*/ } if(flags->delay_assemble || flags->inline_assemble) exitassemble = 1; else exitassemble = 0; /* if given a log file, print an inventory of stuff found */ if(flags->inventory_log) { if(!strcmp(flags->inventory_log, "-")) logstream = stdout; else if((logstream = fopen(flags->inventory_log, "w+")) == NULL) { error(_("Couldn't open log file %s for writing: %s"), flags->inventory_log, strerror(errno)); /*NOTREACHED*/ } } /* Suss what tape device we're using, whether there's a changer, etc. */ if (use_changer) { use_changer = changer_init(); } if (!use_changer) { cur_tapedev = NULL; if (flags->alt_tapedev) { cur_tapedev = stralloc(flags->alt_tapedev); } else if(!cur_tapedev) { cur_tapedev = getconf_str(CNF_TAPEDEV); if (cur_tapedev == NULL) { error(_("No tapedev specified")); } } /* XXX oughta complain if no config is loaded */ g_fprintf(stderr, _("%s: Using tapedev %s\n"), get_pname(), cur_tapedev); } else{ /* good, the changer works, see what it can do */ amfree(curslot); changer_info(&slots, &curslot, &backwards); } if (tapelist && !flags->amidxtaped) { print_expected_tape_list(prompt_out, prompt_in, tapelist, flags); } desired_tape = tapelist; if (use_changer) { /* load current slot */ amfree(curslot); cur_tapedev = NULL; changer_loadslot("current", &curslot, &cur_tapedev); } /* * If we're not given a tapelist, iterate over everything our changer can * find. If there's no changer, we'll prompt to be handfed tapes. * * If we *are* given a tapelist, restore from those tapes in the order in * which they're listed. Unless the changer (if we have one) can't go * backwards, in which case check every tape we see and restore from it if * appropriate. * * (obnoxious, isn't this?) */ if (tapelist) { restore_from_tapelist(prompt_out, prompt_in, tapelist, dumpspecs, flags, their_features, cur_tapedev, use_changer, logstream); } else { restore_without_tapelist(prompt_out, prompt_in, dumpspecs, flags, their_features, cur_tapedev, (use_changer ? slots : -1), logstream); } if(logstream && logstream != stderr && logstream != stdout){ fclose(logstream); } if(flags->delay_assemble || flags->inline_assemble){ flush_open_outputs(1, NULL); } else flush_open_outputs(0, NULL);}/* * Create a new, clean set of restore flags with some sane default values. */rst_flags_t *new_rst_flags(void){ rst_flags_t *flags = alloc(SIZEOF(rst_flags_t)); memset(flags, 0, SIZEOF(rst_flags_t)); flags->fsf = 0; flags->comp_type = COMPRESS_FAST_OPT; flags->inline_assemble = 1; flags->pipe_to_fd = -1; flags->check_labels = 1; return(flags);}/* * Make sure the set of restore options given is sane. Print errors for * things that're odd, and return -1 for fatal errors. */intcheck_rst_flags( rst_flags_t * flags){ int ret = 0; if(!flags) return(-1); if(flags->compress && flags->leave_comp){ g_fprintf(stderr, _("Cannot specify 'compress output' and 'leave compression alone' together\n")); ret = -1; } if(flags->restore_dir != NULL){ struct stat statinfo; if(flags->pipe_to_fd != -1){ g_fprintf(stderr, _("Specifying output directory and piping output are mutually exclusive\n")); ret = -1; } if(stat(flags->restore_dir, &statinfo) < 0){ g_fprintf(stderr, _("Cannot stat restore target dir '%s': %s\n"), flags->restore_dir, strer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -