PageRenderTime 197ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 1ms

/amanda/tags/3_3_0beta1/client-src/sendsize.c

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