PageRenderTime 65ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

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

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

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