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 ReadLabelStatusFlags read_label_status;
101 dumpfile_t first_restored_file;
105 fh_init(&first_restored_file);
107 device = device_open(device_name);
108 if (device == NULL) {
109 error("Could not open device.\n");
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) {
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);
122 g_assert(device->volume_label != NULL);
124 if (!device_start(device, ACCESS_READ, NULL, NULL)) {
125 error("Could not open device %s for reading.\n", device_name);
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);
134 search_a_tape(device, stderr, flags, NULL, NULL, dumpspecs,
135 NULL, &first_restored_file, 0, NULL);
139 * Parses command line, then loops through all files on tape, restoring
140 * files that match the command line criteria.
150 int holding_disk_mode;
151 char *tapename = NULL;
154 rst_flags_t *rst_flags;
157 config_overwrites_t *cfg_ovr;
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.
165 setlocale(LC_MESSAGES, "C");
166 textdomain("amanda");
170 set_pname("amrestore");
172 dbopen(DBG_SUBDIR_SERVER);
174 /* Don't die when child closes pipe */
175 signal(SIGPIPE, SIG_IGN);
177 erroutput_type = ERR_INTERACTIVE;
178 error_exit_status = 2;
180 rst_flags = new_rst_flags();
181 rst_flags->inline_assemble = 0;
183 cfg_ovr = new_config_overwrites(argc/2);
185 while( (opt = getopt(argc, argv, "b:cCd:rphf:l:o:")) != -1) {
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);
198 if(rst_flags->blocksize < DISK_BLOCK_BYTES) {
199 error(_("minimum block size is %dk"), DISK_BLOCK_BYTES / 1024);
203 case 'c': rst_flags->compress = 1; break;
205 add_config_overwrite_opt(cfg_ovr, optarg);
208 rst_flags->compress = 1;
209 rst_flags->comp_type = COMPRESS_BEST_OPT;
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);
217 error(_("invalid fileno value \"%s\""), optarg);
218 g_assert_not_reached();
223 label = stralloc(optarg);
230 /* initialize a generic configuration without reading anything */
231 config_init(CONFIG_INIT_CLIENT, NULL);
232 apply_config_overwrites(cfg_ovr);
234 if(rst_flags->compress && rst_flags->raw) {
236 _("Cannot specify both -r (raw) and -c (compressed) output.\n"));
241 g_fprintf(stderr, _("%s: Must specify tape-device or holdingfile\n"),
246 tapename = argv[optind++];
248 dumpspecs = cmdline_parse_dumpspecs(argc - optind, argv + optind,
249 CMDLINE_PARSE_DATESTAMP |
250 CMDLINE_EMPTY_TO_WILDCARD);
252 holding_disk_mode = check_device_type(tapename);
254 if (holding_disk_mode) {
256 g_fprintf(stderr,_("%s: ignoring -l flag when restoring from a file.\n"),
260 if (rst_flags->fsf > 0) {
262 "%s: ignoring -f flag when restoring from a file.\n",
266 handle_holding_disk_restore(tapename, rst_flags, dumpspecs);
268 handle_tape_restore(tapename, rst_flags, dumpspecs, label);
271 dumpspec_list_free(dumpspecs);