PageRenderTime 51ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

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

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

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