PageRenderTime 64ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

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

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

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