Imported Upstream version 2.6.0p1
[debian/amanda] / restore-src / amrestore.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 University of Maryland at College Park
4  * All Rights Reserved.
5  *
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.
15  *
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.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /*
27  * $Id: amrestore.c 6512 2007-05-24 17:00:24Z ian $
28  *
29  * retrieves files from an amanda tape
30  */
31 /*
32  * Pulls all files from the tape that match the hostname, diskname and
33  * datestamp regular expressions.
34  *
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.
39  */
40
41 #include "amanda.h"
42 #include "util.h"
43 #include "fileheader.h"
44 #include "restore.h"
45 #include "conffile.h"
46 #include "device.h"
47 #include "cmdline.h"
48
49 #define CREAT_MODE      0640
50
51 /*
52  * Print usage message and terminate.
53  */
54
55 static void
56 usage(void)
57 {
58     error(_("Usage: amrestore [-b blocksize] [-r|-c] [-p] [-h] [-f fileno] "
59           "[-l label] tape-device|holdingfile [hostname [diskname [datestamp "
60           "[hostname [diskname [datestamp ... ]]]]]]"));
61     /*NOTREACHED*/
62 }
63
64 /* Checks if the given tape device is actually a holding disk file. We
65    accomplish this by stat()ing the file; if it is a regular file, we
66    assume (somewhat dangerously) that it's a holding disk file. If
67    it doesn't exist or is not a regular file, we assume it's a device
68    name.
69
70    Returns TRUE if we suspect the device is a holding disk, FALSE
71    otherwise. */
72 static gboolean check_device_type(char * device_name) {
73     struct stat stat_buf;
74     int result;
75     
76     result = stat(device_name, &stat_buf);
77
78     return !((result != 0 || !S_ISREG(stat_buf.st_mode)));
79 }
80
81 static void handle_holding_disk_restore(char * filename, rst_flags_t * flags,
82                                         GSList * dumpspecs) {
83     dumpfile_t this_header;
84     tapelist_t this_disk;
85
86     bzero(&this_disk, sizeof(this_disk));
87     this_disk.label = filename;
88
89     if (!restore_holding_disk(stderr, flags, NULL, &this_disk, NULL,
90                               dumpspecs, &this_header, NULL)) {
91         g_fprintf(stderr, "%s did not match requested host.\n", filename);
92         return;
93     }
94 }
95
96 static void handle_tape_restore(char * device_name, rst_flags_t * flags,
97                                 GSList * dumpspecs, char * check_label) {
98     Device * device;
99     ReadLabelStatusFlags read_label_status;
100
101     dumpfile_t first_restored_file;
102
103     device_api_init();
104
105     fh_init(&first_restored_file);
106     
107     device = device_open(device_name);
108     if (device == NULL) {
109         error("Could not open device.\n");
110     }
111     
112     device_set_startup_properties_from_config(device);
113     read_label_status = device_read_label(device);
114     if (read_label_status != READ_LABEL_STATUS_SUCCESS) {
115         char * errstr =
116             g_english_strjoinv_and_free
117                 (g_flags_nick_to_strv(read_label_status,
118                                       READ_LABEL_STATUS_FLAGS_TYPE), "or");
119         error("Error reading volume label: %s.\n", errstr);
120     }
121
122     g_assert(device->volume_label != NULL);
123
124     if (!device_start(device, ACCESS_READ, NULL, NULL)) {
125         error("Could not open device %s for reading.\n", device_name);
126     }
127
128     if (check_label != NULL && strcmp(check_label,
129                                       device->volume_label) != 0) {
130         error("Wrong label: Expected %s, found %s.\n",
131               check_label, device->volume_label);
132     }
133
134     search_a_tape(device, stderr, flags, NULL, NULL, dumpspecs,
135                   NULL, &first_restored_file, 0, NULL);
136 }
137
138 /*
139  * Parses command line, then loops through all files on tape, restoring
140  * files that match the command line criteria.
141  */
142
143 int
144 main(
145     int         argc,
146     char **     argv)
147 {
148     extern int optind;
149     int opt;
150     int holding_disk_mode;
151     char *tapename = NULL;
152     char *e;
153     char *label = NULL;
154     rst_flags_t *rst_flags;
155     long tmplong;
156     GSList *dumpspecs;
157     config_overwrites_t *cfg_ovr;
158
159     /*
160      * Configure program for internationalization:
161      *   1) Only set the message locale for now.
162      *   2) Set textdomain for all amanda related programs to "amanda"
163      *      We don't want to be forced to support dozens of message catalogs.
164      */  
165     setlocale(LC_MESSAGES, "C");
166     textdomain("amanda"); 
167
168     safe_fd(-1, 0);
169
170     set_pname("amrestore");
171
172     dbopen(DBG_SUBDIR_SERVER);
173
174     /* Don't die when child closes pipe */
175     signal(SIGPIPE, SIG_IGN);
176
177     erroutput_type = ERR_INTERACTIVE;
178     error_exit_status = 2;
179
180     rst_flags = new_rst_flags();
181     rst_flags->inline_assemble = 0;
182
183     cfg_ovr = new_config_overwrites(argc/2);
184     /* handle options */
185     while( (opt = getopt(argc, argv, "b:cCd:rphf:l:o:")) != -1) {
186         switch(opt) {
187         case 'b':
188             tmplong = strtol(optarg, &e, 10);
189             rst_flags->blocksize = (ssize_t)tmplong;
190             if(*e == 'k' || *e == 'K') {
191                 rst_flags->blocksize *= 1024;
192             } else if(*e == 'm' || *e == 'M') {
193                 rst_flags->blocksize *= 1024 * 1024;
194             } else if(*e != '\0') {
195                 error(_("invalid blocksize value \"%s\""), optarg);
196                 /*NOTREACHED*/
197             }
198             if(rst_flags->blocksize < DISK_BLOCK_BYTES) {
199                 error(_("minimum block size is %dk"), DISK_BLOCK_BYTES / 1024);
200                 /*NOTREACHED*/
201             }
202             break;
203         case 'c': rst_flags->compress = 1; break;
204         case 'o':
205             add_config_overwrite_opt(cfg_ovr, optarg);
206             break;
207         case 'C':
208             rst_flags->compress = 1;
209             rst_flags->comp_type = COMPRESS_BEST_OPT;
210             break;
211         case 'r': rst_flags->raw = 1; break;
212         case 'p': rst_flags->pipe_to_fd = fileno(stdout); break;
213         case 'h': rst_flags->headers = 1; break;
214         case 'f': rst_flags->fsf = (off_t)OFF_T_STRTOL(optarg, &e, 10);
215             /*@ignore@*/
216             if(*e != '\0') {
217                 error(_("invalid fileno value \"%s\""), optarg);
218                 g_assert_not_reached();
219             }
220             /*@end@*/
221             break;
222         case 'l':
223             label = stralloc(optarg);
224             break;
225         default:
226             usage();
227         }
228     }
229
230     /* initialize a generic configuration without reading anything */
231     config_init(CONFIG_INIT_CLIENT, NULL);
232     apply_config_overwrites(cfg_ovr);
233
234     if(rst_flags->compress && rst_flags->raw) {
235         g_fprintf(stderr,
236                 _("Cannot specify both -r (raw) and -c (compressed) output.\n"));
237         usage();
238     }
239
240     if(optind >= argc) {
241         g_fprintf(stderr, _("%s: Must specify tape-device or holdingfile\n"),
242                         get_pname());
243         usage();
244     }
245
246     tapename = argv[optind++];
247
248     dumpspecs = cmdline_parse_dumpspecs(argc - optind, argv + optind, 
249                                         CMDLINE_PARSE_DATESTAMP |
250                                         CMDLINE_EMPTY_TO_WILDCARD);
251
252     holding_disk_mode = check_device_type(tapename);
253
254     if (holding_disk_mode) {
255         if (label) {
256             g_fprintf(stderr,_("%s: ignoring -l flag when restoring from a file.\n"),
257                     get_pname());
258         }
259
260         if (rst_flags->fsf > 0) {
261             g_fprintf(stderr,
262                     "%s: ignoring -f flag when restoring from a file.\n",
263                     get_pname());
264         }
265
266         handle_holding_disk_restore(tapename, rst_flags, dumpspecs);
267     } else {
268         handle_tape_restore(tapename, rst_flags, dumpspecs, label);
269     }
270
271     dumpspec_list_free(dumpspecs);
272
273     return 0;
274 }