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 6512 2007-05-24 17:00:24Z ian $
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.
43 #include "fileheader.h"
49 #define CREAT_MODE 0640
52 * Print usage message and terminate.
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 ... ]]]]]]"));
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
70 Returns TRUE if we suspect the device is a holding disk, FALSE
72 static gboolean check_device_type(char * device_name) {
76 result = stat(device_name, &stat_buf);
78 return !((result != 0 || !S_ISREG(stat_buf.st_mode)));
81 static void handle_holding_disk_restore(char * filename, rst_flags_t * flags,
83 dumpfile_t this_header;
86 bzero(&this_disk, sizeof(this_disk));
87 this_disk.label = filename;
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);
96 static void handle_tape_restore(char * device_name, rst_flags_t * flags,
97 GSList * dumpspecs, char * check_label) {
99 DeviceStatusFlags device_status;
101 dumpfile_t first_restored_file;
105 fh_init(&first_restored_file);
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));
113 if (!device_configure(device, TRUE)) {
114 error("Error configuring device: %s",
115 device_error_or_status(device));
118 if (!set_restore_device_read_buffer_size(device, flags)) {
119 error("Error setting read block size: %s.\n", device_error_or_status(device));
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));
126 g_assert(device->volume_label != NULL);
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));
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);
139 search_a_tape(device, stderr, flags, NULL, NULL, dumpspecs,
140 NULL, &first_restored_file, 0, NULL);
144 * Parses command line, then loops through all files on tape, restoring
145 * files that match the command line criteria.
155 int holding_disk_mode;
156 char *tapename = NULL;
159 rst_flags_t *rst_flags;
162 config_overwrites_t *cfg_ovr;
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.
170 setlocale(LC_MESSAGES, "C");
171 textdomain("amanda");
175 set_pname("amrestore");
177 dbopen(DBG_SUBDIR_SERVER);
179 /* Don't die when child closes pipe */
180 signal(SIGPIPE, SIG_IGN);
182 erroutput_type = ERR_INTERACTIVE;
183 error_exit_status = 2;
185 rst_flags = new_rst_flags();
186 rst_flags->inline_assemble = 0;
188 cfg_ovr = new_config_overwrites(argc/2);
190 while( (opt = getopt(argc, argv, "b:cCd:rphf:l:o:")) != -1) {
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);
204 case 'c': rst_flags->compress = 1; break;
206 add_config_overwrite_opt(cfg_ovr, optarg);
209 rst_flags->compress = 1;
210 rst_flags->comp_type = COMPRESS_BEST_OPT;
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);
218 error(_("invalid fileno value \"%s\""), optarg);
219 g_assert_not_reached();
225 error(_("Cannot specify multiple labels.\n"));
227 label = stralloc(optarg);
234 /* initialize a generic configuration without reading anything */
235 config_init(0, NULL);
236 apply_config_overwrites(cfg_ovr);
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"));
245 if(rst_flags->compress && rst_flags->raw) {
247 _("Cannot specify both -r (raw) and -c (compressed) output.\n"));
252 g_fprintf(stderr, _("%s: Must specify tape-device or holdingfile\n"),
257 tapename = argv[optind++];
259 dumpspecs = cmdline_parse_dumpspecs(argc - optind, argv + optind,
260 CMDLINE_PARSE_DATESTAMP |
261 CMDLINE_EMPTY_TO_WILDCARD);
263 holding_disk_mode = check_device_type(tapename);
265 if (holding_disk_mode) {
267 g_fprintf(stderr,_("%s: ignoring -l flag when restoring from a file.\n"),
271 if (rst_flags->fsf > 0) {
273 "%s: ignoring -f flag when restoring from a file.\n",
277 handle_holding_disk_restore(tapename, rst_flags, dumpspecs);
279 handle_tape_restore(tapename, rst_flags, dumpspecs, label);
282 dumpspec_list_free(dumpspecs);