PageRenderTime 53ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

/amanda/tags/amanda260p2/recover-src/extract_list.c

#
C | 2550 lines | 2040 code | 248 blank | 262 comment | 568 complexity | 5121ac0fffe36d80638498f6a4926892 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, 2000 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: extract_list.c,v 1.117 2006/08/24 01:57:15 paddy_s Exp $
  28. *
  29. * implements the "extract" command in amrecover
  30. */
  31. #include "amanda.h"
  32. #include "version.h"
  33. #include "amrecover.h"
  34. #include "fileheader.h"
  35. #include "dgram.h"
  36. #include "stream.h"
  37. #include "tapelist.h"
  38. #ifdef SAMBA_CLIENT
  39. #include "findpass.h"
  40. #endif
  41. #include "util.h"
  42. #include "conffile.h"
  43. #include "protocol.h"
  44. #include "event.h"
  45. #include "security.h"
  46. typedef struct EXTRACT_LIST_ITEM {
  47. char *path;
  48. struct EXTRACT_LIST_ITEM *next;
  49. }
  50. EXTRACT_LIST_ITEM;
  51. typedef struct EXTRACT_LIST {
  52. char *date; /* date tape created */
  53. int level; /* level of dump */
  54. char *tape; /* tape label */
  55. off_t fileno; /* fileno on tape */
  56. EXTRACT_LIST_ITEM *files; /* files to get off tape */
  57. struct EXTRACT_LIST *next;
  58. }
  59. EXTRACT_LIST;
  60. #define SKIP_TAPE 2
  61. #define RETRY_TAPE 3
  62. static struct {
  63. const char *name;
  64. security_stream_t *fd;
  65. } amidxtaped_streams[] = {
  66. #define CTLFD 0
  67. { "CTL", NULL },
  68. #define DATAFD 1
  69. { "DATA", NULL },
  70. };
  71. #define NSTREAMS (int)(sizeof(amidxtaped_streams) / sizeof(amidxtaped_streams[0]))
  72. static void amidxtaped_response(void *, pkt_t *, security_handle_t *);
  73. static void stop_amidxtaped(void);
  74. char *amidxtaped_client_get_security_conf(char *, void *);
  75. static char *dump_device_name = NULL;
  76. static char *errstr;
  77. static char *amidxtaped_line = NULL;
  78. extern char *localhost;
  79. /* global pid storage for interrupt handler */
  80. pid_t extract_restore_child_pid = -1;
  81. static EXTRACT_LIST *extract_list = NULL;
  82. static const security_driver_t *amidxtaped_secdrv;
  83. #ifdef SAMBA_CLIENT
  84. unsigned short samba_extract_method = SAMBA_TAR;
  85. #endif /* SAMBA_CLIENT */
  86. #define READ_TIMEOUT 240*60
  87. EXTRACT_LIST *first_tape_list(void);
  88. EXTRACT_LIST *next_tape_list(EXTRACT_LIST *list);
  89. static int is_empty_dir(char *fname);
  90. int is_extract_list_nonempty(void);
  91. int length_of_tape_list(EXTRACT_LIST *tape_list);
  92. void add_file(char *path, char *regex);
  93. void add_glob(char *glob);
  94. void add_regex(char *regex);
  95. void clear_extract_list(void);
  96. void clean_tape_list(EXTRACT_LIST *tape_list);
  97. void clean_extract_list(void);
  98. void check_file_overwrite(char *filename);
  99. void delete_file(char *path, char *regex);
  100. void delete_glob(char *glob);
  101. void delete_regex(char *regex);
  102. void delete_tape_list(EXTRACT_LIST *tape_list);
  103. void display_extract_list(char *file);
  104. void extract_files(void);
  105. void read_file_header(char *buffer,
  106. dumpfile_t *file,
  107. size_t buflen,
  108. int tapedev);
  109. static int add_extract_item(DIR_ITEM *ditem);
  110. static int delete_extract_item(DIR_ITEM *ditem);
  111. static int extract_files_setup(char *label, off_t fsf);
  112. static int okay_to_continue(int allow_tape,
  113. int allow_skip,
  114. int allow_retry);
  115. static ssize_t read_buffer(int datafd,
  116. char *buffer,
  117. size_t buflen,
  118. long timeout_s);
  119. static void clear_tape_list(EXTRACT_LIST *tape_list);
  120. static void extract_files_child(int in_fd, EXTRACT_LIST *elist);
  121. static void send_to_tape_server(security_stream_t *stream, char *cmd);
  122. int writer_intermediary(EXTRACT_LIST *elist);
  123. int get_amidxtaped_line(void);
  124. static void read_amidxtaped_data(void *, void *, ssize_t);
  125. /*
  126. * Function: ssize_t read_buffer(datafd, buffer, buflen, timeout_s)
  127. *
  128. * Description:
  129. * read data from input file desciptor waiting up to timeout_s
  130. * seconds before returning data.
  131. *
  132. * Inputs:
  133. * datafd - File descriptor to read from.
  134. * buffer - Buffer to read into.
  135. * buflen - Maximum number of bytes to read into buffer.
  136. * timeout_s - Seconds to wait before returning what was already read.
  137. *
  138. * Returns:
  139. * >0 - Number of data bytes in buffer.
  140. * 0 - EOF
  141. * -1 - errno == ETIMEDOUT if no data available in specified time.
  142. * errno == ENFILE if datafd is invalid.
  143. * otherwise errno is set by select or read..
  144. */
  145. static ssize_t
  146. read_buffer(
  147. int datafd,
  148. char * buffer,
  149. size_t buflen,
  150. long timeout_s)
  151. {
  152. ssize_t size = 0;
  153. SELECT_ARG_TYPE readset;
  154. struct timeval timeout;
  155. char *dataptr;
  156. ssize_t spaceleft;
  157. int nfound;
  158. if(datafd < 0 || datafd >= (int)FD_SETSIZE) {
  159. errno = EMFILE; /* out of range */
  160. return -1;
  161. }
  162. dataptr = buffer;
  163. spaceleft = (ssize_t)buflen;
  164. do {
  165. FD_ZERO(&readset);
  166. FD_SET(datafd, &readset);
  167. timeout.tv_sec = timeout_s;
  168. timeout.tv_usec = 0;
  169. nfound = select(datafd+1, &readset, NULL, NULL, &timeout);
  170. if(nfound < 0 ) {
  171. /* Select returned an error. */
  172. g_fprintf(stderr,_("select error: %s\n"), strerror(errno));
  173. size = -1;
  174. break;
  175. }
  176. if (nfound == 0) {
  177. /* Select timed out. */
  178. if (timeout_s != 0) {
  179. /* Not polling: a real read timeout */
  180. g_fprintf(stderr,_("timeout waiting for restore\n"));
  181. g_fprintf(stderr,_("increase READ_TIMEOUT in recover-src/extract_list.c if your tape is slow\n"));
  182. }
  183. errno = ETIMEDOUT;
  184. size = -1;
  185. break;
  186. }
  187. if(!FD_ISSET(datafd, &readset))
  188. continue;
  189. /* Select says data is available, so read it. */
  190. size = read(datafd, dataptr, (size_t)spaceleft);
  191. if (size < 0) {
  192. if ((errno == EINTR) || (errno == EAGAIN)) {
  193. continue;
  194. }
  195. if (errno != EPIPE) {
  196. g_fprintf(stderr, _("read_buffer: read error - %s"),
  197. strerror(errno));
  198. break;
  199. }
  200. size = 0;
  201. }
  202. spaceleft -= size;
  203. dataptr += size;
  204. } while ((size > 0) && (spaceleft > 0));
  205. return ((((ssize_t)buflen-spaceleft) > 0) ? ((ssize_t)buflen-spaceleft) : size);
  206. }
  207. EXTRACT_LIST *
  208. first_tape_list(void)
  209. {
  210. return extract_list;
  211. }
  212. EXTRACT_LIST *
  213. next_tape_list(
  214. /*@keep@*/EXTRACT_LIST *list)
  215. {
  216. if (list == NULL)
  217. return NULL;
  218. return list->next;
  219. }
  220. static void
  221. clear_tape_list(
  222. EXTRACT_LIST * tape_list)
  223. {
  224. EXTRACT_LIST_ITEM *this, *next;
  225. this = tape_list->files;
  226. while (this != NULL)
  227. {
  228. next = this->next;
  229. amfree(this->path);
  230. amfree(this);
  231. this = next;
  232. }
  233. tape_list->files = NULL;
  234. }
  235. /* remove a tape list from the extract list, clearing the tape list
  236. beforehand if necessary */
  237. void
  238. delete_tape_list(
  239. EXTRACT_LIST *tape_list)
  240. {
  241. EXTRACT_LIST *this, *prev;
  242. if (tape_list == NULL)
  243. return;
  244. /* is it first on the list? */
  245. if (tape_list == extract_list)
  246. {
  247. extract_list = tape_list->next;
  248. clear_tape_list(tape_list);
  249. amfree(tape_list->date);
  250. amfree(tape_list->tape);
  251. amfree(tape_list);
  252. return;
  253. }
  254. /* so not first on list - find it and delete */
  255. prev = extract_list;
  256. this = extract_list->next;
  257. while (this != NULL)
  258. {
  259. if (this == tape_list)
  260. {
  261. prev->next = tape_list->next;
  262. clear_tape_list(tape_list);
  263. amfree(tape_list->date);
  264. amfree(tape_list->tape);
  265. amfree(tape_list);
  266. return;
  267. }
  268. prev = this;
  269. this = this->next;
  270. }
  271. /*NOTREACHED*/
  272. }
  273. /* return the number of files on a tape's list */
  274. int
  275. length_of_tape_list(
  276. EXTRACT_LIST *tape_list)
  277. {
  278. EXTRACT_LIST_ITEM *fn;
  279. int n;
  280. n = 0;
  281. for (fn = tape_list->files; fn != NULL; fn = fn->next)
  282. n++;
  283. return n;
  284. }
  285. void
  286. clear_extract_list(void)
  287. {
  288. while (extract_list != NULL)
  289. delete_tape_list(extract_list);
  290. }
  291. void
  292. clean_tape_list(
  293. EXTRACT_LIST *tape_list)
  294. {
  295. EXTRACT_LIST_ITEM *fn1, *pfn1, *ofn1;
  296. EXTRACT_LIST_ITEM *fn2, *pfn2, *ofn2;
  297. int remove_fn1;
  298. int remove_fn2;
  299. pfn1 = NULL;
  300. fn1 = tape_list->files;
  301. while (fn1 != NULL) {
  302. remove_fn1 = 0;
  303. pfn2 = fn1;
  304. fn2 = fn1->next;
  305. while (fn2 != NULL && remove_fn1 == 0) {
  306. remove_fn2 = 0;
  307. if(strcmp(fn1->path, fn2->path) == 0) {
  308. remove_fn2 = 1;
  309. } else if (strncmp(fn1->path, fn2->path, strlen(fn1->path)) == 0 &&
  310. ((strlen(fn2->path) > strlen(fn1->path) &&
  311. fn2->path[strlen(fn1->path)] == '/') ||
  312. (fn1->path[strlen(fn1->path)-1] == '/'))) {
  313. remove_fn2 = 1;
  314. } else if (strncmp(fn2->path, fn1->path, strlen(fn2->path)) == 0 &&
  315. ((strlen(fn1->path) > strlen(fn2->path) &&
  316. fn1->path[strlen(fn2->path)] == '/') ||
  317. (fn2->path[strlen(fn2->path)-1] == '/'))) {
  318. remove_fn1 = 1;
  319. break;
  320. }
  321. if (remove_fn2) {
  322. dbprintf(_("removing path %s, it is included in %s\n"),
  323. fn2->path, fn1->path);
  324. ofn2 = fn2;
  325. fn2 = fn2->next;
  326. amfree(ofn2->path);
  327. amfree(ofn2);
  328. pfn2->next = fn2;
  329. } else if (remove_fn1 == 0) {
  330. pfn2 = fn2;
  331. fn2 = fn2->next;
  332. }
  333. }
  334. if(remove_fn1 != 0) {
  335. /* fn2->path is always valid */
  336. /*@i@*/ dbprintf(_("removing path %s, it is included in %s\n"),
  337. /*@i@*/ fn1->path, fn2->path);
  338. ofn1 = fn1;
  339. fn1 = fn1->next;
  340. amfree(ofn1->path);
  341. if(pfn1 == NULL) {
  342. amfree(tape_list->files);
  343. tape_list->files = fn1;
  344. } else {
  345. amfree(pfn1->next);
  346. pfn1->next = fn1;
  347. }
  348. } else {
  349. pfn1 = fn1;
  350. fn1 = fn1->next;
  351. }
  352. }
  353. }
  354. void
  355. clean_extract_list(void)
  356. {
  357. EXTRACT_LIST *this;
  358. for (this = extract_list; this != NULL; this = this->next)
  359. clean_tape_list(this);
  360. }
  361. int add_to_unlink_list(char *path);
  362. int do_unlink_list(void);
  363. void free_unlink_list(void);
  364. typedef struct s_unlink_list {
  365. char *path;
  366. struct s_unlink_list *next;
  367. } t_unlink_list;
  368. t_unlink_list *unlink_list = NULL;
  369. int
  370. add_to_unlink_list(
  371. char *path)
  372. {
  373. t_unlink_list *ul;
  374. if (!unlink_list) {
  375. unlink_list = alloc(SIZEOF(*unlink_list));
  376. unlink_list->path = stralloc(path);
  377. unlink_list->next = NULL;
  378. } else {
  379. for (ul = unlink_list; ul != NULL; ul = ul->next) {
  380. if (strcmp(ul->path, path) == 0)
  381. return 0;
  382. }
  383. ul = alloc(SIZEOF(*ul));
  384. ul->path = stralloc(path);
  385. ul->next = unlink_list;
  386. unlink_list = ul;
  387. }
  388. return 1;
  389. }
  390. int
  391. do_unlink_list(void)
  392. {
  393. t_unlink_list *ul;
  394. int ret = 1;
  395. for (ul = unlink_list; ul != NULL; ul = ul->next) {
  396. if (unlink(ul->path) < 0) {
  397. g_fprintf(stderr,_("Can't unlink %s: %s\n"), ul->path, strerror(errno));
  398. ret = 0;
  399. }
  400. }
  401. return ret;
  402. }
  403. void
  404. free_unlink_list(void)
  405. {
  406. t_unlink_list *ul, *ul1;
  407. for (ul = unlink_list; ul != NULL; ul = ul1) {
  408. amfree(ul->path);
  409. ul1 = ul->next;
  410. amfree(ul);
  411. }
  412. unlink_list = NULL;
  413. }
  414. void
  415. check_file_overwrite(
  416. char *dir)
  417. {
  418. EXTRACT_LIST *this;
  419. EXTRACT_LIST_ITEM *fn;
  420. struct stat stat_buf;
  421. char *filename;
  422. char *path, *s;
  423. for (this = extract_list; this != NULL; this = this->next) {
  424. for (fn = this->files; fn != NULL ; fn = fn->next) {
  425. /* Check path component of fn->path */
  426. path = stralloc2(dir, fn->path);
  427. if (path[strlen(path)-1] == '/') {
  428. path[strlen(path)-1] = '\0';
  429. }
  430. s = path + strlen(dir) + 1;
  431. while((s = strchr(s, '/'))) {
  432. *s = '\0';
  433. if (lstat(path, &stat_buf) == 0) {
  434. if(!S_ISDIR(stat_buf.st_mode)) {
  435. if (add_to_unlink_list(path)) {
  436. g_printf(_("WARNING: %s is not a directory, "
  437. "it will be deleted.\n"),
  438. path);
  439. }
  440. }
  441. }
  442. else if (errno != ENOENT) {
  443. g_printf(_("Can't stat %s: %s\n"), path, strerror(errno));
  444. }
  445. *s = '/';
  446. s++;
  447. }
  448. amfree(path);
  449. /* Check fn->path */
  450. filename = stralloc2(dir, fn->path);
  451. if (filename[strlen(filename)-1] == '/') {
  452. filename[strlen(filename)-1] = '\0';
  453. }
  454. if (lstat(filename, &stat_buf) == 0) {
  455. if(S_ISDIR(stat_buf.st_mode)) {
  456. if(!is_empty_dir(filename)) {
  457. g_printf(_("WARNING: All existing files in %s "
  458. "will be deleted.\n"), filename);
  459. }
  460. } else if(S_ISREG(stat_buf.st_mode)) {
  461. g_printf(_("WARNING: Existing file %s will be overwritten\n"),
  462. filename);
  463. } else {
  464. if (add_to_unlink_list(filename)) {
  465. g_printf(_("WARNING: Existing entry %s will be deleted\n"),
  466. filename);
  467. }
  468. }
  469. } else if (errno != ENOENT) {
  470. g_printf(_("Can't stat %s: %s\n"), filename, strerror(errno));
  471. }
  472. amfree(filename);
  473. }
  474. }
  475. }
  476. /* returns -1 if error */
  477. /* returns 0 on succes */
  478. /* returns 1 if already added */
  479. static int
  480. add_extract_item(
  481. DIR_ITEM *ditem)
  482. {
  483. EXTRACT_LIST *this, *this1;
  484. EXTRACT_LIST_ITEM *that, *curr;
  485. char *ditem_path = NULL;
  486. ditem_path = stralloc(ditem->path);
  487. clean_pathname(ditem_path);
  488. for (this = extract_list; this != NULL; this = this->next)
  489. {
  490. /* see if this is the list for the tape */
  491. if (this->level == ditem->level && strcmp(this->tape, ditem->tape) == 0)
  492. {
  493. /* yes, so add to list */
  494. curr=this->files;
  495. while(curr!=NULL)
  496. {
  497. if (strcmp(curr->path,ditem_path) == 0) {
  498. amfree(ditem_path);
  499. return 1;
  500. }
  501. curr=curr->next;
  502. }
  503. that = (EXTRACT_LIST_ITEM *)alloc(sizeof(EXTRACT_LIST_ITEM));
  504. that->path = stralloc(ditem_path);
  505. that->next = this->files;
  506. this->files = that; /* add at front since easiest */
  507. amfree(ditem_path);
  508. return 0;
  509. }
  510. }
  511. /* so this is the first time we have seen this tape */
  512. this = (EXTRACT_LIST *)alloc(sizeof(EXTRACT_LIST));
  513. this->tape = stralloc(ditem->tape);
  514. this->level = ditem->level;
  515. this->fileno = ditem->fileno;
  516. this->date = stralloc(ditem->date);
  517. that = (EXTRACT_LIST_ITEM *)alloc(sizeof(EXTRACT_LIST_ITEM));
  518. that->path = stralloc(ditem_path);
  519. that->next = NULL;
  520. this->files = that;
  521. /* add this in date increasing order */
  522. /* because restore must be done in this order */
  523. /* add at begining */
  524. if(extract_list==NULL || strcmp(this->date,extract_list->date) < 0)
  525. {
  526. this->next = extract_list;
  527. extract_list = this;
  528. amfree(ditem_path);
  529. return 0;
  530. }
  531. for (this1 = extract_list; this1->next != NULL; this1 = this1->next)
  532. {
  533. /* add in the middle */
  534. if(strcmp(this->date,this1->next->date) < 0)
  535. {
  536. this->next = this1->next;
  537. this1->next = this;
  538. amfree(ditem_path);
  539. return 0;
  540. }
  541. }
  542. /* add at end */
  543. this->next = NULL;
  544. this1->next = this;
  545. amfree(ditem_path);
  546. return 0;
  547. }
  548. /* returns -1 if error */
  549. /* returns 0 on deletion */
  550. /* returns 1 if not there */
  551. static int
  552. delete_extract_item(
  553. DIR_ITEM *ditem)
  554. {
  555. EXTRACT_LIST *this;
  556. EXTRACT_LIST_ITEM *that, *prev;
  557. char *ditem_path = NULL;
  558. ditem_path = stralloc(ditem->path);
  559. clean_pathname(ditem_path);
  560. for (this = extract_list; this != NULL; this = this->next)
  561. {
  562. /* see if this is the list for the tape */
  563. if (this->level == ditem->level && strcmp(this->tape, ditem->tape) == 0)
  564. {
  565. /* yes, so find file on list */
  566. that = this->files;
  567. if (strcmp(that->path, ditem_path) == 0)
  568. {
  569. /* first on list */
  570. this->files = that->next;
  571. amfree(that->path);
  572. amfree(that);
  573. /* if list empty delete it */
  574. if (this->files == NULL)
  575. delete_tape_list(this);
  576. amfree(ditem_path);
  577. return 0;
  578. }
  579. prev = that;
  580. that = that->next;
  581. while (that != NULL)
  582. {
  583. if (strcmp(that->path, ditem_path) == 0)
  584. {
  585. prev->next = that->next;
  586. amfree(that->path);
  587. amfree(that);
  588. amfree(ditem_path);
  589. return 0;
  590. }
  591. prev = that;
  592. that = that->next;
  593. }
  594. amfree(ditem_path);
  595. return 1;
  596. }
  597. }
  598. amfree(ditem_path);
  599. return 1;
  600. }
  601. void
  602. add_glob(
  603. char * glob)
  604. {
  605. char *regex;
  606. char *regex_path;
  607. char *s;
  608. char *uqglob = unquote_string(glob);
  609. regex = glob_to_regex(uqglob);
  610. dbprintf(_("add_glob (%s) -> %s\n"), uqglob, regex);
  611. if ((s = validate_regexp(regex)) != NULL) {
  612. g_printf(_("%s is not a valid shell wildcard pattern: "), glob);
  613. puts(s);
  614. } else {
  615. /*
  616. * glob_to_regex() anchors the beginning of the pattern with ^,
  617. * but we will be tacking it onto the end of the current directory
  618. * in add_file, so strip that off. Also, it anchors the end with
  619. * $, but we need to match an optional trailing /, so tack that on
  620. * the end.
  621. */
  622. regex_path = stralloc(regex + 1);
  623. regex_path[strlen(regex_path) - 1] = '\0';
  624. strappend(regex_path, "[/]*$");
  625. add_file(uqglob, regex_path);
  626. amfree(regex_path);
  627. }
  628. amfree(regex);
  629. amfree(uqglob);
  630. }
  631. void
  632. add_regex(
  633. char * regex)
  634. {
  635. char *s;
  636. char *uqregex = unquote_string(regex);
  637. if ((s = validate_regexp(uqregex)) != NULL) {
  638. g_printf(_("\"%s\" is not a valid regular expression: "), regex);
  639. puts(s);
  640. } else {
  641. add_file(uqregex, regex);
  642. }
  643. amfree(uqregex);
  644. }
  645. void
  646. add_file(
  647. char * path,
  648. char * regex)
  649. {
  650. DIR_ITEM *ditem, lditem;
  651. char *path_on_disk = NULL;
  652. char *cmd = NULL;
  653. char *err = NULL;
  654. int i;
  655. ssize_t j;
  656. char *dir, *dir_undo, dir_undo_ch = '\0';
  657. char *ditem_path = NULL;
  658. char *qditem_path = NULL;
  659. char *l = NULL;
  660. int added;
  661. char *s, *fp, *quoted;
  662. int ch;
  663. int found_one;
  664. int dir_entries;
  665. if (disk_path == NULL) {
  666. g_printf(_("Must select directory before adding files\n"));
  667. return;
  668. }
  669. memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */
  670. dbprintf(_("add_file: Looking for \"%s\"\n"), regex);
  671. if(strcmp(regex, "/[/]*$") == 0) { /* "/" behave like "." */
  672. regex = "\\.[/]*$";
  673. }
  674. else if(strcmp(regex, "[^/]*[/]*$") == 0) { /* "*" */
  675. regex = "([^/.]|\\.[^/]+|[^/.][^/]*)[/]*$";
  676. } else {
  677. /* remove "/" at end of path */
  678. j = (ssize_t)(strlen(regex) - 1);
  679. while(j >= 0 && regex[j] == '/')
  680. regex[j--] = '\0';
  681. }
  682. /* convert path (assumed in cwd) to one on disk */
  683. if (strcmp(disk_path, "/") == 0) {
  684. if (*regex == '/') {
  685. /* No mods needed if already starts with '/' */
  686. path_on_disk = stralloc(regex);
  687. } else {
  688. /* Prepend '/' */
  689. path_on_disk = stralloc2("/", regex);
  690. }
  691. } else {
  692. char *clean_disk_path = clean_regex(disk_path);
  693. path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
  694. amfree(clean_disk_path);
  695. }
  696. dbprintf(_("add_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n"),
  697. regex, path_on_disk);
  698. found_one = 0;
  699. dir_entries = 0;
  700. for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
  701. {
  702. dir_entries++;
  703. quoted = quote_string(ditem->path);
  704. dbprintf(_("add_file: Pondering ditem->path=%s\n"), quoted);
  705. amfree(quoted);
  706. if (match(path_on_disk, ditem->path))
  707. {
  708. found_one = 1;
  709. j = (ssize_t)strlen(ditem->path);
  710. if((j > 0 && ditem->path[j-1] == '/')
  711. || (j > 1 && ditem->path[j-2] == '/' && ditem->path[j-1] == '.'))
  712. { /* It is a directory */
  713. ditem_path = newstralloc(ditem_path, ditem->path);
  714. clean_pathname(ditem_path);
  715. qditem_path = quote_string(ditem_path);
  716. cmd = newstralloc2(cmd, "ORLD ", qditem_path);
  717. amfree(qditem_path);
  718. if(send_command(cmd) == -1) {
  719. amfree(cmd);
  720. amfree(ditem_path);
  721. amfree(path_on_disk);
  722. exit(1);
  723. }
  724. amfree(cmd);
  725. cmd = NULL;
  726. /* skip preamble */
  727. if ((i = get_reply_line()) == -1) {
  728. amfree(ditem_path);
  729. amfree(path_on_disk);
  730. exit(1);
  731. }
  732. if(i==0) { /* assume something wrong */
  733. amfree(ditem_path);
  734. amfree(path_on_disk);
  735. l = reply_line();
  736. g_printf("%s\n", l);
  737. return;
  738. }
  739. dir_undo = NULL;
  740. added=0;
  741. lditem.path = newstralloc(lditem.path, ditem->path);
  742. /* skip the last line -- duplicate of the preamble */
  743. while ((i = get_reply_line()) != 0) {
  744. if (i == -1) {
  745. amfree(ditem_path);
  746. amfree(path_on_disk);
  747. exit(1);
  748. }
  749. if(err) {
  750. if(cmd == NULL) {
  751. if(dir_undo) *dir_undo = dir_undo_ch;
  752. dir_undo = NULL;
  753. cmd = stralloc(l); /* save for error report */
  754. }
  755. continue; /* throw the rest of the lines away */
  756. }
  757. l=reply_line();
  758. if (!server_happy()) {
  759. puts(l);
  760. continue;
  761. }
  762. s = l;
  763. if(strncmp_const_skip(l, "201-", s, ch) != 0) {
  764. err = _("bad reply: not 201-");
  765. continue;
  766. }
  767. ch = *s++;
  768. skip_whitespace(s, ch);
  769. if(ch == '\0') {
  770. err = _("bad reply: missing date field");
  771. continue;
  772. }
  773. fp = s-1;
  774. skip_non_whitespace(s, ch);
  775. s[-1] = '\0';
  776. lditem.date = newstralloc(lditem.date, fp);
  777. s[-1] = (char)ch;
  778. skip_whitespace(s, ch);
  779. if(ch == '\0' || sscanf(s - 1, "%d", &lditem.level) != 1) {
  780. err = _("bad reply: cannot parse level field");
  781. continue;
  782. }
  783. skip_integer(s, ch);
  784. skip_whitespace(s, ch);
  785. if(ch == '\0') {
  786. err = _("bad reply: missing tape field");
  787. continue;
  788. }
  789. fp = s-1;
  790. skip_non_whitespace(s, ch);
  791. s[-1] = '\0';
  792. lditem.tape = newstralloc(lditem.tape, fp);
  793. s[-1] = (char)ch;
  794. if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
  795. long long fileno_ = (long long)0;
  796. skip_whitespace(s, ch);
  797. if(ch == '\0' ||
  798. sscanf(s - 1, "%lld", &fileno_) != 1) {
  799. err = _("bad reply: cannot parse fileno field");
  800. continue;
  801. }
  802. lditem.fileno = (off_t)fileno_;
  803. skip_integer(s, ch);
  804. }
  805. skip_whitespace(s, ch);
  806. if(ch == '\0') {
  807. err = _("bad reply: missing directory field");
  808. continue;
  809. }
  810. dir = s - 1;
  811. skip_quoted_string(s, ch);
  812. dir_undo = s - 1;
  813. dir_undo_ch = *dir_undo;
  814. *dir_undo = '\0';
  815. switch(add_extract_item(&lditem)) {
  816. case -1:
  817. g_printf(_("System error\n"));
  818. dbprintf(_("add_file: (Failed) System error\n"));
  819. break;
  820. case 0:
  821. quoted = quote_string(lditem.path);
  822. g_printf(_("Added dir %s at date %s\n"),
  823. quoted, lditem.date);
  824. dbprintf(_("add_file: (Successful) Added dir %s at date %s\n"),
  825. quoted, lditem.date);
  826. amfree(quoted);
  827. added=1;
  828. break;
  829. case 1:
  830. break;
  831. }
  832. }
  833. if(!server_happy()) {
  834. puts(reply_line());
  835. } else if(err) {
  836. if (*err)
  837. puts(err);
  838. if (cmd)
  839. puts(cmd);
  840. } else if(added == 0) {
  841. quoted = quote_string(ditem_path);
  842. g_printf(_("dir %s already added\n"), quoted);
  843. dbprintf(_("add_file: dir %s already added\n"), quoted);
  844. amfree(quoted);
  845. }
  846. }
  847. else /* It is a file */
  848. {
  849. switch(add_extract_item(ditem)) {
  850. case -1:
  851. g_printf(_("System error\n"));
  852. dbprintf(_("add_file: (Failed) System error\n"));
  853. break;
  854. case 0:
  855. quoted = quote_string(ditem->path);
  856. g_printf(_("Added file %s\n"), quoted);
  857. dbprintf(_("add_file: (Successful) Added %s\n"), quoted);
  858. amfree(quoted);
  859. break;
  860. case 1:
  861. quoted = quote_string(ditem->path);
  862. g_printf(_("File %s already added\n"), quoted);
  863. dbprintf(_("add_file: file %s already added\n"), quoted);
  864. amfree(quoted);
  865. }
  866. }
  867. }
  868. }
  869. amfree(cmd);
  870. amfree(ditem_path);
  871. amfree(path_on_disk);
  872. amfree(lditem.path);
  873. amfree(lditem.date);
  874. amfree(lditem.tape);
  875. if(! found_one) {
  876. quoted = quote_string(path);
  877. g_printf(_("File %s doesn't exist in directory\n"), quoted);
  878. dbprintf(_("add_file: (Failed) File %s doesn't exist in directory\n"),
  879. quoted);
  880. amfree(quoted);
  881. }
  882. }
  883. void
  884. delete_glob(
  885. char * glob)
  886. {
  887. char *regex;
  888. char *regex_path;
  889. char *s;
  890. char *uqglob = unquote_string(glob);
  891. regex = glob_to_regex(uqglob);
  892. dbprintf(_("delete_glob (%s) -> %s\n"), uqglob, regex);
  893. if ((s = validate_regexp(regex)) != NULL) {
  894. g_printf(_("\"%s\" is not a valid shell wildcard pattern: "), glob);
  895. puts(s);
  896. } else {
  897. /*
  898. * glob_to_regex() anchors the beginning of the pattern with ^,
  899. * but we will be tacking it onto the end of the current directory
  900. * in add_file, so strip that off. Also, it anchors the end with
  901. * $, but we need to match an optional trailing /, so tack that on
  902. * the end.
  903. */
  904. regex_path = stralloc(regex + 1);
  905. regex_path[strlen(regex_path) - 1] = '\0';
  906. strappend(regex_path, "[/]*$");
  907. delete_file(uqglob, regex_path);
  908. amfree(regex_path);
  909. }
  910. amfree(regex);
  911. amfree(uqglob);
  912. }
  913. void
  914. delete_regex(
  915. char * regex)
  916. {
  917. char *s;
  918. char *uqregex = unquote_string(regex);
  919. if ((s = validate_regexp(regex)) != NULL) {
  920. g_printf(_("\"%s\" is not a valid regular expression: "), regex);
  921. puts(s);
  922. } else {
  923. delete_file(uqregex, uqregex);
  924. }
  925. amfree(uqregex);
  926. }
  927. void
  928. delete_file(
  929. char * path,
  930. char * regex)
  931. {
  932. DIR_ITEM *ditem, lditem;
  933. char *path_on_disk = NULL;
  934. char *cmd = NULL;
  935. char *err = NULL;
  936. int i;
  937. ssize_t j;
  938. char *date;
  939. char *tape, *tape_undo, tape_undo_ch = '\0';
  940. char *dir_undo, dir_undo_ch = '\0';
  941. int level = 0;
  942. off_t fileno;
  943. char *ditem_path = NULL;
  944. char *qditem_path;
  945. char *l = NULL;
  946. int deleted;
  947. char *s;
  948. int ch;
  949. int found_one;
  950. char *quoted;
  951. if (disk_path == NULL) {
  952. g_printf(_("Must select directory before deleting files\n"));
  953. return;
  954. }
  955. memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */
  956. dbprintf(_("delete_file: Looking for \"%s\"\n"), path);
  957. if (strcmp(regex, "[^/]*[/]*$") == 0) {
  958. /* Looking for * find everything but single . */
  959. regex = "([^/.]|\\.[^/]+|[^/.][^/]*)[/]*$";
  960. } else {
  961. /* remove "/" at end of path */
  962. j = (ssize_t)(strlen(regex) - 1);
  963. while(j >= 0 && regex[j] == '/') regex[j--] = '\0';
  964. }
  965. /* convert path (assumed in cwd) to one on disk */
  966. if (strcmp(disk_path, "/") == 0) {
  967. if (*regex == '/') {
  968. if (strcmp(regex, "/[/]*$") == 0) {
  969. /* We want "/" to match the directory itself: "/." */
  970. path_on_disk = stralloc("/\\.[/]*$");
  971. } else {
  972. /* No mods needed if already starts with '/' */
  973. path_on_disk = stralloc(regex);
  974. }
  975. } else {
  976. /* Prepend '/' */
  977. path_on_disk = stralloc2("/", regex);
  978. }
  979. } else {
  980. char *clean_disk_path = clean_regex(disk_path);
  981. path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
  982. amfree(clean_disk_path);
  983. }
  984. dbprintf(_("delete_file: Converted path=\"%s\" to path_on_disk=\"%s\"\n"),
  985. regex, path_on_disk);
  986. found_one = 0;
  987. for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
  988. {
  989. quoted = quote_string(ditem->path);
  990. dbprintf(_("delete_file: Pondering ditem->path=%s\n"), quoted);
  991. amfree(quoted);
  992. if (match(path_on_disk, ditem->path))
  993. {
  994. found_one = 1;
  995. j = (ssize_t)strlen(ditem->path);
  996. if((j > 0 && ditem->path[j-1] == '/')
  997. || (j > 1 && ditem->path[j-2] == '/' && ditem->path[j-1] == '.'))
  998. { /* It is a directory */
  999. ditem_path = newstralloc(ditem_path, ditem->path);
  1000. clean_pathname(ditem_path);
  1001. qditem_path = quote_string(ditem_path);
  1002. cmd = newstralloc2(cmd, "ORLD ", qditem_path);
  1003. amfree(qditem_path);
  1004. if(send_command(cmd) == -1) {
  1005. amfree(cmd);
  1006. amfree(ditem_path);
  1007. amfree(path_on_disk);
  1008. exit(1);
  1009. }
  1010. amfree(cmd);
  1011. /* skip preamble */
  1012. if ((i = get_reply_line()) == -1) {
  1013. amfree(ditem_path);
  1014. amfree(path_on_disk);
  1015. exit(1);
  1016. }
  1017. if(i==0) /* assume something wrong */
  1018. {
  1019. amfree(ditem_path);
  1020. amfree(path_on_disk);
  1021. l = reply_line();
  1022. g_printf("%s\n", l);
  1023. return;
  1024. }
  1025. deleted=0;
  1026. lditem.path = newstralloc(lditem.path, ditem->path);
  1027. amfree(cmd);
  1028. tape_undo = dir_undo = NULL;
  1029. /* skip the last line -- duplicate of the preamble */
  1030. while ((i = get_reply_line()) != 0)
  1031. {
  1032. if (i == -1) {
  1033. amfree(ditem_path);
  1034. amfree(path_on_disk);
  1035. exit(1);
  1036. }
  1037. if(err) {
  1038. if(cmd == NULL) {
  1039. if(tape_undo) *tape_undo = tape_undo_ch;
  1040. if(dir_undo) *dir_undo = dir_undo_ch;
  1041. tape_undo = dir_undo = NULL;
  1042. cmd = stralloc(l); /* save for the error report */
  1043. }
  1044. continue; /* throw the rest of the lines away */
  1045. }
  1046. l=reply_line();
  1047. if (!server_happy()) {
  1048. puts(l);
  1049. continue;
  1050. }
  1051. s = l;
  1052. if(strncmp_const_skip(l, "201-", s, ch) != 0) {
  1053. err = _("bad reply: not 201-");
  1054. continue;
  1055. }
  1056. ch = *s++;
  1057. skip_whitespace(s, ch);
  1058. if(ch == '\0') {
  1059. err = _("bad reply: missing date field");
  1060. continue;
  1061. }
  1062. date = s - 1;
  1063. skip_non_whitespace(s, ch);
  1064. *(s - 1) = '\0';
  1065. skip_whitespace(s, ch);
  1066. if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
  1067. err = _("bad reply: cannot parse level field");
  1068. continue;
  1069. }
  1070. skip_integer(s, ch);
  1071. skip_whitespace(s, ch);
  1072. if(ch == '\0') {
  1073. err = _("bad reply: missing tape field");
  1074. continue;
  1075. }
  1076. tape = s - 1;
  1077. skip_non_whitespace(s, ch);
  1078. tape_undo = s - 1;
  1079. tape_undo_ch = *tape_undo;
  1080. *tape_undo = '\0';
  1081. if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
  1082. long long fileno_ = (long long)0;
  1083. skip_whitespace(s, ch);
  1084. if(ch == '\0' ||
  1085. sscanf(s - 1, "%lld", &fileno_) != 1) {
  1086. err = _("bad reply: cannot parse fileno field");
  1087. continue;
  1088. }
  1089. fileno = (off_t)fileno_;
  1090. skip_integer(s, ch);
  1091. }
  1092. skip_whitespace(s, ch);
  1093. if(ch == '\0') {
  1094. err = _("bad reply: missing directory field");
  1095. continue;
  1096. }
  1097. skip_non_whitespace(s, ch);
  1098. dir_undo = s - 1;
  1099. dir_undo_ch = *dir_undo;
  1100. *dir_undo = '\0';
  1101. lditem.date = newstralloc(lditem.date, date);
  1102. lditem.level=level;
  1103. lditem.tape = newstralloc(lditem.tape, tape);
  1104. switch(delete_extract_item(&lditem)) {
  1105. case -1:
  1106. g_printf(_("System error\n"));
  1107. dbprintf(_("delete_file: (Failed) System error\n"));
  1108. break;
  1109. case 0:
  1110. g_printf(_("Deleted dir %s at date %s\n"), ditem_path, date);
  1111. dbprintf(_("delete_file: (Successful) Deleted dir %s at date %s\n"),
  1112. ditem_path, date);
  1113. deleted=1;
  1114. break;
  1115. case 1:
  1116. break;
  1117. }
  1118. }
  1119. if(!server_happy()) {
  1120. puts(reply_line());
  1121. } else if(err) {
  1122. if (*err)
  1123. puts(err);
  1124. if (cmd)
  1125. puts(cmd);
  1126. } else if(deleted == 0) {
  1127. g_printf(_("Warning - dir '%s' not on tape list\n"),
  1128. ditem_path);
  1129. dbprintf(_("delete_file: dir '%s' not on tape list\n"),
  1130. ditem_path);
  1131. }
  1132. }
  1133. else
  1134. {
  1135. switch(delete_extract_item(ditem)) {
  1136. case -1:
  1137. g_printf(_("System error\n"));
  1138. dbprintf(_("delete_file: (Failed) System error\n"));
  1139. break;
  1140. case 0:
  1141. g_printf(_("Deleted %s\n"), ditem->path);
  1142. dbprintf(_("delete_file: (Successful) Deleted %s\n"),
  1143. ditem->path);
  1144. break;
  1145. case 1:
  1146. g_printf(_("Warning - file '%s' not on tape list\n"),
  1147. ditem->path);
  1148. dbprintf(_("delete_file: file '%s' not on tape list\n"),
  1149. ditem->path);
  1150. break;
  1151. }
  1152. }
  1153. }
  1154. }
  1155. amfree(cmd);
  1156. amfree(ditem_path);
  1157. amfree(path_on_disk);
  1158. if(! found_one) {
  1159. g_printf(_("File %s doesn't exist in directory\n"), path);
  1160. dbprintf(_("delete_file: (Failed) File %s doesn't exist in directory\n"),
  1161. path);
  1162. }
  1163. }
  1164. /* print extract list into file. If NULL ptr passed print to screen */
  1165. void
  1166. display_extract_list(
  1167. char * file)
  1168. {
  1169. EXTRACT_LIST *this;
  1170. EXTRACT_LIST_ITEM *that;
  1171. FILE *fp;
  1172. char *pager;
  1173. char *pager_command;
  1174. char *uqfile;
  1175. if (file == NULL)
  1176. {
  1177. if ((pager = getenv("PAGER")) == NULL)
  1178. {
  1179. pager = "more";
  1180. }
  1181. /*
  1182. * Set up the pager command so if the pager is terminated, we do
  1183. * not get a SIGPIPE back.
  1184. */
  1185. pager_command = stralloc2(pager, " ; /bin/cat > /dev/null");
  1186. if ((fp = popen(pager_command, "w")) == NULL)
  1187. {
  1188. g_printf(_("Warning - can't pipe through %s\n"), pager);
  1189. fp = stdout;
  1190. }
  1191. amfree(pager_command);
  1192. }
  1193. else
  1194. {
  1195. uqfile = unquote_string(file);
  1196. if ((fp = fopen(uqfile, "w")) == NULL)
  1197. {
  1198. g_printf(_("Can't open file %s to print extract list into\n"), file);
  1199. amfree(uqfile);
  1200. return;
  1201. }
  1202. amfree(uqfile);
  1203. }
  1204. for (this = extract_list; this != NULL; this = this->next)
  1205. {
  1206. g_fprintf(fp, _("TAPE %s LEVEL %d DATE %s\n"),
  1207. this->tape, this->level, this->date);
  1208. for (that = this->files; that != NULL; that = that->next)
  1209. g_fprintf(fp, "\t%s\n", that->path);
  1210. }
  1211. if (file == NULL) {
  1212. apclose(fp);
  1213. } else {
  1214. g_printf(_("Extract list written to file %s\n"), file);
  1215. afclose(fp);
  1216. }
  1217. }
  1218. static int
  1219. is_empty_dir(
  1220. char *fname)
  1221. {
  1222. DIR *dir;
  1223. struct dirent *entry;
  1224. int gotentry;
  1225. if((dir = opendir(fname)) == NULL)
  1226. return 1;
  1227. gotentry = 0;
  1228. while(!gotentry && (entry = readdir(dir)) != NULL) {
  1229. gotentry = !is_dot_or_dotdot(entry->d_name);
  1230. }
  1231. closedir(dir);
  1232. return !gotentry;
  1233. }
  1234. /* returns 0 if extract list empty and 1 if it isn't */
  1235. int
  1236. is_extract_list_nonempty(void)
  1237. {
  1238. return (extract_list != NULL);
  1239. }
  1240. /* prints continue prompt and waits for response,
  1241. returns 0 if don't, non-0 if do */
  1242. static int
  1243. okay_to_continue(
  1244. int allow_tape,
  1245. int allow_skip,
  1246. int allow_retry)
  1247. {
  1248. int ch;
  1249. int ret = -1;
  1250. char *line = NULL;
  1251. char *s;
  1252. char *prompt;
  1253. int get_device;
  1254. get_device = 0;
  1255. while (ret < 0) {
  1256. if (get_device) {
  1257. prompt = _("New device name [?]: ");
  1258. } else if (allow_tape && allow_skip) {
  1259. prompt = _("Continue [?/Y/n/s/d]? ");
  1260. } else if (allow_tape && !allow_skip) {
  1261. prompt = _("Continue [?/Y/n/d]? ");
  1262. } else if (allow_retry) {
  1263. prompt = _("Continue [?/Y/n/r]? ");
  1264. } else {
  1265. prompt = _("Continue [?/Y/n]? ");
  1266. }
  1267. fputs(prompt, stdout);
  1268. fflush(stdout); fflush(stderr);
  1269. amfree(line);
  1270. if ((line = agets(stdin)) == NULL) {
  1271. putchar('\n');
  1272. clearerr(stdin);
  1273. if (get_device) {
  1274. get_device = 0;
  1275. continue;
  1276. }
  1277. ret = 0;
  1278. break;
  1279. }
  1280. dbprintf("User prompt: '%s'; response: '%s'\n", prompt, line);
  1281. s = line;
  1282. while ((ch = *s++) != '\0' && isspace(ch)) {
  1283. (void)ch; /* Quiet empty loop compiler warning */
  1284. }
  1285. if (ch == '?') {
  1286. if (get_device) {
  1287. g_printf(_("Enter a new device name or \"default\"\n"));
  1288. } else {
  1289. g_printf(_("Enter \"y\"es to continue, \"n\"o to stop"));
  1290. if(allow_skip) {
  1291. g_printf(_(", \"s\"kip this tape"));
  1292. }
  1293. if(allow_retry) {
  1294. g_printf(_(" or \"r\"etry this tape"));
  1295. }
  1296. if (allow_tape) {
  1297. g_printf(_(" or \"d\" to change to a new device"));
  1298. }
  1299. putchar('\n');
  1300. }
  1301. } else if (get_device) {
  1302. char *tmp = stralloc(tape_server_name);
  1303. if (strncmp_const(s - 1, "default") == 0) {
  1304. set_device(tmp, NULL); /* default device, existing host */
  1305. } else if (s[-1] != '\0') {
  1306. set_device(tmp, s - 1); /* specified device, existing host */
  1307. } else {
  1308. g_printf(_("No change.\n"));
  1309. }
  1310. amfree(tmp);
  1311. get_device = 0;
  1312. } else if (ch == '\0' || ch == 'Y' || ch == 'y') {
  1313. ret = 1;
  1314. } else if (allow_tape && (ch == 'D' || ch == 'd' || ch == 'T' || ch == 't')) {
  1315. get_device = 1; /* ('T' and 't' are for backward-compatibility) */
  1316. } else if (ch == 'N' || ch == 'n') {
  1317. ret = 0;
  1318. } else if (allow_retry && (ch == 'R' || ch == 'r')) {
  1319. ret = RETRY_TAPE;
  1320. } else if (allow_skip && (ch == 'S' || ch == 's')) {
  1321. ret = SKIP_TAPE;
  1322. }
  1323. }
  1324. /*@ignore@*/
  1325. amfree(line);
  1326. /*@end@*/
  1327. return ret;
  1328. }
  1329. static void
  1330. send_to_tape_server(
  1331. security_stream_t * stream,
  1332. char * cmd)
  1333. {
  1334. char *msg = stralloc2(cmd, "\r\n");
  1335. if (security_stream_write(stream, msg, strlen(msg)) < 0)
  1336. {
  1337. error(_("Error writing to tape server"));
  1338. exit(101);
  1339. /*NOTREACHED*/
  1340. }
  1341. amfree(msg);
  1342. }
  1343. /* start up connection to tape server and set commands to initiate
  1344. transfer of dump image.
  1345. Return tape server socket on success, -1 on error. */
  1346. static int
  1347. extract_files_setup(
  1348. char * label,
  1349. off_t fsf)
  1350. {
  1351. char *disk_regex = NULL;
  1352. char *host_regex = NULL;
  1353. char *clean_datestamp, *ch, *ch1;
  1354. char *tt = NULL;
  1355. char *req;
  1356. int response_error;
  1357. amidxtaped_secdrv = security_getdriver(authopt);
  1358. if (amidxtaped_secdrv == NULL) {
  1359. error(_("no '%s' security driver available for host '%s'"),
  1360. authopt, tape_server_name);
  1361. }
  1362. /* We assume that amidxtaped support fe_amidxtaped_options_features */
  1363. /* and fe_amidxtaped_options_auth */
  1364. /* We should send a noop to really know */
  1365. req = vstralloc("SERVICE amidxtaped\n",
  1366. "OPTIONS ", "features=", our_features_string, ";",
  1367. "auth=", authopt, ";",
  1368. "\n", NULL);
  1369. protocol_sendreq(tape_server_name, amidxtaped_secdrv,
  1370. generic_client_get_security_conf, req, STARTUP_TIMEOUT,
  1371. amidxtaped_response, &response_error);
  1372. amfree(req);
  1373. protocol_run();
  1374. if(response_error != 0) {
  1375. return -1;
  1376. }
  1377. disk_regex = alloc(strlen(disk_name) * 2 + 3);
  1378. ch = disk_name;
  1379. ch1 = disk_regex;
  1380. /* we want to force amrestore to only match disk_name exactly */
  1381. *(ch1++) = '^';
  1382. /* We need to escape some characters first... NT compatibilty crap */
  1383. for (; *ch != 0; ch++, ch1++) {
  1384. switch (*ch) { /* done this way in case there are more */
  1385. case '$':
  1386. *(ch1++) = '\\';
  1387. /* no break; we do want to fall through... */
  1388. default:
  1389. *ch1 = *ch;
  1390. }
  1391. }
  1392. /* we want to force amrestore to only match disk_name exactly */
  1393. *(ch1++) = '$';
  1394. *ch1 = '\0';
  1395. host_regex = alloc(strlen(dump_hostname) * 2 + 3);
  1396. ch = dump_hostname;
  1397. ch1 = host_regex;
  1398. /* we want to force amrestore to only match dump_hostname exactly */
  1399. *(ch1++) = '^';
  1400. /* We need to escape some characters first... NT compatibilty crap */
  1401. for (; *ch != 0; ch++, ch1++) {
  1402. switch (*ch) { /* done this way in case there are more */
  1403. case '$':
  1404. *(ch1++) = '\\';
  1405. /* no break; we do want to fall through... */
  1406. default:
  1407. *ch1 = *ch;
  1408. }
  1409. }
  1410. /* we want to force amrestore to only match dump_hostname exactly */
  1411. *(ch1++) = '$';
  1412. *ch1 = '\0';
  1413. clean_datestamp = stralloc(dump_datestamp);
  1414. for(ch=ch1=clean_datestamp;*ch1 != '\0';ch1++) {
  1415. if(*ch1 != '-') {
  1416. *ch = *ch1;
  1417. ch++;
  1418. }
  1419. }
  1420. *ch = '\0';
  1421. /* push our feature list off to the tape server */
  1422. /* XXX assumes that index server and tape server are equivalent, ew */
  1423. if(am_has_feature(indexsrv_features, fe_amidxtaped_exchange_features)){
  1424. tt = newstralloc2(tt, "FEATURES=", our_features_string);
  1425. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1426. get_amidxtaped_line();
  1427. if(strncmp_const(amidxtaped_line,"FEATURES=") == 0) {
  1428. tapesrv_features = am_string_to_feature(amidxtaped_line+9);
  1429. } else {
  1430. g_fprintf(stderr, _("amrecover - expecting FEATURES line from amidxtaped\n"));
  1431. stop_amidxtaped();
  1432. amfree(disk_regex);
  1433. amfree(host_regex);
  1434. amfree(clean_datestamp);
  1435. return -1;
  1436. }
  1437. am_release_feature_set(tapesrv_features);
  1438. }
  1439. if(am_has_feature(indexsrv_features, fe_amidxtaped_header) &&
  1440. am_has_feature(indexsrv_features, fe_amidxtaped_device) &&
  1441. am_has_feature(indexsrv_features, fe_amidxtaped_host) &&
  1442. am_has_feature(indexsrv_features, fe_amidxtaped_disk) &&
  1443. am_has_feature(indexsrv_features, fe_amidxtaped_datestamp)) {
  1444. if(am_has_feature(indexsrv_features, fe_amidxtaped_config)) {
  1445. tt = newstralloc2(tt, "CONFIG=", config_name);
  1446. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1447. }
  1448. if(am_has_feature(indexsrv_features, fe_amidxtaped_label) &&
  1449. label && label[0] != '/') {
  1450. tt = newstralloc2(tt,"LABEL=",label);
  1451. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1452. }
  1453. if(am_has_feature(indexsrv_features, fe_amidxtaped_fsf)) {
  1454. char v_fsf[100];
  1455. g_snprintf(v_fsf, 99, "%lld", (long long)fsf);
  1456. tt = newstralloc2(tt, "FSF=",v_fsf);
  1457. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1458. }
  1459. send_to_tape_server(amidxtaped_streams[CTLFD].fd, "HEADER");
  1460. tt = newstralloc2(tt, "DEVICE=", dump_device_name);
  1461. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1462. tt = newstralloc2(tt, "HOST=", host_regex);
  1463. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1464. tt = newstralloc2(tt, "DISK=", disk_regex);
  1465. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1466. tt = newstralloc2(tt, "DATESTAMP=", clean_datestamp);
  1467. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1468. send_to_tape_server(amidxtaped_streams[CTLFD].fd, "END");
  1469. amfree(tt);
  1470. }
  1471. else if(am_has_feature(indexsrv_features, fe_amidxtaped_nargs)) {
  1472. /* send to the tape server what tape file we want */
  1473. /* 6 args:
  1474. * "-h"
  1475. * "-p"
  1476. * "tape device"
  1477. * "hostname"
  1478. * "diskname"
  1479. * "datestamp"
  1480. */
  1481. send_to_tape_server(amidxtaped_streams[CTLFD].fd, "6");
  1482. send_to_tape_server(amidxtaped_streams[CTLFD].fd, "-h");
  1483. send_to_tape_server(amidxtaped_streams[CTLFD].fd, "-p");
  1484. send_to_tape_server(amidxtaped_streams[CTLFD].fd, dump_device_name);
  1485. send_to_tape_server(amidxtaped_streams[CTLFD].fd, host_regex);
  1486. send_to_tape_server(amidxtaped_streams[CTLFD].fd, disk_regex);
  1487. send_to_tape_server(amidxtaped_streams[CTLFD].fd, clean_datestamp);
  1488. dbprintf(_("Started amidxtaped with arguments \"6 -h -p %s %s %s %s\"\n"),
  1489. dump_device_name, host_regex, disk_regex, clean_datestamp);
  1490. }
  1491. amfree(disk_regex);
  1492. amfree(host_regex);
  1493. amfree(clean_datestamp);
  1494. return 0;
  1495. }
  1496. /*
  1497. * Reads the first block of a tape file.
  1498. */
  1499. void
  1500. read_file_header(
  1501. char * buffer,
  1502. dumpfile_t *file,
  1503. size_t buflen,
  1504. int tapedev)
  1505. {
  1506. ssize_t bytes_read;
  1507. bytes_read = read_buffer(tapedev, buffer, buflen, READ_TIMEOUT);
  1508. if(bytes_read < 0) {
  1509. error(_("error reading header (%s), check amidxtaped.*.debug on server"),
  1510. strerror(errno));
  1511. /*NOTREACHED*/
  1512. }
  1513. if((size_t)bytes_read < buflen) {
  1514. g_fprintf(stderr, plural(_("%s: short block %d byte\n"),
  1515. _("%s: short block %d bytes\n"), bytes_read),
  1516. get_pname(), (int)bytes_read);
  1517. print_header(stdout, file);
  1518. error(_("Can't read file header"));
  1519. /*NOTREACHED*/
  1520. }
  1521. /* bytes_read == buflen */
  1522. parse_file_header(buffer, file, (size_t)bytes_read);
  1523. }
  1524. enum dumptypes {
  1525. IS_UNKNOWN,
  1526. IS_DUMP,
  1527. IS_GNUTAR,
  1528. IS_TAR,
  1529. IS_SAMBA,
  1530. IS_SAMBA_TAR,
  1531. IS_BACKUP_API
  1532. };
  1533. static void
  1534. extract_files_child(
  1535. int in_fd,
  1536. EXTRACT_LIST * elist)
  1537. {
  1538. int save_errno;
  1539. int extra_params = 0;
  1540. int i,j=0;
  1541. char **restore_args = NULL;
  1542. int files_off_tape;
  1543. EXTRACT_LIST_ITEM *fn;
  1544. enum dumptypes dumptype = IS_UNKNOWN;
  1545. char buffer[DISK_BLOCK_BYTES];
  1546. dumpfile_t file;
  1547. size_t len_program;
  1548. char *cmd = NULL;
  1549. int passwd_field = -1;
  1550. #ifdef SAMBA_CLIENT
  1551. char *domain = NULL, *smbpass = NULL;
  1552. #endif
  1553. /* code executed by child to do extraction */
  1554. /* never returns */
  1555. /* make in_fd be our stdin */
  1556. if (dup2(in_fd, STDIN_FILENO) == -1)
  1557. {
  1558. error(_("dup2 failed in extract_files_child: %s"), strerror(errno));
  1559. /*NOTREACHED*/
  1560. }
  1561. /* read the file header */
  1562. fh_init(&file);
  1563. read_file_header(buffer, &file, sizeof(buffer), STDIN_FILENO);
  1564. if(file.type != F_DUMPFILE) {
  1565. print_header(stdout, &file);
  1566. error(_("bad header"));
  1567. /*NOTREACHED*/
  1568. }
  1569. if (file.program != NULL) {
  1570. if (strcmp(file.program, "BACKUP") == 0)
  1571. dumptype = IS_BACKUP_API;
  1572. #ifdef GNUTAR
  1573. if (strcmp(file.program, GNUTAR) == 0)
  1574. dumptype = IS_GNUTAR;
  1575. #endif
  1576. if (dumptype == IS_UNKNOWN) {
  1577. len_program = strlen(file.program);
  1578. if(len_program >= 3 &&
  1579. strcmp(&file.program[len_program-3],"tar") == 0)
  1580. dumptype = IS_TAR;
  1581. }
  1582. #ifdef SAMBA_CLIENT
  1583. if (dumptype == IS_UNKNOWN && strcmp(file.program, SAMBA_CLIENT) ==0) {
  1584. if (samba_extract_method == SAMBA_TAR)
  1585. dumptype = IS_SAMBA_TAR;
  1586. else
  1587. dumptype = IS_SAMBA;
  1588. }
  1589. #endif
  1590. }
  1591. /* form the arguments to restore */
  1592. files_off_tape = length_of_tape_list(elist);
  1593. switch (dumptype) {
  1594. case IS_SAMBA:
  1595. #ifdef SAMBA_CLIENT
  1596. extra_params = 10;
  1597. break;
  1598. #endif
  1599. case IS_TAR:
  1600. case IS_GNUTAR:
  1601. extra_params = 4;
  1602. break;
  1603. case IS_SAMBA_TAR:
  1604. extra_params = 3;
  1605. break;
  1606. case IS_UNKNOWN:
  1607. case IS_DUMP:
  1608. #ifdef AIX_BACKUP
  1609. extra_params = 2;
  1610. #else
  1611. #if defined(XFSDUMP)
  1612. if (strcmp(file.program, XFSDUMP) == 0) {
  1613. extra_params = 4 + files_off_tape;
  1614. } else
  1615. #endif
  1616. {
  1617. extra_params = 4;
  1618. }
  1619. #endif
  1620. break;
  1621. case IS_BACKUP_API:
  1622. extra_params = 5;
  1623. break;
  1624. }
  1625. restore_args = (char **)alloc((size_t)((extra_params + files_off_tape + 1)
  1626. * sizeof(char *)));
  1627. switch(dumptype) {
  1628. case IS_SAMBA:
  1629. #ifdef SAMBA_CLIENT
  1630. restore_args[j++] = stralloc("smbclient");
  1631. smbpass = findpass(file.disk, &domain);
  1632. if (smbpass) {
  1633. restore_args[j++] = stralloc(file.disk);
  1634. passwd_field=j;
  1635. restore_args[j++] = stralloc("-U");
  1636. restore_args[j++] = smbpass;
  1637. if (domain) {
  1638. restore_args[j++] = stralloc("-W");
  1639. restore_args[j++] = stralloc(domain);
  1640. } else
  1641. extra_params -= 2;
  1642. } else
  1643. extra_params -= 6;
  1644. restore_args[j++] = stralloc("-d0");
  1645. restore_args[j++] = stralloc("-Tx");
  1646. restore_args[j++] = stralloc("-"); /* data on stdin */
  1647. break;
  1648. #endif
  1649. case IS_TAR:
  1650. case IS_GNUTAR:
  1651. restore_args[j++] = stralloc("tar");
  1652. restore_args[j++] = stralloc("--numeric-owner");
  1653. restore_args[j++] = stralloc("-xpGvf");
  1654. restore_args[j++] = stralloc("-"); /* data on stdin */
  1655. break;
  1656. case IS_SAMBA_TAR:
  1657. restore_args[j++] = stralloc("tar");
  1658. restore_args[j++] = stralloc("-xpvf");
  1659. restore_args[j++] = stralloc("-"); /* data on stdin */
  1660. break;
  1661. case IS_UNKNOWN:
  1662. case IS_DUMP:
  1663. restore_args[j++] = stralloc("restore");
  1664. #ifdef AIX_BACKUP
  1665. restore_args[j++] = stralloc("-xB");
  1666. #else
  1667. #if defined(XFSDUMP)
  1668. if (strcmp(file.program, XFSDUMP) == 0) {
  1669. restore_args[j++] = stralloc("-v");
  1670. restore_args[j++] = stralloc("silent");
  1671. } else
  1672. #endif
  1673. #if defined(VDUMP)
  1674. if (strcmp(file.program, VDUMP) == 0) {
  1675. restore_args[j++] = stralloc("xf");
  1676. restore_args[j++] = stralloc("-"); /* data on stdin */
  1677. } else
  1678. #endif
  1679. {
  1680. restore_args[j++] = stralloc("xbf");
  1681. restore_args[j++] = stralloc("2"); /* read in units of 1K */
  1682. restore_args[j++] = stralloc("-"); /* data on stdin */
  1683. }
  1684. #endif
  1685. break;
  1686. case IS_BACKUP_API:
  1687. restore_args[j++] = stralloc(file.dumper);
  1688. restore_args[j++] = stralloc("restore");
  1689. restore_args[j++] = stralloc("--config");
  1690. restore_args[j++] = stralloc(config_name);
  1691. restore_args[j++] = stralloc("--disk");
  1692. restore_args[j++] = stralloc(file.disk);
  1693. break;
  1694. }
  1695. for (i = 0, fn = elist->files; i < files_off_tape; i++, fn = fn->next)
  1696. {
  1697. switch (dumptype) {
  1698. case IS_BACKUP_API:
  1699. case IS_TAR:
  1700. case IS_GNUTAR:
  1701. case IS_SAMBA_TAR:
  1702. case IS_SAMBA:
  1703. if (strcmp(fn->path, "/") == 0)
  1704. restore_args[j++] = stralloc(".");
  1705. else
  1706. restore_args[j++] = stralloc2(".", fn->path);
  1707. break;
  1708. case IS_UNKNOWN:
  1709. case IS_DUMP:
  1710. #if defined(XFSDUMP)
  1711. if (strcmp(file.program, XFSDUMP) == 0) {
  1712. /*
  1713. * xfsrestore needs a -s option before each file to be
  1714. * restored, and also wants them to be relative paths.
  1715. */
  1716. restore_args[j++] = stralloc("-s");
  1717. restore_args[j++] = stralloc(fn->path + 1);
  1718. } else
  1719. #endif
  1720. {
  1721. restore_args[j++] = stralloc(fn->path);
  1722. }
  1723. break;
  1724. }
  1725. }
  1726. #if defined(XFSDUMP)
  1727. if (strcmp(file.program, XFSDUMP) == 0) {
  1728. restore_args[j++] = stralloc("-");
  1729. restore_args[j++] = stralloc(".");
  1730. }
  1731. #endif
  1732. restore_args[j] = NULL;
  1733. switch (dumptype) {
  1734. case IS_SAMBA:
  1735. #ifdef SAMBA_CLIENT
  1736. cmd = stralloc(SAMBA_CLIENT);
  1737. break;
  1738. #else
  1739. /* fall through to ... */
  1740. #endif
  1741. case IS_TAR:
  1742. case IS_GNUTAR:
  1743. case IS_SAMBA_TAR:
  1744. #ifndef GNUTAR
  1745. g_fprintf(stderr, _("warning: GNUTAR program not available.\n"));
  1746. cmd = stralloc("tar");
  1747. #else
  1748. cmd = stralloc(GNUTAR);
  1749. #endif
  1750. break;
  1751. case IS_UNKNOWN:
  1752. case IS_DUMP:
  1753. cmd = NULL;
  1754. #if defined(DUMP)
  1755. if (strcmp(file.program, DUMP) == 0) {
  1756. cmd = stralloc(RESTORE);
  1757. }
  1758. #endif
  1759. #if defined(VDUMP)
  1760. if (strcmp(file.program, VDUMP) == 0) {
  1761. cmd = stralloc(VRESTORE);
  1762. }
  1763. #endif
  1764. #if defined(VXDUMP)
  1765. if (strcmp(file.program, VXDUMP) == 0) {
  1766. cmd = stralloc(VXRESTORE);
  1767. }
  1768. #endif
  1769. #if defined(XFSDUMP)
  1770. if (strcmp(file.program, XFSDUMP) == 0) {
  1771. cmd = stralloc(XFSRESTORE);
  1772. }
  1773. #endif
  1774. if (cmd == NULL) {
  1775. g_fprintf(stderr, _("warning: restore program for %s not available.\n"),
  1776. file.program);
  1777. cmd = stralloc("restore");
  1778. }
  1779. break;
  1780. case IS_BACKUP_API:
  1781. cmd = vstralloc(DUMPER_DIR, "/", file.dumper, NULL);
  1782. break;
  1783. }
  1784. if (cmd) {
  1785. dbprintf(_("Exec'ing %s with arguments:\n"), cmd);
  1786. for (i = 0; i < j; i+

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