2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: amrestore.c,v 1.63 2006/07/25 18:58:10 martinea Exp $
29 * retrieves files from an amanda tape
32 * Pulls all files from the tape that match the hostname, diskname and
33 * datestamp regular expressions.
35 * If the header is output, only up to DISK_BLOCK_BYTES worth of it is
36 * sent, regardless of the tape blocksize. This makes the disk image
37 * look like a holding disk image, and also makes it easier to remove
38 * the header (e.g. in amrecover) since it has a fixed size.
44 #include "fileheader.h"
47 #define CREAT_MODE 0640
49 static off_t file_number;
50 static pid_t comp_enc_pid = -1;
52 static off_t filefsf = (off_t)-1;
56 static void errexit(void);
57 static void usage(void);
58 int main(int argc, char **argv);
61 * Do exit(2) after an error, rather than exit(1).
72 * Print usage message and terminate.
78 error("Usage: amrestore [-b blocksize] [-r|-c] [-p] [-h] [-f fileno] "
79 "[-l label] tape-device|holdingfile [hostname [diskname [datestamp "
80 "[hostname [diskname [datestamp ... ]]]]]]");
86 * Parses command line, then loops through all files on tape, restoring
87 * files that match the command line criteria.
99 struct stat stat_tape;
101 char *filename = NULL;
102 char *tapename = NULL;
107 struct match_list *next;
108 } *match_list = NULL, *me = NULL;
111 amwait_t compress_status;
116 rst_flags_t *rst_flags;
123 set_pname("amrestore");
125 dbopen(DBG_SUBDIR_SERVER);
127 /* Don't die when child closes pipe */
128 signal(SIGPIPE, SIG_IGN);
130 erroutput_type = ERR_INTERACTIVE;
134 rst_flags = new_rst_flags();
135 rst_flags->inline_assemble = 0;
138 while( (opt = getopt(argc, argv, "b:cCd:rphf:l:")) != -1) {
141 tmplong = strtol(optarg, &e, 10);
142 rst_flags->blocksize = (ssize_t)tmplong;
143 if(*e == 'k' || *e == 'K') {
144 rst_flags->blocksize *= 1024;
145 } else if(*e == 'm' || *e == 'M') {
146 rst_flags->blocksize *= 1024 * 1024;
147 } else if(*e != '\0') {
148 error("invalid rst_flags->blocksize value \"%s\"", optarg);
151 if(rst_flags->blocksize < DISK_BLOCK_BYTES) {
152 error("minimum block size is %dk", DISK_BLOCK_BYTES / 1024);
155 if(rst_flags->blocksize > MAX_TAPE_BLOCK_KB * 1024) {
156 fprintf(stderr,"maximum block size is %dk, using it\n",
158 rst_flags->blocksize = MAX_TAPE_BLOCK_KB * 1024;
162 case 'c': rst_flags->compress = 1; break;
164 rst_flags->compress = 1;
165 rst_flags->comp_type = COMPRESS_BEST_OPT;
167 case 'r': rst_flags->raw = 1; break;
168 case 'p': rst_flags->pipe_to_fd = fileno(stdout); break;
169 case 'h': rst_flags->headers = 1; break;
171 filefsf = (off_t)OFF_T_STRTOL(optarg, &e, 10);
174 error("invalid fileno value \"%s\"", optarg);
180 label = stralloc(optarg);
187 if(rst_flags->compress && rst_flags->raw) {
189 "Cannot specify both -r (raw) and -c (compressed) output.\n");
194 fprintf(stderr, "%s: Must specify tape-device or holdingfile\n",
199 tapename = argv[optind++];
201 #define ARG_GET_HOST 0
202 #define ARG_GET_DISK 1
203 #define ARG_GET_DATE 2
205 arg_state = ARG_GET_HOST;
206 while(optind < argc) {
210 * This is a new host/disk/date triple, so allocate a match_list.
212 me = alloc(SIZEOF(*me));
213 me->hostname = argv[optind++];
216 me->next = match_list;
218 if(me->hostname[0] != '\0'
219 && (errstr=validate_regexp(me->hostname)) != NULL) {
220 fprintf(stderr, "%s: bad hostname regex \"%s\": %s\n",
221 get_pname(), me->hostname, errstr);
224 arg_state = ARG_GET_DISK;
227 me->diskname = argv[optind++];
228 if(me->diskname[0] != '\0'
229 && (errstr=validate_regexp(me->diskname)) != NULL) {
230 fprintf(stderr, "%s: bad diskname regex \"%s\": %s\n",
231 get_pname(), me->diskname, errstr);
234 arg_state = ARG_GET_DATE;
237 me->datestamp = argv[optind++];
238 if(me->datestamp[0] != '\0'
239 && (errstr=validate_regexp(me->datestamp)) != NULL) {
240 fprintf(stderr, "%s: bad datestamp regex \"%s\": %s\n",
241 get_pname(), me->datestamp, errstr);
244 arg_state = ARG_GET_HOST;
248 if(match_list == NULL) {
249 match_list = alloc(SIZEOF(*match_list));
250 match_list->hostname = "";
251 match_list->diskname = "";
252 match_list->datestamp = "";
253 match_list->next = NULL;
256 if(tape_stat(tapename,&stat_tape)!=0) {
257 error("could not stat %s: %s", tapename, strerror(errno));
260 isafile=S_ISREG((stat_tape.st_mode));
264 fprintf(stderr,"%s: ignoring -l flag when restoring from a file.\n",
268 if((err = tape_rewind(tapename)) != NULL) {
269 error("Could not rewind device '%s': %s", tapename, err);
272 if ((tapedev = tape_open(tapename, 0)) == -1) {;
273 error("Could not open device '%s': %s", tapename, err);
276 read_file_header(&file, tapedev, isafile, rst_flags);
277 if(file.type != F_TAPESTART) {
278 fprintf(stderr,"Not an amanda tape\n");
281 if(strcmp(label, file.name) != 0) {
282 fprintf(stderr,"Wrong label: '%s'\n", file.name);
285 tapefd_close(tapedev);
286 if((err = tape_rewind(tapename)) != NULL) {
287 error("Could not rewind device '%s': %s", tapename, err);
292 file_number = (off_t)0;
293 if(filefsf != (off_t)-1) {
295 fprintf(stderr,"%s: ignoring -f flag when restoring from a file.\n",
299 if((err = tape_rewind(tapename)) != NULL) {
300 error("Could not rewind device '%s': %s", tapename, err);
303 if((err = tape_fsf(tapename, filefsf)) != NULL) {
304 error("Could not fsf device '%s': %s", tapename, err);
307 file_number = filefsf;
312 tapedev = open(tapename, O_RDWR);
314 tapedev = tape_open(tapename, 0);
317 error("could not open %s: %s", tapename, strerror(errno));
321 read_result = read_file_header(&file, tapedev, isafile, rst_flags);
322 if(file.type != F_TAPESTART && !isafile && filefsf == (off_t)-1) {
323 fprintf(stderr, "%s: WARNING: not at start of tape, file numbers will be offset\n",
328 while(count_error < 10) {
329 if(file.type == F_TAPEEND) break;
331 if(file.type == F_DUMPFILE || file.type == F_SPLIT_DUMPFILE) {
333 filename = make_filename(&file);
334 for(me = match_list; me; me = me->next) {
335 if(disk_match(&file,me->datestamp,me->hostname,me->diskname,"") != 0) {
340 fprintf(stderr, "%s: " OFF_T_FMT ": %s ",
342 (OFF_T_FMT_TYPE)file_number,
343 found_match ? "restoring" : "skipping");
344 if(file.type != F_DUMPFILE && file.type != F_SPLIT_DUMPFILE) {
345 print_header(stderr, &file);
347 fprintf(stderr, "%s\n", filename);
352 read_result = restore(&file, filename,
353 tapedev, isafile, rst_flags);
354 if(comp_enc_pid > 0) {
355 waitpid(comp_enc_pid, &compress_status, 0);
358 if(rst_flags->pipe_to_fd != -1) {
359 file_number++; /* for the last message */
367 * Note that at this point we know we are working with a tape,
368 * not a holding disk file, so we can call the tape functions
371 if(read_result == 0) {
373 * If the last read got EOF, how to get to the next
374 * file depends on how the tape device driver is acting.
375 * If it is BSD-like, we do not really need to do anything.
376 * If it is Sys-V-like, we need to either fsf or close/open.
377 * The good news is, a close/open works in either case,
378 * so that's what we do.
380 tapefd_close(tapedev);
381 if((tapedev = tape_open(tapename, 0)) < 0) {
382 error("could not open %s: %s", tapename, strerror(errno));
388 * If the last read got something (even an error), we can
389 * do an fsf to get to the next file.
391 if(tapefd_fsf(tapedev, (off_t)1) < 0) {
392 error("could not fsf %s: %s", tapename, strerror(errno));
398 read_result = read_file_header(&file, tapedev, isafile, rst_flags);
404 * See the notes above about advancing to the next file.
406 if(read_result == 0) {
407 tapefd_close(tapedev);
408 if((tapedev = tape_open(tapename, 0)) < 0) {
409 error("could not open %s: %s", tapename, strerror(errno));
413 if(tapefd_fsf(tapedev, (off_t)1) < 0) {
414 error("could not fsf %s: %s", tapename, strerror(errno));
418 tapefd_close(tapedev);
421 if((read_result <= 0 || file.type == F_TAPEEND) && !isafile) {
422 fprintf(stderr, "%s: " OFF_T_FMT ": reached ",
423 get_pname(), (OFF_T_FMT_TYPE)file_number);
424 if(read_result <= 0) {
425 fprintf(stderr, "end of information\n");
427 print_header(stderr,&file);