PageRenderTime 70ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

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

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

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