PageRenderTime 70ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/amanda/tags/amanda252p1/client-src/sendsize.c

#
C | 2398 lines | 2038 code | 229 blank | 131 comment | 469 complexity | 9d96a8208e37e351f3cdaab65ea1ba16 MD5 | raw file
  1. /*
  2. * Amanda, The Advanced Maryland Automatic Network Disk Archiver
  3. * Copyright (c) 1991-1998 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: sendsize.c,v 1.171 2006/08/24 01:57:15 paddy_s Exp $
  28. *
  29. * send estimated backup sizes using dump
  30. */
  31. #include "amanda.h"
  32. #include "pipespawn.h"
  33. #include "amfeatures.h"
  34. #include "amandates.h"
  35. #include "clock.h"
  36. #include "util.h"
  37. #include "getfsent.h"
  38. #include "version.h"
  39. #include "client_util.h"
  40. #include "conffile.h"
  41. #include "amandad.h"
  42. #ifdef SAMBA_CLIENT
  43. #include "findpass.h"
  44. #endif
  45. #define sendsize_debug(i,x) do { \
  46. if ((i) <= debug_sebdsize) { \
  47. dbprintf(x); \
  48. } \
  49. } while (0)
  50. #ifdef HAVE_SETPGID
  51. # define SETPGRP setpgid(getpid(), getpid())
  52. # define SETPGRP_FAILED() do { \
  53. dbprintf(("setpgid(%ld,%ld) failed: %s\n", \
  54. (long)getpid(), (long)getpid(), strerror(errno))); \
  55. } while(0)
  56. #else /* () line 0 */
  57. #if defined(SETPGRP_VOID)
  58. # define SETPGRP setpgrp()
  59. # define SETPGRP_FAILED() do { \
  60. dbprintf(("setpgrp() failed: %s\n", strerror(errno))); \
  61. } while(0)
  62. #else
  63. # define SETPGRP setpgrp(0, getpid())
  64. # define SETPGRP_FAILED() do { \
  65. dbprintf(("setpgrp(0,%ld) failed: %s\n", \
  66. (long)getpid(), strerror(errno))); \
  67. } while(0)
  68. #endif
  69. #endif
  70. typedef struct level_estimates_s {
  71. time_t dumpsince;
  72. int estsize;
  73. int needestimate;
  74. } level_estimate_t;
  75. typedef struct disk_estimates_s {
  76. struct disk_estimates_s *next;
  77. char *amname;
  78. char *qamname;
  79. char *amdevice;
  80. char *qamdevice;
  81. char *dirname;
  82. char *qdirname;
  83. char *program;
  84. char *calcprog;
  85. int program_is_backup_api;
  86. int spindle;
  87. pid_t child;
  88. int done;
  89. option_t *options;
  90. level_estimate_t est[DUMP_LEVELS];
  91. } disk_estimates_t;
  92. disk_estimates_t *est_list;
  93. static am_feature_t *our_features = NULL;
  94. static char *our_feature_string = NULL;
  95. static g_option_t *g_options = NULL;
  96. /* local functions */
  97. int main(int argc, char **argv);
  98. void add_diskest(char *disk, char *amdevice, int level, int spindle,
  99. int program_is_backup_api, char *prog, char *calcprog,
  100. option_t *options);
  101. void calc_estimates(disk_estimates_t *est);
  102. void free_estimates(disk_estimates_t *est);
  103. void dump_calc_estimates(disk_estimates_t *);
  104. void star_calc_estimates(disk_estimates_t *);
  105. void smbtar_calc_estimates(disk_estimates_t *);
  106. void gnutar_calc_estimates(disk_estimates_t *);
  107. void backup_api_calc_estimate(disk_estimates_t *);
  108. void generic_calc_estimates(disk_estimates_t *);
  109. int
  110. main(
  111. int argc,
  112. char ** argv)
  113. {
  114. int level, spindle;
  115. char *prog, *calcprog, *dumpdate;
  116. option_t *options = NULL;
  117. int program_is_backup_api;
  118. disk_estimates_t *est;
  119. disk_estimates_t *est1;
  120. disk_estimates_t *est_prev;
  121. char *line = NULL;
  122. char *s, *fp;
  123. int ch;
  124. char *err_extra = NULL;
  125. int done;
  126. int need_wait;
  127. int dumpsrunning;
  128. char *disk = NULL;
  129. char *qdisk = NULL;
  130. char *qlist = NULL;
  131. char *amdevice = NULL;
  132. char *qamdevice = NULL;
  133. char *conffile;
  134. char *amandates_file;
  135. int amandates_read = 0;
  136. #if defined(USE_DBMALLOC)
  137. unsigned long malloc_hist_1, malloc_size_1;
  138. unsigned long malloc_hist_2, malloc_size_2;
  139. #endif
  140. (void)argc; /* Quiet unused parameter warning */
  141. (void)argv; /* Quiet unused parameter warning */
  142. /* initialize */
  143. safe_fd(-1, 0);
  144. safe_cd();
  145. set_pname("sendsize");
  146. /* Don't die when child closes pipe */
  147. signal(SIGPIPE, SIG_IGN);
  148. #if defined(USE_DBMALLOC)
  149. malloc_size_1 = malloc_inuse(&malloc_hist_1);
  150. #endif
  151. erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
  152. dbopen(DBG_SUBDIR_CLIENT);
  153. startclock();
  154. dbprintf(("%s: version %s\n", get_pname(), version()));
  155. our_features = am_init_feature_set();
  156. our_feature_string = am_feature_to_string(our_features);
  157. set_debug_prefix_pid(getpid());
  158. conffile = vstralloc(CONFIG_DIR, "/", "amanda-client.conf", NULL);
  159. if (read_clientconf(conffile) > 0) {
  160. error("error reading conffile: %s", conffile);
  161. /*NOTREACHED*/
  162. }
  163. amfree(conffile);
  164. /* handle all service requests */
  165. for(; (line = agets(stdin)) != NULL; free(line)) {
  166. if (line[0] == '\0')
  167. continue;
  168. if(strncmp_const(line, "OPTIONS ") == 0) {
  169. g_options = parse_g_options(line+8, 1);
  170. if(!g_options->hostname) {
  171. g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
  172. gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH);
  173. g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0';
  174. }
  175. printf("OPTIONS ");
  176. if(am_has_feature(g_options->features, fe_rep_options_features)) {
  177. printf("features=%s;", our_feature_string);
  178. }
  179. if(am_has_feature(g_options->features, fe_rep_options_maxdumps)) {
  180. printf("maxdumps=%d;", g_options->maxdumps);
  181. }
  182. if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
  183. printf("hostname=%s;", g_options->hostname);
  184. }
  185. printf("\n");
  186. fflush(stdout);
  187. if (g_options->config) {
  188. conffile = vstralloc(CONFIG_DIR, "/", g_options->config, "/",
  189. "amanda-client.conf", NULL);
  190. if (read_clientconf(conffile) > 0) {
  191. error("error reading conffile: %s", conffile);
  192. /*NOTREACHED*/
  193. }
  194. amfree(conffile);
  195. dbrename(g_options->config, DBG_SUBDIR_CLIENT);
  196. }
  197. continue;
  198. }
  199. if (amandates_read == 0) {
  200. amandates_file = getconf_str(CNF_AMANDATES);
  201. if(!start_amandates(amandates_file, 0))
  202. error("error [opening %s: %s]", amandates_file,
  203. strerror(errno));
  204. amandates_read = 1;
  205. }
  206. s = line;
  207. ch = *s++;
  208. skip_whitespace(s, ch); /* find the program name */
  209. if(ch == '\0') {
  210. err_extra = stralloc("no program name");
  211. goto err; /* no program name */
  212. }
  213. prog = s - 1;
  214. skip_non_whitespace(s, ch);
  215. s[-1] = '\0';
  216. program_is_backup_api=0;
  217. if(strncmp_const(prog, "CALCSIZE") == 0) {
  218. skip_whitespace(s, ch); /* find the program name */
  219. if(ch == '\0') {
  220. err_extra = stralloc("no program name");
  221. goto err;
  222. }
  223. calcprog = s - 1;
  224. skip_non_whitespace(s, ch);
  225. s[-1] = '\0';
  226. if (strcmp(calcprog,"BACKUP") == 0) {
  227. program_is_backup_api=1;
  228. skip_whitespace(s, ch); /* find dumper name */
  229. if (ch == '\0') {
  230. goto err; /* no program */
  231. }
  232. calcprog = s - 1;
  233. skip_non_whitespace(s, ch);
  234. s[-1] = '\0';
  235. }
  236. }
  237. else {
  238. calcprog = NULL;
  239. if (strcmp(prog,"BACKUP") == 0) {
  240. program_is_backup_api=1;
  241. skip_whitespace(s, ch); /* find dumper name */
  242. if (ch == '\0') {
  243. goto err; /* no program */
  244. }
  245. prog = s - 1;
  246. skip_non_whitespace(s, ch);
  247. s[-1] = '\0';
  248. }
  249. }
  250. skip_whitespace(s, ch); /* find the disk name */
  251. if(ch == '\0') {
  252. err_extra = stralloc("no disk name");
  253. goto err; /* no disk name */
  254. }
  255. if (qdisk != NULL)
  256. amfree(qdisk);
  257. if (disk != NULL)
  258. amfree(disk);
  259. fp = s - 1;
  260. skip_quoted_string(s, ch);
  261. s[-1] = '\0'; /* terminate the disk name */
  262. qdisk = stralloc(fp);
  263. disk = unquote_string(qdisk);
  264. skip_whitespace(s, ch); /* find the device or level */
  265. if (ch == '\0') {
  266. err_extra = stralloc("bad level");
  267. goto err;
  268. }
  269. if(!isdigit((int)s[-1])) {
  270. fp = s - 1;
  271. skip_quoted_string(s, ch);
  272. s[-1] = '\0';
  273. qamdevice = stralloc(fp);
  274. amdevice = unquote_string(qamdevice);
  275. skip_whitespace(s, ch); /* find level number */
  276. }
  277. else {
  278. amdevice = stralloc(disk);
  279. qamdevice = stralloc(qdisk);
  280. }
  281. /* find the level number */
  282. if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
  283. err_extra = stralloc("bad level");
  284. goto err; /* bad level */
  285. }
  286. if (level < 0 || level >= DUMP_LEVELS) {
  287. err_extra = stralloc("bad level");
  288. goto err;
  289. }
  290. skip_integer(s, ch);
  291. skip_whitespace(s, ch); /* find the dump date */
  292. if(ch == '\0') {
  293. err_extra = stralloc("no dumpdate");
  294. goto err; /* no dumpdate */
  295. }
  296. dumpdate = s - 1;
  297. skip_non_whitespace(s, ch);
  298. s[-1] = '\0';
  299. (void)dumpdate; /* XXX: Set but not used */
  300. spindle = 0; /* default spindle */
  301. skip_whitespace(s, ch); /* find the spindle */
  302. if(ch != '\0') {
  303. if(sscanf(s - 1, "%d", &spindle) != 1) {
  304. err_extra = stralloc("bad spindle");
  305. goto err; /* bad spindle */
  306. }
  307. skip_integer(s, ch);
  308. skip_whitespace(s, ch); /* find the parameters */
  309. if(ch != '\0') {
  310. if(strncmp_const(s-1, "OPTIONS |;") == 0) {
  311. options = parse_options(s + 8,
  312. disk,
  313. amdevice,
  314. g_options->features,
  315. 0);
  316. }
  317. else {
  318. options = alloc(SIZEOF(option_t));
  319. init_options(options);
  320. while (ch != '\0') {
  321. if(strncmp_const(s-1, "exclude-file=") == 0) {
  322. qlist = unquote_string(s+12);
  323. options->exclude_file =
  324. append_sl(options->exclude_file, qlist);
  325. amfree(qlist);
  326. } else if(strncmp_const(s-1, "exclude-list=") == 0) {
  327. qlist = unquote_string(s+12);
  328. options->exclude_list =
  329. append_sl(options->exclude_list, qlist);
  330. amfree(qlist);
  331. } else if(strncmp_const(s-1, "include-file=") == 0) {
  332. qlist = unquote_string(s+12);
  333. options->include_file =
  334. append_sl(options->include_file, qlist);
  335. amfree(qlist);
  336. } else if(strncmp_const(s-1, "include-list=") == 0) {
  337. qlist = unquote_string(s+12);
  338. options->include_list =
  339. append_sl(options->include_list, qlist);
  340. amfree(qlist);
  341. } else {
  342. err_extra = vstralloc("Invalid parameter (",
  343. s-1, ")", NULL);
  344. goto err; /* should have gotten to end */
  345. }
  346. skip_quoted_string(s, ch);
  347. skip_whitespace(s, ch); /* find the inclusion list */
  348. amfree(qlist);
  349. }
  350. }
  351. }
  352. else {
  353. options = alloc(SIZEOF(option_t));
  354. init_options(options);
  355. }
  356. }
  357. else {
  358. options = alloc(SIZEOF(option_t));
  359. init_options(options);
  360. }
  361. /*@ignore@*/
  362. add_diskest(disk, amdevice, level, spindle, program_is_backup_api, prog, calcprog, options);
  363. /*@end@*/
  364. amfree(disk);
  365. amfree(qdisk);
  366. amfree(amdevice);
  367. amfree(qamdevice);
  368. }
  369. if (g_options == NULL) {
  370. error("Missing OPTIONS line in sendsize input\n");
  371. /*NOTREACHED*/
  372. }
  373. amfree(line);
  374. finish_amandates();
  375. free_amandates();
  376. dumpsrunning = 0;
  377. need_wait = 0;
  378. done = 0;
  379. while(! done) {
  380. done = 1;
  381. /*
  382. * See if we need to wait for a child before we can do anything
  383. * else in this pass.
  384. */
  385. if(need_wait) {
  386. pid_t child_pid;
  387. amwait_t child_status;
  388. int exit_code;
  389. need_wait = 0;
  390. dbprintf(("%s: waiting for any estimate child: %d running\n",
  391. debug_prefix_time(NULL), dumpsrunning));
  392. child_pid = wait(&child_status);
  393. if(child_pid == -1) {
  394. error("wait failed: %s", strerror(errno));
  395. /*NOTREACHED*/
  396. }
  397. if(WIFSIGNALED(child_status)) {
  398. dbprintf(("%s: child %ld terminated with signal %d\n",
  399. debug_prefix_time(NULL),
  400. (long) child_pid, WTERMSIG(child_status)));
  401. } else {
  402. exit_code = WEXITSTATUS(child_status);
  403. if(exit_code == 0) {
  404. dbprintf(("%s: child %ld terminated normally\n",
  405. debug_prefix_time(NULL), (long) child_pid));
  406. } else {
  407. dbprintf(("%s: child %ld terminated with code %d\n",
  408. debug_prefix_time(NULL),
  409. (long) child_pid, exit_code));
  410. }
  411. }
  412. /*
  413. * Find the child and mark it done.
  414. */
  415. for(est = est_list; est != NULL; est = est->next) {
  416. if(est->child == child_pid) {
  417. break;
  418. }
  419. }
  420. if(est == NULL) {
  421. dbprintf(("%s: unexpected child %ld\n",
  422. debug_prefix_time(NULL), (long)child_pid));
  423. } else {
  424. est->done = 1;
  425. est->child = 0;
  426. dumpsrunning--;
  427. }
  428. }
  429. /*
  430. * If we are already running the maximum number of children
  431. * go back and wait until one of them finishes.
  432. */
  433. if(dumpsrunning >= g_options->maxdumps) {
  434. done = 0;
  435. need_wait = 1;
  436. continue; /* have to wait first */
  437. }
  438. /*
  439. * Find a new child to start.
  440. */
  441. for(est = est_list; est != NULL; est = est->next) {
  442. if(est->done == 0) {
  443. done = 0; /* more to do */
  444. }
  445. if(est->child != 0 || est->done) {
  446. continue; /* child is running or done */
  447. }
  448. /*
  449. * Make sure there is no spindle conflict.
  450. */
  451. if(est->spindle != -1) {
  452. for(est1 = est_list; est1 != NULL; est1 = est1->next) {
  453. if(est1->child == 0 || est == est1 || est1->done) {
  454. /*
  455. * Ignore anything not yet started, ourself,
  456. * and anything completed.
  457. */
  458. continue;
  459. }
  460. if(est1->spindle == est->spindle) {
  461. break; /* oops -- they match */
  462. }
  463. }
  464. if(est1 != NULL) {
  465. continue; /* spindle conflict */
  466. }
  467. }
  468. break; /* start this estimate */
  469. }
  470. if(est == NULL) {
  471. if(dumpsrunning > 0) {
  472. need_wait = 1; /* nothing to do but wait */
  473. }
  474. } else {
  475. done = 0;
  476. if((est->child = fork()) == 0) {
  477. set_debug_prefix_pid(getpid());
  478. calc_estimates(est); /* child does the estimate */
  479. exit(0);
  480. } else if(est->child == -1) {
  481. error("calc_estimates fork failed: %s", strerror(errno));
  482. /*NOTREACHED*/
  483. }
  484. dumpsrunning++; /* parent */
  485. }
  486. }
  487. est_prev = NULL;
  488. for(est = est_list; est != NULL; est = est->next) {
  489. free_estimates(est);
  490. amfree(est_prev);
  491. est_prev = est;
  492. }
  493. amfree(est_prev);
  494. amfree(our_feature_string);
  495. am_release_feature_set(our_features);
  496. our_features = NULL;
  497. am_release_feature_set(g_options->features);
  498. g_options->features = NULL;
  499. amfree(g_options->hostname);
  500. amfree(g_options->str);
  501. amfree(g_options);
  502. #if defined(USE_DBMALLOC)
  503. malloc_size_2 = malloc_inuse(&malloc_hist_2);
  504. if(malloc_size_1 != malloc_size_2) {
  505. malloc_list(dbfd(), malloc_hist_1, malloc_hist_2);
  506. }
  507. #endif
  508. dbclose();
  509. return 0;
  510. err:
  511. printf("FORMAT ERROR IN REQUEST PACKET\n");
  512. dbprintf(("%s: REQ packet is bogus%s%s\n",
  513. debug_prefix_time(NULL),
  514. err_extra ? ": " : "",
  515. err_extra ? err_extra : ""));
  516. amfree(err_extra);
  517. dbclose();
  518. return 1;
  519. }
  520. void
  521. add_diskest(
  522. char * disk,
  523. char * amdevice,
  524. int level,
  525. int spindle,
  526. int program_is_backup_api,
  527. char * prog,
  528. char * calcprog,
  529. option_t * options)
  530. {
  531. disk_estimates_t *newp, *curp;
  532. amandates_t *amdp;
  533. int dumplev, estlev;
  534. time_t dumpdate;
  535. if (level < 0)
  536. level = 0;
  537. if (level >= DUMP_LEVELS)
  538. level = DUMP_LEVELS - 1;
  539. for(curp = est_list; curp != NULL; curp = curp->next) {
  540. if(strcmp(curp->amname, disk) == 0) {
  541. /* already have disk info, just note the level request */
  542. curp->est[level].needestimate = 1;
  543. if(options) {
  544. free_sl(options->exclude_file);
  545. free_sl(options->exclude_list);
  546. free_sl(options->include_file);
  547. free_sl(options->include_list);
  548. amfree(options->auth);
  549. amfree(options->str);
  550. amfree(options);
  551. }
  552. return;
  553. }
  554. }
  555. newp = (disk_estimates_t *) alloc(SIZEOF(disk_estimates_t));
  556. memset(newp, 0, SIZEOF(*newp));
  557. newp->next = est_list;
  558. est_list = newp;
  559. newp->amname = stralloc(disk);
  560. newp->qamname = quote_string(disk);
  561. newp->amdevice = stralloc(amdevice);
  562. newp->qamdevice = quote_string(amdevice);
  563. newp->dirname = amname_to_dirname(newp->amdevice);
  564. newp->qdirname = quote_string(newp->dirname);
  565. newp->program = stralloc(prog);
  566. if(calcprog != NULL)
  567. newp->calcprog = stralloc(calcprog);
  568. else
  569. newp->calcprog = NULL;
  570. newp->program_is_backup_api = program_is_backup_api;
  571. newp->spindle = spindle;
  572. newp->est[level].needestimate = 1;
  573. newp->options = options;
  574. /* fill in dump-since dates */
  575. amdp = amandates_lookup(newp->amname);
  576. newp->est[0].dumpsince = EPOCH;
  577. for(dumplev = 0; dumplev < DUMP_LEVELS; dumplev++) {
  578. dumpdate = amdp->dates[dumplev];
  579. for(estlev = dumplev+1; estlev < DUMP_LEVELS; estlev++) {
  580. if(dumpdate > newp->est[estlev].dumpsince)
  581. newp->est[estlev].dumpsince = dumpdate;
  582. }
  583. }
  584. }
  585. void
  586. free_estimates(
  587. disk_estimates_t * est)
  588. {
  589. amfree(est->amname);
  590. amfree(est->qamname);
  591. amfree(est->amdevice);
  592. amfree(est->qamdevice);
  593. amfree(est->dirname);
  594. amfree(est->qdirname);
  595. amfree(est->program);
  596. if(est->options) {
  597. free_sl(est->options->exclude_file);
  598. free_sl(est->options->exclude_list);
  599. free_sl(est->options->include_file);
  600. free_sl(est->options->include_list);
  601. amfree(est->options->str);
  602. amfree(est->options->auth);
  603. amfree(est->options);
  604. }
  605. }
  606. /*
  607. * ------------------------------------------------------------------------
  608. *
  609. */
  610. void
  611. calc_estimates(
  612. disk_estimates_t * est)
  613. {
  614. dbprintf(("%s: calculating for amname %s, dirname %s, spindle %d\n",
  615. debug_prefix_time(NULL),
  616. est->qamname, est->qdirname, est->spindle));
  617. if(est->program_is_backup_api == 1)
  618. backup_api_calc_estimate(est);
  619. else
  620. #ifndef USE_GENERIC_CALCSIZE
  621. if(strcmp(est->program, "DUMP") == 0)
  622. dump_calc_estimates(est);
  623. else
  624. #endif
  625. #ifdef SAMBA_CLIENT
  626. if (strcmp(est->program, "GNUTAR") == 0 &&
  627. est->amdevice[0] == '/' && est->amdevice[1] == '/')
  628. smbtar_calc_estimates(est);
  629. else
  630. #endif
  631. #ifdef GNUTAR
  632. if (strcmp(est->program, "GNUTAR") == 0)
  633. gnutar_calc_estimates(est);
  634. else
  635. #endif
  636. #ifdef SAMBA_CLIENT
  637. if (est->amdevice[0] == '/' && est->amdevice[1] == '/')
  638. dbprintf(("%s: Can't use CALCSIZE for samba estimate: %s %s\n",
  639. debug_prefix_time(NULL),
  640. est->qamname, est->qdirname));
  641. else
  642. #endif
  643. generic_calc_estimates(est);
  644. dbprintf(("%s: done with amname %s dirname %s spindle %d\n",
  645. debug_prefix_time(NULL),
  646. est->qamname, est->qdirname, est->spindle));
  647. }
  648. /*
  649. * ------------------------------------------------------------------------
  650. *
  651. */
  652. /* local functions */
  653. off_t getsize_dump(char *disk, char *amdevice, int level, option_t *options,
  654. char **errmsg);
  655. off_t getsize_smbtar(char *disk, char *amdevice, int level, option_t *options,
  656. char **errmsg);
  657. off_t getsize_gnutar(char *disk, char *amdevice, int level,
  658. option_t *options, time_t dumpsince, char **errmsg);
  659. off_t getsize_backup_api(char *program, char *disk, char *amdevice, int level,
  660. option_t *options, time_t dumpsince, char **errmsg);
  661. off_t handle_dumpline(char *str);
  662. double first_num(char *str);
  663. void
  664. backup_api_calc_estimate(
  665. disk_estimates_t * est)
  666. {
  667. int level;
  668. off_t size;
  669. char *errmsg = NULL, *qerrmsg;
  670. for(level = 0; level < DUMP_LEVELS; level++) {
  671. if (est->est[level].needestimate) {
  672. dbprintf(("%s: getting size via backup-api for %s %s level %d\n",
  673. debug_prefix_time(NULL), est->qamname, est->qamdevice,
  674. level));
  675. size = getsize_backup_api(est->program, est->amname, est->amdevice,
  676. level, est->options,
  677. est->est[level].dumpsince, &errmsg);
  678. amflock(1, "size");
  679. printf("%s %d SIZE " OFF_T_FMT "\n", est->qamname, level,
  680. (OFF_T_FMT_TYPE)size);
  681. if (errmsg && errmsg[0] != '\0') {
  682. if(am_has_feature(g_options->features,
  683. fe_rep_sendsize_quoted_error)) {
  684. qerrmsg = quote_string(errmsg);
  685. dbprintf(("errmsg is %s\n", errmsg));
  686. printf("%s %d ERROR %s\n",
  687. est->qamname, level, qerrmsg);
  688. amfree(qerrmsg);
  689. }
  690. }
  691. amfree(errmsg);
  692. fflush(stdout);
  693. amfunlock(1, "size");
  694. }
  695. }
  696. }
  697. void
  698. generic_calc_estimates(
  699. disk_estimates_t * est)
  700. {
  701. int pipefd = -1, nullfd = -1;
  702. char *cmd;
  703. char *my_argv[DUMP_LEVELS*2+22];
  704. char number[NUM_STR_SIZE];
  705. int i, level, my_argc;
  706. pid_t calcpid;
  707. int nb_exclude = 0;
  708. int nb_include = 0;
  709. char *file_exclude = NULL;
  710. char *file_include = NULL;
  711. times_t start_time;
  712. FILE *dumpout = NULL;
  713. off_t size = (off_t)1;
  714. char *line = NULL;
  715. char *match_expr;
  716. amwait_t wait_status;
  717. char *errmsg = NULL, *qerrmsg;
  718. cmd = vstralloc(libexecdir, "/", "calcsize", versionsuffix(), NULL);
  719. my_argc = 0;
  720. my_argv[my_argc++] = stralloc("calcsize");
  721. if (g_options->config)
  722. my_argv[my_argc++] = stralloc(g_options->config);
  723. else
  724. my_argv[my_argc++] = stralloc("NOCONFIG");
  725. my_argv[my_argc++] = stralloc(est->calcprog);
  726. my_argv[my_argc++] = stralloc(est->amname);
  727. my_argv[my_argc++] = stralloc(est->dirname);
  728. if(est->options->exclude_file)
  729. nb_exclude += est->options->exclude_file->nb_element;
  730. if(est->options->exclude_list)
  731. nb_exclude += est->options->exclude_list->nb_element;
  732. if(est->options->include_file)
  733. nb_include += est->options->include_file->nb_element;
  734. if(est->options->include_list)
  735. nb_include += est->options->include_list->nb_element;
  736. if(nb_exclude > 0)
  737. file_exclude = build_exclude(est->amname,
  738. est->amdevice, est->options, 0);
  739. if(nb_include > 0)
  740. file_include = build_include(est->amname,
  741. est->amdevice, est->options, 0);
  742. if(file_exclude) {
  743. my_argv[my_argc++] = stralloc("-X");
  744. my_argv[my_argc++] = file_exclude;
  745. }
  746. if(file_include) {
  747. my_argv[my_argc++] = stralloc("-I");
  748. my_argv[my_argc++] = file_include;
  749. }
  750. start_time = curclock();
  751. dbprintf(("%s: running cmd: %s", debug_prefix_time(NULL), my_argv[0]));
  752. for(i=0; i<my_argc; ++i)
  753. dbprintf((" %s", my_argv[i]));
  754. for(level = 0; level < DUMP_LEVELS; level++) {
  755. if(est->est[level].needestimate) {
  756. snprintf(number, SIZEOF(number), "%d", level);
  757. my_argv[my_argc++] = stralloc(number);
  758. dbprintf((" %s", number));
  759. snprintf(number, SIZEOF(number),
  760. "%ld", (long)est->est[level].dumpsince);
  761. my_argv[my_argc++] = stralloc(number);
  762. dbprintf((" %s", number));
  763. }
  764. }
  765. my_argv[my_argc] = NULL;
  766. dbprintf(("\n"));
  767. fflush(stderr); fflush(stdout);
  768. if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
  769. errmsg = vstrallocf("Cannot access /dev/null : %s",
  770. strerror(errno));
  771. dbprintf(("%s\n", errmsg));
  772. goto common_exit;
  773. }
  774. calcpid = pipespawnv(cmd, STDERR_PIPE, &nullfd, &nullfd, &pipefd, my_argv);
  775. amfree(cmd);
  776. dumpout = fdopen(pipefd,"r");
  777. if (!dumpout) {
  778. error("Can't fdopen: %s", strerror(errno));
  779. /*NOTREACHED*/
  780. }
  781. match_expr = vstralloc(est->qamname," %d SIZE " OFF_T_FMT, NULL);
  782. for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
  783. OFF_T_FMT_TYPE size_ = (OFF_T_FMT_TYPE)0;
  784. if (line[0] == '\0')
  785. continue;
  786. if(sscanf(line, match_expr, &level, &size_) == 2) {
  787. printf("%s\n", line); /* write to amandad */
  788. dbprintf(("%s: estimate size for %s level %d: " OFF_T_FMT " KB\n",
  789. debug_prefix_time(NULL),
  790. est->qamname,
  791. level,
  792. size_));
  793. }
  794. size = (off_t)size_;
  795. }
  796. amfree(match_expr);
  797. dbprintf(("%s: waiting for %s %s child (pid=%d)\n",
  798. debug_prefix_time(NULL), my_argv[0], est->qamdevice, calcpid));
  799. waitpid(calcpid, &wait_status, 0);
  800. if (WIFSIGNALED(wait_status)) {
  801. errmsg = vstrallocf("%s terminated with signal %d: see %s",
  802. "calcsize", WTERMSIG(wait_status),
  803. debug_fn());
  804. } else if (WIFEXITED(wait_status)) {
  805. if (WEXITSTATUS(wait_status) != 0) {
  806. errmsg = vstrallocf("%s exited with status %d: see %s",
  807. "calcsize", WEXITSTATUS(wait_status),
  808. debug_fn());
  809. } else {
  810. /* Normal exit */
  811. }
  812. } else {
  813. errmsg = vstrallocf("%s got bad exit: see %s",
  814. "calcsize", debug_fn());
  815. }
  816. dbprintf(("%s: after %s %s wait: child pid=%d status=%d\n",
  817. debug_prefix_time(NULL), my_argv[0], est->qamdevice,
  818. calcpid, WEXITSTATUS(wait_status)));
  819. dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
  820. dbprintf(("%s: estimate time for %s: %s\n",
  821. debug_prefix_time(NULL),
  822. est->qamname,
  823. walltime_str(timessub(curclock(), start_time))));
  824. common_exit:
  825. if (errmsg && errmsg[0] != '\0') {
  826. if(am_has_feature(g_options->features, fe_rep_sendsize_quoted_error)) {
  827. qerrmsg = quote_string(errmsg);
  828. dbprintf(("errmsg is %s\n", errmsg));
  829. printf("%s %d ERROR %s\n",
  830. est->qamname, 0, qerrmsg);
  831. amfree(qerrmsg);
  832. }
  833. }
  834. amfree(errmsg);
  835. for(i = 0; i < my_argc; i++) {
  836. amfree(my_argv[i]);
  837. }
  838. amfree(cmd);
  839. }
  840. void
  841. dump_calc_estimates(
  842. disk_estimates_t * est)
  843. {
  844. int level;
  845. off_t size;
  846. char *errmsg=NULL, *qerrmsg;
  847. for(level = 0; level < DUMP_LEVELS; level++) {
  848. if(est->est[level].needestimate) {
  849. dbprintf(("%s: getting size via dump for %s level %d\n",
  850. debug_prefix_time(NULL), est->qamname, level));
  851. size = getsize_dump(est->amname, est->amdevice,
  852. level, est->options, &errmsg);
  853. amflock(1, "size");
  854. printf("%s %d SIZE " OFF_T_FMT "\n",
  855. est->qamname, level, (OFF_T_FMT_TYPE)size);
  856. if (errmsg && errmsg[0] != '\0') {
  857. if(am_has_feature(g_options->features,
  858. fe_rep_sendsize_quoted_error)) {
  859. qerrmsg = quote_string(errmsg);
  860. dbprintf(("errmsg is %s\n", errmsg));
  861. printf("%s %d ERROR %s\n",
  862. est->qamname, level, qerrmsg);
  863. amfree(qerrmsg);
  864. }
  865. }
  866. amfree(errmsg);
  867. fflush(stdout);
  868. amfunlock(1, "size");
  869. }
  870. }
  871. }
  872. #ifdef SAMBA_CLIENT
  873. void
  874. smbtar_calc_estimates(
  875. disk_estimates_t * est)
  876. {
  877. int level;
  878. off_t size;
  879. char *errmsg = NULL, *qerrmsg;
  880. for(level = 0; level < DUMP_LEVELS; level++) {
  881. if(est->est[level].needestimate) {
  882. dbprintf(("%s: getting size via smbclient for %s level %d\n",
  883. debug_prefix_time(NULL), est->qamname, level));
  884. size = getsize_smbtar(est->amname, est->amdevice, level,
  885. est->options, &errmsg);
  886. amflock(1, "size");
  887. printf("%s %d SIZE " OFF_T_FMT "\n",
  888. est->qamname, level, (OFF_T_FMT_TYPE)size);
  889. if (errmsg && errmsg[0] != '\0') {
  890. if(am_has_feature(g_options->features,
  891. fe_rep_sendsize_quoted_error)) {
  892. qerrmsg = quote_string(errmsg);
  893. dbprintf(("errmsg is %s\n", errmsg));
  894. printf("%s %d ERROR %s\n",
  895. est->qamname, level, qerrmsg);
  896. amfree(qerrmsg);
  897. }
  898. }
  899. amfree(errmsg);
  900. fflush(stdout);
  901. amfunlock(1, "size");
  902. }
  903. }
  904. }
  905. #endif
  906. #ifdef GNUTAR
  907. void
  908. gnutar_calc_estimates(
  909. disk_estimates_t * est)
  910. {
  911. int level;
  912. off_t size;
  913. char *errmsg = NULL, *qerrmsg;
  914. for(level = 0; level < DUMP_LEVELS; level++) {
  915. if (est->est[level].needestimate) {
  916. dbprintf(("%s: getting size via gnutar for %s level %d\n",
  917. debug_prefix_time(NULL), est->qamname, level));
  918. size = getsize_gnutar(est->amname, est->amdevice, level,
  919. est->options, est->est[level].dumpsince,
  920. &errmsg);
  921. amflock(1, "size");
  922. printf("%s %d SIZE " OFF_T_FMT "\n",
  923. est->qamname, level, (OFF_T_FMT_TYPE)size);
  924. if (errmsg && errmsg[0] != '\0') {
  925. if(am_has_feature(g_options->features,
  926. fe_rep_sendsize_quoted_error)) {
  927. qerrmsg = quote_string(errmsg);
  928. dbprintf(("errmsg is %s\n", errmsg));
  929. printf("%s %d ERROR %s\n",
  930. est->qamname, level, qerrmsg);
  931. amfree(qerrmsg);
  932. }
  933. }
  934. amfree(errmsg);
  935. fflush(stdout);
  936. amfunlock(1, "size");
  937. }
  938. }
  939. }
  940. #endif
  941. typedef struct regex_s {
  942. char *regex;
  943. int scale;
  944. } regex_t;
  945. /*@ignore@*/
  946. regex_t re_size[] = {
  947. #ifdef DUMP
  948. {" DUMP: estimated -*[0-9][0-9]* tape blocks", 1024},
  949. {" DUMP: [Ee]stimated [0-9][0-9]* blocks", 512},
  950. {" DUMP: [Ee]stimated [0-9][0-9]* bytes", 1}, /* Ultrix 4.4 */
  951. {" UFSDUMP: estimated [0-9][0-9]* blocks", 512}, /* NEC EWS-UX */
  952. {"dump: Estimate: [0-9][0-9]* tape blocks", 1024}, /* OSF/1 */
  953. {"backup: There are an estimated [0-9][0-9]* tape blocks.",1024}, /* AIX */
  954. {"backup: estimated [0-9][0-9]* 1k blocks", 1024}, /* AIX */
  955. {"backup: estimated [0-9][0-9]* tape blocks", 1024}, /* AIX */
  956. {"backup: [0-9][0-9]* tape blocks on [0-9][0-9]* tape(s)",1024}, /* AIX */
  957. {"backup: [0-9][0-9]* 1k blocks on [0-9][0-9]* volume(s)",1024}, /* AIX */
  958. {"dump: Estimate: [0-9][0-9]* blocks being output to pipe",1024},
  959. /* DU 4.0 dump */
  960. {"dump: Dumping [0-9][0-9]* bytes, ", 1}, /* DU 4.0 vdump */
  961. {"DUMP: estimated [0-9][0-9]* KB output", 1024}, /* HPUX */
  962. {"DUMP: estimated [0-9][0-9]* KB\\.", 1024}, /* NetApp */
  963. {" UFSDUMP: estimated [0-9][0-9]* blocks", 512}, /* Sinix */
  964. #ifdef HAVE_DUMP_ESTIMATE
  965. {"[0-9][0-9]* blocks, [0-9][0-9]*.[0-9][0-9]* volumes", 1024},
  966. /* DU 3.2g dump -E */
  967. {"^[0-9][0-9]* blocks$", 1024}, /* DU 4.0 dump -E */
  968. {"^[0-9][0-9]*$", 1}, /* Solaris ufsdump -S */
  969. #endif
  970. #endif
  971. #ifdef VDUMP
  972. {"vdump: Dumping [0-9][0-9]* bytes, ", 1}, /* OSF/1 vdump */
  973. #endif
  974. #ifdef VXDUMP
  975. {"vxdump: estimated [0-9][0-9]* blocks", 512}, /* HPUX's vxdump */
  976. {" VXDUMP: estimated [0-9][0-9]* blocks", 512}, /* Sinix */
  977. #endif
  978. #ifdef XFSDUMP
  979. {"xfsdump: estimated dump size: [0-9][0-9]* bytes", 1}, /* Irix 6.2 xfs */
  980. #endif
  981. #ifdef GNUTAR
  982. {"Total bytes written: [0-9][0-9]*", 1}, /* Gnutar client */
  983. #endif
  984. #ifdef SAMBA_CLIENT
  985. #if SAMBA_VERSION >= 2
  986. #define SAMBA_DEBUG_LEVEL "0"
  987. {"Total number of bytes: [0-9][0-9]*", 1}, /* Samba du */
  988. #else
  989. #define SAMBA_DEBUG_LEVEL "3"
  990. {"Total bytes listed: [0-9][0-9]*", 1}, /* Samba dir */
  991. #endif
  992. #endif
  993. { NULL, 0 }
  994. };
  995. /*@end@*/
  996. off_t
  997. getsize_dump(
  998. char *disk,
  999. char *amdevice,
  1000. int level,
  1001. option_t *options,
  1002. char **errmsg)
  1003. {
  1004. int pipefd[2], nullfd, stdoutfd, killctl[2];
  1005. pid_t dumppid;
  1006. off_t size;
  1007. FILE *dumpout;
  1008. char *dumpkeys = NULL;
  1009. char *device = NULL;
  1010. char *fstype = NULL;
  1011. char *cmd = NULL;
  1012. char *name = NULL;
  1013. char *line = NULL;
  1014. char *rundump_cmd = NULL;
  1015. char level_str[NUM_STR_SIZE];
  1016. int s;
  1017. times_t start_time;
  1018. char *qdisk = quote_string(disk);
  1019. char *qdevice;
  1020. char *config;
  1021. amwait_t wait_status;
  1022. #if defined(DUMP) || defined(VDUMP) || defined(VXDUMP) || defined(XFSDUMP)
  1023. int is_rundump = 1;
  1024. #endif
  1025. (void)options; /* Quiet unused parameter warning */
  1026. (void)getsize_smbtar; /* Quiet unused parameter warning */
  1027. snprintf(level_str, SIZEOF(level_str), "%d", level);
  1028. device = amname_to_devname(amdevice);
  1029. qdevice = quote_string(device);
  1030. fstype = amname_to_fstype(amdevice);
  1031. dbprintf(("%s: calculating for device %s with %s\n",
  1032. debug_prefix_time(NULL), qdevice, fstype));
  1033. cmd = vstralloc(libexecdir, "/rundump", versionsuffix(), NULL);
  1034. rundump_cmd = stralloc(cmd);
  1035. if (g_options->config)
  1036. config = g_options->config;
  1037. else
  1038. config = "NOCONFIG";
  1039. if ((stdoutfd = nullfd = open("/dev/null", O_RDWR)) == -1) {
  1040. *errmsg = vstrallocf("getsize_dump could not open /dev/null: %s",
  1041. strerror(errno));
  1042. dbprintf(("%s\n", *errmsg));
  1043. amfree(cmd);
  1044. amfree(rundump_cmd);
  1045. amfree(fstype);
  1046. amfree(device);
  1047. amfree(qdevice);
  1048. amfree(qdisk);
  1049. return(-1);
  1050. }
  1051. pipefd[0] = pipefd[1] = killctl[0] = killctl[1] = -1;
  1052. if (pipe(pipefd) < 0) {
  1053. *errmsg = vstrallocf("getsize_dump could create data pipes: %s",
  1054. strerror(errno));
  1055. dbprintf(("%s\n", *errmsg));
  1056. amfree(cmd);
  1057. amfree(rundump_cmd);
  1058. amfree(fstype);
  1059. amfree(device);
  1060. amfree(qdevice);
  1061. amfree(qdisk);
  1062. return(-1);
  1063. }
  1064. #ifdef XFSDUMP /* { */
  1065. #ifdef DUMP /* { */
  1066. if (strcmp(fstype, "xfs") == 0)
  1067. #else /* } { */
  1068. if (1)
  1069. #endif /* } */
  1070. {
  1071. name = stralloc(" (xfsdump)");
  1072. dbprintf(("%s: running \"%s%s -F -J -l %s - %s\"\n",
  1073. debug_prefix_time(NULL), cmd, name, level_str, qdevice));
  1074. }
  1075. else
  1076. #endif /* } */
  1077. #ifdef VXDUMP /* { */
  1078. #ifdef DUMP /* { */
  1079. if (strcmp(fstype, "vxfs") == 0)
  1080. #else /* } { */
  1081. if (1)
  1082. #endif /* } */
  1083. {
  1084. #ifdef USE_RUNDUMP
  1085. name = stralloc(" (vxdump)");
  1086. #else
  1087. name = stralloc("");
  1088. cmd = newstralloc(cmd, VXDUMP);
  1089. config = skip_argument;
  1090. is_rundump = 0;
  1091. #endif
  1092. dumpkeys = vstralloc(level_str, "s", "f", NULL);
  1093. dbprintf(("%s: running \"%s%s %s 1048576 - %s\"\n",
  1094. debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
  1095. }
  1096. else
  1097. #endif /* } */
  1098. #ifdef VDUMP /* { */
  1099. #ifdef DUMP /* { */
  1100. if (strcmp(fstype, "advfs") == 0)
  1101. #else /* } { */
  1102. if (1)
  1103. #endif /* } */
  1104. {
  1105. name = stralloc(" (vdump)");
  1106. amfree(device);
  1107. amfree(qdevice);
  1108. device = amname_to_dirname(amdevice);
  1109. qdevice = quote_string(device);
  1110. dumpkeys = vstralloc(level_str, "b", "f", NULL);
  1111. dbprintf(("%s: running \"%s%s %s 60 - %s\"\n",
  1112. debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
  1113. }
  1114. else
  1115. #endif /* } */
  1116. #ifdef DUMP /* { */
  1117. if (1) {
  1118. # ifdef USE_RUNDUMP /* { */
  1119. # ifdef AIX_BACKUP /* { */
  1120. name = stralloc(" (backup)");
  1121. # else /* } { */
  1122. name = vstralloc(" (", DUMP, ")", NULL);
  1123. # endif /* } */
  1124. # else /* } { */
  1125. name = stralloc("");
  1126. cmd = newstralloc(cmd, DUMP);
  1127. config = skip_argument;
  1128. is_rundump = 0;
  1129. # endif /* } */
  1130. # ifdef AIX_BACKUP /* { */
  1131. dumpkeys = vstralloc("-", level_str, "f", NULL);
  1132. dbprintf(("%s: running \"%s%s %s - %s\"\n",
  1133. debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
  1134. # else /* } { */
  1135. # ifdef HAVE_DUMP_ESTIMATE
  1136. # define PARAM_DUMP_ESTIMATE HAVE_DUMP_ESTIMATE
  1137. # else
  1138. # define PARAM_DUMP_ESTIMATE ""
  1139. # endif
  1140. # ifdef HAVE_HONOR_NODUMP
  1141. # define PARAM_HONOR_NODUMP "h"
  1142. # else
  1143. # define PARAM_HONOR_NODUMP ""
  1144. # endif
  1145. dumpkeys = vstralloc(level_str,
  1146. PARAM_DUMP_ESTIMATE,
  1147. PARAM_HONOR_NODUMP,
  1148. "s", "f", NULL);
  1149. # ifdef HAVE_DUMP_ESTIMATE
  1150. stdoutfd = pipefd[1];
  1151. # endif
  1152. # ifdef HAVE_HONOR_NODUMP /* { */
  1153. dbprintf(("%s: running \"%s%s %s 0 1048576 - %s\"\n",
  1154. debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
  1155. # else /* } { */
  1156. dbprintf(("%s: running \"%s%s %s 1048576 - %s\"\n",
  1157. debug_prefix_time(NULL), cmd, name, dumpkeys, qdevice));
  1158. # endif /* } */
  1159. # endif /* } */
  1160. }
  1161. else
  1162. #endif /* } */
  1163. {
  1164. error("no dump program available");
  1165. /*NOTREACHED*/
  1166. }
  1167. if (pipe(killctl) < 0) {
  1168. dbprintf(("%s: Could not create pipe: %s\n",
  1169. debug_prefix_time(NULL), strerror(errno)));
  1170. /* Message will be printed later... */
  1171. killctl[0] = killctl[1] = -1;
  1172. }
  1173. start_time = curclock();
  1174. switch(dumppid = fork()) {
  1175. case -1:
  1176. *errmsg = vstrallocf("cannot fork for killpgrp: %s",
  1177. strerror(errno));
  1178. dbprintf(("%s\n", *errmsg));
  1179. amfree(dumpkeys);
  1180. amfree(cmd);
  1181. amfree(rundump_cmd);
  1182. amfree(device);
  1183. amfree(qdevice);
  1184. amfree(qdisk);
  1185. amfree(name);
  1186. amfree(fstype);
  1187. return -1;
  1188. default:
  1189. break;
  1190. case 0: /* child process */
  1191. if(SETPGRP == -1)
  1192. SETPGRP_FAILED();
  1193. else if (killctl[0] == -1 || killctl[1] == -1)
  1194. dbprintf(("%s: Trying without killpgrp\n", debug_prefix_time(NULL)));
  1195. else {
  1196. switch(fork()) {
  1197. case -1:
  1198. dbprintf(("%s: fork failed, trying without killpgrp\n",
  1199. debug_prefix_time(NULL)));
  1200. break;
  1201. default:
  1202. {
  1203. char *config;
  1204. char *killpgrp_cmd = vstralloc(libexecdir, "/killpgrp",
  1205. versionsuffix(), NULL);
  1206. dbprintf(("%s: running %s\n",
  1207. debug_prefix_time(NULL), killpgrp_cmd));
  1208. dup2(killctl[0], 0);
  1209. dup2(nullfd, 1);
  1210. dup2(nullfd, 2);
  1211. close(pipefd[0]);
  1212. close(pipefd[1]);
  1213. close(killctl[1]);
  1214. close(nullfd);
  1215. if (g_options->config)
  1216. config = g_options->config;
  1217. else
  1218. config = "NOCONFIG";
  1219. execle(killpgrp_cmd, killpgrp_cmd, config, (char *)0,
  1220. safe_env());
  1221. dbprintf(("%s: cannot execute %s: %s\n",
  1222. debug_prefix_time(NULL), killpgrp_cmd, strerror(errno)));
  1223. exit(-1);
  1224. }
  1225. case 0: /* child process */
  1226. break;
  1227. }
  1228. }
  1229. dup2(nullfd, 0);
  1230. dup2(stdoutfd, 1);
  1231. dup2(pipefd[1], 2);
  1232. aclose(pipefd[0]);
  1233. if (killctl[0] != -1)
  1234. aclose(killctl[0]);
  1235. if (killctl[1] != -1)
  1236. aclose(killctl[1]);
  1237. #ifdef XFSDUMP
  1238. #ifdef DUMP
  1239. if (strcmp(fstype, "xfs") == 0)
  1240. #else
  1241. if (1)
  1242. #endif
  1243. if (is_rundump)
  1244. execle(cmd, "rundump", config, "xfsdump", "-F", "-J", "-l",
  1245. level_str, "-", device, (char *)0, safe_env());
  1246. else
  1247. execle(cmd, "xfsdump", "-F", "-J", "-l",
  1248. level_str, "-", device, (char *)0, safe_env());
  1249. else
  1250. #endif
  1251. #ifdef VXDUMP
  1252. #ifdef DUMP
  1253. if (strcmp(fstype, "vxfs") == 0)
  1254. #else
  1255. if (1)
  1256. #endif
  1257. if (is_rundump)
  1258. execle(cmd, "rundump", config, "vxdump", dumpkeys, "1048576",
  1259. "-", device, (char *)0, safe_env());
  1260. else
  1261. execle(cmd, "vxdump", dumpkeys, "1048576", "-",
  1262. device, (char *)0, safe_env());
  1263. else
  1264. #endif
  1265. #ifdef VDUMP
  1266. #ifdef DUMP
  1267. if (strcmp(fstype, "advfs") == 0)
  1268. #else
  1269. if (1)
  1270. #endif
  1271. if (is_rundump)
  1272. execle(cmd, "rundump", config, "vdump", dumpkeys, "60", "-",
  1273. device, (char *)0, safe_env());
  1274. else
  1275. execle(cmd, "vdump", dumpkeys, "60", "-",
  1276. device, (char *)0, safe_env());
  1277. else
  1278. #endif
  1279. #ifdef DUMP
  1280. # ifdef AIX_BACKUP
  1281. if (is_rundump)
  1282. execle(cmd, "rundump", config, "backup", dumpkeys, "-",
  1283. device, (char *)0, safe_env());
  1284. else
  1285. execle(cmd, "backup", dumpkeys, "-",
  1286. device, (char *)0, safe_env());
  1287. # else
  1288. if (is_rundump) {
  1289. execle(cmd, "rundump", config, "dump", dumpkeys,
  1290. #ifdef HAVE_HONOR_NODUMP
  1291. "0",
  1292. #endif
  1293. "1048576", "-", device, (char *)0, safe_env());
  1294. } else {
  1295. execle(cmd, "dump", dumpkeys,
  1296. #ifdef HAVE_HONOR_NODUMP
  1297. "0",
  1298. #endif
  1299. "1048576", "-", device, (char *)0, safe_env());
  1300. }
  1301. # endif
  1302. #endif
  1303. {
  1304. error("exec %s failed or no dump program available: %s",
  1305. cmd, strerror(errno));
  1306. /*NOTREACHED*/
  1307. }
  1308. }
  1309. amfree(dumpkeys);
  1310. amfree(rundump_cmd);
  1311. aclose(pipefd[1]);
  1312. if (killctl[0] != -1)
  1313. aclose(killctl[0]);
  1314. dumpout = fdopen(pipefd[0],"r");
  1315. if (!dumpout) {
  1316. error("Can't fdopen: %s", strerror(errno));
  1317. /*NOTREACHED*/
  1318. }
  1319. for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
  1320. if (line[0] == '\0')
  1321. continue;
  1322. dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
  1323. size = handle_dumpline(line);
  1324. if(size > (off_t)-1) {
  1325. amfree(line);
  1326. while ((line = agets(dumpout)) != NULL) {
  1327. if (line[0] != '\0')
  1328. break;
  1329. amfree(line);
  1330. }
  1331. if (line != NULL) {
  1332. dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
  1333. }
  1334. break;
  1335. }
  1336. }
  1337. amfree(line);
  1338. dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
  1339. dbprintf(("%s: estimate time for %s level %d: %s\n",
  1340. debug_prefix_time(NULL),
  1341. qdisk,
  1342. level,
  1343. walltime_str(timessub(curclock(), start_time))));
  1344. if(size == (off_t)-1) {
  1345. *errmsg = vstrallocf("no size line match in %s%s output",
  1346. cmd, name);
  1347. dbprintf(("%s: %s for %s\n", debug_prefix_time(NULL),
  1348. *errmsg, qdisk));
  1349. dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
  1350. dbprintf(("%s: Run %s%s manually to check for errors\n",
  1351. debug_prefix_time(NULL), cmd, name));
  1352. } else if(size == (off_t)0 && level == 0) {
  1353. dbprintf(("%s: possible %s%s problem -- is \"%s\" really empty?\n",
  1354. debug_prefix_time(NULL), cmd, name, disk));
  1355. dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
  1356. } else {
  1357. dbprintf(("%s: estimate size for %s level %d: " OFF_T_FMT " KB\n",
  1358. debug_prefix_time(NULL),
  1359. qdisk,
  1360. level,
  1361. (OFF_T_FMT_TYPE)size));
  1362. }
  1363. if (killctl[1] != -1) {
  1364. dbprintf(("%s: asking killpgrp to terminate\n",
  1365. debug_prefix_time(NULL)));
  1366. aclose(killctl[1]);
  1367. for(s = 5; s > 0; --s) {
  1368. sleep(1);
  1369. if (waitpid(dumppid, NULL, WNOHANG) != -1)
  1370. goto terminated;
  1371. }
  1372. }
  1373. /*
  1374. * First, try to kill the dump process nicely. If it ignores us
  1375. * for several seconds, hit it harder.
  1376. */
  1377. dbprintf(("%s: sending SIGTERM to process group %ld\n",
  1378. debug_prefix_time(NULL), (long)dumppid));
  1379. if (kill(-dumppid, SIGTERM) == -1) {
  1380. dbprintf(("%s: kill failed: %s\n",
  1381. debug_prefix_time(NULL), strerror(errno)));
  1382. }
  1383. /* Now check whether it dies */
  1384. for(s = 5; s > 0; --s) {
  1385. sleep(1);
  1386. if (waitpid(dumppid, NULL, WNOHANG) != -1)
  1387. goto terminated;
  1388. }
  1389. dbprintf(("%s: sending SIGKILL to process group %ld\n",
  1390. debug_prefix_time(NULL), (long)dumppid));
  1391. if (kill(-dumppid, SIGKILL) == -1) {
  1392. dbprintf(("%s: kill failed: %s\n",
  1393. debug_prefix_time(NULL), strerror(errno)));
  1394. }
  1395. for(s = 5; s > 0; --s) {
  1396. sleep(1);
  1397. if (waitpid(dumppid, NULL, WNOHANG) != -1)
  1398. goto terminated;
  1399. }
  1400. dbprintf(("%s: waiting for %s%s \"%s\" child\n",
  1401. debug_prefix_time(NULL), cmd, name, qdisk));
  1402. waitpid(dumppid, &wait_status, 0);
  1403. if (WIFSIGNALED(wait_status)) {
  1404. *errmsg = vstrallocf("%s terminated with signal %d: see %s",
  1405. cmd, WTERMSIG(wait_status), debug_fn());
  1406. } else if (WIFEXITED(wait_status)) {
  1407. if (WEXITSTATUS(wait_status) != 0) {
  1408. *errmsg = vstrallocf("%s exited with status %d: see %s",
  1409. cmd, WEXITSTATUS(wait_status), debug_fn());
  1410. } else {
  1411. /* Normal exit */
  1412. }
  1413. } else {
  1414. *errmsg = vstrallocf("%s got bad exit: see %s",
  1415. cmd, debug_fn());
  1416. }
  1417. dbprintf(("%s: after %s%s %s wait\n",
  1418. debug_prefix_time(NULL), cmd, name, qdisk));
  1419. terminated:
  1420. aclose(nullfd);
  1421. afclose(dumpout);
  1422. amfree(device);
  1423. amfree(qdevice);
  1424. amfree(qdisk);
  1425. amfree(fstype);
  1426. amfree(cmd);
  1427. amfree(name);
  1428. return size;
  1429. }
  1430. #ifdef SAMBA_CLIENT
  1431. off_t
  1432. getsize_smbtar(
  1433. char *disk,
  1434. char *amdevice,
  1435. int level,
  1436. option_t *options,
  1437. char **errmsg)
  1438. {
  1439. int pipefd = -1, nullfd = -1, passwdfd = -1;
  1440. pid_t dumppid;
  1441. off_t size;
  1442. FILE *dumpout;
  1443. char *tarkeys, *sharename, *user_and_password = NULL, *domain = NULL;
  1444. char *share = NULL, *subdir = NULL;
  1445. size_t lpass;
  1446. char *pwtext;
  1447. size_t pwtext_len;
  1448. char *line;
  1449. char *pw_fd_env;
  1450. times_t start_time;
  1451. char *error_pn = NULL;
  1452. char *qdisk = quote_string(disk);
  1453. amwait_t wait_status;
  1454. (void)options; /* Quiet unused parameter warning */
  1455. error_pn = stralloc2(get_pname(), "-smbclient");
  1456. parsesharename(amdevice, &share, &subdir);
  1457. if (!share) {
  1458. amfree(share);
  1459. amfree(subdir);
  1460. set_pname(error_pn);
  1461. amfree(error_pn);
  1462. error("cannot parse disk entry %s for share/subdir", qdisk);
  1463. /*NOTREACHED*/
  1464. }
  1465. if ((subdir) && (SAMBA_VERSION < 2)) {
  1466. amfree(share);
  1467. amfree(subdir);
  1468. set_pname(error_pn);
  1469. amfree(error_pn);
  1470. error("subdirectory specified for share %s but samba not v2 or better", qdisk);
  1471. /*NOTREACHED*/
  1472. }
  1473. if ((user_and_password = findpass(share, &domain)) == NULL) {
  1474. if(domain) {
  1475. memset(domain, '\0', strlen(domain));
  1476. amfree(domain);
  1477. }
  1478. set_pname(error_pn);
  1479. amfree(error_pn);
  1480. error("cannot find password for %s", disk);
  1481. /*NOTREACHED*/
  1482. }
  1483. lpass = strlen(user_and_password);
  1484. if ((pwtext = strchr(user_and_password, '%')) == NULL) {
  1485. memset(user_and_password, '\0', (size_t)lpass);
  1486. amfree(user_and_password);
  1487. if(domain) {
  1488. memset(domain, '\0', strlen(domain));
  1489. amfree(domain);
  1490. }
  1491. set_pname(error_pn);
  1492. amfree(error_pn);
  1493. error("password field not \'user%%pass\' for %s", disk);
  1494. /*NOTREACHED*/
  1495. }
  1496. *pwtext++ = '\0';
  1497. pwtext_len = strlen(pwtext);
  1498. if ((sharename = makesharename(share, 0)) == NULL) {
  1499. memset(user_and_password, '\0', (size_t)lpass);
  1500. amfree(user_and_password);
  1501. if(domain) {
  1502. memset(domain, '\0', strlen(domain));
  1503. amfree(domain);
  1504. }
  1505. set_pname(error_pn);
  1506. amfree(error_pn);
  1507. error("cannot make share name of %s", share);
  1508. /*NOTREACHED*/
  1509. }
  1510. if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
  1511. memset(user_and_password, '\0', (size_t)lpass);
  1512. amfree(user_and_password);
  1513. if(domain) {
  1514. memset(domain, '\0', strlen(domain));
  1515. amfree(domain);
  1516. }
  1517. set_pname(error_pn);
  1518. amfree(error_pn);
  1519. amfree(sharename);
  1520. error("could not open /dev/null: %s\n",
  1521. strerror(errno));
  1522. /*NOTREACHED*/
  1523. }
  1524. #if SAMBA_VERSION >= 2
  1525. if (level == 0)
  1526. tarkeys = "archive 0;recurse;du";
  1527. else
  1528. tarkeys = "archive 1;recurse;du";
  1529. #else
  1530. if (level == 0)
  1531. tarkeys = "archive 0;recurse;dir";
  1532. else
  1533. tarkeys = "archive 1;recurse;dir";
  1534. #endif
  1535. start_time = curclock();
  1536. if (pwtext_len > 0) {
  1537. pw_fd_env = "PASSWD_FD";
  1538. } else {
  1539. pw_fd_env = "dummy_PASSWD_FD";
  1540. }
  1541. dumppid = pipespawn(SAMBA_CLIENT, STDERR_PIPE|PASSWD_PIPE,
  1542. &nullfd, &nullfd, &pipefd,
  1543. pw_fd_env, &passwdfd,
  1544. "smbclient",
  1545. sharename,
  1546. "-d", SAMBA_DEBUG_LEVEL,
  1547. *user_and_password ? "-U" : skip_argument,
  1548. *user_and_password ? user_and_password : skip_argument,
  1549. "-E",
  1550. domain ? "-W" : skip_argument,
  1551. domain ? domain : skip_argument,
  1552. #if SAMBA_VERSION >= 2
  1553. subdir ? "-D" : skip_argument,
  1554. subdir ? subdir : skip_argument,
  1555. #endif
  1556. "-c", tarkeys,
  1557. NULL);
  1558. if(domain) {
  1559. memset(domain, '\0', strlen(domain));
  1560. amfree(domain);
  1561. }
  1562. aclose(nullfd);
  1563. if(pwtext_len > 0 && fullwrite(passwdfd, pwtext, (size_t)pwtext_len) < 0) {
  1564. int save_errno = errno;
  1565. memset(user_and_password, '\0', (size_t)lpass);
  1566. amfree(user_and_password);
  1567. aclose(passwdfd);
  1568. set_pname(error_pn);
  1569. amfree(error_pn);
  1570. error("password write failed: %s", strerror(save_errno));
  1571. /*NOTREACHED*/
  1572. }
  1573. memset(user_and_password, '\0', (size_t)lpass);
  1574. amfree(user_and_password);
  1575. aclose(passwdfd);
  1576. amfree(sharename);
  1577. amfree(share);
  1578. amfree(subdir);
  1579. amfree(error_pn);
  1580. dumpout = fdopen(pipefd,"r");
  1581. if (!dumpout) {
  1582. error("Can't fdopen: %s", strerror(errno));
  1583. /*NOTREACHED*/
  1584. }
  1585. for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
  1586. if (line[0] == '\0')
  1587. continue;
  1588. dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
  1589. size = handle_dumpline(line);
  1590. if(size > -1) {
  1591. amfree(line);
  1592. while ((line = agets(dumpout)) != NULL) {
  1593. if (line[0] != '\0')
  1594. break;
  1595. amfree(line);
  1596. }
  1597. if(line != NULL) {
  1598. dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
  1599. }
  1600. break;
  1601. }
  1602. }
  1603. amfree(line);
  1604. dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
  1605. dbprintf(("%s: estimate time for %s level %d: %s\n",
  1606. debug_prefix_time(NULL),
  1607. qdisk,
  1608. level,
  1609. walltime_str(timessub(curclock(), start_time))));
  1610. if(size == (off_t)-1) {
  1611. *errmsg = vstrallocf("no size line match in %s output",
  1612. SAMBA_CLIENT);
  1613. dbprintf(("%s: %s for %s\n", debug_prefix_time(NULL),
  1614. *errmsg, qdisk));
  1615. dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
  1616. } else if(size == (off_t)0 && level == 0) {
  1617. dbprintf(("%s: possible %s problem -- is \"%s\" really empty?\n",
  1618. debug_prefix_time(NULL), SAMBA_CLIENT, disk));
  1619. dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
  1620. }
  1621. dbprintf(("%s: estimate size for %s level %d: " OFF_T_FMT " KB\n",
  1622. debug_prefix_time(NULL),
  1623. qdisk,
  1624. level,
  1625. (OFF_T_FMT_TYPE)size));
  1626. kill(-dumppid, SIGTERM);
  1627. dbprintf(("%s: waiting for %s \"%s\" child\n",
  1628. debug_prefix_time(NULL), SAMBA_CLIENT, qdisk));
  1629. waitpid(dumppid, &wait_status, 0);
  1630. if (WIFSIGNALED(wait_status)) {
  1631. *errmsg = vstrallocf("%s terminated with signal %d: see %s",
  1632. "smbclient", WTERMSIG(wait_status), debug_fn());
  1633. } else if (WIFEXITED(wait_status)) {
  1634. if (WEXITSTATUS(wait_status) != 0) {
  1635. *errmsg = vstrallocf("%s exited with status %d: see %s",
  1636. "smbclient", WEXITSTATUS(wait_status),
  1637. debug_fn());
  1638. } else {
  1639. /* Normal exit */
  1640. }
  1641. } else {
  1642. *errmsg = vstrallocf("%s got bad exit: see %s",
  1643. "smbclient", debug_fn());
  1644. }
  1645. dbprintf(("%s: after %s %s wait\n",
  1646. debug_prefix_time(NULL), SAMBA_CLIENT, qdisk));
  1647. afclose(dumpout);
  1648. pipefd = -1;
  1649. amfree(error_pn);
  1650. amfree(qdisk);
  1651. return size;
  1652. }
  1653. #endif
  1654. #ifdef GNUTAR
  1655. off_t
  1656. getsize_gnutar(
  1657. char *disk,
  1658. char *amdevice,
  1659. int level,
  1660. option_t *options,
  1661. time_t dumpsince,
  1662. char **errmsg)
  1663. {
  1664. int pipefd = -1, nullfd = -1;
  1665. pid_t dumppid;
  1666. off_t size = (off_t)-1;
  1667. FILE *dumpout = NULL;
  1668. char *incrname = NULL;
  1669. char *basename = NULL;
  1670. char *dirname = NULL;
  1671. char *inputname = NULL;
  1672. FILE *in = NULL;
  1673. FILE *out = NULL;
  1674. char *line = NULL;
  1675. char *cmd = NULL;
  1676. char dumptimestr[80];
  1677. struct tm *gmtm;
  1678. int nb_exclude = 0;
  1679. int nb_include = 0;
  1680. char **my_argv;
  1681. int i;
  1682. char *file_exclude = NULL;
  1683. char *file_include = NULL;
  1684. times_t start_time;
  1685. int infd, outfd;
  1686. ssize_t nb;
  1687. char buf[32768];
  1688. char *qdisk = quote_string(disk);
  1689. char *gnutar_list_dir;
  1690. amwait_t wait_status;
  1691. if(options->exclude_file) nb_exclude += options->exclude_file->nb_element;
  1692. if(options->exclude_list) nb_exclude += options->exclude_list->nb_element;
  1693. if(options->include_file) nb_include += options->include_file->nb_element;
  1694. if(options->include_list) nb_include += options->include_list->nb_element;
  1695. if(nb_exclude > 0) file_exclude = build_exclude(disk, amdevice, options, 0);
  1696. if(nb_include > 0) file_include = build_include(disk, amdevice, options, 0);
  1697. my_argv = alloc(SIZEOF(char *) * 22);
  1698. i = 0;
  1699. gnutar_list_dir = getconf_str(CNF_GNUTAR_LIST_DIR);
  1700. if (strlen(gnutar_list_dir) == 0)
  1701. gnutar_list_dir = NULL;
  1702. if (gnutar_list_dir) {
  1703. char number[NUM_STR_SIZE];
  1704. char *s;
  1705. int ch;
  1706. int baselevel;
  1707. basename = vstralloc(gnutar_list_dir,
  1708. "/",
  1709. g_options->hostname,
  1710. disk,
  1711. NULL);
  1712. /*
  1713. * The loop starts at the first character of the host name,
  1714. * not the '/'.
  1715. */
  1716. s = basename + strlen(gnutar_list_dir) + 1;
  1717. while((ch = *s++) != '\0') {
  1718. if(ch == '/' || isspace(ch)) s[-1] = '_';
  1719. }
  1720. snprintf(number, SIZEOF(number), "%d", level);
  1721. incrname = vstralloc(basename, "_", number, ".new", NULL);
  1722. unlink(incrname);
  1723. /*
  1724. * Open the listed incremental file from the previous level. Search
  1725. * backward until one is found. If none are found (which will also
  1726. * be true for a level 0), arrange to read from /dev/null.
  1727. */
  1728. baselevel = level;
  1729. infd = -1;
  1730. while (infd == -1) {
  1731. if (--baselevel >= 0) {
  1732. snprintf(number, SIZEOF(number), "%d", baselevel);
  1733. inputname = newvstralloc(inputname,
  1734. basename, "_", number, NULL);
  1735. } else {
  1736. inputname = newstralloc(inputname, "/dev/null");
  1737. }
  1738. if ((infd = open(inputname, O_RDONLY)) == -1) {
  1739. *errmsg = vstrallocf("gnutar: error opening %s: %s",
  1740. inputname, strerror(errno));
  1741. dbprintf(("%s: %s\n", debug_prefix_time(NULL), *errmsg));
  1742. if (baselevel < 0) {
  1743. goto common_exit;
  1744. }
  1745. amfree(*errmsg);
  1746. }
  1747. }
  1748. /*
  1749. * Copy the previous listed incremental file to the new one.
  1750. */
  1751. if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) {
  1752. *errmsg = vstrallocf("opening %s: %s",
  1753. incrname, strerror(errno));
  1754. dbprintf(("%s: %s\n", debug_prefix_time(NULL), *errmsg));
  1755. goto common_exit;
  1756. }
  1757. while ((nb = read(infd, &buf, SIZEOF(buf))) > 0) {
  1758. if (fullwrite(outfd, &buf, (size_t)nb) < nb) {
  1759. *errmsg = vstrallocf("writing to %s: %s",
  1760. incrname, strerror(errno));
  1761. dbprintf(("%s: %s\n", debug_prefix_time(NULL), *errmsg));
  1762. goto common_exit;
  1763. }
  1764. }
  1765. if (nb < 0) {
  1766. *errmsg = vstrallocf("reading from %s: %s",
  1767. inputname, strerror(errno));
  1768. dbprintf(("%s: %s\n", debug_prefix_time(NULL), *errmsg));
  1769. goto common_exit;
  1770. }
  1771. if (close(infd) != 0) {
  1772. *errmsg = vstrallocf("closing %s: %s",
  1773. inputname, strerror(errno));
  1774. dbprintf(("%s: %s\n", debug_prefix_time(NULL), *errmsg));
  1775. goto common_exit;
  1776. }
  1777. if (close(outfd) != 0) {
  1778. *errmsg = vstrallocf("closing %s: %s",
  1779. incrname, strerror(errno));
  1780. dbprintf(("%s: %s\n", debug_prefix_time(NULL), *errmsg));
  1781. goto common_exit;
  1782. }
  1783. amfree(inputname);
  1784. amfree(basename);
  1785. }
  1786. gmtm = gmtime(&dumpsince);
  1787. snprintf(dumptimestr, SIZEOF(dumptimestr),
  1788. "%04d-%02d-%02d %2d:%02d:%02d GMT",
  1789. gmtm->tm_year + 1900, gmtm->tm_mon+1, gmtm->tm_mday,
  1790. gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec);
  1791. dirname = amname_to_dirname(amdevice);
  1792. cmd = vstralloc(libexecdir, "/", "runtar", versionsuffix(), NULL);
  1793. my_argv[i++] = "runtar";
  1794. if (g_options->config)
  1795. my_argv[i++] = g_options->config;
  1796. else
  1797. my_argv[i++] = "NOCONFIG";
  1798. #ifdef GNUTAR
  1799. my_argv[i++] = GNUTAR;
  1800. #else
  1801. my_argv[i++] = "tar";
  1802. #endif
  1803. my_argv[i++] = "--create";
  1804. my_argv[i++] = "--file";
  1805. my_argv[i++] = "/dev/null";
  1806. my_argv[i++] = "--directory";
  1807. my_argv[i++] = dirname;
  1808. my_argv[i++] = "--one-file-system";
  1809. if (gnutar_list_dir) {
  1810. my_argv[i++] = "--listed-incremental";
  1811. my_argv[i++] = incrname;
  1812. } else {
  1813. my_argv[i++] = "--incremental";
  1814. my_argv[i++] = "--newer";
  1815. my_argv[i++] = dumptimestr;
  1816. }
  1817. #ifdef ENABLE_GNUTAR_ATIME_PRESERVE
  1818. /* --atime-preserve causes gnutar to call
  1819. * utime() after reading files in order to
  1820. * adjust their atime. However, utime()
  1821. * updates the file's ctime, so incremental
  1822. * dumps will think the file has changed. */
  1823. my_argv[i++] = "--atime-preserve";
  1824. #endif
  1825. my_argv[i++] = "--sparse";
  1826. my_argv[i++] = "--ignore-failed-read";
  1827. my_argv[i++] = "--totals";
  1828. if(file_exclude) {
  1829. my_argv[i++] = "--exclude-from";
  1830. my_argv[i++] = file_exclude;
  1831. }
  1832. if(file_include) {
  1833. my_argv[i++] = "--files-from";
  1834. my_argv[i++] = file_include;
  1835. }
  1836. else {
  1837. my_argv[i++] = ".";
  1838. }
  1839. my_argv[i++] = NULL;
  1840. start_time = curclock();
  1841. if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
  1842. *errmsg = vstrallocf("Cannot access /dev/null : %s",
  1843. strerror(errno));
  1844. dbprintf(("%s: %s\n", debug_prefix_time(NULL), *errmsg));
  1845. goto common_exit;
  1846. }
  1847. dumppid = pipespawnv(cmd, STDERR_PIPE, &nullfd, &nullfd, &pipefd, my_argv);
  1848. dumpout = fdopen(pipefd,"r");
  1849. if (!dumpout) {
  1850. error("Can't fdopen: %s", strerror(errno));
  1851. /*NOTREACHED*/
  1852. }
  1853. for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
  1854. if (line[0] == '\0')
  1855. continue;
  1856. dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
  1857. size = handle_dumpline(line);
  1858. if(size > (off_t)-1) {
  1859. amfree(line);
  1860. while ((line = agets(dumpout)) != NULL) {
  1861. if (line[0] != '\0') {
  1862. break;
  1863. }
  1864. amfree(line);
  1865. }
  1866. if (line != NULL) {
  1867. dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
  1868. break;
  1869. }
  1870. break;
  1871. }
  1872. }
  1873. amfree(line);
  1874. dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
  1875. dbprintf(("%s: estimate time for %s level %d: %s\n",
  1876. debug_prefix_time(NULL),
  1877. qdisk,
  1878. level,
  1879. walltime_str(timessub(curclock(), start_time))));
  1880. if(size == (off_t)-1) {
  1881. *errmsg = vstrallocf("no size line match in %s output", my_argv[0]);
  1882. dbprintf(("%s: %s for %s\n", debug_prefix_time(NULL),
  1883. *errmsg, qdisk));
  1884. dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
  1885. } else if(size == (off_t)0 && level == 0) {
  1886. dbprintf(("%s: possible %s problem -- is \"%s\" really empty?\n",
  1887. debug_prefix_time(NULL), my_argv[0], disk));
  1888. dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
  1889. }
  1890. dbprintf(("%s: estimate size for %s level %d: " OFF_T_FMT " KB\n",
  1891. debug_prefix_time(NULL),
  1892. qdisk,
  1893. level,
  1894. (OFF_T_FMT_TYPE)size));
  1895. kill(-dumppid, SIGTERM);
  1896. dbprintf(("%s: waiting for %s \"%s\" child\n",
  1897. debug_prefix_time(NULL), my_argv[0], qdisk));
  1898. waitpid(dumppid, &wait_status, 0);
  1899. if (WIFSIGNALED(wait_status)) {
  1900. *errmsg = vstrallocf("%s terminated with signal %d: see %s",
  1901. cmd, WTERMSIG(wait_status), debug_fn());
  1902. } else if (WIFEXITED(wait_status)) {
  1903. if (WEXITSTATUS(wait_status) != 0) {
  1904. *errmsg = vstrallocf("%s exited with status %d: see %s",
  1905. cmd, WEXITSTATUS(wait_status), debug_fn());
  1906. } else {
  1907. /* Normal exit */
  1908. }
  1909. } else {
  1910. *errmsg = vstrallocf("%s got bad exit: see %s",
  1911. cmd, debug_fn());
  1912. }
  1913. dbprintf(("%s: after %s %s wait\n",
  1914. debug_prefix_time(NULL), my_argv[0], qdisk));
  1915. common_exit:
  1916. if (incrname) {
  1917. unlink(incrname);
  1918. }
  1919. amfree(incrname);
  1920. amfree(basename);
  1921. amfree(dirname);
  1922. amfree(inputname);
  1923. amfree(my_argv);
  1924. amfree(qdisk);
  1925. amfree(cmd);
  1926. amfree(file_exclude);
  1927. amfree(file_include);
  1928. aclose(nullfd);
  1929. afclose(dumpout);
  1930. afclose(in);
  1931. afclose(out);
  1932. return size;
  1933. }
  1934. #endif
  1935. off_t
  1936. getsize_backup_api(
  1937. char *program,
  1938. char *disk,
  1939. char *amdevice,
  1940. int level,
  1941. option_t *options,
  1942. time_t dumpsince,
  1943. char **errmsg)
  1944. {
  1945. int pipeinfd[2], pipeoutfd[2], nullfd;
  1946. pid_t dumppid;
  1947. off_t size = (off_t)-1;
  1948. FILE *dumpout, *toolin;
  1949. char *line = NULL;
  1950. char *cmd = NULL;
  1951. char dumptimestr[80];
  1952. struct tm *gmtm;
  1953. int i, j;
  1954. char *argvchild[10];
  1955. char *newoptstr = NULL;
  1956. off_t size1, size2;
  1957. times_t start_time;
  1958. char *qdisk = quote_string(disk);
  1959. char *qamdevice = quote_string(amdevice);
  1960. amwait_t wait_status;
  1961. char levelstr[NUM_STR_SIZE];
  1962. backup_support_option_t *bsu;
  1963. (void)options;
  1964. gmtm = gmtime(&dumpsince);
  1965. snprintf(dumptimestr, SIZEOF(dumptimestr),
  1966. "%04d-%02d-%02d %2d:%02d:%02d GMT",
  1967. gmtm->tm_year + 1900, gmtm->tm_mon+1, gmtm->tm_mday,
  1968. gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec);
  1969. cmd = vstralloc(DUMPER_DIR, "/", program, NULL);
  1970. bsu = backup_support_option(program, g_options, disk, amdevice);
  1971. i=0;
  1972. argvchild[i++] = program;
  1973. argvchild[i++] = "estimate";
  1974. if (bsu->message_line == 1) {
  1975. argvchild[i++] = "--message";
  1976. argvchild[i++] = "line";
  1977. }
  1978. if (g_options->config && bsu->config == 1) {
  1979. argvchild[i++] = "--config";
  1980. argvchild[i++] = g_options->config;
  1981. }
  1982. if (g_options->hostname && bsu->host == 1) {
  1983. argvchild[i++] = "--host";
  1984. argvchild[i++] = g_options->hostname;
  1985. }
  1986. argvchild[i++] = "--device";
  1987. argvchild[i++] = amdevice;
  1988. if (disk && bsu->disk == 1) {
  1989. argvchild[i++] = "--disk";
  1990. argvchild[i++] = disk;
  1991. }
  1992. if (level <= bsu->max_level) {
  1993. argvchild[i++] = "--level";
  1994. snprintf(levelstr,SIZEOF(levelstr),"%d",level);
  1995. argvchild[i++] = levelstr;
  1996. }
  1997. argvchild[i] = NULL;
  1998. dbprintf(("%s: running %s", debug_prefix_time(NULL), cmd));
  1999. for(j = 1; j < i; j++) {
  2000. dbprintf((" %s", argvchild[j]));
  2001. }
  2002. dbprintf(("\n"));
  2003. if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
  2004. *errmsg = vstrallocf("Cannot access /dev/null : %s",
  2005. strerror(errno));
  2006. dbprintf(("%s: %s\n", debug_prefix_time(NULL), *errmsg));
  2007. goto common_exit;
  2008. }
  2009. if (pipe(pipeinfd) < 0) {
  2010. *errmsg = vstrallocf("getsize_backup_api could create data pipes: %s",
  2011. strerror(errno));
  2012. dbprintf(("%s: %s\n", debug_prefix_time(NULL), *errmsg));
  2013. goto common_exit;
  2014. }
  2015. if (pipe(pipeoutfd) < 0) {
  2016. *errmsg = vstrallocf("getsize_backup_api could create data pipes: %s",
  2017. strerror(errno));
  2018. dbprintf(("%s: %s\n", debug_prefix_time(NULL), *errmsg));
  2019. goto common_exit;
  2020. }
  2021. start_time = curclock();
  2022. switch(dumppid = fork()) {
  2023. case -1:
  2024. size = (off_t)-1;
  2025. goto common_exit;
  2026. default:
  2027. break; /* parent */
  2028. case 0:
  2029. dup2(pipeinfd[0], 0);
  2030. dup2(pipeoutfd[1], 1);
  2031. dup2(nullfd, 2);
  2032. aclose(pipeinfd[1]);
  2033. aclose(pipeoutfd[0]);
  2034. execve(cmd, argvchild, safe_env());
  2035. error("exec %s failed: %s", cmd, strerror(errno));
  2036. /*NOTREACHED*/
  2037. }
  2038. amfree(newoptstr);
  2039. aclose(pipeinfd[0]);
  2040. aclose(pipeoutfd[1]);
  2041. toolin = fdopen(pipeinfd[1],"w");
  2042. if (!toolin) {
  2043. error("Can't fdopen: %s", strerror(errno));
  2044. /*NOTREACHED*/
  2045. }
  2046. output_tool_property(toolin, options);
  2047. fflush(toolin);
  2048. fclose(toolin);
  2049. dumpout = fdopen(pipeoutfd[0],"r");
  2050. if (!dumpout) {
  2051. error("Can't fdopen: %s", strerror(errno));
  2052. /*NOTREACHED*/
  2053. }
  2054. for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
  2055. OFF_T_FMT_TYPE size1_ = (OFF_T_FMT_TYPE)0;
  2056. OFF_T_FMT_TYPE size2_ = (OFF_T_FMT_TYPE)0;
  2057. if (line[0] == '\0')
  2058. continue;
  2059. dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
  2060. i = sscanf(line, OFF_T_FMT " " OFF_T_FMT, &size1_, &size2_);
  2061. size1 = (off_t)size1_;
  2062. size2 = (off_t)size2_;
  2063. if(i == 2) {
  2064. size = size1 * size2;
  2065. }
  2066. if(size > -1) {
  2067. amfree(line);
  2068. while ((line = agets(dumpout)) != NULL) {
  2069. if (line[0] != '\0')
  2070. break;
  2071. amfree(line);
  2072. }
  2073. if(line != NULL) {
  2074. dbprintf(("%s: %s\n", debug_prefix_time(NULL), line));
  2075. }
  2076. break;
  2077. }
  2078. }
  2079. amfree(line);
  2080. dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
  2081. dbprintf(("%s: estimate time for %s level %d: %s\n",
  2082. debug_prefix_time(NULL),
  2083. qamdevice,
  2084. level,
  2085. walltime_str(timessub(curclock(), start_time))));
  2086. if(size == (off_t)-1) {
  2087. *errmsg = vstrallocf("no size line match in %s output", cmd);
  2088. dbprintf(("%s: %s for %s\n", debug_prefix_time(NULL), cmd, qdisk));
  2089. dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
  2090. } else if(size == (off_t)0 && level == 0) {
  2091. dbprintf(("%s: possible %s problem -- is \"%s\" really empty?\n",
  2092. debug_prefix_time(NULL), cmd, qdisk));
  2093. dbprintf(("%s: .....\n", debug_prefix_time(NULL)));
  2094. }
  2095. dbprintf(("%s: estimate size for %s level %d: " OFF_T_FMT " KB\n",
  2096. debug_prefix_time(NULL),
  2097. qamdevice,
  2098. level,
  2099. (OFF_T_FMT_TYPE)size));
  2100. kill(-dumppid, SIGTERM);
  2101. dbprintf(("%s: waiting for %s \"%s\" child\n",
  2102. debug_prefix_time(NULL), cmd, qdisk));
  2103. waitpid(dumppid, &wait_status, 0);
  2104. if (WIFSIGNALED(wait_status)) {
  2105. *errmsg = vstrallocf("%s terminated with signal %d: see %s",
  2106. cmd, WTERMSIG(wait_status), debug_fn());
  2107. } else if (WIFEXITED(wait_status)) {
  2108. if (WEXITSTATUS(wait_status) != 0) {
  2109. *errmsg = vstrallocf("%s exited with status %d: see %s", cmd,
  2110. WEXITSTATUS(wait_status), debug_fn());
  2111. } else {
  2112. /* Normal exit */
  2113. }
  2114. } else {
  2115. *errmsg = vstrallocf("%s got bad exit: see %s",
  2116. cmd, debug_fn());
  2117. }
  2118. dbprintf(("%s: after %s %s wait\n",
  2119. debug_prefix_time(NULL), cmd, qdisk));
  2120. aclose(nullfd);
  2121. afclose(dumpout);
  2122. common_exit:
  2123. amfree(cmd);
  2124. amfree(newoptstr);
  2125. amfree(qdisk);
  2126. amfree(qamdevice);
  2127. return size;
  2128. }
  2129. /*
  2130. * Returns the value of the first integer in a string.
  2131. */
  2132. double
  2133. first_num(
  2134. char * str)
  2135. {
  2136. char *start;
  2137. int ch;
  2138. double d;
  2139. ch = *str++;
  2140. while(ch && !isdigit(ch)) ch = *str++;
  2141. start = str-1;
  2142. while(isdigit(ch) || (ch == '.')) ch = *str++;
  2143. str[-1] = '\0';
  2144. d = atof(start);
  2145. str[-1] = (char)ch;
  2146. return d;
  2147. }
  2148. /*
  2149. * Checks the dump output line against the error and size regex tables.
  2150. */
  2151. off_t
  2152. handle_dumpline(
  2153. char * str)
  2154. {
  2155. regex_t *rp;
  2156. double size;
  2157. /* check for size match */
  2158. /*@ignore@*/
  2159. for(rp = re_size; rp->regex != NULL; rp++) {
  2160. if(match(rp->regex, str)) {
  2161. size = ((first_num(str)*rp->scale+1023.0)/1024.0);
  2162. if(size < 0.0)
  2163. size = 1.0; /* found on NeXT -- sigh */
  2164. return (off_t)size;
  2165. }
  2166. }
  2167. /*@end@*/
  2168. return (off_t)-1;
  2169. }