Imported Upstream version 2.6.1p2
[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     DeviceStatusFlags device_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     g_assert(device != NULL);
109     if (device->status != DEVICE_STATUS_SUCCESS) {
110         error("Could not open device %s: %s.\n", device_name, device_error(device));
111     }
112     
113     if (!device_configure(device, TRUE)) {
114         error("Error configuring device: %s",
115                 device_error_or_status(device));
116     }
117
118     if (!set_restore_device_read_buffer_size(device, flags)) {
119         error("Error setting read block size: %s.\n", device_error_or_status(device));
120     }
121     device_status = device_read_label(device);
122     if (device_status != DEVICE_STATUS_SUCCESS) {
123         error("Error reading volume label: %s.\n", device_error_or_status(device));
124     }
125
126     g_assert(device->volume_label != NULL);
127
128     if (!device_start(device, ACCESS_READ, NULL, NULL)) {
129         error("Could not open device %s for reading: %s.\n", device_name,
130               device_error(device));
131     }
132
133     if (check_label != NULL && strcmp(check_label,
134                                       device->volume_label) != 0) {
135         error("Wrong label: Expected %s, found %s.\n",
136               check_label, device->volume_label);
137     }
138
139     search_a_tape(device, stderr, flags, NULL, NULL, dumpspecs,
140                   NULL, &first_restored_file, 0, NULL);
141 }
142
143 /*
144  * Parses command line, then loops through all files on tape, restoring
145  * files that match the command line criteria.
146  */
147
148 int
149 main(
150     int         argc,
151     char **     argv)
152 {
153     extern int optind;
154     int opt;
155     int holding_disk_mode;
156     char *tapename = NULL;
157     char *e;
158     char *label = NULL;
159     rst_flags_t *rst_flags;
160     long tmplong;
161     GSList *dumpspecs;
162     config_overwrites_t *cfg_ovr;
163
164     /*
165      * Configure program for internationalization:
166      *   1) Only set the message locale for now.
167      *   2) Set textdomain for all amanda related programs to "amanda"
168      *      We don't want to be forced to support dozens of message catalogs.
169      */  
170     setlocale(LC_MESSAGES, "C");
171     textdomain("amanda"); 
172
173     safe_fd(-1, 0);
174
175     set_pname("amrestore");
176
177     dbopen(DBG_SUBDIR_SERVER);
178
179     /* Don't die when child closes pipe */
180     signal(SIGPIPE, SIG_IGN);
181
182     erroutput_type = ERR_INTERACTIVE;
183     error_exit_status = 2;
184
185     rst_flags = new_rst_flags();
186     rst_flags->inline_assemble = 0;
187
188     cfg_ovr = new_config_overwrites(argc/2);
189     /* handle options */
190     while( (opt = getopt(argc, argv, "b:cCd:rphf:l:o:")) != -1) {
191         switch(opt) {
192         case 'b':
193             tmplong = strtol(optarg, &e, 10);
194             rst_flags->blocksize = (ssize_t)tmplong;
195             if(*e == 'k' || *e == 'K') {
196                 rst_flags->blocksize *= 1024;
197             } else if(*e == 'm' || *e == 'M') {
198                 rst_flags->blocksize *= 1024 * 1024;
199             } else if(*e != '\0') {
200                 error(_("invalid blocksize value \"%s\""), optarg);
201                 /*NOTREACHED*/
202             }
203             break;
204         case 'c': rst_flags->compress = 1; break;
205         case 'o':
206             add_config_overwrite_opt(cfg_ovr, optarg);
207             break;
208         case 'C':
209             rst_flags->compress = 1;
210             rst_flags->comp_type = COMPRESS_BEST_OPT;
211             break;
212         case 'r': rst_flags->raw = 1; break;
213         case 'p': rst_flags->pipe_to_fd = fileno(stdout); break;
214         case 'h': rst_flags->headers = 1; break;
215         case 'f': rst_flags->fsf = (off_t)OFF_T_STRTOL(optarg, &e, 10);
216             /*@ignore@*/
217             if(*e != '\0') {
218                 error(_("invalid fileno value \"%s\""), optarg);
219                 g_assert_not_reached();
220             }
221             /*@end@*/
222             break;
223         case 'l':
224             if (label) {
225                 error(_("Cannot specify multiple labels.\n"));
226             }
227             label = stralloc(optarg);
228             break;
229         default:
230             usage();
231         }
232     }
233
234     /* initialize a generic configuration without reading anything */
235     config_init(0, NULL);
236     apply_config_overwrites(cfg_ovr);
237
238     if (config_errors(NULL) >= CFGERR_WARNINGS) {
239         config_print_errors();
240         if (config_errors(NULL) >= CFGERR_ERRORS) {
241             g_critical(_("errors processing config file"));
242         }
243     }
244
245     if(rst_flags->compress && rst_flags->raw) {
246         g_fprintf(stderr,
247                 _("Cannot specify both -r (raw) and -c (compressed) output.\n"));
248         usage();
249     }
250
251     if(optind >= argc) {
252         g_fprintf(stderr, _("%s: Must specify tape-device or holdingfile\n"),
253                         get_pname());
254         usage();
255     }
256
257     tapename = argv[optind++];
258
259     dumpspecs = cmdline_parse_dumpspecs(argc - optind, argv + optind, 
260                                         CMDLINE_PARSE_DATESTAMP |
261                                         CMDLINE_EMPTY_TO_WILDCARD);
262
263     holding_disk_mode = check_device_type(tapename);
264
265     if (holding_disk_mode) {
266         if (label) {
267             g_fprintf(stderr,_("%s: ignoring -l flag when restoring from a file.\n"),
268                     get_pname());
269         }
270
271         if (rst_flags->fsf > 0) {
272             g_fprintf(stderr,
273                     "%s: ignoring -f flag when restoring from a file.\n",
274                     get_pname());
275         }
276
277         handle_holding_disk_restore(tapename, rst_flags, dumpspecs);
278     } else {
279         handle_tape_restore(tapename, rst_flags, dumpspecs, label);
280     }
281
282     dumpspec_list_free(dumpspecs);
283
284     return 0;
285 }