📄 restore.c
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-1998 University of Maryland at College Park * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Authors: the Amanda Development Team. Its members are listed in a * file named AUTHORS, in the root directory of this distribution. *//* * $Id: restore.c 6512 2007-05-24 17:00:24Z ian $ * * retrieves files from an amanda tape */#include "amanda.h"#include "util.h"#include "restore.h"#include "find.h"#include "changer.h"#include "logfile.h"#include "fileheader.h"#include "arglist.h"#include "cmdline.h"#include <signal.h>#include <timestamp.h>#include <device.h>#include <queueing.h>#include <glib.h>typedef enum { LOAD_NEXT = 1, /* An unknown new slot has been loaded. */ LOAD_CHANGER = -2, /* The requested slot has been loaded. */ LOAD_STOP = -1, /* The search is complete. */} LoadStatus;typedef enum { RESTORE_STATUS_NEXT_FILE, RESTORE_STATUS_NEXT_TAPE, RESTORE_STATUS_STOP} RestoreFileStatus;int file_number;/* stuff we're stuck having global */static int backwards;static int exitassemble = 0;char *rst_conf_logdir = NULL;char *rst_conf_logfile = NULL;static char *curslot = NULL;typedef struct open_output_s { struct open_output_s *next; dumpfile_t *file; int lastpartnum; pid_t comp_enc_pid; int outfd;} open_output_t;typedef struct dumplist_s { struct dumplist_s *next; dumpfile_t *file;} dumplist_t;struct seentapes_s { struct seentapes_s *next; char *slotstr; char *label; dumplist_t *files;};static open_output_t *open_outputs = NULL;static dumplist_t *alldumps_list = NULL;/* local functions */static void append_file_to_fd(char *filename, int fd);static int headers_equal(dumpfile_t *file1, dumpfile_t *file2, int ignore_partnums);static int already_have_dump(dumpfile_t *file);static void handle_sigint(int sig);static int scan_init(void *ud, int rc, int ns, int bk, int s);static Device * conditional_device_open(char * tapedev, FILE * orompt_out, rst_flags_t * flags, am_feature_t * their_features, tapelist_t * desired_tape);int loadlabel_slot(void *ud, int rc, char *slotstr, char *device);char *label_of_current_slot(char *cur_tapedev, FILE *prompt_out, int *tapefd, dumpfile_t *file, rst_flags_t *flags, am_feature_t *their_features, ssize_t *read_result, tapelist_t *desired_tape);LoadStatus load_next_tape(char **cur_tapedev, FILE *prompt_out, int backwards, rst_flags_t *flags, am_feature_t *their_features, tapelist_t *desired_tape);LoadStatus load_manual_tape(char **cur_tapedev, FILE *prompt_out, FILE *prompt_in, rst_flags_t *flags, am_feature_t *their_features, tapelist_t *desired_tape);/* * We might want to flush any open dumps and unmerged splits before exiting * on SIGINT, so do so. */static voidhandle_sigint( int sig){ (void)sig; /* Quiet unused parameter warning */ flush_open_outputs(exitassemble, NULL); if(rst_conf_logfile) unlink(rst_conf_logfile); exit(0);}intlock_logfile(void){ rst_conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR)); rst_conf_logfile = vstralloc(rst_conf_logdir, "/log", NULL); if (access(rst_conf_logfile, F_OK) == 0) { dbprintf(_("%s exists: amdump or amflush is already running, " "or you must run amcleanup\n"), rst_conf_logfile); return 0; } log_add(L_INFO, get_pname()); return 1;}/* * Return 1 if the two fileheaders match in name, disk, type, split chunk part * number, and datestamp, and 0 if not. The part number can be optionally * ignored. */intheaders_equal( dumpfile_t *file1, dumpfile_t *file2, int ignore_partnums){ if(!file1 || !file2) return(0); if(file1->dumplevel == file2->dumplevel && file1->type == file2->type && !strcmp(file1->datestamp, file2->datestamp) && !strcmp(file1->name, file2->name) && !strcmp(file1->disk, file2->disk) && (ignore_partnums || file1->partnum == file2->partnum)){ return(1); } return(0);}/* * See whether we're already pulled an exact copy of the given file (chunk * number and all). Returns 0 if not, 1 if so. */intalready_have_dump( dumpfile_t *file){ dumplist_t *fileentry = NULL; if(!file) return(0); for(fileentry=alldumps_list;fileentry;fileentry=fileentry->next){ if(headers_equal(file, fileentry->file, 0)) return(1); } return(0);}/* * Open the named file and append its contents to the (hopefully open) file * descriptor supplies. */static voidappend_file_to_fd( char * filename, int write_fd){ int read_fd; read_fd = robust_open(filename, O_RDONLY, 0); if (read_fd < 0) { error(_("can't open %s: %s"), filename, strerror(errno)); /*NOTREACHED*/ } if (!do_consumer_producer_queue(fd_read_producer, GINT_TO_POINTER(read_fd), fd_write_consumer, GINT_TO_POINTER(write_fd))) { error("Error copying data from file \"%s\" to fd %d.\n", filename, write_fd); g_assert_not_reached(); } aclose(read_fd);}/* A user_init function for changer_find(). See changer.h for documentation. */static int scan_init(G_GNUC_UNUSED void * ud, int rc, G_GNUC_UNUSED int ns, int bk, G_GNUC_UNUSED int s) { if(rc) { error(_("could not get changer info: %s"), changer_resultstr); /*NOTREACHED*/ } backwards = bk; return 0;}typedef struct { char ** cur_tapedev; char * searchlabel;} loadlabel_data;/* DANGER WILL ROBINSON: This function references globals: char * curslot; */intloadlabel_slot(void * datap, int rc, char * slotstr, char * device_name){ loadlabel_data * data = (loadlabel_data*)datap; Device * device; ReadLabelStatusFlags label_status; g_return_val_if_fail(rc > 1 || device_name != NULL, 0); g_return_val_if_fail(slotstr != NULL, 0); amfree(curslot); if(rc > 1) { error(_("could not load slot %s: %s"), slotstr, changer_resultstr); g_assert_not_reached(); } if(rc == 1) { g_fprintf(stderr, _("%s: slot %s: %s\n"), get_pname(), slotstr, changer_resultstr); return 0; } device = device_open(device_name); if (device == NULL) { g_fprintf(stderr, "%s: slot %s: Could not open device.\n", get_pname(), slotstr); return 0; } device_set_startup_properties_from_config(device); label_status = device_read_label(device); if (label_status != READ_LABEL_STATUS_SUCCESS) { char * errstr = g_english_strjoinv_and_free (g_flags_nick_to_strv(label_status, READ_LABEL_STATUS_FLAGS_TYPE), "or"); g_fprintf(stderr, "%s: slot %s: Error reading tape label:\n" "%s: slot %s: %s\n", get_pname(), slotstr, get_pname(), slotstr, errstr); g_object_unref(device); return 0; } g_assert(device->volume_label != NULL); if (device->volume_label == NULL) { g_fprintf(stderr, "%s: slot %s: Could not read tape label.\n", get_pname(), slotstr); g_object_unref(device); return 0; } if (!device_start(device, ACCESS_READ, NULL, NULL)) { g_fprintf(stderr, "%s: slot %s: Could not open device for reading.\n", get_pname(), slotstr); return 0; } g_fprintf(stderr, "%s: slot %s: time %-14s label %s", get_pname(), slotstr, device->volume_time, device->volume_label); if(strcmp(device->volume_label, data->searchlabel) != 0) { g_fprintf(stderr, " (wrong tape)\n"); g_object_unref(device); return 0; } g_fprintf(stderr, " (exact label match)\n"); g_object_unref(device); curslot = newstralloc(curslot, slotstr); amfree(*(data->cur_tapedev)); *(data->cur_tapedev) = stralloc(device_name); return 1;}/* non-local functions follow *//* * Check whether we've read all of the preceding parts of a given split dump, * generally used to see if we're done and can close the thing. */inthave_all_parts ( dumpfile_t *file, int upto){ int c; int *foundparts = NULL; dumplist_t *fileentry = NULL; if(!file || file->partnum < 1) return(0); if(upto < 1) upto = file->totalparts; foundparts = alloc(SIZEOF(*foundparts) * upto); for(c = 0 ; c< upto; c++) foundparts[c] = 0; for(fileentry=alldumps_list;fileentry; fileentry=fileentry->next){ dumpfile_t *cur_file = fileentry->file; if(headers_equal(file, cur_file, 1)){ if(cur_file->partnum > upto){ amfree(foundparts); return(0); } foundparts[cur_file->partnum - 1] = 1; } } for(c = 0 ; c< upto; c++){ if(!foundparts[c]){ amfree(foundparts); return(0); } } amfree(foundparts); return(1);}/* * Free up the open filehandles and memory we were using to track in-progress * dumpfiles (generally for split ones we're putting back together). If * applicable, also find the ones that are continuations of one another and * string them together. If given an optional file header argument, flush * only that dump and do not flush/free any others. */voidflush_open_outputs( int reassemble, dumpfile_t *only_file){ open_output_t *cur_out = NULL, *prev = NULL; find_result_t *sorted_files = NULL; amwait_t compress_status; if(!only_file){ g_fprintf(stderr, "\n"); } /* * Deal with any split dumps we've been working on, appending pieces * that haven't yet been appended and closing filehandles we've been * holding onto. */ if(reassemble){ find_result_t *cur_find_res = NULL; int outfd = -1, lastpartnum = -1; dumpfile_t *main_file = NULL; cur_out = open_outputs; /* stick the dumpfile_t's into a list find_result_t's so that we can abuse existing sort functionality */ for(cur_out=open_outputs; cur_out; cur_out=cur_out->next){ find_result_t *cur_find_res = NULL; dumpfile_t *cur_file = cur_out->file; /* if we requested a particular file, do only that one */ if(only_file && !headers_equal(cur_file, only_file, 1)){ continue; } cur_find_res = alloc(SIZEOF(find_result_t)); memset(cur_find_res, '\0', SIZEOF(find_result_t)); cur_find_res->timestamp = stralloc(cur_file->datestamp); cur_find_res->hostname = stralloc(cur_file->name); cur_find_res->diskname = stralloc(cur_file->disk); cur_find_res->level = cur_file->dumplevel; if(cur_file->partnum < 1) cur_find_res->partnum = stralloc("--"); else{ char part_str[NUM_STR_SIZE]; g_snprintf(part_str, SIZEOF(part_str), "%d", cur_file->partnum); cur_find_res->partnum = stralloc(part_str); } cur_find_res->user_ptr = (void*)cur_out;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -