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

/amanda/tags/3_1_0_mac01/recover-src/extract_list.c

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

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