PageRenderTime 58ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

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

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

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