⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 amfetchdump.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 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: amfetchdump.c,v 1.16 2006/08/24 01:57:15 paddy_s Exp $ * * retrieves specific dumps from a set of amanda tapes */#include "amanda.h"#include "fileheader.h"#include "util.h"#include "restore.h"#include "diskfile.h"#include "tapefile.h"#include "find.h"#include "changer.h"#include "logfile.h"#include "cmdline.h"#define CREAT_MODE	0640extern char *rst_conf_logfile;extern char *config_dir;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;} needed_tape_t;/* local functions */tapelist_t *list_needed_tapes(GSList *dumpspecs, int only_one);void usage(void);int main(int argc, char **argv);/* exit routine */static pid_t parent_pid = -1;static void cleanup(void);/* * Print usage message and terminate. */voidusage(void){    g_fprintf(stderr, _("Usage: amfetchdump [options] config hostname [diskname [datestamp [level [hostname [diskname [datestamp [level ... ]]]]]]] [-o configoption]*\n\n"));    g_fprintf(stderr, _("Goes and grabs a dump from tape, moving tapes around and assembling parts as\n"));    g_fprintf(stderr, _("necessary.  Files are restored to the current directory, unless otherwise\nspecified.\n\n"));    g_fprintf(stderr, _("  -p Pipe exactly *one* complete dumpfile to stdout, instead of to disk.\n"));    g_fprintf(stderr, _("  -O <output dir> Restore files to this directory.\n"));    g_fprintf(stderr, _("  -d <device> Force restoration from a particular tape device.\n"));    g_fprintf(stderr, _("  -c Compress output, fastest method available.\n"));    g_fprintf(stderr, _("  -C Compress output, best filesize method available.\n"));    g_fprintf(stderr, _("  -l Leave dumps (un)compressed, whichever way they were originally on tape.\n"));    g_fprintf(stderr, _("  -a Assume all tapes are available via changer, do not prompt for initial load.\n"));    g_fprintf(stderr, _("  -i <dst_file> Search through tapes and write out an inventory while we\n     restore.  Useful only if normal logs are unavailable.\n"));    g_fprintf(stderr, _("  -w Wait to put split dumps together until all chunks have been restored.\n"));    g_fprintf(stderr, _("  -n Do not reassemble split dumpfiles.\n"));    g_fprintf(stderr, _("  -k Skip the rewind/label read when reading a new tape.\n"));    g_fprintf(stderr, _("  -s Do not use fast forward to skip files we won't restore.  Use only if fsf\n     causes your tapes to skip too far.\n"));    g_fprintf(stderr, _("  -b <blocksize> Force a particular block size (default is 32kb).\n"));    exit(1);}/* * 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){    needed_tape_t *needed_tapes = NULL, *curtape = NULL;    disklist_t diskqp;    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);    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);    free_disklist(&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);    for(curmatch = matches; curmatch; curmatch = curmatch->next) {	int havetape = 0;	int have_part = 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;	}	/* 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) {	    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){		    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;		}		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;		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;	    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++;	} /* if(!havetape) */    } /* for(curmatch = matches ... */    if(numtapes == 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);	}    }    g_fprintf(stderr, _("%d tape(s) needed for restoration\n"), numtapes);    return(tapes);}/* * Parses command line, then loops through all files on tape, restoring * files that match the command line criteria. */intmain(    int		argc,    char **	argv){    extern int optind;    int opt;    GSList *dumpspecs = NULL;    int fd;    tapelist_t *needed_tapes = NULL;    char *e;    rst_flags_t *rst_flags;    int minimum_arguments;    config_overwrites_t *cfg_ovr = NULL;    /*     * Configure program for internationalization:     *   1) Only set the message locale for now.     *   2) Set textdomain for all amanda related programs to "amanda"     *      We don't want to be forced to support dozens of message catalogs.     */      setlocale(LC_MESSAGES, "C");    textdomain("amanda");     for(fd = 3; fd < (int)FD_SETSIZE; fd++) {	/*	 * Make sure nobody spoofs us with a lot of extra open files	 * that would cause a successful open to get a very high file	 * descriptor, which in turn might be used as an index into	 * an array (e.g. an fd_set).	 */	close(fd);    }    set_pname("amfetchdump");    /* Don't die when child closes pipe */    signal(SIGPIPE, SIG_IGN);    dbopen(DBG_SUBDIR_SERVER);    erroutput_type = ERR_INTERACTIVE;    error_exit_status = 2;    rst_flags = new_rst_flags();    rst_flags->wait_tape_prompt = 1;    /* handle options */    cfg_ovr = new_config_overwrites(argc/2);    while( (opt = getopt(argc, argv, "alht:scCpb:nwi:d:O:o:")) != -1) {	switch(opt) {	case 'b':            rst_flags->blocksize = (ssize_t)strtol(optarg, &e, 10);            if(*e == 'k' || *e == 'K') {	        rst_flags->blocksize *= 1024;	    } else if(*e == 'm' || *e == 'M') {	        rst_flags->blocksize *= 1024 * 1024;	    } else if(*e != '\0') {	        error(_("invalid blocksize value \"%s\""), optarg);		/*NOTREACHED*/	    }	    if(rst_flags->blocksize < DISK_BLOCK_BYTES) {	        error(_("minimum block size is %dk"), DISK_BLOCK_BYTES / 1024);		/*NOTREACHED*/	    }	    break;	case 'c': rst_flags->compress = 1; break;	case 'O': rst_flags->restore_dir = stralloc(optarg) ; break;	case 'd': rst_flags->alt_tapedev = stralloc(optarg) ; break;	case 'C':	    rst_flags->compress = 1;	    rst_flags->comp_type = COMPRESS_BEST_OPT;	    break;	case 'p': rst_flags->pipe_to_fd = STDOUT_FILENO; break;	case 's': rst_flags->fsf = (off_t)0; break;	case 'l': rst_flags->leave_comp = 1; break;	case 'i': rst_flags->inventory_log = stralloc(optarg); break;	case 'n': rst_flags->inline_assemble = 0; break;	case 'w': rst_flags->delay_assemble = 1; break;	case 'a': rst_flags->wait_tape_prompt = 0; break;	case 'h': rst_flags->headers = 1; break;	case 'o': add_config_overwrite_opt(cfg_ovr, optarg); break;	default:	    usage();	    /*NOTREACHED*/	}    }    /* Check some flags that affect inventorying */    if(rst_flags->inventory_log){	if(rst_flags->inline_assemble) rst_flags->delay_assemble = 1;	rst_flags->inline_assemble = 0;	rst_flags->leave_comp = 1;	if(rst_flags->compress){	    error(_("Cannot force compression when doing inventory/search"));	    /*NOTREACHED*/	}	g_fprintf(stderr, _("Doing inventory/search, dumps will not be uncompressed or assembled on-the-fly.\n"));    }    else{	if(rst_flags->delay_assemble){	    g_fprintf(stderr, _("Using -w, split dumpfiles will *not* be automatically uncompressed.\n"));	}    }    /* make sure our options all make sense otherwise */    if(check_rst_flags(rst_flags) == -1) {    	usage();	/*NOTREACHED*/    }    if (rst_flags->inventory_log) {        minimum_arguments = 1;    } else {        minimum_arguments = 2;    }     if(argc - optind < minimum_arguments) {	usage();	/*NOTREACHED*/    }    config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_FATAL, argv[optind++]);    apply_config_overwrites(cfg_ovr);    check_running_as(RUNNING_AS_DUMPUSER);    dbrename(config_name, DBG_SUBDIR_SERVER);    dumpspecs = cmdline_parse_dumpspecs(argc - optind, argv + optind,					CMDLINE_PARSE_DATESTAMP |					CMDLINE_PARSE_LEVEL |					CMDLINE_EMPTY_TO_WILDCARD);    /*     * We've been told explicitly to go and search through the tapes the hard     * way.     */    if(rst_flags->inventory_log){	g_fprintf(stderr, _("Beginning tape-by-tape search.\n"));	search_tapes(stderr, stdin, rst_flags->alt_tapedev == NULL,                     NULL, dumpspecs, rst_flags, NULL);	exit(0);    }    /* Decide what tapes we'll need */    needed_tapes = list_needed_tapes(dumpspecs,				     rst_flags->pipe_to_fd == STDOUT_FILENO);    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);    }    search_tapes(NULL, stdin, rst_flags->alt_tapedev == NULL,                 needed_tapes, dumpspecs, rst_flags, NULL);    cleanup();    dumpspec_list_free(dumpspecs);    if(rst_flags->inline_assemble || rst_flags->delay_assemble)	flush_open_outputs(1, NULL);    else flush_open_outputs(0, NULL);    free_rst_flags(rst_flags);    return(0);}static voidcleanup(void){    if(parent_pid == getpid()) {	if(get_lock) unlink(rst_conf_logfile);    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -