PageRenderTime 50ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/amanda/tags/amanda260p2/restore-src/restore.c

#
C | 2090 lines | 1590 code | 228 blank | 272 comment | 444 complexity | 74dcc5f1203406d5aab6a07b29ddf001 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  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: restore.c 6512 2007-05-24 17:00:24Z ian $
  28. *
  29. * retrieves files from an amanda tape
  30. */
  31. #include "amanda.h"
  32. #include "util.h"
  33. #include "restore.h"
  34. #include "find.h"
  35. #include "changer.h"
  36. #include "logfile.h"
  37. #include "fileheader.h"
  38. #include "arglist.h"
  39. #include "cmdline.h"
  40. #include <signal.h>
  41. #include <timestamp.h>
  42. #include <device.h>
  43. #include <queueing.h>
  44. #include <glib.h>
  45. typedef enum {
  46. LOAD_NEXT = 1, /* An unknown new slot has been loaded. */
  47. LOAD_CHANGER = -2, /* The requested slot has been loaded. */
  48. LOAD_STOP = -1, /* The search is complete. */
  49. } LoadStatus;
  50. typedef enum {
  51. RESTORE_STATUS_NEXT_FILE,
  52. RESTORE_STATUS_NEXT_TAPE,
  53. RESTORE_STATUS_STOP
  54. } RestoreFileStatus;
  55. int file_number;
  56. /* stuff we're stuck having global */
  57. static int backwards;
  58. static int exitassemble = 0;
  59. char *rst_conf_logdir = NULL;
  60. char *rst_conf_logfile = NULL;
  61. static char *curslot = NULL;
  62. typedef struct open_output_s {
  63. struct open_output_s *next;
  64. dumpfile_t *file;
  65. int lastpartnum;
  66. pid_t comp_enc_pid;
  67. int outfd;
  68. } open_output_t;
  69. typedef struct dumplist_s {
  70. struct dumplist_s *next;
  71. dumpfile_t *file;
  72. } dumplist_t;
  73. struct seentapes_s {
  74. struct seentapes_s *next;
  75. char *slotstr;
  76. char *label;
  77. dumplist_t *files;
  78. };
  79. static open_output_t *open_outputs = NULL;
  80. static dumplist_t *alldumps_list = NULL;
  81. /* local functions */
  82. static void append_file_to_fd(char *filename, int fd);
  83. static int headers_equal(dumpfile_t *file1, dumpfile_t *file2, int ignore_partnums);
  84. static int already_have_dump(dumpfile_t *file);
  85. static void handle_sigint(int sig);
  86. static int scan_init(void *ud, int rc, int ns, int bk, int s);
  87. static Device * conditional_device_open(char * tapedev, FILE * orompt_out,
  88. rst_flags_t * flags,
  89. am_feature_t * their_features,
  90. tapelist_t * desired_tape);
  91. int loadlabel_slot(void *ud, int rc, char *slotstr, char *device);
  92. char *label_of_current_slot(char *cur_tapedev, FILE *prompt_out,
  93. int *tapefd, dumpfile_t *file, rst_flags_t *flags,
  94. am_feature_t *their_features,
  95. ssize_t *read_result, tapelist_t *desired_tape);
  96. LoadStatus load_next_tape(char **cur_tapedev, FILE *prompt_out, int backwards,
  97. rst_flags_t *flags, am_feature_t *their_features,
  98. tapelist_t *desired_tape);
  99. LoadStatus load_manual_tape(char **cur_tapedev, FILE *prompt_out, FILE *prompt_in,
  100. rst_flags_t *flags, am_feature_t *their_features,
  101. tapelist_t *desired_tape);
  102. /*
  103. * We might want to flush any open dumps and unmerged splits before exiting
  104. * on SIGINT, so do so.
  105. */
  106. static void
  107. handle_sigint(
  108. int sig)
  109. {
  110. (void)sig; /* Quiet unused parameter warning */
  111. flush_open_outputs(exitassemble, NULL);
  112. if(rst_conf_logfile) unlink(rst_conf_logfile);
  113. exit(0);
  114. }
  115. int
  116. lock_logfile(void)
  117. {
  118. rst_conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
  119. rst_conf_logfile = vstralloc(rst_conf_logdir, "/log", NULL);
  120. if (access(rst_conf_logfile, F_OK) == 0) {
  121. dbprintf(_("%s exists: amdump or amflush is already running, "
  122. "or you must run amcleanup\n"), rst_conf_logfile);
  123. return 0;
  124. }
  125. log_add(L_INFO, get_pname());
  126. return 1;
  127. }
  128. /*
  129. * Return 1 if the two fileheaders match in name, disk, type, split chunk part
  130. * number, and datestamp, and 0 if not. The part number can be optionally
  131. * ignored.
  132. */
  133. int
  134. headers_equal(
  135. dumpfile_t *file1,
  136. dumpfile_t *file2,
  137. int ignore_partnums)
  138. {
  139. if(!file1 || !file2) return(0);
  140. if(file1->dumplevel == file2->dumplevel &&
  141. file1->type == file2->type &&
  142. !strcmp(file1->datestamp, file2->datestamp) &&
  143. !strcmp(file1->name, file2->name) &&
  144. !strcmp(file1->disk, file2->disk) &&
  145. (ignore_partnums || file1->partnum == file2->partnum)){
  146. return(1);
  147. }
  148. return(0);
  149. }
  150. /*
  151. * See whether we're already pulled an exact copy of the given file (chunk
  152. * number and all). Returns 0 if not, 1 if so.
  153. */
  154. int
  155. already_have_dump(
  156. dumpfile_t *file)
  157. {
  158. dumplist_t *fileentry = NULL;
  159. if(!file) return(0);
  160. for(fileentry=alldumps_list;fileentry;fileentry=fileentry->next){
  161. if(headers_equal(file, fileentry->file, 0)) return(1);
  162. }
  163. return(0);
  164. }
  165. /*
  166. * Open the named file and append its contents to the (hopefully open) file
  167. * descriptor supplies.
  168. */
  169. static void
  170. append_file_to_fd(
  171. char * filename,
  172. int write_fd)
  173. {
  174. int read_fd;
  175. read_fd = robust_open(filename, O_RDONLY, 0);
  176. if (read_fd < 0) {
  177. error(_("can't open %s: %s"), filename, strerror(errno));
  178. /*NOTREACHED*/
  179. }
  180. if (!do_consumer_producer_queue(fd_read_producer, GINT_TO_POINTER(read_fd),
  181. fd_write_consumer,
  182. GINT_TO_POINTER(write_fd))) {
  183. error("Error copying data from file \"%s\" to fd %d.\n",
  184. filename, write_fd);
  185. g_assert_not_reached();
  186. }
  187. aclose(read_fd);
  188. }
  189. /* A user_init function for changer_find(). See changer.h for
  190. documentation. */
  191. static int
  192. scan_init(G_GNUC_UNUSED void * ud, int rc, G_GNUC_UNUSED int ns,
  193. int bk, G_GNUC_UNUSED int s) {
  194. if(rc) {
  195. error(_("could not get changer info: %s"), changer_resultstr);
  196. /*NOTREACHED*/
  197. }
  198. backwards = bk;
  199. return 0;
  200. }
  201. typedef struct {
  202. char ** cur_tapedev;
  203. char * searchlabel;
  204. } loadlabel_data;
  205. /* DANGER WILL ROBINSON: This function references globals:
  206. char * curslot;
  207. */
  208. int
  209. loadlabel_slot(void * datap,
  210. int rc,
  211. char * slotstr,
  212. char * device_name)
  213. {
  214. loadlabel_data * data = (loadlabel_data*)datap;
  215. Device * device;
  216. ReadLabelStatusFlags label_status;
  217. g_return_val_if_fail(rc > 1 || device_name != NULL, 0);
  218. g_return_val_if_fail(slotstr != NULL, 0);
  219. amfree(curslot);
  220. if(rc > 1) {
  221. error(_("could not load slot %s: %s"), slotstr, changer_resultstr);
  222. g_assert_not_reached();
  223. }
  224. if(rc == 1) {
  225. g_fprintf(stderr, _("%s: slot %s: %s\n"),
  226. get_pname(), slotstr, changer_resultstr);
  227. return 0;
  228. }
  229. device = device_open(device_name);
  230. if (device == NULL) {
  231. g_fprintf(stderr, "%s: slot %s: Could not open device.\n",
  232. get_pname(), slotstr);
  233. return 0;
  234. }
  235. device_set_startup_properties_from_config(device);
  236. label_status = device_read_label(device);
  237. if (label_status != READ_LABEL_STATUS_SUCCESS) {
  238. char * errstr =
  239. g_english_strjoinv_and_free
  240. (g_flags_nick_to_strv(label_status,
  241. READ_LABEL_STATUS_FLAGS_TYPE), "or");
  242. g_fprintf(stderr, "%s: slot %s: Error reading tape label:\n"
  243. "%s: slot %s: %s\n",
  244. get_pname(), slotstr, get_pname(), slotstr, errstr);
  245. g_object_unref(device);
  246. return 0;
  247. }
  248. g_assert(device->volume_label != NULL);
  249. if (device->volume_label == NULL) {
  250. g_fprintf(stderr, "%s: slot %s: Could not read tape label.\n",
  251. get_pname(), slotstr);
  252. g_object_unref(device);
  253. return 0;
  254. }
  255. if (!device_start(device, ACCESS_READ, NULL, NULL)) {
  256. g_fprintf(stderr, "%s: slot %s: Could not open device for reading.\n",
  257. get_pname(), slotstr);
  258. return 0;
  259. }
  260. g_fprintf(stderr, "%s: slot %s: time %-14s label %s",
  261. get_pname(), slotstr, device->volume_time, device->volume_label);
  262. if(strcmp(device->volume_label, data->searchlabel) != 0) {
  263. g_fprintf(stderr, " (wrong tape)\n");
  264. g_object_unref(device);
  265. return 0;
  266. }
  267. g_fprintf(stderr, " (exact label match)\n");
  268. g_object_unref(device);
  269. curslot = newstralloc(curslot, slotstr);
  270. amfree(*(data->cur_tapedev));
  271. *(data->cur_tapedev) = stralloc(device_name);
  272. return 1;
  273. }
  274. /* non-local functions follow */
  275. /*
  276. * Check whether we've read all of the preceding parts of a given split dump,
  277. * generally used to see if we're done and can close the thing.
  278. */
  279. int
  280. have_all_parts (
  281. dumpfile_t *file,
  282. int upto)
  283. {
  284. int c;
  285. int *foundparts = NULL;
  286. dumplist_t *fileentry = NULL;
  287. if(!file || file->partnum < 1) return(0);
  288. if(upto < 1) upto = file->totalparts;
  289. foundparts = alloc(SIZEOF(*foundparts) * upto);
  290. for(c = 0 ; c< upto; c++) foundparts[c] = 0;
  291. for(fileentry=alldumps_list;fileentry; fileentry=fileentry->next){
  292. dumpfile_t *cur_file = fileentry->file;
  293. if(headers_equal(file, cur_file, 1)){
  294. if(cur_file->partnum > upto){
  295. amfree(foundparts);
  296. return(0);
  297. }
  298. foundparts[cur_file->partnum - 1] = 1;
  299. }
  300. }
  301. for(c = 0 ; c< upto; c++){
  302. if(!foundparts[c]){
  303. amfree(foundparts);
  304. return(0);
  305. }
  306. }
  307. amfree(foundparts);
  308. return(1);
  309. }
  310. /*
  311. * Free up the open filehandles and memory we were using to track in-progress
  312. * dumpfiles (generally for split ones we're putting back together). If
  313. * applicable, also find the ones that are continuations of one another and
  314. * string them together. If given an optional file header argument, flush
  315. * only that dump and do not flush/free any others.
  316. */
  317. void
  318. flush_open_outputs(
  319. int reassemble,
  320. dumpfile_t *only_file)
  321. {
  322. open_output_t *cur_out = NULL, *prev = NULL;
  323. find_result_t *sorted_files = NULL;
  324. amwait_t compress_status;
  325. if(!only_file){
  326. g_fprintf(stderr, "\n");
  327. }
  328. /*
  329. * Deal with any split dumps we've been working on, appending pieces
  330. * that haven't yet been appended and closing filehandles we've been
  331. * holding onto.
  332. */
  333. if(reassemble){
  334. find_result_t *cur_find_res = NULL;
  335. int outfd = -1, lastpartnum = -1;
  336. dumpfile_t *main_file = NULL;
  337. cur_out = open_outputs;
  338. /* stick the dumpfile_t's into a list find_result_t's so that we can
  339. abuse existing sort functionality */
  340. for(cur_out=open_outputs; cur_out; cur_out=cur_out->next){
  341. find_result_t *cur_find_res = NULL;
  342. dumpfile_t *cur_file = cur_out->file;
  343. /* if we requested a particular file, do only that one */
  344. if(only_file && !headers_equal(cur_file, only_file, 1)){
  345. continue;
  346. }
  347. cur_find_res = alloc(SIZEOF(find_result_t));
  348. memset(cur_find_res, '\0', SIZEOF(find_result_t));
  349. cur_find_res->timestamp = stralloc(cur_file->datestamp);
  350. cur_find_res->hostname = stralloc(cur_file->name);
  351. cur_find_res->diskname = stralloc(cur_file->disk);
  352. cur_find_res->level = cur_file->dumplevel;
  353. if(cur_file->partnum < 1) cur_find_res->partnum = stralloc("--");
  354. else{
  355. char part_str[NUM_STR_SIZE];
  356. g_snprintf(part_str, SIZEOF(part_str), "%d", cur_file->partnum);
  357. cur_find_res->partnum = stralloc(part_str);
  358. }
  359. cur_find_res->user_ptr = (void*)cur_out;
  360. cur_find_res->next = sorted_files;
  361. sorted_files = cur_find_res;
  362. }
  363. sort_find_result("hkdlp", &sorted_files);
  364. /* now we have an in-order list of the files we need to concatenate */
  365. cur_find_res = sorted_files;
  366. for(cur_find_res=sorted_files;
  367. cur_find_res;
  368. cur_find_res=cur_find_res->next){
  369. dumpfile_t *cur_file = NULL;
  370. cur_out = (open_output_t*)cur_find_res->user_ptr;
  371. cur_file = cur_out->file;
  372. /* if we requested a particular file, do only that one */
  373. if(only_file && !headers_equal(cur_file, only_file, 1)){
  374. continue;
  375. }
  376. if(cur_file->type == F_SPLIT_DUMPFILE) {
  377. /* is it a continuation of one we've been writing? */
  378. if(main_file && cur_file->partnum > lastpartnum &&
  379. headers_equal(cur_file, main_file, 1)){
  380. char *cur_filename;
  381. char *main_filename;
  382. /* effectively changing filehandles */
  383. aclose(cur_out->outfd);
  384. cur_out->outfd = outfd;
  385. cur_filename = make_filename(cur_file);
  386. main_filename = make_filename(main_file);
  387. g_fprintf(stderr, _("Merging %s with %s\n"),
  388. cur_filename, main_filename);
  389. append_file_to_fd(cur_filename, outfd);
  390. if(unlink(cur_filename) < 0){
  391. g_fprintf(stderr, _("Failed to unlink %s: %s\n"),
  392. cur_filename, strerror(errno));
  393. }
  394. amfree(cur_filename);
  395. amfree(main_filename);
  396. }
  397. /* or a new file? */
  398. else {
  399. if(outfd >= 0) aclose(outfd);
  400. amfree(main_file);
  401. main_file = alloc(SIZEOF(dumpfile_t));
  402. memcpy(main_file, cur_file, SIZEOF(dumpfile_t));
  403. outfd = cur_out->outfd;
  404. if(outfd < 0) {
  405. char *cur_filename = make_filename(cur_file);
  406. open(cur_filename, O_RDWR|O_APPEND);
  407. if (outfd < 0) {
  408. error(_("Couldn't open %s for appending: %s"),
  409. cur_filename, strerror(errno));
  410. /*NOTREACHED*/
  411. }
  412. amfree(cur_filename);
  413. }
  414. }
  415. lastpartnum = cur_file->partnum;
  416. }
  417. else {
  418. aclose(cur_out->outfd);
  419. }
  420. }
  421. if(outfd >= 0) {
  422. aclose(outfd);
  423. }
  424. amfree(main_file);
  425. free_find_result(&sorted_files);
  426. }
  427. /*
  428. * Now that the split dump closure is done, free up resources we don't
  429. * need anymore.
  430. */
  431. for(cur_out=open_outputs; cur_out; cur_out=cur_out->next){
  432. dumpfile_t *cur_file = NULL;
  433. amfree(prev);
  434. cur_file = cur_out->file;
  435. /* if we requested a particular file, do only that one */
  436. if(only_file && !headers_equal(cur_file, only_file, 1)){
  437. continue;
  438. }
  439. if(!reassemble) {
  440. aclose(cur_out->outfd);
  441. }
  442. if(cur_out->comp_enc_pid > 0){
  443. waitpid(cur_out->comp_enc_pid, &compress_status, 0);
  444. }
  445. amfree(cur_out->file);
  446. prev = cur_out;
  447. }
  448. open_outputs = NULL;
  449. }
  450. /*
  451. * Turn a fileheader into a string suited for use on the filesystem.
  452. */
  453. char *
  454. make_filename(
  455. dumpfile_t *file)
  456. {
  457. char number[NUM_STR_SIZE];
  458. char part[NUM_STR_SIZE];
  459. char totalparts[NUM_STR_SIZE];
  460. char *sfn = NULL;
  461. char *fn = NULL;
  462. char *pad = NULL;
  463. size_t padlen = 0;
  464. g_snprintf(number, SIZEOF(number), "%d", file->dumplevel);
  465. g_snprintf(part, SIZEOF(part), "%d", file->partnum);
  466. if(file->totalparts < 0) {
  467. g_snprintf(totalparts, SIZEOF(totalparts), "UNKNOWN");
  468. }
  469. else {
  470. g_snprintf(totalparts, SIZEOF(totalparts), "%d", file->totalparts);
  471. }
  472. padlen = strlen(totalparts) + 1 - strlen(part);
  473. pad = alloc(padlen);
  474. memset(pad, '0', padlen);
  475. pad[padlen - 1] = '\0';
  476. g_snprintf(part, SIZEOF(part), "%s%d", pad, file->partnum);
  477. sfn = sanitise_filename(file->disk);
  478. fn = vstralloc(file->name,
  479. ".",
  480. sfn,
  481. ".",
  482. file->datestamp,
  483. ".",
  484. number,
  485. NULL);
  486. if (file->partnum > 0) {
  487. vstrextend(&fn, ".", part, NULL);
  488. }
  489. amfree(sfn);
  490. amfree(pad);
  491. return fn;
  492. }
  493. /* Returns 1 if the dump file matches the hostname and diskname
  494. * regular expressions given on the command line, 0 otherwise. As a
  495. * special case, empty regexs and NULLs are considered equivalent to
  496. * ".*": they match everything.
  497. *
  498. * @param file: the file to examine
  499. * @param datestamp: the datestamp regex, or NULL for any
  500. * @param hostname: the hostname regex, or NULL for any
  501. * @param diskname: the diskname regex, or NULL for any
  502. * @param level: the level regex, or NULL for any
  503. * @returns: 1 if the dump file matches
  504. */
  505. static int
  506. disk_match(
  507. dumpfile_t *file,
  508. char * datestamp,
  509. char * hostname,
  510. char * diskname,
  511. char * level)
  512. {
  513. char level_str[NUM_STR_SIZE];
  514. g_snprintf(level_str, SIZEOF(level_str), "%d", file->dumplevel);
  515. if(file->type != F_DUMPFILE && file->type != F_SPLIT_DUMPFILE) return 0;
  516. if((!hostname || *hostname == '\0' || match_host(hostname, file->name)) &&
  517. (!diskname || *diskname == '\0' || match_disk(diskname, file->disk)) &&
  518. (!datestamp || *datestamp == '\0' || match_datestamp(datestamp, file->datestamp)) &&
  519. (!level || *level == '\0' || match_level(level, level_str)))
  520. return 1;
  521. else
  522. return 0;
  523. }
  524. /*
  525. * Reads the first block of a holding disk file.
  526. */
  527. static gboolean
  528. read_holding_disk_header(
  529. dumpfile_t * file,
  530. int tapefd,
  531. rst_flags_t * flags)
  532. {
  533. ssize_t bytes_read;
  534. char *buffer;
  535. size_t blocksize;
  536. if(flags->blocksize > 0)
  537. blocksize = (size_t)flags->blocksize;
  538. else
  539. blocksize = DISK_BLOCK_BYTES;
  540. buffer = alloc(blocksize);
  541. bytes_read = fullread(tapefd, buffer, blocksize);
  542. if(bytes_read < 0) {
  543. g_fprintf(stderr, _("%s: error reading file header: %s\n"),
  544. get_pname(), strerror(errno));
  545. file->type = F_UNKNOWN;
  546. } else if((size_t)bytes_read < DISK_BLOCK_BYTES) {
  547. if(bytes_read == 0) {
  548. g_fprintf(stderr, _("%s: missing file header block\n"), get_pname());
  549. } else {
  550. g_fprintf(stderr,
  551. plural(_("%s: short file header block: %zd byte"),
  552. _("%s: short file header block: %zd bytes\n"),
  553. bytes_read),
  554. get_pname(), (size_t)bytes_read);
  555. }
  556. file->type = F_UNKNOWN;
  557. } else {
  558. parse_file_header(buffer, file, (size_t)bytes_read);
  559. }
  560. amfree(buffer);
  561. return (file->type != F_UNKNOWN &&
  562. file->type != F_EMPTY &&
  563. file->type != F_WEIRD);
  564. }
  565. /*
  566. * Restore the current file from tape. Depending on the settings of
  567. * the command line flags, the file might need to be compressed or
  568. * uncompressed. If so, a pipe through compress or uncompress is set
  569. * up. The final output usually goes to a file named host.disk.date.lev,
  570. * but with the -p flag the output goes to stdout (and presumably is
  571. * piped to restore).
  572. */
  573. /* FIXME: Mondo function that needs refactoring. */
  574. void restore(RestoreSource * source,
  575. rst_flags_t * flags)
  576. {
  577. int dest = -1, out;
  578. int file_is_compressed;
  579. int is_continuation = 0;
  580. int check_for_aborted = 0;
  581. char *tmp_filename = NULL, *final_filename = NULL;
  582. struct stat statinfo;
  583. open_output_t *myout = NULL, *oldout = NULL;
  584. dumplist_t *tempdump = NULL, *fileentry = NULL;
  585. char *buffer;
  586. int need_compress=0, need_uncompress=0, need_decrypt=0;
  587. int stage=0;
  588. struct pipeline {
  589. int pipe[2];
  590. } pipes[3];
  591. char * filename;
  592. filename = make_filename(source->header);
  593. memset(pipes, -1, SIZEOF(pipes));
  594. if(already_have_dump(source->header)){
  595. g_fprintf(stderr, _(" *** Duplicate file %s, one is probably an aborted write\n"), filename);
  596. check_for_aborted = 1;
  597. }
  598. /* store a shorthand record of this dump */
  599. tempdump = malloc(SIZEOF(dumplist_t));
  600. tempdump->file = malloc(SIZEOF(dumpfile_t));
  601. tempdump->next = NULL;
  602. memcpy(tempdump->file, source->header, SIZEOF(dumpfile_t));
  603. /*
  604. * If we're appending chunked files to one another, and if this is a
  605. * continuation of a file we just restored, and we've still got the
  606. * output handle from that previous restore, we're golden. Phew.
  607. */
  608. if(flags->inline_assemble && source->header->type == F_SPLIT_DUMPFILE){
  609. myout = open_outputs;
  610. while(myout != NULL){
  611. if(myout->file->type == F_SPLIT_DUMPFILE &&
  612. headers_equal(source->header, myout->file, 1)){
  613. if(source->header->partnum == myout->lastpartnum + 1){
  614. is_continuation = 1;
  615. break;
  616. }
  617. }
  618. myout = myout->next;
  619. }
  620. if(myout != NULL) myout->lastpartnum = source->header->partnum;
  621. else if(source->header->partnum != 1){
  622. g_fprintf(stderr, _("%s: Chunk out of order, will save to disk and append to output.\n"), get_pname());
  623. flags->pipe_to_fd = -1;
  624. flags->compress = 0;
  625. flags->leave_comp = 1;
  626. }
  627. if(myout == NULL){
  628. myout = alloc(SIZEOF(open_output_t));
  629. memset(myout, 0, SIZEOF(open_output_t));
  630. }
  631. }
  632. else{
  633. myout = alloc(SIZEOF(open_output_t));
  634. memset(myout, 0, SIZEOF(open_output_t));
  635. }
  636. if(is_continuation && flags->pipe_to_fd == -1){
  637. char *filename;
  638. filename = make_filename(myout->file);
  639. g_fprintf(stderr, _("%s: appending to %s\n"), get_pname(),
  640. filename);
  641. amfree(filename);
  642. }
  643. /* adjust compression flag */
  644. file_is_compressed = source->header->compressed;
  645. if(!flags->compress && file_is_compressed &&
  646. !known_compress_type(source->header)) {
  647. g_fprintf(stderr,
  648. _("%s: unknown compression suffix %s, can't uncompress\n"),
  649. get_pname(), source->header->comp_suffix);
  650. flags->compress = 1;
  651. }
  652. /* set up final destination file */
  653. if(is_continuation && myout != NULL) {
  654. out = myout->outfd;
  655. } else {
  656. if(flags->pipe_to_fd != -1) {
  657. dest = flags->pipe_to_fd;
  658. } else {
  659. char *filename_ext = NULL;
  660. if(flags->compress) {
  661. filename_ext = file_is_compressed ? source->header->comp_suffix
  662. : COMPRESS_SUFFIX;
  663. } else if(flags->raw) {
  664. filename_ext = ".RAW";
  665. } else {
  666. filename_ext = "";
  667. }
  668. filename_ext = stralloc2(filename, filename_ext);
  669. tmp_filename = stralloc(filename_ext);
  670. if(flags->restore_dir != NULL) {
  671. char *tmpstr = vstralloc(flags->restore_dir, "/",
  672. tmp_filename, NULL);
  673. amfree(tmp_filename);
  674. tmp_filename = tmpstr;
  675. }
  676. final_filename = tmp_filename;
  677. tmp_filename = vstralloc(final_filename, ".tmp", NULL);
  678. if((dest = open(tmp_filename, (O_CREAT | O_RDWR | O_TRUNC),
  679. CREAT_MODE)) < 0) {
  680. error(_("could not create output file %s: %s"),
  681. tmp_filename, strerror(errno));
  682. /*NOTREACHED*/
  683. }
  684. amfree(filename_ext);
  685. }
  686. out = dest;
  687. }
  688. /*
  689. * If -r or -h, write the header before compress or uncompress pipe.
  690. * Only write DISK_BLOCK_BYTES, regardless of how much was read.
  691. * This makes the output look like a holding disk image, and also
  692. * makes it easier to remove the header (e.g. in amrecover) since
  693. * it has a fixed size.
  694. */
  695. if(flags->raw || (flags->headers && !is_continuation)) {
  696. ssize_t w;
  697. dumpfile_t tmp_hdr;
  698. if(flags->compress && !file_is_compressed) {
  699. source->header->compressed = 1;
  700. g_snprintf(source->header->uncompress_cmd,
  701. SIZEOF(source->header->uncompress_cmd),
  702. " %s %s |", UNCOMPRESS_PATH,
  703. #ifdef UNCOMPRESS_OPT
  704. UNCOMPRESS_OPT
  705. #else
  706. ""
  707. #endif
  708. );
  709. strncpy(source->header->comp_suffix,
  710. COMPRESS_SUFFIX,
  711. SIZEOF(source->header->comp_suffix)-1);
  712. source->header->comp_suffix[SIZEOF(source->header->comp_suffix)-1]
  713. = '\0';
  714. }
  715. memcpy(&tmp_hdr, source->header, SIZEOF(dumpfile_t));
  716. /* remove CONT_FILENAME from header */
  717. memset(source->header->cont_filename, '\0',
  718. SIZEOF(source->header->cont_filename));
  719. source->header->blocksize = DISK_BLOCK_BYTES;
  720. /*
  721. * Dumb down split file headers as well, so that older versions of
  722. * things like amrecover won't gag on them.
  723. */
  724. if(source->header->type == F_SPLIT_DUMPFILE && flags->mask_splits){
  725. source->header->type = F_DUMPFILE;
  726. }
  727. buffer = alloc(DISK_BLOCK_BYTES);
  728. buffer = build_header(source->header, DISK_BLOCK_BYTES);
  729. if((w = fullwrite(out, buffer,
  730. DISK_BLOCK_BYTES)) != DISK_BLOCK_BYTES) {
  731. if(w < 0) {
  732. error(_("write error: %s"), strerror(errno));
  733. /*NOTREACHED*/
  734. } else {
  735. error(_("write error: %zd instead of %d"), w, DISK_BLOCK_BYTES);
  736. /*NOTREACHED*/
  737. }
  738. }
  739. amfree(buffer);
  740. memcpy(source->header, &tmp_hdr, SIZEOF(dumpfile_t));
  741. }
  742. /* find out if compression or uncompression is needed here */
  743. if(flags->compress && !file_is_compressed && !is_continuation
  744. && !flags->leave_comp
  745. && (flags->inline_assemble ||
  746. source->header->type != F_SPLIT_DUMPFILE))
  747. need_compress=1;
  748. if(!flags->raw && !flags->compress && file_is_compressed
  749. && !is_continuation && !flags->leave_comp && (flags->inline_assemble
  750. || source->header->type != F_SPLIT_DUMPFILE))
  751. need_uncompress=1;
  752. if(!flags->raw && source->header->encrypted && !is_continuation &&
  753. (flags->inline_assemble || source->header->type != F_SPLIT_DUMPFILE)) {
  754. need_decrypt=1;
  755. }
  756. /* Setup pipes for decryption / compression / uncompression */
  757. stage = 0;
  758. if (need_decrypt) {
  759. if (pipe(&pipes[stage].pipe[0]) < 0) {
  760. error(_("error [pipe[%d]: %s]"), stage, strerror(errno));
  761. /*NOTREACHED*/
  762. }
  763. stage++;
  764. }
  765. if (need_compress || need_uncompress) {
  766. if (pipe(&pipes[stage].pipe[0]) < 0) {
  767. error(_("error [pipe[%d]: %s]"), stage, strerror(errno));
  768. /*NOTREACHED*/
  769. }
  770. stage++;
  771. }
  772. pipes[stage].pipe[0] = -1;
  773. pipes[stage].pipe[1] = out;
  774. stage = 0;
  775. /* decrypt first if it's encrypted and no -r */
  776. if(need_decrypt) {
  777. switch(myout->comp_enc_pid = fork()) {
  778. case -1:
  779. error(_("could not fork for decrypt: %s"), strerror(errno));
  780. /*NOTREACHED*/
  781. default:
  782. aclose(pipes[stage].pipe[0]);
  783. aclose(pipes[stage+1].pipe[1]);
  784. stage++;
  785. break;
  786. case 0:
  787. if(dup2(pipes[stage].pipe[0], 0) == -1) {
  788. error(_("error decrypt stdin [dup2 %d %d: %s]"), stage,
  789. pipes[stage].pipe[0], strerror(errno));
  790. /*NOTREACHED*/
  791. }
  792. if(dup2(pipes[stage+1].pipe[1], 1) == -1) {
  793. error(_("error decrypt stdout [dup2 %d %d: %s]"), stage + 1,
  794. pipes[stage+1].pipe[1], strerror(errno));
  795. /*NOTREACHED*/
  796. }
  797. safe_fd(-1, 0);
  798. if (source->header->srv_encrypt[0] != '\0') {
  799. (void) execlp(source->header->srv_encrypt,
  800. source->header->srv_encrypt,
  801. source->header->srv_decrypt_opt, NULL);
  802. error("could not exec %s: %s",
  803. source->header->srv_encrypt, strerror(errno));
  804. g_assert_not_reached();
  805. } else if (source->header->clnt_encrypt[0] != '\0') {
  806. (void) execlp(source->header->clnt_encrypt,
  807. source->header->clnt_encrypt,
  808. source->header->clnt_decrypt_opt, NULL);
  809. error("could not exec %s: %s",
  810. source->header->clnt_encrypt, strerror(errno));
  811. g_assert_not_reached();
  812. }
  813. }
  814. }
  815. if (need_compress) {
  816. /*
  817. * Insert a compress pipe
  818. */
  819. switch(myout->comp_enc_pid = fork()) {
  820. case -1:
  821. error(_("could not fork for %s: %s"), COMPRESS_PATH, strerror(errno));
  822. /*NOTREACHED*/
  823. default:
  824. aclose(pipes[stage].pipe[0]);
  825. aclose(pipes[stage+1].pipe[1]);
  826. stage++;
  827. break;
  828. case 0:
  829. if(dup2(pipes[stage].pipe[0], 0) == -1) {
  830. error(_("error compress stdin [dup2 %d %d: %s]"), stage,
  831. pipes[stage].pipe[0], strerror(errno));
  832. /*NOTREACHED*/
  833. }
  834. if(dup2(pipes[stage+1].pipe[1], 1) == -1) {
  835. error(_("error compress stdout [dup2 %d %d: %s]"), stage + 1,
  836. pipes[stage+1].pipe[1], strerror(errno));
  837. /*NOTREACHED*/
  838. }
  839. if (*flags->comp_type == '\0') {
  840. flags->comp_type = NULL;
  841. }
  842. safe_fd(-1, 0);
  843. (void) execlp(COMPRESS_PATH, COMPRESS_PATH, flags->comp_type, (char *)0);
  844. error(_("could not exec %s: %s"), COMPRESS_PATH, strerror(errno));
  845. /*NOTREACHED*/
  846. }
  847. } else if(need_uncompress) {
  848. /*
  849. * If not -r, -c, -l, and file is compressed, and split reassembly
  850. * options are sane, insert uncompress pipe
  851. */
  852. /*
  853. * XXX for now we know that for the two compression types we
  854. * understand, .Z and optionally .gz, UNCOMPRESS_PATH will take
  855. * care of both. Later, we may need to reference a table of
  856. * possible uncompress programs.
  857. */
  858. switch(myout->comp_enc_pid = fork()) {
  859. case -1:
  860. error(_("could not fork for %s: %s"),
  861. UNCOMPRESS_PATH, strerror(errno));
  862. /*NOTREACHED*/
  863. default:
  864. aclose(pipes[stage].pipe[0]);
  865. aclose(pipes[stage+1].pipe[1]);
  866. stage++;
  867. break;
  868. case 0:
  869. if(dup2(pipes[stage].pipe[0], 0) == -1) {
  870. error(_("error uncompress stdin [dup2 %d %d: %s]"), stage,
  871. pipes[stage].pipe[0], strerror(errno));
  872. /*NOTREACHED*/
  873. }
  874. if(dup2(pipes[stage+1].pipe[1], 1) == -1) {
  875. error(_("error uncompress stdout [dup2 %d %d: %s]"), stage + 1,
  876. pipes[stage+1].pipe[1], strerror(errno));
  877. /*NOTREACHED*/
  878. }
  879. safe_fd(-1, 0);
  880. if (source->header->srvcompprog[0] != '\0') {
  881. (void) execlp(source->header->srvcompprog,
  882. source->header->srvcompprog, "-d", NULL);
  883. error("could not exec %s: %s", source->header->srvcompprog,
  884. strerror(errno));
  885. g_assert_not_reached();
  886. } else if (source->header->clntcompprog[0] != '\0') {
  887. (void) execlp(source->header->clntcompprog,
  888. source->header->clntcompprog, "-d", NULL);
  889. error("could not exec %s: %s", source->header->clntcompprog,
  890. strerror(errno));
  891. g_assert_not_reached();
  892. } else {
  893. (void) execlp(UNCOMPRESS_PATH, UNCOMPRESS_PATH,
  894. #ifdef UNCOMPRESS_OPT
  895. UNCOMPRESS_OPT,
  896. #endif
  897. (char *)NULL);
  898. error(_("could not exec %s: %s"), UNCOMPRESS_PATH, strerror(errno));
  899. /*NOTREACHED*/
  900. }
  901. }
  902. }
  903. /* copy the rest of the file from tape to the output */
  904. if (source->restore_mode == HOLDING_MODE) {
  905. dumpfile_t file;
  906. int fd = source->u.holding_fd;
  907. memcpy(& file, source->header, sizeof(file));
  908. for (;;) {
  909. do_consumer_producer_queue(fd_read_producer,
  910. GINT_TO_POINTER(fd),
  911. fd_write_consumer,
  912. GINT_TO_POINTER(pipes[0].pipe[1]));
  913. /*
  914. * See if we need to switch to the next file in a holding restore
  915. */
  916. if(file.cont_filename[0] == '\0') {
  917. break; /* no more files */
  918. }
  919. aclose(fd);
  920. if((fd = open(file.cont_filename, O_RDONLY)) == -1) {
  921. char *cont_filename =
  922. strrchr(file.cont_filename,'/');
  923. if(cont_filename) {
  924. cont_filename++;
  925. if((fd = open(cont_filename,O_RDONLY)) == -1) {
  926. error(_("can't open %s: %s"), file.cont_filename,
  927. strerror(errno));
  928. /*NOTREACHED*/
  929. }
  930. else {
  931. g_fprintf(stderr, _("cannot open %s: %s\n"),
  932. file.cont_filename, strerror(errno));
  933. g_fprintf(stderr, _("using %s\n"),
  934. cont_filename);
  935. }
  936. }
  937. else {
  938. error(_("can't open %s: %s"), file.cont_filename,
  939. strerror(errno));
  940. /*NOTREACHED*/
  941. }
  942. }
  943. read_holding_disk_header(&file, fd, flags);
  944. if(file.type != F_DUMPFILE && file.type != F_CONT_DUMPFILE
  945. && file.type != F_SPLIT_DUMPFILE) {
  946. g_fprintf(stderr, _("unexpected header type: "));
  947. print_header(stderr, source->header);
  948. exit(2);
  949. }
  950. }
  951. } else {
  952. device_read_to_fd(source->u.device, pipes[0].pipe[1]);
  953. }
  954. if(!flags->inline_assemble) {
  955. if(out != dest)
  956. aclose(out);
  957. }
  958. if(!is_continuation){
  959. if(tmp_filename && stat(tmp_filename, &statinfo) < 0){
  960. error(_("Can't stat the file I just created (%s)!"), tmp_filename);
  961. /*NOTREACHED*/
  962. } else {
  963. statinfo.st_size = (off_t)0;
  964. }
  965. if (check_for_aborted && final_filename) {
  966. char *old_dump = final_filename;
  967. struct stat oldstat;
  968. if(stat(old_dump, &oldstat) >= 0){
  969. if(oldstat.st_size <= statinfo.st_size){
  970. dumplist_t *prev_fileentry = NULL;
  971. open_output_t *prev_out = NULL;
  972. g_fprintf(stderr, _("Newer restore is larger, using that\n"));
  973. /* nuke the old dump's entry in alldump_list */
  974. for(fileentry=alldumps_list;
  975. fileentry->next;
  976. fileentry=fileentry->next){
  977. if(headers_equal(source->header,
  978. fileentry->file, 0)){
  979. if(prev_fileentry){
  980. prev_fileentry->next = fileentry->next;
  981. }
  982. else {
  983. alldumps_list = fileentry->next;
  984. }
  985. amfree(fileentry);
  986. break;
  987. }
  988. prev_fileentry = fileentry;
  989. }
  990. myout = open_outputs;
  991. while(myout != NULL){
  992. if(headers_equal(source->header, myout->file, 0)){
  993. if(myout->outfd >= 0)
  994. aclose(myout->outfd);
  995. if(prev_out){
  996. prev_out->next = myout->next;
  997. }
  998. else open_outputs = myout->next;
  999. amfree(myout);
  1000. break;
  1001. }
  1002. prev_out = myout;
  1003. myout = myout->next;
  1004. }
  1005. }
  1006. else{
  1007. g_fprintf(stderr, _("Older restore is larger, using that\n"));
  1008. if (tmp_filename)
  1009. unlink(tmp_filename);
  1010. amfree(tempdump->file);
  1011. amfree(tempdump);
  1012. amfree(tmp_filename);
  1013. amfree(final_filename);
  1014. amfree(filename);
  1015. return;
  1016. }
  1017. }
  1018. }
  1019. if(tmp_filename && final_filename &&
  1020. rename(tmp_filename, final_filename) < 0) {
  1021. error(_("Can't rename %s to %s: %s"),
  1022. tmp_filename, final_filename, strerror(errno));
  1023. /*NOTREACHED*/
  1024. }
  1025. }
  1026. amfree(tmp_filename);
  1027. amfree(final_filename);
  1028. /*
  1029. * actually insert tracking data for this file into our various
  1030. * structures (we waited in case we needed to give up)
  1031. */
  1032. if(!is_continuation){
  1033. oldout = alloc(SIZEOF(open_output_t));
  1034. oldout->file = alloc(SIZEOF(dumpfile_t));
  1035. memcpy(oldout->file, source->header, SIZEOF(dumpfile_t));
  1036. if(flags->inline_assemble) oldout->outfd = pipes[0].pipe[1];
  1037. else oldout->outfd = -1;
  1038. oldout->comp_enc_pid = -1;
  1039. oldout->lastpartnum = source->header->partnum;
  1040. oldout->next = open_outputs;
  1041. open_outputs = oldout;
  1042. }
  1043. if(alldumps_list){
  1044. fileentry = alldumps_list;
  1045. while (fileentry->next != NULL)
  1046. fileentry=fileentry->next;
  1047. fileentry->next = tempdump;
  1048. }
  1049. else {
  1050. alldumps_list = tempdump;
  1051. }
  1052. }
  1053. /* return NULL if the label is not the expected one */
  1054. /* returns a Device handle if it is the expected one. */
  1055. /* FIXME: Was label_of_current_slot */
  1056. static Device *
  1057. conditional_device_open(char *tapedev,
  1058. FILE *prompt_out,
  1059. rst_flags_t *flags,
  1060. am_feature_t *their_features,
  1061. tapelist_t *desired_tape)
  1062. {
  1063. Device * rval;
  1064. if (tapedev == NULL) {
  1065. send_message(prompt_out, flags, their_features,
  1066. _("Volume labeled '%s' not found."), desired_tape->label);
  1067. return NULL;
  1068. }
  1069. rval = device_open(tapedev);
  1070. if (rval == NULL) {
  1071. send_message(prompt_out, flags, their_features,
  1072. "Error opening device '%s'.",
  1073. tapedev);
  1074. return NULL;
  1075. }
  1076. device_set_startup_properties_from_config(rval);
  1077. device_read_label(rval);
  1078. if (rval->volume_label == NULL) {
  1079. send_message(prompt_out, flags, their_features,
  1080. "Not an amanda tape");
  1081. g_object_unref(rval);
  1082. return NULL;
  1083. }
  1084. if (!device_start(rval, ACCESS_READ, NULL, NULL)) {
  1085. send_message(prompt_out, flags, their_features,
  1086. "Colud not open device %s for reading.\n",
  1087. tapedev);
  1088. return NULL;
  1089. }
  1090. if (flags->check_labels && desired_tape &&
  1091. strcmp(rval->volume_label, desired_tape->label) != 0) {
  1092. send_message(prompt_out, flags, their_features,
  1093. "Label mismatch, got %s and expected %s",
  1094. rval->volume_label, desired_tape->label);
  1095. g_object_unref(rval);
  1096. return NULL;
  1097. }
  1098. return rval;
  1099. }
  1100. /* Do the right thing to try and load the next required tape. See
  1101. LoadStatus above for return value meaning. */
  1102. LoadStatus
  1103. load_next_tape(
  1104. char **cur_tapedev,
  1105. FILE *prompt_out,
  1106. int backwards,
  1107. rst_flags_t *flags,
  1108. am_feature_t *their_features,
  1109. tapelist_t *desired_tape)
  1110. {
  1111. if (desired_tape) {
  1112. send_message(prompt_out, flags, their_features,
  1113. _("Looking for tape %s..."),
  1114. desired_tape->label);
  1115. if (backwards) {
  1116. loadlabel_data data;
  1117. data.cur_tapedev = cur_tapedev;
  1118. data.searchlabel = desired_tape->label;
  1119. changer_find(&data, scan_init, loadlabel_slot,
  1120. desired_tape->label);
  1121. return LOAD_CHANGER;
  1122. } else {
  1123. amfree(curslot);
  1124. changer_loadslot("next", &curslot,
  1125. cur_tapedev);
  1126. return LOAD_NEXT;
  1127. }
  1128. } else {
  1129. assert(!flags->amidxtaped);
  1130. amfree(curslot);
  1131. changer_loadslot("next", &curslot, cur_tapedev);
  1132. return LOAD_NEXT;
  1133. }
  1134. g_assert_not_reached();
  1135. }
  1136. /* will never return LOAD_CHANGER. */
  1137. LoadStatus
  1138. load_manual_tape(
  1139. char **tapedev_ptr,
  1140. FILE *prompt_out,
  1141. FILE *prompt_in,
  1142. rst_flags_t *flags,
  1143. am_feature_t *their_features,
  1144. tapelist_t *desired_tape)
  1145. {
  1146. char *input = NULL;
  1147. if (flags->amidxtaped) {
  1148. if (their_features &&
  1149. am_has_feature(their_features,
  1150. fe_amrecover_FEEDME)) {
  1151. g_fprintf(prompt_out, "FEEDME %s\r\n",
  1152. desired_tape->label);
  1153. fflush(prompt_out);
  1154. input = agets(prompt_in);/* Strips \n but not \r */
  1155. if(!input) {
  1156. error(_("Connection lost with amrecover"));
  1157. /*NOTREACHED*/
  1158. } else if (strcmp("OK\r", input) == 0) {
  1159. } else if (strncmp("TAPE ", input, 5) == 0) {
  1160. amfree(*tapedev_ptr);
  1161. *tapedev_ptr = alloc(1025);
  1162. if (sscanf(input, "TAPE %1024s\r", *tapedev_ptr) != 1) {
  1163. error(_("Got bad response from amrecover: %s"), input);
  1164. /*NOTREACHED*/
  1165. }
  1166. } else {
  1167. send_message(prompt_out, flags, their_features,
  1168. _("Got bad response from amrecover: %s"), input);
  1169. error(_("Got bad response from amrecover: %s"), input);
  1170. /*NOTREACHED*/
  1171. }
  1172. } else {
  1173. send_message(prompt_out, flags, their_features,
  1174. _("Client doesn't support fe_amrecover_FEEDME"));
  1175. error(_("Client doesn't support fe_amrecover_FEEDME"));
  1176. /*NOTREACHED*/
  1177. }
  1178. }
  1179. else {
  1180. if (desired_tape) {
  1181. g_fprintf(prompt_out,
  1182. _("Insert tape labeled %s in device %s \n"
  1183. "and press enter, ^D to finish reading tapes\n"),
  1184. desired_tape->label, *tapedev_ptr);
  1185. } else {
  1186. g_fprintf(prompt_out,_("Insert a tape to search and press "
  1187. "enter, ^D to finish reading tapes\n"));
  1188. }
  1189. fflush(prompt_out);
  1190. if((input = agets(prompt_in)) == NULL)
  1191. return LOAD_STOP;
  1192. }
  1193. amfree(input);
  1194. return LOAD_NEXT;
  1195. }
  1196. /* Search a seen-tapes list for a particular name, to see if we've already
  1197. * processed this tape. Returns TRUE if this label has already been seen. */
  1198. static gboolean check_volume_seen(seentapes_t * list, char * label) {
  1199. seentapes_t * cur_tape;
  1200. for (cur_tape = list; cur_tape != NULL; cur_tape = cur_tape->next) {
  1201. if (strcmp(cur_tape->label, label) == 0) {
  1202. return TRUE;
  1203. }
  1204. }
  1205. return FALSE;
  1206. }
  1207. /* Add a volume to the seen tapes list. */
  1208. static void record_seen_volume(seentapes_t ** list, char * label,
  1209. char * slotstr) {
  1210. seentapes_t * new_entry;
  1211. if (list == NULL)
  1212. return;
  1213. new_entry = malloc(sizeof(seentapes_t));
  1214. new_entry->label = stralloc(label);
  1215. if (slotstr == NULL) {
  1216. new_entry->slotstr = NULL;
  1217. } else {
  1218. new_entry->slotstr = stralloc(slotstr);
  1219. }
  1220. new_entry->files = NULL;
  1221. new_entry->next = *list;
  1222. *list = new_entry;
  1223. }
  1224. /* Record a specific dump on a volume. */
  1225. static void record_seen_dump(seentapes_t * volume, dumpfile_t * header) {
  1226. dumplist_t * this_dump;
  1227. if (volume == NULL)
  1228. return;
  1229. this_dump = malloc(sizeof(*this_dump));
  1230. this_dump->file = g_memdup(header, sizeof(*header));
  1231. this_dump->next = NULL;
  1232. if (volume->files) {
  1233. dumplist_t * tmp_dump = volume->files;
  1234. while (tmp_dump->next != NULL) {
  1235. tmp_dump = tmp_dump->next;
  1236. }
  1237. tmp_dump->next = this_dump;
  1238. } else {
  1239. volume->files = this_dump;
  1240. }
  1241. }
  1242. static void print_tape_inventory(FILE * logstream, seentapes_t * tape_seen,
  1243. char * timestamp, char * label,
  1244. int tape_count) {
  1245. char * logline;
  1246. dumplist_t * fileentry;
  1247. logline = log_genstring(L_START, "taper",
  1248. "datestamp %s label %s tape %d",
  1249. timestamp, label, tape_count);
  1250. fputs(logline, logstream);
  1251. amfree(logline);
  1252. for(fileentry=tape_seen->files; fileentry; fileentry=fileentry->next){
  1253. switch (fileentry->file->type) {
  1254. case F_DUMPFILE:
  1255. logline = log_genstring(L_SUCCESS, "taper",
  1256. "%s %s %s %d [faked log entry]",
  1257. fileentry->file->name,
  1258. fileentry->file->disk,
  1259. fileentry->file->datestamp,
  1260. fileentry->file->dumplevel);
  1261. break;
  1262. case F_SPLIT_DUMPFILE:
  1263. logline = log_genstring(L_CHUNK, "taper",
  1264. "%s %s %s %d %d [faked log entry]",
  1265. fileentry->file->name,
  1266. fileentry->file->disk,
  1267. fileentry->file->datestamp,
  1268. fileentry->file->partnum,
  1269. fileentry->file->dumplevel);
  1270. break;
  1271. default:
  1272. break;
  1273. }
  1274. if(logline != NULL){
  1275. fputs(logline, logstream);
  1276. amfree(logline);
  1277. fflush(logstream);
  1278. }
  1279. }
  1280. }
  1281. /* Check if the given header matches the given dumpspecs. Returns
  1282. TRUE if dumpspecs is NULL and false if the header is NULL. Returns
  1283. true if the header matches the match list. */
  1284. static gboolean run_dumpspecs(GSList * dumpspecs,
  1285. dumpfile_t * header) {
  1286. dumpspec_t *ds;
  1287. if (dumpspecs == NULL)
  1288. return TRUE;
  1289. if (header == NULL)
  1290. return FALSE;
  1291. while (dumpspecs) {
  1292. ds = (dumpspec_t *)dumpspecs->data;
  1293. if (disk_match(header, ds->datestamp, ds->host,
  1294. ds->disk, ds->level) != 0) {
  1295. return TRUE;
  1296. }
  1297. dumpspecs = dumpspecs->next;
  1298. }
  1299. return FALSE;
  1300. }
  1301. /* A wrapper around restore() above. This function does some extra
  1302. checking to seek to the file in question and ensure that we really,
  1303. really want to use it.
  1304. The next_file argument provides instruction on what to do if the
  1305. requested file does not exist on the volume: If next_file is NULL
  1306. then if the requested file is missing the function will return
  1307. RESTORE_STATUS_NEXT_FILE. If next_file is not NULL then the first
  1308. extant file whose number is equal to or greater than file_num will
  1309. be attempted. *next_file will be filled in with the number of the
  1310. file following the one that was attempted. */
  1311. static RestoreFileStatus
  1312. try_restore_single_file(Device * device, int file_num, int* next_file,
  1313. FILE * prompt_out,
  1314. rst_flags_t * flags,
  1315. am_feature_t * their_features,
  1316. dumpfile_t * first_restored_file,
  1317. GSList * dumpspecs,
  1318. seentapes_t * tape_seen) {
  1319. RestoreSource source;
  1320. source.u.device = device;
  1321. source.restore_mode = DEVICE_MODE;
  1322. source.header = device_seek_file(device, file_num);
  1323. if (source.header == NULL) {
  1324. /* This definitely indicates an error. */
  1325. send_message(prompt_out, flags, their_features,
  1326. "Could not seek device %s to file %d.",
  1327. device->device_name, file_num);
  1328. return RESTORE_STATUS_NEXT_TAPE;
  1329. } else if (source.header->type == F_TAPEEND) {
  1330. amfree(source.header);
  1331. return RESTORE_STATUS_NEXT_TAPE;
  1332. } else if (device->file != file_num) {
  1333. if (next_file == NULL) {
  1334. send_message(prompt_out, flags, their_features,
  1335. "Requested file %d does not exist.",
  1336. file_num);
  1337. return RESTORE_STATUS_NEXT_FILE;
  1338. } else {
  1339. send_message(prompt_out, flags, their_features,
  1340. "Skipped from file %d to file %d.",
  1341. file_num, device->file);
  1342. file_num = device->file;
  1343. }
  1344. }
  1345. if (next_file != NULL) {
  1346. *next_file = file_num + 1;
  1347. }
  1348. g_return_val_if_fail(source.header->type == F_DUMPFILE ||
  1349. source.header->type == F_CONT_DUMPFILE ||
  1350. source.header->type == F_SPLIT_DUMPFILE,
  1351. RESTORE_STATUS_NEXT_FILE);
  1352. if (!run_dumpspecs(dumpspecs, source.header)) {
  1353. if(!flags->amidxtaped) {
  1354. g_fprintf(prompt_out, "%s: %d: skipping ",
  1355. get_pname(), file_num);
  1356. print_header(prompt_out, source.header);
  1357. }
  1358. return RESTORE_STATUS_NEXT_FILE;
  1359. }
  1360. if (first_restored_file != NULL &&
  1361. first_restored_file->type != F_UNKNOWN &&
  1362. !headers_equal(first_restored_file, source.header, 1) &&
  1363. (flags->pipe_to_fd == fileno(stdout))) {
  1364. return RESTORE_STATUS_STOP;
  1365. }
  1366. if (!flags->amidxtaped) {
  1367. g_fprintf(stderr, "%s: %d: restoring ",
  1368. get_pname(), file_num);
  1369. print_header(stderr, source.header);
  1370. }
  1371. record_seen_dump(tape_seen, source.header);
  1372. restore(&source, flags);
  1373. if (first_restored_file) {
  1374. memcpy(first_restored_file, source.header, sizeof(dumpfile_t));
  1375. }
  1376. return RESTORE_STATUS_NEXT_FILE;
  1377. }
  1378. /* This function handles processing of a particular tape or holding
  1379. disk file. It returns TRUE if it is useful to load another tape.*/
  1380. gboolean
  1381. search_a_tape(Device * device,
  1382. FILE *prompt_out, /* Where to send any prompts */
  1383. rst_flags_t *flags, /* Restore options. */
  1384. am_feature_t *their_features,
  1385. tapelist_t *desired_tape, /* A list of desired tape files */
  1386. GSList *dumpspecs, /* What disks to restore. */
  1387. seentapes_t **tape_seen, /* Where to record data on
  1388. this tape. */
  1389. /* May be NULL. If zeroed, will be filled in with the
  1390. first restored file. If already filled in, then we
  1391. may only restore other files from the same dump. */
  1392. dumpfile_t * first_restored_file,
  1393. int tape_count,
  1394. FILE * logstream) {
  1395. seentapes_t * tape_seen_head = NULL;
  1396. RestoreSource source;
  1397. off_t filenum;
  1398. int tapefile_idx = -1;
  1399. int i;
  1400. RestoreFileStatus restore_status = RESTORE_STATUS_NEXT_TAPE;
  1401. source.restore_mode = DEVICE_MODE;
  1402. source.u.device = device;
  1403. filenum = (off_t)0;
  1404. if(desired_tape && desired_tape->numfiles > 0)
  1405. tapefile_idx = 0;
  1406. if (desired_tape) {
  1407. dbprintf(_("search_a_tape: desired_tape=%p label=%s\n"),
  1408. desired_tape, desired_tape->label);
  1409. dbprintf(_("tape: numfiles = %d\n"), desired_tape->numfiles);
  1410. for (i=0; i < desired_tape->numfiles; i++) {
  1411. dbprintf(_("tape: files[%d] = %lld\n"),
  1412. i, (long long)desired_tape->files[i]);
  1413. }
  1414. } else {
  1415. dbprintf(_("search_a_tape: no desired_tape\n"));
  1416. }
  1417. dbprintf(_("current tapefile_idx = %d\n"), tapefile_idx);
  1418. if (tape_seen) {
  1419. if (check_volume_seen(*tape_seen, device->volume_label)) {
  1420. send_message(prompt_out, flags, their_features,
  1421. "Skipping repeat tape %s in slot %s",
  1422. device->volume_label, curslot);
  1423. return TRUE;
  1424. }
  1425. record_seen_volume(tape_seen, device->volume_label, curslot);
  1426. tape_seen_head = *tape_seen;
  1427. }
  1428. if (desired_tape && desired_tape->numfiles > 0) {
  1429. /* Iterate the tape list, handle each file in order. */
  1430. int file_index;
  1431. for (file_index = 0; file_index < desired_tape->numfiles;
  1432. file_index ++) {
  1433. int file_num = desired_tape->files[file_index];
  1434. restore_status = try_restore_single_file(device, file_num, NULL,
  1435. prompt_out, flags,
  1436. their_features,
  1437. first_restored_file,
  1438. NULL, tape_seen_head);
  1439. if (restore_status != RESTORE_STATUS_NEXT_FILE)
  1440. break;
  1441. }
  1442. } else if(flags->fsf && flags->amidxtaped) {
  1443. /* Restore a single file, then quit. */
  1444. restore_status =
  1445. try_restore_single_file(device, flags->fsf, NULL, prompt_out, flags,
  1446. their_features, first_restored_file,
  1447. dumpspecs, tape_seen_head);
  1448. } else {
  1449. /* Search the tape from beginning to end. */
  1450. int file_num;
  1451. if (flags->fsf > 0) {
  1452. file_num = flags->fsf;
  1453. } else {
  1454. file_num = 1;
  1455. }
  1456. if

Large files files are truncated, but you can click here to view the full file