PageRenderTime 71ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

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

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

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