PageRenderTime 69ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/amanda/trunk/recover-src/extract_list.c

#
C | 2474 lines | 2066 code | 218 blank | 190 comment | 533 complexity | 09383b7bcbdc34a85f163a93370ab804 MD5 | raw 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$
  28. *
  29. * implements the "extract" command in amrecover
  30. */
  31. #include "amanda.h"
  32. #include "match.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. #include "pipespawn.h"
  48. typedef struct EXTRACT_LIST_ITEM {
  49. char *path;
  50. char *tpath;
  51. struct EXTRACT_LIST_ITEM *next;
  52. }
  53. EXTRACT_LIST_ITEM;
  54. typedef struct EXTRACT_LIST {
  55. char *date; /* date tape created */
  56. int level; /* level of dump */
  57. char *tape; /* tape label */
  58. off_t fileno; /* fileno on tape */
  59. EXTRACT_LIST_ITEM *files; /* files to get off tape */
  60. struct EXTRACT_LIST *next;
  61. }
  62. EXTRACT_LIST;
  63. typedef struct ctl_data_s {
  64. int header_done;
  65. int child_pipe[2];
  66. int pid;
  67. EXTRACT_LIST *elist;
  68. dumpfile_t file;
  69. data_path_t data_path;
  70. char *addrs;
  71. backup_support_option_t *bsu;
  72. gint64 bytes_read;
  73. } ctl_data_t;
  74. #define SKIP_TAPE 2
  75. #define RETRY_TAPE 3
  76. static struct {
  77. const char *name;
  78. security_stream_t *fd;
  79. } amidxtaped_streams[] = {
  80. #define CTLFD 0
  81. { "CTL", NULL },
  82. #define DATAFD 1
  83. { "DATA", NULL },
  84. };
  85. #define NSTREAMS G_N_ELEMENTS(amidxtaped_streams)
  86. static void amidxtaped_response(void *, pkt_t *, security_handle_t *);
  87. static void stop_amidxtaped(void);
  88. static char *dump_device_name = NULL;
  89. static char *errstr;
  90. static char *amidxtaped_line = NULL;
  91. extern char *localhost;
  92. static char header_buf[32768];
  93. static int header_size = 0;
  94. /* global pid storage for interrupt handler */
  95. pid_t extract_restore_child_pid = -1;
  96. static EXTRACT_LIST *extract_list = NULL;
  97. static const security_driver_t *amidxtaped_secdrv;
  98. unsigned short samba_extract_method = SAMBA_TAR;
  99. #define READ_TIMEOUT 240*60
  100. EXTRACT_LIST *first_tape_list(void);
  101. EXTRACT_LIST *next_tape_list(EXTRACT_LIST *list);
  102. static int is_empty_dir(char *fname);
  103. int is_extract_list_nonempty(void);
  104. int length_of_tape_list(EXTRACT_LIST *tape_list);
  105. void add_file(char *path, char *regex);
  106. void add_glob(char *glob);
  107. void add_regex(char *regex);
  108. void clear_extract_list(void);
  109. void clean_tape_list(EXTRACT_LIST *tape_list);
  110. void clean_extract_list(void);
  111. void check_file_overwrite(char *filename);
  112. void delete_file(char *path, char *regex);
  113. void delete_glob(char *glob);
  114. void delete_regex(char *regex);
  115. void delete_tape_list(EXTRACT_LIST *tape_list);
  116. void display_extract_list(char *file);
  117. void extract_files(void);
  118. void read_file_header(char *buffer,
  119. dumpfile_t *file,
  120. size_t buflen,
  121. int tapedev);
  122. static int add_extract_item(DIR_ITEM *ditem);
  123. static int delete_extract_item(DIR_ITEM *ditem);
  124. static int extract_files_setup(char *label, off_t fsf);
  125. static int okay_to_continue(int allow_tape,
  126. int allow_skip,
  127. int allow_retry);
  128. static ssize_t read_buffer(int datafd,
  129. char *buffer,
  130. size_t buflen,
  131. long timeout_s);
  132. static void clear_tape_list(EXTRACT_LIST *tape_list);
  133. static void extract_files_child(ctl_data_t *ctl_data);
  134. static void send_to_tape_server(security_stream_t *stream, char *cmd);
  135. int writer_intermediary(EXTRACT_LIST *elist);
  136. int get_amidxtaped_line(void);
  137. static void read_amidxtaped_data(void *, void *, ssize_t);
  138. static char *merge_path(char *path1, char *path2);
  139. static gboolean ask_file_overwrite(ctl_data_t *ctl_data);
  140. static void start_processing_data(ctl_data_t *ctl_data);
  141. /*
  142. * Function: ssize_t read_buffer(datafd, buffer, buflen, timeout_s)
  143. *
  144. * Description:
  145. * read data from input file desciptor waiting up to timeout_s
  146. * seconds before returning data.
  147. *
  148. * Inputs:
  149. * datafd - File descriptor to read from.
  150. * buffer - Buffer to read into.
  151. * buflen - Maximum number of bytes to read into buffer.
  152. * timeout_s - Seconds to wait before returning what was already read.
  153. *
  154. * Returns:
  155. * >0 - Number of data bytes in buffer.
  156. * 0 - EOF
  157. * -1 - errno == ETIMEDOUT if no data available in specified time.
  158. * errno == ENFILE if datafd is invalid.
  159. * otherwise errno is set by select or read..
  160. */
  161. static ssize_t
  162. read_buffer(
  163. int datafd,
  164. char * buffer,
  165. size_t buflen,
  166. long timeout_s)
  167. {
  168. ssize_t size = 0;
  169. SELECT_ARG_TYPE readset;
  170. struct timeval timeout;
  171. char *dataptr;
  172. ssize_t spaceleft;
  173. int nfound;
  174. if(datafd < 0 || datafd >= (int)FD_SETSIZE) {
  175. errno = EMFILE; /* out of range */
  176. return -1;
  177. }
  178. dataptr = buffer;
  179. spaceleft = (ssize_t)buflen;
  180. do {
  181. FD_ZERO(&readset);
  182. FD_SET(datafd, &readset);
  183. timeout.tv_sec = timeout_s;
  184. timeout.tv_usec = 0;
  185. nfound = select(datafd+1, &readset, NULL, NULL, &timeout);
  186. if(nfound < 0 ) {
  187. /* Select returned an error. */
  188. g_fprintf(stderr,_("select error: %s\n"), strerror(errno));
  189. size = -1;
  190. break;
  191. }
  192. if (nfound == 0) {
  193. /* Select timed out. */
  194. if (timeout_s != 0) {
  195. /* Not polling: a real read timeout */
  196. g_fprintf(stderr,_("timeout waiting for restore\n"));
  197. g_fprintf(stderr,_("increase READ_TIMEOUT in recover-src/extract_list.c if your tape is slow\n"));
  198. }
  199. errno = ETIMEDOUT;
  200. size = -1;
  201. break;
  202. }
  203. if(!FD_ISSET(datafd, &readset))
  204. continue;
  205. /* Select says data is available, so read it. */
  206. size = read(datafd, dataptr, (size_t)spaceleft);
  207. if (size < 0) {
  208. if ((errno == EINTR) || (errno == EAGAIN)) {
  209. continue;
  210. }
  211. if (errno != EPIPE) {
  212. g_fprintf(stderr, _("read_buffer: read error - %s"),
  213. strerror(errno));
  214. break;
  215. }
  216. size = 0;
  217. }
  218. spaceleft -= size;
  219. dataptr += size;
  220. } while ((size > 0) && (spaceleft > 0));
  221. return ((((ssize_t)buflen-spaceleft) > 0) ? ((ssize_t)buflen-spaceleft) : size);
  222. }
  223. EXTRACT_LIST *
  224. first_tape_list(void)
  225. {
  226. return extract_list;
  227. }
  228. EXTRACT_LIST *
  229. next_tape_list(
  230. /*@keep@*/EXTRACT_LIST *list)
  231. {
  232. if (list == NULL)
  233. return NULL;
  234. return list->next;
  235. }
  236. static void
  237. clear_tape_list(
  238. EXTRACT_LIST * tape_list)
  239. {
  240. EXTRACT_LIST_ITEM *this, *next;
  241. this = tape_list->files;
  242. while (this != NULL)
  243. {
  244. next = this->next;
  245. amfree(this->path);
  246. amfree(this->tpath);
  247. amfree(this);
  248. this = next;
  249. }
  250. tape_list->files = NULL;
  251. }
  252. /* remove a tape list from the extract list, clearing the tape list
  253. beforehand if necessary */
  254. void
  255. delete_tape_list(
  256. EXTRACT_LIST *tape_list)
  257. {
  258. EXTRACT_LIST *this, *prev;
  259. if (tape_list == NULL)
  260. return;
  261. /* is it first on the list? */
  262. if (tape_list == extract_list)
  263. {
  264. extract_list = tape_list->next;
  265. clear_tape_list(tape_list);
  266. amfree(tape_list->date);
  267. amfree(tape_list->tape);
  268. amfree(tape_list);
  269. return;
  270. }
  271. /* so not first on list - find it and delete */
  272. prev = extract_list;
  273. this = extract_list->next;
  274. while (this != NULL)
  275. {
  276. if (this == tape_list)
  277. {
  278. prev->next = tape_list->next;
  279. clear_tape_list(tape_list);
  280. amfree(tape_list->date);
  281. amfree(tape_list->tape);
  282. amfree(tape_list);
  283. return;
  284. }
  285. prev = this;
  286. this = this->next;
  287. }
  288. /*NOTREACHED*/
  289. }
  290. /* return the number of files on a tape's list */
  291. int
  292. length_of_tape_list(
  293. EXTRACT_LIST *tape_list)
  294. {
  295. EXTRACT_LIST_ITEM *fn;
  296. int n;
  297. n = 0;
  298. for (fn = tape_list->files; fn != NULL; fn = fn->next)
  299. n++;
  300. return n;
  301. }
  302. void
  303. clear_extract_list(void)
  304. {
  305. while (extract_list != NULL)
  306. delete_tape_list(extract_list);
  307. }
  308. void
  309. clean_tape_list(
  310. EXTRACT_LIST *tape_list)
  311. {
  312. EXTRACT_LIST_ITEM *fn1, *pfn1, *ofn1;
  313. EXTRACT_LIST_ITEM *fn2, *pfn2, *ofn2;
  314. int remove_fn1;
  315. int remove_fn2;
  316. pfn1 = NULL;
  317. fn1 = tape_list->files;
  318. while (fn1 != NULL) {
  319. remove_fn1 = 0;
  320. pfn2 = fn1;
  321. fn2 = fn1->next;
  322. while (fn2 != NULL && remove_fn1 == 0) {
  323. remove_fn2 = 0;
  324. if(g_str_equal(fn1->path, fn2->path)) {
  325. remove_fn2 = 1;
  326. } else if (g_str_has_prefix(fn2->path, fn1->path) &&
  327. ((strlen(fn2->path) > strlen(fn1->path) &&
  328. fn2->path[strlen(fn1->path)] == '/') ||
  329. (fn1->path[strlen(fn1->path)-1] == '/'))) {
  330. remove_fn2 = 1;
  331. } else if (g_str_has_prefix(fn1->path, fn2->path) &&
  332. ((strlen(fn1->path) > strlen(fn2->path) &&
  333. fn1->path[strlen(fn2->path)] == '/') ||
  334. (fn2->path[strlen(fn2->path)-1] == '/'))) {
  335. remove_fn1 = 1;
  336. break;
  337. }
  338. if (remove_fn2) {
  339. dbprintf(_("removing path %s, it is included in %s\n"),
  340. fn2->path, fn1->path);
  341. ofn2 = fn2;
  342. fn2 = fn2->next;
  343. amfree(ofn2->path);
  344. amfree(ofn2->tpath);
  345. amfree(ofn2);
  346. pfn2->next = fn2;
  347. } else if (remove_fn1 == 0) {
  348. pfn2 = fn2;
  349. fn2 = fn2->next;
  350. }
  351. }
  352. if(remove_fn1 != 0) {
  353. /* fn2->path is always valid */
  354. /*@i@*/ dbprintf(_("removing path %s, it is included in %s\n"),
  355. /*@i@*/ fn1->tpath, fn2->tpath);
  356. ofn1 = fn1;
  357. fn1 = fn1->next;
  358. amfree(ofn1->path);
  359. amfree(ofn1->tpath);
  360. if(pfn1 == NULL) {
  361. amfree(tape_list->files);
  362. tape_list->files = fn1;
  363. } else {
  364. amfree(pfn1->next);
  365. pfn1->next = fn1;
  366. }
  367. } else {
  368. pfn1 = fn1;
  369. fn1 = fn1->next;
  370. }
  371. }
  372. }
  373. static char *
  374. file_of_path(
  375. char *path,
  376. char **dir)
  377. {
  378. char *npath = g_path_get_basename(path);
  379. *dir = g_path_get_dirname(path);
  380. if (g_str_equal(*dir, ".")) {
  381. amfree(*dir);
  382. }
  383. return npath;
  384. }
  385. void
  386. clean_extract_list(void)
  387. {
  388. EXTRACT_LIST *this;
  389. for (this = extract_list; this != NULL; this = this->next)
  390. clean_tape_list(this);
  391. }
  392. int add_to_unlink_list(char *path);
  393. int do_unlink_list(void);
  394. void free_unlink_list(void);
  395. typedef struct s_unlink_list {
  396. char *path;
  397. struct s_unlink_list *next;
  398. } t_unlink_list;
  399. t_unlink_list *unlink_list = NULL;
  400. int
  401. add_to_unlink_list(
  402. char *path)
  403. {
  404. t_unlink_list *ul;
  405. if (!unlink_list) {
  406. unlink_list = g_malloc(sizeof(*unlink_list));
  407. unlink_list->path = g_strdup(path);
  408. unlink_list->next = NULL;
  409. } else {
  410. for (ul = unlink_list; ul != NULL; ul = ul->next) {
  411. if (g_str_equal(ul->path, path))
  412. return 0;
  413. }
  414. ul = g_malloc(sizeof(*ul));
  415. ul->path = g_strdup(path);
  416. ul->next = unlink_list;
  417. unlink_list = ul;
  418. }
  419. return 1;
  420. }
  421. int
  422. do_unlink_list(void)
  423. {
  424. t_unlink_list *ul;
  425. int ret = 1;
  426. for (ul = unlink_list; ul != NULL; ul = ul->next) {
  427. if (unlink(ul->path) < 0) {
  428. g_fprintf(stderr,_("Can't unlink %s: %s\n"), ul->path, strerror(errno));
  429. ret = 0;
  430. }
  431. }
  432. return ret;
  433. }
  434. void
  435. free_unlink_list(void)
  436. {
  437. t_unlink_list *ul, *ul1;
  438. for (ul = unlink_list; ul != NULL; ul = ul1) {
  439. amfree(ul->path);
  440. ul1 = ul->next;
  441. amfree(ul);
  442. }
  443. unlink_list = NULL;
  444. }
  445. void
  446. check_file_overwrite(
  447. char *dir)
  448. {
  449. EXTRACT_LIST *this;
  450. EXTRACT_LIST_ITEM *fn;
  451. struct stat stat_buf;
  452. char *filename;
  453. char *path, *s;
  454. for (this = extract_list; this != NULL; this = this->next) {
  455. for (fn = this->files; fn != NULL ; fn = fn->next) {
  456. /* Check path component of fn->path */
  457. path = g_strconcat(dir, fn->path, NULL);
  458. if (path[strlen(path)-1] == '/') {
  459. path[strlen(path)-1] = '\0';
  460. }
  461. s = path + strlen(dir) + 1;
  462. while((s = strchr(s, '/'))) {
  463. *s = '\0';
  464. if (lstat(path, &stat_buf) == 0) {
  465. if(!S_ISDIR(stat_buf.st_mode)) {
  466. if (add_to_unlink_list(path)) {
  467. g_printf(_("WARNING: %s is not a directory, "
  468. "it will be deleted.\n"),
  469. path);
  470. }
  471. }
  472. }
  473. else if (errno != ENOENT) {
  474. g_printf(_("Can't stat %s: %s\n"), path, strerror(errno));
  475. }
  476. *s = '/';
  477. s++;
  478. }
  479. amfree(path);
  480. /* Check fn->path */
  481. filename = g_strconcat(dir, fn->path, NULL);
  482. if (filename[strlen(filename)-1] == '/') {
  483. filename[strlen(filename)-1] = '\0';
  484. }
  485. if (lstat(filename, &stat_buf) == 0) {
  486. if(S_ISDIR(stat_buf.st_mode)) {
  487. if(!is_empty_dir(filename)) {
  488. g_printf(_("WARNING: All existing files in %s "
  489. "will be deleted.\n"), filename);
  490. }
  491. } else if(S_ISREG(stat_buf.st_mode)) {
  492. g_printf(_("WARNING: Existing file %s will be overwritten\n"),
  493. filename);
  494. } else {
  495. if (add_to_unlink_list(filename)) {
  496. g_printf(_("WARNING: Existing entry %s will be deleted\n"),
  497. filename);
  498. }
  499. }
  500. } else if (errno != ENOENT) {
  501. g_printf(_("Can't stat %s: %s\n"), filename, strerror(errno));
  502. }
  503. amfree(filename);
  504. }
  505. }
  506. }
  507. /* returns -1 if error */
  508. /* returns 0 on succes */
  509. /* returns 1 if already added */
  510. static int
  511. add_extract_item(
  512. DIR_ITEM *ditem)
  513. {
  514. EXTRACT_LIST *this, *this1;
  515. EXTRACT_LIST_ITEM *that, *curr;
  516. char *ditem_path;
  517. ditem_path = g_strdup(ditem->path);
  518. clean_pathname(ditem_path);
  519. for (this = extract_list; this != NULL; this = this->next)
  520. {
  521. /* see if this is the list for the tape */
  522. if (this->level == ditem->level && g_str_equal(this->tape,
  523. ditem->tape))
  524. {
  525. /* yes, so add to list */
  526. curr=this->files;
  527. while(curr!=NULL)
  528. {
  529. if (g_str_equal(curr->path, ditem_path)) {
  530. g_free(ditem_path);
  531. return 1;
  532. }
  533. curr=curr->next;
  534. }
  535. that = (EXTRACT_LIST_ITEM *)g_malloc(sizeof(EXTRACT_LIST_ITEM));
  536. that->path = ditem_path;
  537. that->tpath = clean_pathname(g_strdup(ditem->tpath));
  538. that->next = this->files;
  539. this->files = that; /* add at front since easiest */
  540. return 0;
  541. }
  542. }
  543. /* so this is the first time we have seen this tape */
  544. this = (EXTRACT_LIST *)g_malloc(sizeof(EXTRACT_LIST));
  545. this->tape = g_strdup(ditem->tape);
  546. this->level = ditem->level;
  547. this->fileno = ditem->fileno;
  548. this->date = g_strdup(ditem->date);
  549. that = (EXTRACT_LIST_ITEM *)g_malloc(sizeof(EXTRACT_LIST_ITEM));
  550. that->path = ditem_path;
  551. that->tpath = clean_pathname(g_strdup(ditem->tpath));
  552. that->next = NULL;
  553. this->files = that;
  554. /* add this in date increasing order */
  555. /* because restore must be done in this order */
  556. /* add at begining */
  557. if(extract_list==NULL || strcmp(this->date,extract_list->date) < 0)
  558. {
  559. this->next = extract_list;
  560. extract_list = this;
  561. return 0;
  562. }
  563. for (this1 = extract_list; this1->next != NULL; this1 = this1->next)
  564. {
  565. /* add in the middle */
  566. if(strcmp(this->date,this1->next->date) < 0)
  567. {
  568. this->next = this1->next;
  569. this1->next = this;
  570. return 0;
  571. }
  572. }
  573. /* add at end */
  574. this->next = NULL;
  575. this1->next = this;
  576. return 0;
  577. }
  578. /* returns -1 if error */
  579. /* returns 0 on deletion */
  580. /* returns 1 if not there */
  581. static int
  582. delete_extract_item(
  583. DIR_ITEM *ditem)
  584. {
  585. EXTRACT_LIST *this;
  586. EXTRACT_LIST_ITEM *that, *prev;
  587. char *ditem_path = NULL;
  588. ditem_path = g_strdup(ditem->path);
  589. clean_pathname(ditem_path);
  590. for (this = extract_list; this != NULL; this = this->next)
  591. {
  592. /* see if this is the list for the tape */
  593. if (this->level == ditem->level && g_str_equal(this->tape,
  594. ditem->tape))
  595. {
  596. /* yes, so find file on list */
  597. that = this->files;
  598. if (g_str_equal(that->path, ditem_path))
  599. {
  600. /* first on list */
  601. this->files = that->next;
  602. amfree(that->path);
  603. amfree(that->tpath);
  604. amfree(that);
  605. /* if list empty delete it */
  606. if (this->files == NULL)
  607. delete_tape_list(this);
  608. amfree(ditem_path);
  609. return 0;
  610. }
  611. prev = that;
  612. that = that->next;
  613. while (that != NULL)
  614. {
  615. if (g_str_equal(that->path, ditem_path))
  616. {
  617. prev->next = that->next;
  618. amfree(that->path);
  619. amfree(that->tpath);
  620. amfree(that);
  621. amfree(ditem_path);
  622. return 0;
  623. }
  624. prev = that;
  625. that = that->next;
  626. }
  627. amfree(ditem_path);
  628. return 1;
  629. }
  630. }
  631. amfree(ditem_path);
  632. return 1;
  633. }
  634. static char *
  635. merge_path(
  636. char *path1,
  637. char *path2)
  638. {
  639. char *result;
  640. int len = strlen(path1);
  641. if (path1[len-1] == '/' && path2[0] == '/') {
  642. result = g_strconcat(path1, path2 + 1, NULL);
  643. } else if (path1[len-1] != '/' && path2[0] != '/') {
  644. result = g_strjoin(NULL, path1, "/", path2, NULL);
  645. } else {
  646. result = g_strconcat(path1, path2, NULL);
  647. }
  648. return result;
  649. }
  650. void
  651. add_glob(
  652. char * glob)
  653. {
  654. char *regex;
  655. char *regex_path;
  656. char *s;
  657. char *uqglob;
  658. char *dir;
  659. char *sdir = NULL;
  660. int result = 1;
  661. if (disk_path == NULL) {
  662. g_printf(_("Must select directory before adding files\n"));
  663. return;
  664. }
  665. uqglob = unquote_string(glob);
  666. glob = file_of_path(uqglob, &dir);
  667. if (dir) {
  668. sdir = merge_path(mount_point, disk_path);
  669. result = cd_glob(dir, 0);
  670. amfree(dir);
  671. }
  672. if (result) {
  673. regex = glob_to_regex(glob);
  674. dbprintf(_("add_glob (%s) -> %s\n"), uqglob, regex);
  675. if ((s = validate_regexp(regex)) != NULL) {
  676. g_printf(_("%s is not a valid shell wildcard pattern: "), glob);
  677. puts(s);
  678. } else {
  679. /*
  680. * glob_to_regex() anchors the beginning of the pattern with ^,
  681. * but we will be tacking it onto the end of the current directory
  682. * in add_file, so strip that off. Also, it anchors the end with
  683. * $, but we need to match an optional trailing /, so tack that on
  684. * the end.
  685. */
  686. regex_path = g_strdup(regex + 1);
  687. regex_path[strlen(regex_path) - 1] = '\0';
  688. strappend(regex_path, "[/]*$");
  689. add_file(uqglob, regex_path);
  690. amfree(regex_path);
  691. }
  692. if (sdir) {
  693. set_directory(sdir, 0);
  694. }
  695. amfree(regex);
  696. }
  697. amfree(sdir);
  698. amfree(uqglob);
  699. amfree(glob);
  700. }
  701. void
  702. add_regex(
  703. char * regex)
  704. {
  705. char *s;
  706. char *dir;
  707. char *sdir = NULL;
  708. char *uqregex;
  709. char *newregex;
  710. int result = 1;
  711. if (disk_path == NULL) {
  712. g_printf(_("Must select directory before adding files\n"));
  713. return;
  714. }
  715. uqregex = unquote_string(regex);
  716. newregex = file_of_path(uqregex, &dir);
  717. if (dir) {
  718. sdir = merge_path(mount_point, disk_path);
  719. result = cd_regex(dir, 0);
  720. amfree(dir);
  721. }
  722. if (result) {
  723. if ((s = validate_regexp(newregex)) != NULL) {
  724. g_printf(_("\"%s\" is not a valid regular expression: "), newregex);
  725. puts(s);
  726. } else {
  727. add_file(uqregex, newregex);
  728. }
  729. if (sdir) {
  730. set_directory(sdir, 0);
  731. }
  732. }
  733. amfree(sdir);
  734. amfree(uqregex);
  735. amfree(newregex);
  736. }
  737. void
  738. add_file(
  739. char * path,
  740. char * regex)
  741. {
  742. DIR_ITEM *ditem, lditem;
  743. char *tpath_on_disk = NULL;
  744. char *cmd = NULL;
  745. char *err = NULL;
  746. int i;
  747. ssize_t j;
  748. char *dir_undo, dir_undo_ch = '\0';
  749. char *ditem_path = NULL;
  750. char *qditem_path = NULL;
  751. char *l = NULL;
  752. int added;
  753. char *s, *fp, *quoted;
  754. int ch;
  755. int found_one;
  756. int dir_entries;
  757. if (disk_path == NULL) {
  758. g_printf(_("Must select directory before adding files\n"));
  759. return;
  760. }
  761. memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */
  762. dbprintf(_("add_file: Looking for \"%s\"\n"), regex);
  763. if(g_str_equal(regex, "/[/]*$")) { /* "/" behave like "." */
  764. regex = "\\.[/]*$";
  765. }
  766. else if(g_str_equal(regex, "[^/]*[/]*$")) { /* "*" */
  767. regex = "([^/.]|\\.[^/]+|[^/.][^/]*)[/]*$";
  768. } else {
  769. /* remove "/" at end of path */
  770. j = (ssize_t)(strlen(regex) - 1);
  771. while(j >= 0 && regex[j] == '/')
  772. regex[j--] = '\0';
  773. }
  774. /* convert path (assumed in cwd) to one on disk */
  775. if (g_str_equal(disk_path, "/")) {
  776. if (*regex == '/') {
  777. /* No mods needed if already starts with '/' */
  778. tpath_on_disk = g_strdup(regex);
  779. } else {
  780. /* Prepend '/' */
  781. tpath_on_disk = g_strconcat("/", regex, NULL);
  782. }
  783. } else {
  784. char *clean_disk_tpath = clean_regex(disk_tpath, 0);
  785. tpath_on_disk = g_strjoin(NULL, clean_disk_tpath, "/", regex, NULL);
  786. amfree(clean_disk_tpath);
  787. }
  788. dbprintf(_("add_file: Converted path=\"%s\" to tpath_on_disk=\"%s\"\n"),
  789. regex, tpath_on_disk);
  790. found_one = 0;
  791. dir_entries = 0;
  792. for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
  793. {
  794. dir_entries++;
  795. quoted = quote_string(ditem->tpath);
  796. dbprintf(_("add_file: Pondering ditem->path=%s\n"), quoted);
  797. amfree(quoted);
  798. if (match(tpath_on_disk, ditem->tpath))
  799. {
  800. found_one = 1;
  801. j = (ssize_t)strlen(ditem->tpath);
  802. if((j > 0 && ditem->tpath[j-1] == '/')
  803. || (j > 1 && ditem->tpath[j-2] == '/' && ditem->tpath[j-1] == '.'))
  804. { /* It is a directory */
  805. g_free(ditem_path);
  806. ditem_path = g_strdup(ditem->path);
  807. clean_pathname(ditem_path);
  808. qditem_path = quote_string(ditem_path);
  809. g_free(cmd);
  810. cmd = g_strconcat("ORLD ", qditem_path, NULL);
  811. amfree(qditem_path);
  812. if(send_command(cmd) == -1) {
  813. amfree(cmd);
  814. amfree(ditem_path);
  815. amfree(tpath_on_disk);
  816. exit(1);
  817. }
  818. amfree(cmd);
  819. cmd = NULL;
  820. /* skip preamble */
  821. if ((i = get_reply_line()) == -1) {
  822. amfree(ditem_path);
  823. amfree(tpath_on_disk);
  824. exit(1);
  825. }
  826. if(i==0) { /* assume something wrong */
  827. amfree(ditem_path);
  828. amfree(tpath_on_disk);
  829. amfree(lditem.path);
  830. amfree(lditem.date);
  831. amfree(lditem.tape);
  832. l = reply_line();
  833. g_printf("%s\n", l);
  834. return;
  835. }
  836. dir_undo = NULL;
  837. added=0;
  838. g_free(lditem.path);
  839. g_free(lditem.tpath);
  840. lditem.path = g_strdup(ditem->path);
  841. lditem.tpath = g_strdup(ditem->tpath);
  842. /* skip the last line -- duplicate of the preamble */
  843. while ((i = get_reply_line()) != 0) {
  844. if (i == -1) {
  845. amfree(ditem_path);
  846. amfree(tpath_on_disk);
  847. exit(1);
  848. }
  849. if(err) {
  850. if(cmd == NULL) {
  851. if(dir_undo) *dir_undo = dir_undo_ch;
  852. dir_undo = NULL;
  853. cmd = g_strdup(l); /* save for error report */
  854. }
  855. continue; /* throw the rest of the lines away */
  856. }
  857. l=reply_line();
  858. if (!server_happy()) {
  859. puts(l);
  860. continue;
  861. }
  862. s = l;
  863. if(strncmp_const_skip(l, "201-", s, ch) != 0) {
  864. err = _("bad reply: not 201-");
  865. continue;
  866. }
  867. ch = *s++;
  868. skip_whitespace(s, ch);
  869. if(ch == '\0') {
  870. err = _("bad reply: missing date field");
  871. continue;
  872. }
  873. fp = s-1;
  874. skip_non_whitespace(s, ch);
  875. s[-1] = '\0';
  876. g_free(lditem.date);
  877. lditem.date = g_strdup(fp);
  878. s[-1] = (char)ch;
  879. skip_whitespace(s, ch);
  880. if(ch == '\0' || sscanf(s - 1, "%d", &lditem.level) != 1) {
  881. err = _("bad reply: cannot parse level field");
  882. continue;
  883. }
  884. skip_integer(s, ch);
  885. skip_whitespace(s, ch);
  886. if(ch == '\0') {
  887. err = _("bad reply: missing tape field");
  888. continue;
  889. }
  890. fp = s-1;
  891. skip_quoted_string(s, ch);
  892. s[-1] = '\0';
  893. amfree(lditem.tape);
  894. lditem.tape = unquote_string(fp);
  895. s[-1] = (char)ch;
  896. if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
  897. long long fileno_ = (long long)0;
  898. skip_whitespace(s, ch);
  899. if(ch == '\0' ||
  900. sscanf(s - 1, "%lld", &fileno_) != 1) {
  901. err = _("bad reply: cannot parse fileno field");
  902. continue;
  903. }
  904. lditem.fileno = (off_t)fileno_;
  905. skip_integer(s, ch);
  906. }
  907. skip_whitespace(s, ch);
  908. if(ch == '\0') {
  909. err = _("bad reply: missing directory field");
  910. continue;
  911. }
  912. skip_quoted_string(s, ch);
  913. dir_undo = s - 1;
  914. dir_undo_ch = *dir_undo;
  915. *dir_undo = '\0';
  916. switch(add_extract_item(&lditem)) {
  917. case -1:
  918. g_printf(_("System error\n"));
  919. dbprintf(_("add_file: (Failed) System error\n"));
  920. break;
  921. case 0:
  922. quoted = quote_string(lditem.tpath);
  923. g_printf(_("Added dir %s at date %s\n"),
  924. quoted, lditem.date);
  925. dbprintf(_("add_file: (Successful) Added dir %s at date %s\n"),
  926. quoted, lditem.date);
  927. amfree(quoted);
  928. added=1;
  929. break;
  930. case 1:
  931. break;
  932. }
  933. }
  934. if(!server_happy()) {
  935. puts(reply_line());
  936. } else if(err) {
  937. if (*err)
  938. puts(err);
  939. if (cmd)
  940. puts(cmd);
  941. } else if(added == 0) {
  942. quoted = quote_string(ditem_path);
  943. g_printf(_("dir %s already added\n"), quoted);
  944. dbprintf(_("add_file: dir %s already added\n"), quoted);
  945. amfree(quoted);
  946. }
  947. }
  948. else /* It is a file */
  949. {
  950. switch(add_extract_item(ditem)) {
  951. case -1:
  952. g_printf(_("System error\n"));
  953. dbprintf(_("add_file: (Failed) System error\n"));
  954. break;
  955. case 0:
  956. quoted = quote_string(ditem->tpath);
  957. g_printf(_("Added file %s\n"), quoted);
  958. dbprintf(_("add_file: (Successful) Added %s\n"), quoted);
  959. amfree(quoted);
  960. break;
  961. case 1:
  962. quoted = quote_string(ditem->tpath);
  963. g_printf(_("File %s already added\n"), quoted);
  964. dbprintf(_("add_file: file %s already added\n"), quoted);
  965. amfree(quoted);
  966. }
  967. }
  968. }
  969. }
  970. amfree(cmd);
  971. amfree(ditem_path);
  972. amfree(tpath_on_disk);
  973. amfree(lditem.path);
  974. amfree(lditem.tpath);
  975. amfree(lditem.date);
  976. amfree(lditem.tape);
  977. if(! found_one) {
  978. quoted = quote_string(path);
  979. g_printf(_("File %s doesn't exist in directory\n"), quoted);
  980. dbprintf(_("add_file: (Failed) File %s doesn't exist in directory\n"),
  981. quoted);
  982. amfree(quoted);
  983. }
  984. }
  985. void
  986. delete_glob(
  987. char * glob)
  988. {
  989. char *regex;
  990. char *regex_path;
  991. char *s;
  992. char *uqglob;
  993. char *newglob;
  994. char *dir;
  995. char *sdir = NULL;
  996. int result = 1;
  997. if (disk_path == NULL) {
  998. g_printf(_("Must select directory before adding files\n"));
  999. return;
  1000. }
  1001. uqglob = unquote_string(glob);
  1002. newglob = file_of_path(uqglob, &dir);
  1003. if (dir) {
  1004. sdir = merge_path(mount_point, disk_path);
  1005. result = cd_glob(dir, 0);
  1006. amfree(dir);
  1007. }
  1008. if (result) {
  1009. regex = glob_to_regex(newglob);
  1010. dbprintf(_("delete_glob (%s) -> %s\n"), newglob, regex);
  1011. if ((s = validate_regexp(regex)) != NULL) {
  1012. g_printf(_("\"%s\" is not a valid shell wildcard pattern: "),
  1013. newglob);
  1014. puts(s);
  1015. } else {
  1016. /*
  1017. * glob_to_regex() anchors the beginning of the pattern with ^,
  1018. * but we will be tacking it onto the end of the current directory
  1019. * in add_file, so strip that off. Also, it anchors the end with
  1020. * $, but we need to match an optional trailing /, so tack that on
  1021. * the end.
  1022. */
  1023. regex_path = g_strdup(regex + 1);
  1024. regex_path[strlen(regex_path) - 1] = '\0';
  1025. strappend(regex_path, "[/]*$");
  1026. delete_file(uqglob, regex_path);
  1027. amfree(regex_path);
  1028. }
  1029. if (sdir) {
  1030. set_directory(sdir, 0);
  1031. }
  1032. amfree(regex);
  1033. }
  1034. amfree(sdir);
  1035. amfree(uqglob);
  1036. amfree(newglob);
  1037. }
  1038. void
  1039. delete_regex(
  1040. char * regex)
  1041. {
  1042. char *s;
  1043. char *dir;
  1044. char *sdir = NULL;
  1045. char *uqregex;
  1046. char *newregex;
  1047. int result = 1;
  1048. if (disk_path == NULL) {
  1049. g_printf(_("Must select directory before adding files\n"));
  1050. return;
  1051. }
  1052. uqregex = unquote_string(regex);
  1053. newregex = file_of_path(uqregex, &dir);
  1054. if (dir) {
  1055. sdir = merge_path(mount_point, disk_path);
  1056. result = cd_regex(dir, 0);
  1057. amfree(dir);
  1058. }
  1059. if (result == 1) {
  1060. if ((s = validate_regexp(newregex)) != NULL) {
  1061. g_printf(_("\"%s\" is not a valid regular expression: "), newregex);
  1062. puts(s);
  1063. } else {
  1064. delete_file(newregex, regex);
  1065. }
  1066. if (sdir) {
  1067. set_directory(sdir, 0);
  1068. }
  1069. }
  1070. amfree(sdir);
  1071. amfree(uqregex);
  1072. amfree(newregex);
  1073. }
  1074. void
  1075. delete_file(
  1076. char * tpath,
  1077. char * regex)
  1078. {
  1079. DIR_ITEM *ditem, lditem;
  1080. char *tpath_on_disk = NULL;
  1081. char *cmd = NULL;
  1082. char *err = NULL;
  1083. int i;
  1084. ssize_t j;
  1085. char *date;
  1086. char *tape, *tape_undo, tape_undo_ch = '\0';
  1087. char *dir_undo, dir_undo_ch = '\0';
  1088. int level = 0;
  1089. char *ditem_path = NULL;
  1090. char *ditem_tpath = NULL;
  1091. char *qditem_path;
  1092. char *l = NULL;
  1093. int deleted;
  1094. char *s;
  1095. int ch;
  1096. int found_one;
  1097. char *quoted;
  1098. if (disk_path == NULL) {
  1099. g_printf(_("Must select directory before deleting files\n"));
  1100. return;
  1101. }
  1102. memset(&lditem, 0, sizeof(lditem)); /* Prevent use of bogus data... */
  1103. dbprintf(_("delete_file: Looking for \"%s\"\n"), tpath);
  1104. if (g_str_equal(regex, "[^/]*[/]*$")) {
  1105. /* Looking for * find everything but single . */
  1106. regex = "([^/.]|\\.[^/]+|[^/.][^/]*)[/]*$";
  1107. } else {
  1108. /* remove "/" at end of path */
  1109. j = (ssize_t)(strlen(regex) - 1);
  1110. while(j >= 0 && regex[j] == '/') regex[j--] = '\0';
  1111. }
  1112. /* convert path (assumed in cwd) to one on disk */
  1113. if (g_str_equal(disk_path, "/")) {
  1114. if (*regex == '/') {
  1115. if (g_str_equal(regex, "/[/]*$")) {
  1116. /* We want "/" to match the directory itself: "/." */
  1117. tpath_on_disk = g_strdup("/\\.[/]*$");
  1118. } else {
  1119. /* No mods needed if already starts with '/' */
  1120. tpath_on_disk = g_strdup(regex);
  1121. }
  1122. } else {
  1123. /* Prepend '/' */
  1124. tpath_on_disk = g_strconcat("/", regex, NULL);
  1125. }
  1126. } else {
  1127. char *clean_disk_tpath = clean_regex(disk_tpath, 0);
  1128. tpath_on_disk = g_strjoin(NULL, clean_disk_tpath, "/", regex, NULL);
  1129. amfree(clean_disk_tpath);
  1130. }
  1131. dbprintf(_("delete_file: Converted path=\"%s\" to tpath_on_disk=\"%s\"\n"),
  1132. regex, tpath_on_disk);
  1133. found_one = 0;
  1134. for (ditem=get_dir_list(); ditem!=NULL; ditem=get_next_dir_item(ditem))
  1135. {
  1136. quoted = quote_string(ditem->tpath);
  1137. dbprintf(_("delete_file: Pondering ditem->path=%s\n"), quoted);
  1138. amfree(quoted);
  1139. if (match(tpath_on_disk, ditem->tpath))
  1140. {
  1141. found_one = 1;
  1142. j = (ssize_t)strlen(ditem->tpath);
  1143. if((j > 0 && ditem->tpath[j-1] == '/')
  1144. || (j > 1 && ditem->tpath[j-2] == '/' && ditem->tpath[j-1] == '.'))
  1145. { /* It is a directory */
  1146. g_free(ditem_path);
  1147. g_free(ditem_tpath);
  1148. ditem_path = g_strdup(ditem->path);
  1149. ditem_tpath = g_strdup(ditem->tpath);
  1150. clean_pathname(ditem_path);
  1151. clean_pathname(ditem_tpath);
  1152. qditem_path = quote_string(ditem_path);
  1153. g_free(cmd);
  1154. cmd = g_strconcat("ORLD ", qditem_path, NULL);
  1155. amfree(qditem_path);
  1156. if(send_command(cmd) == -1) {
  1157. amfree(cmd);
  1158. amfree(ditem_path);
  1159. amfree(tpath_on_disk);
  1160. exit(1);
  1161. }
  1162. amfree(cmd);
  1163. /* skip preamble */
  1164. if ((i = get_reply_line()) == -1) {
  1165. amfree(ditem_path);
  1166. amfree(tpath_on_disk);
  1167. exit(1);
  1168. }
  1169. if(i==0) /* assume something wrong */
  1170. {
  1171. amfree(ditem_path);
  1172. amfree(tpath_on_disk);
  1173. amfree(lditem.path);
  1174. l = reply_line();
  1175. g_printf("%s\n", l);
  1176. return;
  1177. }
  1178. deleted=0;
  1179. g_free(lditem.path);
  1180. g_free(lditem.tpath);
  1181. lditem.path = g_strdup(ditem->path);
  1182. lditem.tpath = g_strdup(ditem->tpath);
  1183. amfree(cmd);
  1184. tape_undo = dir_undo = NULL;
  1185. /* skip the last line -- duplicate of the preamble */
  1186. while ((i = get_reply_line()) != 0)
  1187. {
  1188. if (i == -1) {
  1189. amfree(ditem_path);
  1190. amfree(tpath_on_disk);
  1191. exit(1);
  1192. }
  1193. if(err) {
  1194. if(cmd == NULL) {
  1195. if(tape_undo) *tape_undo = tape_undo_ch;
  1196. if(dir_undo) *dir_undo = dir_undo_ch;
  1197. tape_undo = dir_undo = NULL;
  1198. cmd = g_strdup(l); /* save for the error report */
  1199. }
  1200. continue; /* throw the rest of the lines away */
  1201. }
  1202. l=reply_line();
  1203. if (!server_happy()) {
  1204. puts(l);
  1205. continue;
  1206. }
  1207. s = l;
  1208. if(strncmp_const_skip(l, "201-", s, ch) != 0) {
  1209. err = _("bad reply: not 201-");
  1210. continue;
  1211. }
  1212. ch = *s++;
  1213. skip_whitespace(s, ch);
  1214. if(ch == '\0') {
  1215. err = _("bad reply: missing date field");
  1216. continue;
  1217. }
  1218. date = s - 1;
  1219. skip_non_whitespace(s, ch);
  1220. *(s - 1) = '\0';
  1221. skip_whitespace(s, ch);
  1222. if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
  1223. err = _("bad reply: cannot parse level field");
  1224. continue;
  1225. }
  1226. skip_integer(s, ch);
  1227. skip_whitespace(s, ch);
  1228. if(ch == '\0') {
  1229. err = _("bad reply: missing tape field");
  1230. continue;
  1231. }
  1232. tape = s - 1;
  1233. skip_non_whitespace(s, ch);
  1234. tape_undo = s - 1;
  1235. tape_undo_ch = *tape_undo;
  1236. *tape_undo = '\0';
  1237. if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_ORLD)) {
  1238. long long fileno_ = (long long)0;
  1239. skip_whitespace(s, ch);
  1240. if(ch == '\0' ||
  1241. sscanf(s - 1, "%lld", &fileno_) != 1) {
  1242. err = _("bad reply: cannot parse fileno field");
  1243. continue;
  1244. }
  1245. skip_integer(s, ch);
  1246. }
  1247. skip_whitespace(s, ch);
  1248. if(ch == '\0') {
  1249. err = _("bad reply: missing directory field");
  1250. continue;
  1251. }
  1252. skip_non_whitespace(s, ch);
  1253. dir_undo = s - 1;
  1254. dir_undo_ch = *dir_undo;
  1255. *dir_undo = '\0';
  1256. g_free(lditem.date);
  1257. lditem.date = g_strdup(date);
  1258. lditem.level=level;
  1259. g_free(lditem.tape);
  1260. lditem.tape = unquote_string(tape);
  1261. switch(delete_extract_item(&lditem)) {
  1262. case -1:
  1263. g_printf(_("System error\n"));
  1264. dbprintf(_("delete_file: (Failed) System error\n"));
  1265. break;
  1266. case 0:
  1267. g_printf(_("Deleted dir %s at date %s\n"), ditem_tpath, date);
  1268. dbprintf(_("delete_file: (Successful) Deleted dir %s at date %s\n"),
  1269. ditem_tpath, date);
  1270. deleted=1;
  1271. break;
  1272. case 1:
  1273. break;
  1274. }
  1275. }
  1276. if(!server_happy()) {
  1277. puts(reply_line());
  1278. } else if(err) {
  1279. if (*err)
  1280. puts(err);
  1281. if (cmd)
  1282. puts(cmd);
  1283. } else if(deleted == 0) {
  1284. g_printf(_("Warning - dir '%s' not on tape list\n"),
  1285. ditem_tpath);
  1286. dbprintf(_("delete_file: dir '%s' not on tape list\n"),
  1287. ditem_tpath);
  1288. }
  1289. }
  1290. else
  1291. {
  1292. switch(delete_extract_item(ditem)) {
  1293. case -1:
  1294. g_printf(_("System error\n"));
  1295. dbprintf(_("delete_file: (Failed) System error\n"));
  1296. break;
  1297. case 0:
  1298. g_printf(_("Deleted %s\n"), ditem->tpath);
  1299. dbprintf(_("delete_file: (Successful) Deleted %s\n"),
  1300. ditem->tpath);
  1301. break;
  1302. case 1:
  1303. g_printf(_("Warning - file '%s' not on tape list\n"),
  1304. ditem->tpath);
  1305. dbprintf(_("delete_file: file '%s' not on tape list\n"),
  1306. ditem->tpath);
  1307. break;
  1308. }
  1309. }
  1310. }
  1311. }
  1312. amfree(cmd);
  1313. amfree(ditem_path);
  1314. amfree(ditem_tpath);
  1315. amfree(tpath_on_disk);
  1316. amfree(lditem.path);
  1317. if(! found_one) {
  1318. g_printf(_("File %s doesn't exist in directory\n"), tpath);
  1319. dbprintf(_("delete_file: (Failed) File %s doesn't exist in directory\n"),
  1320. tpath);
  1321. }
  1322. }
  1323. /* print extract list into file. If NULL ptr passed print to screen */
  1324. void
  1325. display_extract_list(
  1326. char * file)
  1327. {
  1328. EXTRACT_LIST *this;
  1329. EXTRACT_LIST_ITEM *that;
  1330. FILE *fp;
  1331. char *pager;
  1332. char *pager_command;
  1333. char *uqfile;
  1334. if (file == NULL)
  1335. {
  1336. if ((pager = getenv("PAGER")) == NULL)
  1337. {
  1338. pager = "more";
  1339. }
  1340. /*
  1341. * Set up the pager command so if the pager is terminated, we do
  1342. * not get a SIGPIPE back.
  1343. */
  1344. pager_command = g_strconcat(pager, " ; /bin/cat > /dev/null", NULL);
  1345. if ((fp = popen(pager_command, "w")) == NULL)
  1346. {
  1347. g_printf(_("Warning - can't pipe through %s\n"), pager);
  1348. fp = stdout;
  1349. }
  1350. amfree(pager_command);
  1351. }
  1352. else
  1353. {
  1354. uqfile = unquote_string(file);
  1355. if ((fp = fopen(uqfile, "w")) == NULL)
  1356. {
  1357. g_printf(_("Can't open file %s to print extract list into\n"), file);
  1358. amfree(uqfile);
  1359. return;
  1360. }
  1361. amfree(uqfile);
  1362. }
  1363. for (this = extract_list; this != NULL; this = this->next)
  1364. {
  1365. g_fprintf(fp, _("TAPE %s LEVEL %d DATE %s\n"),
  1366. this->tape, this->level, this->date);
  1367. for (that = this->files; that != NULL; that = that->next)
  1368. g_fprintf(fp, "\t%s\n", that->tpath);
  1369. }
  1370. if (file == NULL) {
  1371. apclose(fp);
  1372. } else {
  1373. g_printf(_("Extract list written to file %s\n"), file);
  1374. afclose(fp);
  1375. }
  1376. }
  1377. static int
  1378. is_empty_dir(
  1379. char *fname)
  1380. {
  1381. DIR *dir;
  1382. struct dirent *entry;
  1383. int gotentry;
  1384. if((dir = opendir(fname)) == NULL)
  1385. return 1;
  1386. gotentry = 0;
  1387. while(!gotentry && (entry = readdir(dir)) != NULL) {
  1388. gotentry = !is_dot_or_dotdot(entry->d_name);
  1389. }
  1390. closedir(dir);
  1391. return !gotentry;
  1392. }
  1393. /* returns 0 if extract list empty and 1 if it isn't */
  1394. int
  1395. is_extract_list_nonempty(void)
  1396. {
  1397. return (extract_list != NULL);
  1398. }
  1399. /* prints continue prompt and waits for response,
  1400. returns 0 if don't, non-0 if do */
  1401. static int
  1402. okay_to_continue(
  1403. int allow_tape,
  1404. int allow_skip,
  1405. int allow_retry)
  1406. {
  1407. int ch;
  1408. int ret = -1;
  1409. char *line = NULL;
  1410. char *s;
  1411. char *prompt;
  1412. int get_device;
  1413. get_device = 0;
  1414. while (ret < 0) {
  1415. if (get_device) {
  1416. prompt = _("New device name [?]: ");
  1417. } else if (allow_tape && allow_skip) {
  1418. prompt = _("Continue [?/Y/n/s/d]? ");
  1419. } else if (allow_tape && !allow_skip) {
  1420. prompt = _("Continue [?/Y/n/d]? ");
  1421. } else if (allow_retry) {
  1422. prompt = _("Continue [?/Y/n/r]? ");
  1423. } else {
  1424. prompt = _("Continue [?/Y/n]? ");
  1425. }
  1426. fputs(prompt, stdout);
  1427. fflush(stdout); fflush(stderr);
  1428. amfree(line);
  1429. if ((line = agets(stdin)) == NULL) {
  1430. putchar('\n');
  1431. clearerr(stdin);
  1432. if (get_device) {
  1433. get_device = 0;
  1434. continue;
  1435. }
  1436. ret = 0;
  1437. break;
  1438. }
  1439. dbprintf("User prompt: '%s'; response: '%s'\n", prompt, line);
  1440. s = line;
  1441. while ((ch = *s++) != '\0' && g_ascii_isspace(ch)) {
  1442. (void)ch; /* Quiet empty loop compiler warning */
  1443. }
  1444. if (ch == '?') {
  1445. if (get_device) {
  1446. g_printf(_("Enter a new device name or \"default\"\n"));
  1447. } else {
  1448. g_printf(_("Enter \"y\"es to continue, \"n\"o to stop"));
  1449. if(allow_skip) {
  1450. g_printf(_(", \"s\"kip this tape"));
  1451. }
  1452. if(allow_retry) {
  1453. g_printf(_(" or \"r\"etry this tape"));
  1454. }
  1455. if (allow_tape) {
  1456. g_printf(_(" or \"d\" to change to a new device"));
  1457. }
  1458. putchar('\n');
  1459. }
  1460. } else if (get_device) {
  1461. char *tmp = g_strdup(tape_server_name);
  1462. if (strncmp_const(s - 1, "default") == 0) {
  1463. set_device(tmp, NULL); /* default device, existing host */
  1464. } else if (s[-1] != '\0') {
  1465. set_device(tmp, s - 1); /* specified device, existing host */
  1466. } else {
  1467. g_printf(_("No change.\n"));
  1468. }
  1469. amfree(tmp);
  1470. get_device = 0;
  1471. } else if (ch == '\0' || ch == 'Y' || ch == 'y') {
  1472. ret = 1;
  1473. } else if (allow_tape && (ch == 'D' || ch == 'd' || ch == 'T' || ch == 't')) {
  1474. get_device = 1; /* ('T' and 't' are for backward-compatibility) */
  1475. } else if (ch == 'N' || ch == 'n') {
  1476. ret = 0;
  1477. } else if (allow_retry && (ch == 'R' || ch == 'r')) {
  1478. ret = RETRY_TAPE;
  1479. } else if (allow_skip && (ch == 'S' || ch == 's')) {
  1480. ret = SKIP_TAPE;
  1481. }
  1482. }
  1483. /*@ignore@*/
  1484. amfree(line);
  1485. /*@end@*/
  1486. return ret;
  1487. }
  1488. static void
  1489. send_to_tape_server(
  1490. security_stream_t * stream,
  1491. char * cmd)
  1492. {
  1493. char *msg = g_strconcat(cmd, "\r\n", NULL);
  1494. g_debug("send_to_tape_server: %s\n", cmd);
  1495. if (security_stream_write(stream, msg, strlen(msg)) < 0)
  1496. {
  1497. error(_("Error writing to tape server"));
  1498. exit(101);
  1499. /*NOTREACHED*/
  1500. }
  1501. amfree(msg);
  1502. }
  1503. /* start up connection to tape server and set commands to initiate
  1504. transfer of dump image.
  1505. Return tape server socket on success, -1 on error. */
  1506. static int
  1507. extract_files_setup(
  1508. char * label,
  1509. off_t fsf)
  1510. {
  1511. char *disk_regex = NULL;
  1512. char *host_regex = NULL;
  1513. char *clean_datestamp, *ch, *ch1;
  1514. char *tt = NULL;
  1515. char *req;
  1516. int response_error;
  1517. amidxtaped_secdrv = security_getdriver(authopt);
  1518. if (amidxtaped_secdrv == NULL) {
  1519. error(_("no '%s' security driver available for host '%s'"),
  1520. authopt, tape_server_name);
  1521. }
  1522. /* We assume that amidxtaped support fe_amidxtaped_options_features */
  1523. /* and fe_amidxtaped_options_auth */
  1524. /* We should send a noop to really know */
  1525. req = g_strjoin(NULL, "SERVICE amidxtaped\n",
  1526. "OPTIONS ", "features=", our_features_string, ";",
  1527. "auth=", authopt, ";",
  1528. "\n", NULL);
  1529. protocol_sendreq(tape_server_name, amidxtaped_secdrv,
  1530. generic_client_get_security_conf, req, STARTUP_TIMEOUT,
  1531. amidxtaped_response, &response_error);
  1532. amfree(req);
  1533. protocol_run();
  1534. if(response_error != 0) {
  1535. return -1;
  1536. }
  1537. disk_regex = make_exact_disk_expression(disk_name);
  1538. host_regex = make_exact_host_expression(dump_hostname);
  1539. clean_datestamp = g_strdup(dump_datestamp);
  1540. for(ch=ch1=clean_datestamp;*ch1 != '\0';ch1++) {
  1541. if(*ch1 != '-') {
  1542. *ch = *ch1;
  1543. ch++;
  1544. }
  1545. }
  1546. *ch = '\0';
  1547. /* push our feature list off to the tape server */
  1548. /* XXX assumes that index server and tape server are equivalent, ew */
  1549. if(am_has_feature(indexsrv_features, fe_amidxtaped_exchange_features)){
  1550. g_free(tt);
  1551. tt = g_strconcat("FEATURES=", our_features_string, NULL);
  1552. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1553. get_amidxtaped_line();
  1554. if (!amidxtaped_line) {
  1555. g_fprintf(stderr, _("amrecover - amidxtaped closed the connection\n"));
  1556. stop_amidxtaped();
  1557. amfree(disk_regex);
  1558. amfree(host_regex);
  1559. amfree(clean_datestamp);
  1560. return -1;
  1561. } else if(strncmp_const(amidxtaped_line,"FEATURES=") == 0) {
  1562. tapesrv_features = am_string_to_feature(amidxtaped_line+9);
  1563. } else {
  1564. g_fprintf(stderr, _("amrecover - expecting FEATURES line from amidxtaped\n"));
  1565. stop_amidxtaped();
  1566. amfree(disk_regex);
  1567. amfree(host_regex);
  1568. amfree(clean_datestamp);
  1569. return -1;
  1570. }
  1571. } else {
  1572. *tapesrv_features = *indexsrv_features;
  1573. }
  1574. if(am_has_feature(indexsrv_features, fe_amidxtaped_header) &&
  1575. am_has_feature(indexsrv_features, fe_amidxtaped_device) &&
  1576. am_has_feature(indexsrv_features, fe_amidxtaped_host) &&
  1577. am_has_feature(indexsrv_features, fe_amidxtaped_disk) &&
  1578. am_has_feature(indexsrv_features, fe_amidxtaped_datestamp)) {
  1579. if(am_has_feature(indexsrv_features, fe_amidxtaped_config)) {
  1580. g_free(tt);
  1581. tt = g_strconcat("CONFIG=", get_config_name(), NULL);
  1582. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1583. }
  1584. if(am_has_feature(indexsrv_features, fe_amidxtaped_label) &&
  1585. label && label[0] != '/') {
  1586. g_free(tt);
  1587. tt = g_strconcat("LABEL=", label, NULL);
  1588. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1589. }
  1590. if(am_has_feature(indexsrv_features, fe_amidxtaped_fsf)) {
  1591. char v_fsf[100];
  1592. g_snprintf(v_fsf, 99, "%lld", (long long)fsf);
  1593. g_free(tt);
  1594. tt = g_strconcat("FSF=", v_fsf, NULL);
  1595. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1596. }
  1597. send_to_tape_server(amidxtaped_streams[CTLFD].fd, "HEADER");
  1598. g_free(tt);
  1599. tt = g_strconcat("DEVICE=", dump_device_name, NULL);
  1600. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1601. g_free(tt);
  1602. tt = g_strconcat("HOST=", host_regex, NULL);
  1603. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1604. g_free(tt);
  1605. tt = g_strconcat("DISK=", disk_regex, NULL);
  1606. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1607. g_free(tt);
  1608. tt = g_strconcat("DATESTAMP=", clean_datestamp, NULL);
  1609. send_to_tape_server(amidxtaped_streams[CTLFD].fd, tt);
  1610. send_to_tape_server(amidxtaped_streams[CTLFD].fd, "END");
  1611. amfree(tt);
  1612. }
  1613. else if(am_has_feature(indexsrv_features, fe_amidxtaped_nargs)) {
  1614. /* send to the tape server what tape file we want */
  1615. /* 6 args:
  1616. * "-h"
  1617. * "-p"
  1618. * "tape device"
  1619. * "hostname"
  1620. * "diskname"
  1621. * "datestamp"
  1622. */
  1623. send_to_tape_server(amidxtaped_streams[CTLFD].fd, "6");
  1624. send_to_tape_server(amidxtaped_streams[CTLFD].fd, "-h");
  1625. send_to_tape_server(amidxtaped_streams[CTLFD].fd, "-p");
  1626. send_to_tape_server(amidxtaped_streams[CTLFD].fd, dump_device_name);
  1627. send_to_tape_server(amidxtaped_streams[CTLFD].fd, host_regex);
  1628. send_to_tape_server(amidxtaped_streams[CTLFD].fd, disk_regex);
  1629. send_to_tape_server(amidxtaped_streams[CTLFD].fd, clean_datestamp);
  1630. dbprintf(_("Started amidxtaped with arguments \"6 -h -p %s %s %s %s\"\n"),
  1631. dump_device_name, host_regex, disk_regex, clean_datestamp);
  1632. }
  1633. amfree(disk_regex);
  1634. amfree(host_regex);
  1635. amfree(clean_datestamp);
  1636. return 0;
  1637. }
  1638. /*
  1639. * Reads the first block of a tape file.
  1640. */
  1641. void
  1642. read_file_header(
  1643. char * buffer,
  1644. dumpfile_t *file,
  1645. size_t buflen,
  1646. int tapedev)
  1647. {
  1648. ssize_t bytes_read;
  1649. bytes_read = read_buffer(tapedev, buffer, buflen, READ_TIMEOUT);
  1650. if(bytes_read < 0) {
  1651. error(_("error reading header (%s), check amidxtaped.*.debug on server"),
  1652. strerror(errno));
  1653. /*NOTREACHED*/
  1654. }
  1655. if((size_t)bytes_read < buflen) {
  1656. g_fprintf(stderr, plural(_("%s: short block %d byte\n"),
  1657. _("%s: short block %d bytes\n"), bytes_read),
  1658. get_pname(), (int)bytes_read);
  1659. print_header(stdout, file);
  1660. error(_("Can't read file header"));
  1661. /*NOTREACHED*/
  1662. }
  1663. /* bytes_read == buflen */
  1664. parse_file_header(buffer, file, (size_t)bytes_read);
  1665. }
  1666. enum dumptypes {
  1667. IS_UNKNOWN,
  1668. IS_DUMP,
  1669. IS_GNUTAR,
  1670. IS_TAR,
  1671. IS_SAMBA,
  1672. IS_SAMBA_TAR,
  1673. IS_APPLICATION_API
  1674. };
  1675. static void
  1676. extract_files_child(
  1677. ctl_data_t *ctl_data)
  1678. {
  1679. int save_errno;
  1680. int i;
  1681. guint j;
  1682. GPtrArray *argv_ptr = g_ptr_array_new();
  1683. int files_off_tape;
  1684. EXTRACT_LIST_ITEM *fn;
  1685. enum dumptypes dumptype = IS_UNKNOWN;
  1686. size_t len_program;
  1687. char *cmd = NULL;
  1688. guint passwd_field = 999999999;
  1689. #ifdef SAMBA_CLIENT
  1690. char *domain = NULL, *smbpass = NULL;
  1691. #endif
  1692. /* code executed by child to do extraction */
  1693. /* never returns */
  1694. /* make in_fd be our stdin */
  1695. if (dup2(ctl_data->child_pipe[0], STDIN_FILENO) == -1)
  1696. {
  1697. error(_("dup2 failed in extract_files_child: %s"), strerror(errno));
  1698. /*NOTREACHED*/
  1699. }
  1700. if(ctl_data->file.type != F_DUMPFILE) {
  1701. dump_dumpfile_t(&ctl_data->file);
  1702. error(_("bad header"));
  1703. /*NOTREACHED*/
  1704. }
  1705. if (ctl_data->file.program != NULL) {
  1706. if (g_str_equal(ctl_data->file.program, "APPLICATION"))
  1707. dumptype = IS_APPLICATION_API;
  1708. #ifdef GNUTAR
  1709. if (g_str_equal(ctl_data->file.program, GNUTAR))
  1710. dumptype = IS_GNUTAR;
  1711. #endif
  1712. if (dumptype == IS_UNKNOWN) {
  1713. len_program = strlen(ctl_data->file.program);
  1714. if(len_program >= 3 &&
  1715. g_str_equal(&ctl_data->file.program[len_program - 3], "tar"))
  1716. dumptype = IS_TAR;
  1717. }
  1718. #ifdef SAMBA_CLIENT
  1719. if (dumptype == IS_UNKNOWN && g_str_equal(ctl_data->file.program,
  1720. SAMBA_CLIENT)) {
  1721. if (samba_extract_method == SAMBA_TAR)
  1722. dumptype = IS_SAMBA_TAR;
  1723. else
  1724. dumptype = IS_SAMBA;
  1725. }
  1726. #endif
  1727. }
  1728. /* form the arguments to restore */
  1729. files_off_tape = length_of_tape_list(ctl_data->elist);
  1730. switch(dumptype) {
  1731. case IS_SAMBA:
  1732. #ifdef SAMBA_CLIENT
  1733. g_ptr_array_add(argv_ptr, g_strdup("smbclient"));
  1734. smbpass = findpass(ctl_data->file.disk, &domain);
  1735. if (smbpass) {
  1736. g_ptr_array_add(argv_ptr, g_strdup(ctl_data->file.disk));
  1737. g_ptr_array_add(argv_ptr, g_strdup("-U"));
  1738. passwd_field = argv_ptr->len;
  1739. g_ptr_array_add(argv_ptr, g_strdup(smbpass));
  1740. if (domain) {
  1741. g_ptr_array_add(argv_ptr, g_strdup("-W"));
  1742. g_ptr_array_add(argv_ptr, g_strdup(domain));
  1743. }
  1744. }
  1745. g_ptr_array_add(argv_ptr, g_strdup("-d0"));
  1746. g_ptr_array_add(argv_ptr, g_strdup("-Tx"));
  1747. g_ptr_array_add(argv_ptr, g_strdup("-")); /* data on stdin */
  1748. break;
  1749. #endif
  1750. case IS_TAR:
  1751. case IS_GNUTAR:
  1752. g_ptr_array_add(argv_ptr, g_strdup("tar"));
  1753. /* ignore trailing zero blocks on input (this was the default until tar-1.21) */
  1754. g_ptr_array_add(argv_ptr, g_strdup("--ignore-zeros"));
  1755. g_ptr_array_add(argv_ptr, g_strdup("--numeric-owner"));
  1756. g_ptr_array_add(argv_ptr, g_strdup("-xpGvf"));
  1757. g_ptr_array_add(argv_ptr, g_strdup("-")); /* data on stdin */
  1758. break;
  1759. case IS_SAMBA_TAR:
  1760. g_ptr_array_add(argv_ptr, g_strdup("tar"));
  1761. g_ptr_array_add(argv_ptr, g_strdup("-xpvf"));
  1762. g_ptr_array_add(argv_ptr, g_strdup("-")); /* data on stdin */
  1763. break;
  1764. case IS_UNKNOWN:
  1765. case IS_DUMP:
  1766. g_ptr_array_add(argv_ptr, g_strdup("restore"));
  1767. #ifdef AIX_BACKUP
  1768. g_ptr_array_add(argv_ptr, g_strdup("-xB"));
  1769. #else
  1770. #if defined(XFSDUMP)
  1771. if (g_str_equal(ctl_data->file.program, XFSDUMP)) {
  1772. g_ptr_array_add(argv_ptr, g_strdup("-v"));
  1773. g_ptr_array_add(argv_ptr, g_strdup("silent"));
  1774. } else
  1775. #endif
  1776. #if defined(VDUMP)
  1777. if (g_str_equal(ctl_data->file.program, VDUMP)) {
  1778. g_ptr_array_add(argv_ptr, g_strdup("xf"));
  1779. g_ptr_array_add(argv_ptr, g_strdup("-")); /* data on stdin */
  1780. } else
  1781. #endif
  1782. {
  1783. g_ptr_array_add(argv_ptr, g_strdup("xbf"));
  1784. g_ptr_array_add(argv_ptr, g_strdup("2")); /* read in units of 1K */
  1785. g_ptr_array_add(argv_ptr, g_strdup("-")); /* data on stdin */
  1786. }
  1787. #endif
  1788. break;
  1789. case IS_APPLICATION_API:
  1790. g_ptr_array_add(argv_ptr, g_strdup(ctl_data->file.application));
  1791. g_ptr_array_add(argv_ptr, g_strdup("restore"));
  1792. g_ptr_array_add(argv_ptr, g_strdup("--config"));
  1793. g_ptr_array_add(argv_ptr, g_strdup(get_config_name()));
  1794. g_ptr_array_add(argv_ptr, g_strdup("--disk"));
  1795. g_ptr_array_add(argv_ptr, g_strdup(ctl_data->file.disk));
  1796. if (dump_dle && dump_dle->device) {
  1797. g_ptr_array_add(argv_ptr, g_strdup("--device"));
  1798. g_ptr_array_add(argv_ptr, g_strdup(dump_dle->device));
  1799. }
  1800. if (ctl_data->data_path == DATA_PATH_DIRECTTCP) {
  1801. g_ptr_array_add(argv_ptr, g_strdup("--data-path"));
  1802. g_ptr_array_add(argv_ptr, g_strdup("DIRECTTCP"));
  1803. g_ptr_array_add(argv_ptr, g_strdup("--direct-tcp"));
  1804. g_ptr_array_add(argv_ptr, g_strdup(ctl_data->addrs));
  1805. }
  1806. if (ctl_data->bsu && ctl_data->bsu->smb_recover_mode &&
  1807. samba_extract_method == SAMBA_SMBCLIENT){
  1808. g_ptr_array_add(argv_ptr, g_strdup("--recover-mode"));
  1809. g_ptr_array_add(argv_ptr, g_strdup("smb"));
  1810. }
  1811. g_ptr_array_add(argv_ptr, g_strdup("--level"));
  1812. g_ptr_array_add(argv_ptr, g_strdup_printf("%d", ctl_data->elist->level));
  1813. if (dump_dle) {
  1814. GSList *scriptlist;
  1815. script_t *script;
  1816. merge_properties(dump_dle, NULL, dump_dle->application_property,
  1817. proplist, 0);
  1818. application_property_add_to_argv(argv_ptr, dump_dle, NULL,
  1819. tapesrv_features);
  1820. for (scriptlist = dump_dle->scriptlist; scriptlist != NULL;
  1821. scriptlist = scriptlist->next) {
  1822. script = (script_t *)scriptlist->data;
  1823. if (script->result && script->result->proplist) {
  1824. property_add_to_argv(argv_ptr, script->result->proplist);
  1825. }
  1826. }
  1827. } else if (proplist) {
  1828. property_add_to_argv(argv_ptr, proplist);
  1829. }
  1830. break;
  1831. }
  1832. for (i = 0, fn = ctl_data->elist->files; i < files_off_tape;
  1833. i++, fn = fn->next)
  1834. {
  1835. switch (dumptype) {
  1836. case IS_APPLICATION_API:
  1837. case IS_TAR:
  1838. case IS_GNUTAR:
  1839. case IS_SAMBA_TAR:
  1840. case IS_SAMBA:
  1841. if (g_str_equal(fn->path, "/"))
  1842. g_ptr_array_add(argv_ptr, g_strdup("."));
  1843. else
  1844. g_ptr_array_add(argv_ptr, g_strconcat(".", fn->path, NULL));
  1845. break;
  1846. case IS_UNKNOWN:
  1847. case IS_DUMP:
  1848. #if defined(XFSDUMP)
  1849. if (g_str_equal(ctl_data->file.program, XFSDUMP)) {
  1850. /*
  1851. * xfsrestore needs a -s option before each file to be
  1852. * restored, and also wants them to be relative paths.
  1853. */
  1854. g_ptr_array_add(argv_ptr, g_strdup("-s"));
  1855. g_ptr_array_add(argv_ptr, g_strdup(fn->path + 1));
  1856. } else
  1857. #endif
  1858. {
  1859. g_ptr_array_add(argv_ptr, g_strdup(fn->path));
  1860. }
  1861. break;
  1862. }
  1863. }
  1864. #if defined(XFSDUMP)
  1865. if (g_str_equal(ctl_data->file.program, XFSDUMP)) {
  1866. g_ptr_array_add(argv_ptr, g_strdup("-"));
  1867. g_ptr_array_add(argv_ptr, g_strdup("."));
  1868. }
  1869. #endif
  1870. g_ptr_array_add(argv_ptr, NULL);
  1871. switch (dumptype) {
  1872. case IS_SAMBA:
  1873. #ifdef SAMBA_CLIENT
  1874. cmd = g_strdup(SAMBA_CLIENT);
  1875. break;
  1876. #else
  1877. /* fall through to ... */
  1878. #endif
  1879. case IS_TAR:
  1880. case IS_GNUTAR:
  1881. case IS_SAMBA_TAR:
  1882. #ifndef GNUTAR
  1883. g_fprintf(stderr, _("warning: GNUTAR program not available.\n"));
  1884. cmd = g_strdup("tar");
  1885. #else
  1886. cmd = g_strdup(GNUTAR);
  1887. #endif
  1888. break;
  1889. case IS_UNKNOWN:
  1890. case IS_DUMP:
  1891. cmd = NULL;
  1892. #if defined(DUMP)
  1893. if (g_str_equal(ctl_data->file.program, DUMP)) {
  1894. cmd = g_strdup(RESTORE);
  1895. }
  1896. #endif
  1897. #if defined(VDUMP)
  1898. if (g_str_equal(ctl_data->file.program, VDUMP)) {
  1899. cmd = g_strdup(VRESTORE);
  1900. }
  1901. #endif
  1902. #if defined(VXDUMP)
  1903. if (g_str_equal(ctl_data->file.program, VXDUMP)) {
  1904. cmd = g_strdup(VXRESTORE);
  1905. }
  1906. #endif
  1907. #if defined(XFSDUMP)
  1908. if (g_str_equal(ctl_data->file.program, XFSDUMP)) {
  1909. cmd = g_strdup(XFSRESTORE);
  1910. }
  1911. #endif
  1912. if (cmd == NULL) {
  1913. g_fprintf(stderr, _("warning: restore program for %s not available.\n"),
  1914. ctl_data->file.program);
  1915. cmd = g_strdup("restore");
  1916. }
  1917. break;
  1918. case IS_APPLICATION_API:
  1919. cmd = g_strjoin(NULL, APPLICATION_DIR, "/", ctl_data->file.application, NULL);
  1920. break;
  1921. }
  1922. if (cmd) {
  1923. dbprintf(_("Exec'ing %s with arguments:\n"), cmd);
  1924. for (j = 0; j < argv_ptr->len - 1; j++) {
  1925. if (j == passwd_field)
  1926. dbprintf("\tXXXXX\n");
  1927. else
  1928. dbprintf(_("\t%s\n"), (char *)g_ptr_array_index(argv_ptr, j));
  1929. }
  1930. safe_fd(-1, 0);
  1931. (void)execv(cmd, (char **)argv_ptr->pdata);
  1932. /* only get here if exec failed */
  1933. save_errno = errno;
  1934. g_ptr_array_free_full(argv_ptr);
  1935. errno = save_errno;
  1936. perror(_("amrecover couldn't exec"));
  1937. g_fprintf(stderr, _(" problem executing %s\n"), cmd);
  1938. amfree(cmd);
  1939. }
  1940. exit(1);
  1941. /*NOT REACHED */
  1942. }
  1943. /*
  1944. * Interpose something between the process writing out the dump (writing it to
  1945. * some extraction program, really) and the socket from which we're reading, so
  1946. * that we can do things like prompt for human interaction for multiple tapes.
  1947. */
  1948. int
  1949. writer_intermediary(
  1950. EXTRACT_LIST * elist)
  1951. {
  1952. ctl_data_t ctl_data;
  1953. amwait_t extractor_status;
  1954. ctl_data.header_done = 0;
  1955. ctl_data.child_pipe[0] = -1;
  1956. ctl_data.child_pipe[1] = -1;
  1957. ctl_data.pid = -1;
  1958. ctl_data.elist = elist;
  1959. fh_init(&ctl_data.file);
  1960. ctl_data.data_path = DATA_PATH_AMANDA;
  1961. ctl_data.addrs = NULL;
  1962. ctl_data.bsu = NULL;
  1963. ctl_data.bytes_read = 0;
  1964. header_size = 0;
  1965. security_stream_read(amidxtaped_streams[DATAFD].fd,
  1966. read_amidxtaped_data, &ctl_data);
  1967. while(get_amidxtaped_line() >= 0) {
  1968. char desired_tape[MAX_TAPE_LABEL_BUF];
  1969. g_debug("get amidxtaped line: %s", amidxtaped_line);
  1970. /* if prompted for a tape, relay said prompt to the user */
  1971. if(sscanf(amidxtaped_line, "FEEDME %132s\n", desired_tape) == 1) {
  1972. int done;
  1973. g_printf(_("Load tape %s now\n"), desired_tape);
  1974. dbprintf(_("Requesting tape %s from user\n"), desired_tape);
  1975. done = okay_to_continue(am_has_feature(indexsrv_features,
  1976. fe_amrecover_feedme_tape),
  1977. 0, 0);
  1978. if (done == 1) {
  1979. if (am_has_feature(indexsrv_features,
  1980. fe_amrecover_feedme_tape)) {
  1981. char *reply = g_strconcat("TAPE ", tape_device_name, NULL);
  1982. send_to_tape_server(amidxtaped_streams[CTLFD].fd, reply);
  1983. amfree(reply);
  1984. } else {
  1985. send_to_tape_server(amidxtaped_streams[CTLFD].fd, "OK");
  1986. }
  1987. } else {
  1988. send_to_tape_server(amidxtaped_streams[CTLFD].fd, "ERROR");
  1989. break;
  1990. }
  1991. } else if (strncmp_const(amidxtaped_line, "USE-DATAPATH ") == 0) {
  1992. if (strncmp_const(amidxtaped_line+13, "AMANDA") == 0) {
  1993. ctl_data.data_path = DATA_PATH_AMANDA;
  1994. g_debug("Using AMANDA data-path");
  1995. } else if (strncmp_const(amidxtaped_line+13, "DIRECT-TCP") == 0) {
  1996. ctl_data.data_path = DATA_PATH_DIRECTTCP;
  1997. ctl_data.addrs = g_strdup(amidxtaped_line+24);
  1998. g_debug("Using DIRECT-TCP data-path with %s", ctl_data.addrs);
  1999. }
  2000. start_processing_data(&ctl_data);
  2001. } else if(strncmp_const(amidxtaped_line, "MESSAGE ") == 0) {
  2002. g_printf("%s\n",&amidxtaped_line[8]);
  2003. } else {
  2004. g_fprintf(stderr, _("Strange message from tape server: %s"),
  2005. amidxtaped_line);
  2006. break;
  2007. }
  2008. }
  2009. /* CTL might be close before DATA */
  2010. event_loop(0);
  2011. dumpfile_free_data(&ctl_data.file);
  2012. amfree(ctl_data.addrs);
  2013. amfree(ctl_data.bsu);
  2014. if (ctl_data.child_pipe[1] != -1)
  2015. aclose(ctl_data.child_pipe[1]);
  2016. if (ctl_data.header_done == 0) {
  2017. g_printf(_("Got no header and data from server, check in amidxtaped.*.debug and amandad.*.debug files on server\n"));
  2018. }
  2019. if (ctl_data.pid != -1) {
  2020. waitpid(ctl_data.pid, &extractor_status, 0);
  2021. if(WEXITSTATUS(extractor_status) != 0){
  2022. int ret = WEXITSTATUS(extractor_status);
  2023. if(ret == 255) ret = -1;
  2024. g_printf(_("Extractor child exited with status %d\n"), ret);
  2025. return -1;
  2026. }
  2027. }
  2028. g_debug("bytes read: %jd", (intmax_t)ctl_data.bytes_read);
  2029. return(0);
  2030. }
  2031. /* exec restore to do the actual restoration */
  2032. /* does the actual extraction of files */
  2033. /*
  2034. * The original design had the dump image being returned exactly as it
  2035. * appears on the tape, and this routine getting from the index server
  2036. * whether or not it is compressed, on the assumption that the tape
  2037. * server may not know how to uncompress it. But
  2038. * - Amrestore can't do that. It returns either compressed or uncompressed
  2039. * (always). Amrestore assumes it can uncompress files. It is thus a good
  2040. * idea to run the tape server on a machine with gzip.
  2041. * - The information about compression in the disklist is really only
  2042. * for future dumps. It is possible to change compression on a drive
  2043. * so the information in the disklist may not necessarily relate to
  2044. * the dump image on the tape.
  2045. * Consequently the design was changed to assuming that amrestore can
  2046. * uncompress any dump image and have it return an uncompressed file
  2047. * always.
  2048. */
  2049. void
  2050. extract_files(void)
  2051. {
  2052. EXTRACT_LIST *elist;
  2053. char *l;
  2054. int first;
  2055. int otc;
  2056. tapelist_t *tlist = NULL, *a_tlist;
  2057. g_option_t g_options;
  2058. levellist_t all_level = NULL;
  2059. int last_level;
  2060. if (!is_extract_list_nonempty())
  2061. {
  2062. g_printf(_("Extract list empty - No files to extract!\n"));
  2063. return;
  2064. }
  2065. clean_extract_list();
  2066. /* get tape device name from index server if none specified */
  2067. if (tape_server_name == NULL) {
  2068. g_free(tape_server_name);
  2069. tape_server_name = g_strdup(server_name);
  2070. }
  2071. if (tape_device_name == NULL) {
  2072. if (send_command("TAPE") == -1)
  2073. exit(1);
  2074. if (get_reply_line() == -1)
  2075. exit(1);
  2076. l = reply_line();
  2077. if (!server_happy())
  2078. {
  2079. g_printf("%s\n", l);
  2080. exit(1);
  2081. }
  2082. /* skip reply number */
  2083. g_free(tape_device_name);
  2084. tape_device_name = g_strdup(l + 4);
  2085. }
  2086. if (g_str_equal(tape_device_name, "/dev/null"))
  2087. {
  2088. g_printf(_("amrecover: warning: using %s as the tape device will not work\n"),
  2089. tape_device_name);
  2090. }
  2091. first=1;
  2092. for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist)) {
  2093. if(elist->tape[0]!='/') {
  2094. if(first) {
  2095. g_printf(_("\nExtracting files using tape drive %s on host %s.\n"),
  2096. tape_device_name, tape_server_name);
  2097. g_printf(_("The following tapes are needed:"));
  2098. first=0;
  2099. }
  2100. else
  2101. g_printf(" ");
  2102. tlist = unmarshal_tapelist_str(elist->tape);
  2103. for(a_tlist = tlist ; a_tlist != NULL; a_tlist = a_tlist->next)
  2104. g_printf(" %s", a_tlist->label);
  2105. g_printf("\n");
  2106. free_tapelist(tlist);
  2107. }
  2108. }
  2109. first=1;
  2110. for (elist = first_tape_list(); elist != NULL; elist = next_tape_list(elist)) {
  2111. if(elist->tape[0]=='/') {
  2112. if(first) {
  2113. g_printf(_("\nExtracting files from holding disk on host %s.\n"),
  2114. tape_server_name);
  2115. g_printf(_("The following files are needed:"));
  2116. first=0;
  2117. }
  2118. else
  2119. g_printf(" ");
  2120. tlist = unmarshal_tapelist_str(elist->tape);
  2121. for(a_tlist = tlist; a_tlist != NULL; a_tlist = a_tlist->next)
  2122. g_printf(" %s", a_tlist->label);
  2123. g_printf("\n");
  2124. free_tapelist(tlist);
  2125. }
  2126. }
  2127. g_printf("\n");
  2128. g_options.config = get_config_name();
  2129. g_options.hostname = dump_hostname;
  2130. for (elist = first_tape_list(); elist != NULL;
  2131. elist = next_tape_list(elist)) {
  2132. am_level_t *level = g_new0(am_level_t, 1);
  2133. level->level = elist->level;
  2134. all_level = g_slist_append(all_level, level);
  2135. }
  2136. if (dump_dle) {
  2137. slist_free_full(dump_dle->levellist, g_free);
  2138. dump_dle->levellist = all_level;
  2139. run_client_scripts(EXECUTE_ON_PRE_RECOVER, &g_options, dump_dle,
  2140. stderr);
  2141. dump_dle->levellist = NULL;
  2142. }
  2143. last_level = -1;
  2144. while ((elist = first_tape_list()) != NULL)
  2145. {
  2146. if(elist->tape[0]=='/') {
  2147. g_free(dump_device_name);
  2148. dump_device_name = g_strdup(elist->tape);
  2149. g_printf(_("Extracting from file "));
  2150. tlist = unmarshal_tapelist_str(dump_device_name);
  2151. for(a_tlist = tlist; a_tlist != NULL; a_tlist = a_tlist->next)
  2152. g_printf(" %s", a_tlist->label);
  2153. g_printf("\n");
  2154. free_tapelist(tlist);
  2155. }
  2156. else {
  2157. g_printf(_("Extracting files using tape drive %s on host %s.\n"),
  2158. tape_device_name, tape_server_name);
  2159. tlist = unmarshal_tapelist_str(elist->tape);
  2160. g_printf(_("Load tape %s now\n"), tlist->label);
  2161. dbprintf(_("Requesting tape %s from user\n"), tlist->label);
  2162. free_tapelist(tlist);
  2163. otc = okay_to_continue(1,1,0);
  2164. if (otc == 0)
  2165. return;
  2166. else if (otc == SKIP_TAPE) {
  2167. delete_tape_list(elist); /* skip this tape */
  2168. continue;
  2169. }
  2170. g_free(dump_device_name);
  2171. dump_device_name = g_strdup(tape_device_name);
  2172. }
  2173. g_free(dump_datestamp);
  2174. dump_datestamp = g_strdup(elist->date);
  2175. if (last_level != -1 && dump_dle) {
  2176. am_level_t *level;
  2177. level = g_new0(am_level_t, 1);
  2178. level->level = last_level;
  2179. dump_dle->levellist = g_slist_append(dump_dle->levellist, level);
  2180. level = g_new0(am_level_t, 1);
  2181. level->level = elist->level;
  2182. dump_dle->levellist = g_slist_append(dump_dle->levellist, level);
  2183. run_client_scripts(EXECUTE_ON_INTER_LEVEL_RECOVER, &g_options,
  2184. dump_dle, stderr);
  2185. slist_free_full(dump_dle->levellist, g_free);
  2186. dump_dle->levellist = NULL;
  2187. }
  2188. /* connect to the tape handler daemon on the tape drive server */
  2189. if ((extract_files_setup(elist->tape, elist->fileno)) == -1)
  2190. {
  2191. g_fprintf(stderr, _("amrecover - can't talk to tape server: %s\n"),
  2192. errstr);
  2193. return;
  2194. }
  2195. if (dump_dle) {
  2196. am_level_t *level;
  2197. level = g_new0(am_level_t, 1);
  2198. level->level = elist->level;
  2199. dump_dle->levellist = g_slist_append(dump_dle->levellist, level);
  2200. run_client_scripts(EXECUTE_ON_PRE_LEVEL_RECOVER, &g_options,
  2201. dump_dle, stderr);
  2202. }
  2203. last_level = elist->level;
  2204. /* if the server have fe_amrecover_feedme_tape, it has asked for
  2205. * the tape itself, even if the restore didn't succeed, we should
  2206. * remove it.
  2207. */
  2208. if(writer_intermediary(elist) == 0 ||
  2209. am_has_feature(indexsrv_features, fe_amrecover_feedme_tape))
  2210. delete_tape_list(elist); /* tape done so delete from list */
  2211. am_release_feature_set(tapesrv_features);
  2212. stop_amidxtaped();
  2213. if (dump_dle) {
  2214. run_client_scripts(EXECUTE_ON_POST_LEVEL_RECOVER, &g_options,
  2215. dump_dle, stderr);
  2216. slist_free_full(dump_dle->levellist, g_free);
  2217. dump_dle->levellist = NULL;
  2218. }
  2219. }
  2220. if (dump_dle) {
  2221. dump_dle->levellist = all_level;
  2222. run_client_scripts(EXECUTE_ON_POST_RECOVER, &g_options, dump_dle,
  2223. stderr);
  2224. slist_free_full(dump_dle->levellist, g_free);
  2225. all_level = NULL;
  2226. dump_dle->levellist = NULL;
  2227. }
  2228. }
  2229. static void
  2230. amidxtaped_response(
  2231. void * datap,
  2232. pkt_t * pkt,
  2233. security_handle_t * sech)
  2234. {
  2235. int ports[NSTREAMS], *response_error = datap;
  2236. guint i;
  2237. char *p;
  2238. char *tok;
  2239. char *extra = NULL;
  2240. assert(response_error != NULL);
  2241. assert(sech != NULL);
  2242. memset(ports, -1, sizeof(ports));
  2243. if (pkt == NULL) {
  2244. g_free(errstr);
  2245. errstr = g_strdup_printf(_("[request failed: %s]"),
  2246. security_geterror(sech));
  2247. *response_error = 1;
  2248. return;
  2249. }
  2250. security_close_connection(sech, dump_hostname);
  2251. if (pkt->type == P_NAK) {
  2252. #if defined(PACKET_DEBUG)
  2253. g_fprintf(stderr, _("got nak response:\n----\n%s\n----\n\n"), pkt->body);
  2254. #endif
  2255. tok = strtok(pkt->body, " ");
  2256. if (tok ==