PageRenderTime 53ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/amanda/tags/amanda252p1/recover-src/extract_list.c

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

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