PageRenderTime 43ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/amanda/tags/amanda252p1/restore-src/amrestore.c

#
C | 432 lines | 307 code | 32 blank | 93 comment | 101 complexity | 6532f47c8d3aebcdb508fdb69484ba47 MD5 | raw 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: amrestore.c,v 1.63 2006/07/25 18:58:10 martinea Exp $
  28. *
  29. * retrieves files from an amanda tape
  30. */
  31. /*
  32. * Pulls all files from the tape that match the hostname, diskname and
  33. * datestamp regular expressions.
  34. *
  35. * If the header is output, only up to DISK_BLOCK_BYTES worth of it is
  36. * sent, regardless of the tape blocksize. This makes the disk image
  37. * look like a holding disk image, and also makes it easier to remove
  38. * the header (e.g. in amrecover) since it has a fixed size.
  39. */
  40. #include "amanda.h"
  41. #include "util.h"
  42. #include "tapeio.h"
  43. #include "fileheader.h"
  44. #include "restore.h"
  45. #define CREAT_MODE 0640
  46. static off_t file_number;
  47. static pid_t comp_enc_pid = -1;
  48. static int tapedev;
  49. static off_t filefsf = (off_t)-1;
  50. /* local functions */
  51. static void errexit(void);
  52. static void usage(void);
  53. int main(int argc, char **argv);
  54. /*
  55. * Do exit(2) after an error, rather than exit(1).
  56. */
  57. static void
  58. errexit(void)
  59. {
  60. exit(2);
  61. }
  62. /*
  63. * Print usage message and terminate.
  64. */
  65. static void
  66. usage(void)
  67. {
  68. error("Usage: amrestore [-b blocksize] [-r|-c] [-p] [-h] [-f fileno] "
  69. "[-l label] tape-device|holdingfile [hostname [diskname [datestamp "
  70. "[hostname [diskname [datestamp ... ]]]]]]");
  71. /*NOTREACHED*/
  72. }
  73. /*
  74. * Parses command line, then loops through all files on tape, restoring
  75. * files that match the command line criteria.
  76. */
  77. int
  78. main(
  79. int argc,
  80. char ** argv)
  81. {
  82. extern int optind;
  83. int opt;
  84. char *errstr;
  85. int isafile;
  86. struct stat stat_tape;
  87. dumpfile_t file;
  88. char *filename = NULL;
  89. char *tapename = NULL;
  90. struct match_list {
  91. char *hostname;
  92. char *diskname;
  93. char *datestamp;
  94. struct match_list *next;
  95. } *match_list = NULL, *me = NULL;
  96. int found_match;
  97. int arg_state;
  98. amwait_t compress_status;
  99. int r = 0;
  100. char *e;
  101. char *err;
  102. char *label = NULL;
  103. rst_flags_t *rst_flags;
  104. int count_error;
  105. long tmplong;
  106. ssize_t read_result;
  107. safe_fd(-1, 0);
  108. set_pname("amrestore");
  109. dbopen(DBG_SUBDIR_SERVER);
  110. /* Don't die when child closes pipe */
  111. signal(SIGPIPE, SIG_IGN);
  112. erroutput_type = ERR_INTERACTIVE;
  113. onerror(errexit);
  114. rst_flags = new_rst_flags();
  115. rst_flags->inline_assemble = 0;
  116. /* handle options */
  117. while( (opt = getopt(argc, argv, "b:cCd:rphf:l:")) != -1) {
  118. switch(opt) {
  119. case 'b':
  120. tmplong = strtol(optarg, &e, 10);
  121. rst_flags->blocksize = (ssize_t)tmplong;
  122. if(*e == 'k' || *e == 'K') {
  123. rst_flags->blocksize *= 1024;
  124. } else if(*e == 'm' || *e == 'M') {
  125. rst_flags->blocksize *= 1024 * 1024;
  126. } else if(*e != '\0') {
  127. error("invalid rst_flags->blocksize value \"%s\"", optarg);
  128. /*NOTREACHED*/
  129. }
  130. if(rst_flags->blocksize < DISK_BLOCK_BYTES) {
  131. error("minimum block size is %dk", DISK_BLOCK_BYTES / 1024);
  132. /*NOTREACHED*/
  133. }
  134. if(rst_flags->blocksize > MAX_TAPE_BLOCK_KB * 1024) {
  135. fprintf(stderr,"maximum block size is %dk, using it\n",
  136. MAX_TAPE_BLOCK_KB);
  137. rst_flags->blocksize = MAX_TAPE_BLOCK_KB * 1024;
  138. /*NOTREACHED*/
  139. }
  140. break;
  141. case 'c': rst_flags->compress = 1; break;
  142. case 'C':
  143. rst_flags->compress = 1;
  144. rst_flags->comp_type = COMPRESS_BEST_OPT;
  145. break;
  146. case 'r': rst_flags->raw = 1; break;
  147. case 'p': rst_flags->pipe_to_fd = fileno(stdout); break;
  148. case 'h': rst_flags->headers = 1; break;
  149. case 'f':
  150. filefsf = (off_t)OFF_T_STRTOL(optarg, &e, 10);
  151. /*@ignore@*/
  152. if(*e != '\0') {
  153. error("invalid fileno value \"%s\"", optarg);
  154. /*NOTREACHED*/
  155. }
  156. /*@end@*/
  157. break;
  158. case 'l':
  159. label = stralloc(optarg);
  160. break;
  161. default:
  162. usage();
  163. }
  164. }
  165. if(rst_flags->compress && rst_flags->raw) {
  166. fprintf(stderr,
  167. "Cannot specify both -r (raw) and -c (compressed) output.\n");
  168. usage();
  169. }
  170. if(optind >= argc) {
  171. fprintf(stderr, "%s: Must specify tape-device or holdingfile\n",
  172. get_pname());
  173. usage();
  174. }
  175. tapename = argv[optind++];
  176. #define ARG_GET_HOST 0
  177. #define ARG_GET_DISK 1
  178. #define ARG_GET_DATE 2
  179. arg_state = ARG_GET_HOST;
  180. while(optind < argc) {
  181. switch(arg_state) {
  182. case ARG_GET_HOST:
  183. /*
  184. * This is a new host/disk/date triple, so allocate a match_list.
  185. */
  186. me = alloc(SIZEOF(*me));
  187. me->hostname = argv[optind++];
  188. me->diskname = "";
  189. me->datestamp = "";
  190. me->next = match_list;
  191. match_list = me;
  192. if(me->hostname[0] != '\0'
  193. && (errstr=validate_regexp(me->hostname)) != NULL) {
  194. fprintf(stderr, "%s: bad hostname regex \"%s\": %s\n",
  195. get_pname(), me->hostname, errstr);
  196. usage();
  197. }
  198. arg_state = ARG_GET_DISK;
  199. break;
  200. case ARG_GET_DISK:
  201. me->diskname = argv[optind++];
  202. if(me->diskname[0] != '\0'
  203. && (errstr=validate_regexp(me->diskname)) != NULL) {
  204. fprintf(stderr, "%s: bad diskname regex \"%s\": %s\n",
  205. get_pname(), me->diskname, errstr);
  206. usage();
  207. }
  208. arg_state = ARG_GET_DATE;
  209. break;
  210. case ARG_GET_DATE:
  211. me->datestamp = argv[optind++];
  212. if(me->datestamp[0] != '\0'
  213. && (errstr=validate_regexp(me->datestamp)) != NULL) {
  214. fprintf(stderr, "%s: bad datestamp regex \"%s\": %s\n",
  215. get_pname(), me->datestamp, errstr);
  216. usage();
  217. }
  218. arg_state = ARG_GET_HOST;
  219. break;
  220. }
  221. }
  222. if(match_list == NULL) {
  223. match_list = alloc(SIZEOF(*match_list));
  224. match_list->hostname = "";
  225. match_list->diskname = "";
  226. match_list->datestamp = "";
  227. match_list->next = NULL;
  228. }
  229. if(tape_stat(tapename,&stat_tape)!=0) {
  230. error("could not stat %s: %s", tapename, strerror(errno));
  231. /*NOTREACHED*/
  232. }
  233. isafile=S_ISREG((stat_tape.st_mode));
  234. if(label) {
  235. if(isafile) {
  236. fprintf(stderr,"%s: ignoring -l flag when restoring from a file.\n",
  237. get_pname());
  238. }
  239. else {
  240. if((err = tape_rewind(tapename)) != NULL) {
  241. error("Could not rewind device '%s': %s", tapename, err);
  242. /*NOTREACHED*/
  243. }
  244. if ((tapedev = tape_open(tapename, 0)) == -1) {;
  245. error("Could not open device '%s': %s", tapename, err);
  246. /*NOTREACHED*/
  247. }
  248. read_file_header(&file, tapedev, isafile, rst_flags);
  249. if(file.type != F_TAPESTART) {
  250. fprintf(stderr,"Not an amanda tape\n");
  251. exit (1);
  252. }
  253. if(strcmp(label, file.name) != 0) {
  254. fprintf(stderr,"Wrong label: '%s'\n", file.name);
  255. exit (1);
  256. }
  257. tapefd_close(tapedev);
  258. if((err = tape_rewind(tapename)) != NULL) {
  259. error("Could not rewind device '%s': %s", tapename, err);
  260. /*NOTREACHED*/
  261. }
  262. }
  263. }
  264. file_number = (off_t)0;
  265. if(filefsf != (off_t)-1) {
  266. if(isafile) {
  267. fprintf(stderr,"%s: ignoring -f flag when restoring from a file.\n",
  268. get_pname());
  269. }
  270. else {
  271. if((err = tape_rewind(tapename)) != NULL) {
  272. error("Could not rewind device '%s': %s", tapename, err);
  273. /*NOTREACHED*/
  274. }
  275. if((err = tape_fsf(tapename, filefsf)) != NULL) {
  276. error("Could not fsf device '%s': %s", tapename, err);
  277. /*NOTREACHED*/
  278. }
  279. file_number = filefsf;
  280. }
  281. }
  282. if(isafile) {
  283. tapedev = open(tapename, O_RDWR);
  284. } else {
  285. tapedev = tape_open(tapename, 0);
  286. }
  287. if(tapedev < 0) {
  288. error("could not open %s: %s", tapename, strerror(errno));
  289. /*NOTREACHED*/
  290. }
  291. read_result = read_file_header(&file, tapedev, isafile, rst_flags);
  292. if(file.type != F_TAPESTART && !isafile && filefsf == (off_t)-1) {
  293. fprintf(stderr, "%s: WARNING: not at start of tape, file numbers will be offset\n",
  294. get_pname());
  295. }
  296. count_error = 0;
  297. while(count_error < 10) {
  298. if(file.type == F_TAPEEND) break;
  299. found_match = 0;
  300. if(file.type == F_DUMPFILE || file.type == F_SPLIT_DUMPFILE) {
  301. amfree(filename);
  302. filename = make_filename(&file);
  303. for(me = match_list; me; me = me->next) {
  304. if(disk_match(&file,me->datestamp,me->hostname,me->diskname,"") != 0) {
  305. found_match = 1;
  306. break;
  307. }
  308. }
  309. fprintf(stderr, "%s: " OFF_T_FMT ": %s ",
  310. get_pname(),
  311. (OFF_T_FMT_TYPE)file_number,
  312. found_match ? "restoring" : "skipping");
  313. if(file.type != F_DUMPFILE && file.type != F_SPLIT_DUMPFILE) {
  314. print_header(stderr, &file);
  315. } else {
  316. fprintf(stderr, "%s\n", filename);
  317. }
  318. }
  319. if(found_match) {
  320. count_error=0;
  321. read_result = restore(&file, filename,
  322. tapedev, isafile, rst_flags);
  323. if(comp_enc_pid > 0) {
  324. waitpid(comp_enc_pid, &compress_status, 0);
  325. comp_enc_pid = -1;
  326. }
  327. if(rst_flags->pipe_to_fd != -1) {
  328. file_number++; /* for the last message */
  329. break;
  330. }
  331. }
  332. if(isafile) {
  333. break;
  334. }
  335. /*
  336. * Note that at this point we know we are working with a tape,
  337. * not a holding disk file, so we can call the tape functions
  338. * without checking.
  339. */
  340. if(read_result == 0) {
  341. /*
  342. * If the last read got EOF, how to get to the next
  343. * file depends on how the tape device driver is acting.
  344. * If it is BSD-like, we do not really need to do anything.
  345. * If it is Sys-V-like, we need to either fsf or close/open.
  346. * The good news is, a close/open works in either case,
  347. * so that's what we do.
  348. */
  349. tapefd_close(tapedev);
  350. if((tapedev = tape_open(tapename, 0)) < 0) {
  351. error("could not open %s: %s", tapename, strerror(errno));
  352. /*NOTREACHED*/
  353. }
  354. count_error++;
  355. } else {
  356. /*
  357. * If the last read got something (even an error), we can
  358. * do an fsf to get to the next file.
  359. */
  360. if(tapefd_fsf(tapedev, (off_t)1) < 0) {
  361. error("could not fsf %s: %s", tapename, strerror(errno));
  362. /*NOTREACHED*/
  363. }
  364. count_error=0;
  365. }
  366. file_number++;
  367. read_result = read_file_header(&file, tapedev, isafile, rst_flags);
  368. }
  369. if(isafile) {
  370. close(tapedev);
  371. } else {
  372. /*
  373. * See the notes above about advancing to the next file.
  374. */
  375. if(read_result == 0) {
  376. tapefd_close(tapedev);
  377. if((tapedev = tape_open(tapename, 0)) < 0) {
  378. error("could not open %s: %s", tapename, strerror(errno));
  379. /*NOTREACHED*/
  380. }
  381. } else {
  382. if(tapefd_fsf(tapedev, (off_t)1) < 0) {
  383. error("could not fsf %s: %s", tapename, strerror(errno));
  384. /*NOTREACHED*/
  385. }
  386. }
  387. tapefd_close(tapedev);
  388. }
  389. if((read_result <= 0 || file.type == F_TAPEEND) && !isafile) {
  390. fprintf(stderr, "%s: " OFF_T_FMT ": reached ",
  391. get_pname(), (OFF_T_FMT_TYPE)file_number);
  392. if(read_result <= 0) {
  393. fprintf(stderr, "end of information\n");
  394. } else {
  395. print_header(stderr,&file);
  396. }
  397. r = 1;
  398. }
  399. return r;
  400. }