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