PageRenderTime 68ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

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

#
C | 2399 lines | 2049 code | 214 blank | 136 comment | 564 complexity | 740a55feb06b0f11fc2b9b070015f6b5 MD5 | raw file

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

  1. /*
  2. * Amanda, The Advanced Maryland Automatic Network Disk Archiver
  3. * Copyright (c) 1991-1998 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. if (argc > 1 && argv && argv[1] && g_str_equal(argv[1], "--version")) {
  129. printf("sendsize-%s\n", VERSION);
  130. return (0);
  131. }
  132. /* initialize */
  133. /*
  134. * Configure program for internationalization:
  135. * 1) Only set the message locale for now.
  136. * 2) Set textdomain for all amanda related programs to "amanda"
  137. * We don't want to be forced to support dozens of message catalogs.
  138. */
  139. setlocale(LC_MESSAGES, "C");
  140. textdomain("amanda");
  141. safe_fd(-1, 0);
  142. openbsd_fd_inform();
  143. safe_cd();
  144. set_pname("sendsize");
  145. /* Don't die when child closes pipe */
  146. signal(SIGPIPE, SIG_IGN);
  147. add_amanda_log_handler(amanda_log_stderr);
  148. add_amanda_log_handler(amanda_log_syslog);
  149. dbopen(DBG_SUBDIR_CLIENT);
  150. startclock();
  151. dbprintf(_("version %s\n"), VERSION);
  152. our_features = am_init_feature_set();
  153. our_feature_string = am_feature_to_string(our_features);
  154. config_init(CONFIG_INIT_CLIENT, NULL);
  155. /* (check for config errors comes later) */
  156. check_running_as(RUNNING_AS_CLIENT_LOGIN);
  157. /* handle all service requests */
  158. for(; (line = agets(stdin)) != NULL; free(line)) {
  159. if (line[0] == '\0')
  160. continue;
  161. if(strncmp_const(line, "OPTIONS ") == 0) {
  162. g_options = parse_g_options(line+8, 1);
  163. if(!g_options->hostname) {
  164. g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
  165. gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH);
  166. g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0';
  167. }
  168. g_printf("OPTIONS ");
  169. if(am_has_feature(g_options->features, fe_rep_options_features)) {
  170. g_printf("features=%s;", our_feature_string);
  171. }
  172. if(am_has_feature(g_options->features, fe_rep_options_maxdumps)) {
  173. g_printf("maxdumps=%d;", g_options->maxdumps);
  174. }
  175. if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
  176. g_printf("hostname=%s;", g_options->hostname);
  177. }
  178. g_printf("\n");
  179. fflush(stdout);
  180. if (g_options->config) {
  181. /* overlay this configuration on the existing (nameless) configuration */
  182. config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
  183. g_options->config);
  184. dbrename(get_config_name(), DBG_SUBDIR_CLIENT);
  185. }
  186. /* check for any config errors now */
  187. if (config_errors(&errlist) >= CFGERR_ERRORS) {
  188. char *errstr = config_errors_to_error_string(errlist);
  189. g_printf("%s\n", errstr);
  190. dbclose();
  191. return 1;
  192. }
  193. if (am_has_feature(g_options->features, fe_req_xml)) {
  194. break;
  195. }
  196. continue;
  197. }
  198. dle = alloc_dle();
  199. s = line;
  200. ch = *s++;
  201. skip_whitespace(s, ch); /* find the program name */
  202. if(ch == '\0') {
  203. err_extra = stralloc(_("no program name"));
  204. goto err; /* no program name */
  205. }
  206. dle->program = s - 1;
  207. skip_non_whitespace(s, ch);
  208. s[-1] = '\0';
  209. dle->program_is_application_api=0;
  210. if(strncmp_const(dle->program, "CALCSIZE") == 0) {
  211. skip_whitespace(s, ch); /* find the program name */
  212. if(ch == '\0') {
  213. err_extra = stralloc(_("no program name"));
  214. goto err;
  215. }
  216. dle->estimatelist = g_slist_append(dle->estimatelist,
  217. GINT_TO_POINTER(ES_CALCSIZE));
  218. dle->program = s - 1;
  219. skip_non_whitespace(s, ch);
  220. s[-1] = '\0';
  221. if (strcmp(dle->program,"APPLICATION") == 0) {
  222. dle->program_is_application_api=1;
  223. skip_whitespace(s, ch); /* find dumper name */
  224. if (ch == '\0') {
  225. goto err; /* no program */
  226. }
  227. dle->program = s - 1;
  228. skip_non_whitespace(s, ch);
  229. s[-1] = '\0';
  230. }
  231. }
  232. else {
  233. dle->estimatelist = g_slist_append(dle->estimatelist,
  234. GINT_TO_POINTER(ES_CLIENT));
  235. if (strcmp(dle->program,"APPLICATION") == 0) {
  236. dle->program_is_application_api=1;
  237. skip_whitespace(s, ch); /* find dumper name */
  238. if (ch == '\0') {
  239. goto err; /* no program */
  240. }
  241. dle->program = s - 1;
  242. skip_non_whitespace(s, ch);
  243. s[-1] = '\0';
  244. }
  245. }
  246. dle->program = stralloc(dle->program);
  247. skip_whitespace(s, ch); /* find the disk name */
  248. if(ch == '\0') {
  249. err_extra = stralloc(_("no disk name"));
  250. goto err; /* no disk name */
  251. }
  252. if (qdisk != NULL)
  253. amfree(qdisk);
  254. fp = s - 1;
  255. skip_quoted_string(s, ch);
  256. s[-1] = '\0'; /* terminate the disk name */
  257. qdisk = stralloc(fp);
  258. dle->disk = unquote_string(qdisk);
  259. skip_whitespace(s, ch); /* find the device or level */
  260. if (ch == '\0') {
  261. err_extra = stralloc(_("bad level"));
  262. goto err;
  263. }
  264. if(!isdigit((int)s[-1])) {
  265. fp = s - 1;
  266. skip_quoted_string(s, ch);
  267. s[-1] = '\0';
  268. qamdevice = stralloc(fp);
  269. dle->device = unquote_string(qamdevice);
  270. skip_whitespace(s, ch); /* find level number */
  271. }
  272. else {
  273. dle->device = stralloc(dle->disk);
  274. qamdevice = stralloc(qdisk);
  275. }
  276. /* find the level number */
  277. if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
  278. err_extra = stralloc(_("bad level"));
  279. goto err; /* bad level */
  280. }
  281. if (level < 0 || level >= DUMP_LEVELS) {
  282. err_extra = stralloc(_("bad level"));
  283. goto err;
  284. }
  285. skip_integer(s, ch);
  286. alevel = g_new0(level_t, 1);
  287. alevel->level = level;
  288. dle->levellist = g_slist_append(dle->levellist, alevel);
  289. skip_whitespace(s, ch); /* find the dump date */
  290. if(ch == '\0') {
  291. err_extra = stralloc(_("no dumpdate"));
  292. goto err; /* no dumpdate */
  293. }
  294. dumpdate = s - 1;
  295. skip_non_whitespace(s, ch);
  296. s[-1] = '\0';
  297. (void)dumpdate; /* XXX: Set but not used */
  298. dle->spindle = 0; /* default spindle */
  299. skip_whitespace(s, ch); /* find the spindle */
  300. if(ch != '\0') {
  301. if(sscanf(s - 1, "%d", &dle->spindle) != 1) {
  302. err_extra = stralloc(_("bad spindle"));
  303. goto err; /* bad spindle */
  304. }
  305. skip_integer(s, ch);
  306. skip_whitespace(s, ch); /* find the parameters */
  307. if(ch != '\0') {
  308. if(strncmp_const(s-1, "OPTIONS |;") == 0) {
  309. parse_options(s + 8,
  310. dle,
  311. g_options->features,
  312. 0);
  313. }
  314. else {
  315. while (ch != '\0') {
  316. if(strncmp_const(s-1, "exclude-file=") == 0) {
  317. qlist = unquote_string(s+12);
  318. dle->exclude_file =
  319. append_sl(dle->exclude_file, qlist);
  320. amfree(qlist);
  321. } else if(strncmp_const(s-1, "exclude-list=") == 0) {
  322. qlist = unquote_string(s+12);
  323. dle->exclude_list =
  324. append_sl(dle->exclude_list, qlist);
  325. amfree(qlist);
  326. } else if(strncmp_const(s-1, "include-file=") == 0) {
  327. qlist = unquote_string(s+12);
  328. dle->include_file =
  329. append_sl(dle->include_file, qlist);
  330. amfree(qlist);
  331. } else if(strncmp_const(s-1, "include-list=") == 0) {
  332. qlist = unquote_string(s+12);
  333. dle->include_list =
  334. append_sl(dle->include_list, qlist);
  335. amfree(qlist);
  336. } else {
  337. err_extra = vstrallocf(_("Invalid parameter (%s)"), s-1);
  338. goto err; /* should have gotten to end */
  339. }
  340. skip_quoted_string(s, ch);
  341. skip_whitespace(s, ch); /* find the inclusion list */
  342. amfree(qlist);
  343. }
  344. }
  345. }
  346. }
  347. /*@ignore@*/
  348. dle_add_diskest(dle);
  349. /*@end@*/
  350. }
  351. if (g_options == NULL) {
  352. g_printf(_("ERROR [Missing OPTIONS line in sendsize input]\n"));
  353. error(_("Missing OPTIONS line in sendsize input\n"));
  354. /*NOTREACHED*/
  355. }
  356. amfree(line);
  357. if (am_has_feature(g_options->features, fe_req_xml)) {
  358. char *errmsg = NULL;
  359. dle_t *dles, *dle;
  360. dles = amxml_parse_node_FILE(stdin, &errmsg);
  361. if (errmsg) {
  362. err_extra = errmsg;
  363. goto err;
  364. }
  365. for (dle = dles; dle != NULL; dle = dle->next) {
  366. dle_add_diskest(dle);
  367. }
  368. }
  369. if (amandates_started) {
  370. finish_amandates();
  371. free_amandates();
  372. amandates_started = FALSE;
  373. }
  374. est_prev = NULL;
  375. for(est = est_list; est != NULL; est = est_next) {
  376. int good = merge_dles_properties(est->dle, 0);
  377. est_next = est->next;
  378. if (!good) {
  379. if (est == est_list) {
  380. est_list = est_next;
  381. } else {
  382. est_prev->next = est_next;
  383. }
  384. } else {
  385. est_prev = est;
  386. }
  387. }
  388. for(est = est_list; est != NULL; est = est->next) {
  389. run_client_scripts(EXECUTE_ON_PRE_HOST_ESTIMATE, g_options, est->dle,
  390. stdout);
  391. }
  392. dumpsrunning = 0;
  393. need_wait = 0;
  394. done = 0;
  395. while(! done) {
  396. done = 1;
  397. /*
  398. * See if we need to wait for a child before we can do anything
  399. * else in this pass.
  400. */
  401. if(need_wait) {
  402. pid_t child_pid;
  403. amwait_t child_status;
  404. need_wait = 0;
  405. dbprintf(_("waiting for any estimate child: %d running\n"),
  406. dumpsrunning);
  407. child_pid = wait(&child_status);
  408. if(child_pid == -1) {
  409. error(_("wait failed: %s"), strerror(errno));
  410. /*NOTREACHED*/
  411. }
  412. if (!WIFEXITED(child_status) || WEXITSTATUS(child_status) != 0) {
  413. char *child_name = vstrallocf(_("child %ld"), (long)child_pid);
  414. char *child_status_str = str_exit_status(child_name, child_status);
  415. dbprintf("%s\n", child_status_str);
  416. amfree(child_status_str);
  417. amfree(child_name);
  418. }
  419. /*
  420. * Find the child and mark it done.
  421. */
  422. for(est = est_list; est != NULL; est = est->next) {
  423. if(est->child == child_pid) {
  424. break;
  425. }
  426. }
  427. if(est == NULL) {
  428. dbprintf(_("unexpected child %ld\n"), (long)child_pid);
  429. } else {
  430. est->done = 1;
  431. est->child = 0;
  432. dumpsrunning--;
  433. run_client_scripts(EXECUTE_ON_POST_DLE_ESTIMATE, g_options,
  434. est->dle, stdout);
  435. }
  436. }
  437. /*
  438. * If we are already running the maximum number of children
  439. * go back and wait until one of them finishes.
  440. */
  441. if(dumpsrunning >= g_options->maxdumps) {
  442. done = 0;
  443. need_wait = 1;
  444. continue; /* have to wait first */
  445. }
  446. /*
  447. * Find a new child to start.
  448. */
  449. for(est = est_list; est != NULL; est = est->next) {
  450. if(est->done == 0) {
  451. done = 0; /* more to do */
  452. }
  453. if(est->child != 0 || est->done) {
  454. continue; /* child is running or done */
  455. }
  456. /*
  457. * Make sure there is no spindle conflict.
  458. */
  459. if(est->dle->spindle != -1) {
  460. for(est1 = est_list; est1 != NULL; est1 = est1->next) {
  461. if(est1->child == 0 || est == est1 || est1->done) {
  462. /*
  463. * Ignore anything not yet started, ourself,
  464. * and anything completed.
  465. */
  466. continue;
  467. }
  468. if(est1->dle->spindle == est->dle->spindle) {
  469. break; /* oops -- they match */
  470. }
  471. }
  472. if(est1 != NULL) {
  473. continue; /* spindle conflict */
  474. }
  475. }
  476. break; /* start this estimate */
  477. }
  478. if(est == NULL) {
  479. if(dumpsrunning > 0) {
  480. need_wait = 1; /* nothing to do but wait */
  481. }
  482. } else {
  483. done = 0;
  484. run_client_scripts(EXECUTE_ON_PRE_DLE_ESTIMATE, g_options,
  485. est->dle, stdout);
  486. if((est->child = fork()) == 0) {
  487. calc_estimates(est); /* child does the estimate */
  488. exit(0);
  489. } else if(est->child == -1) {
  490. error(_("calc_estimates fork failed: %s"), strerror(errno));
  491. /*NOTREACHED*/
  492. }
  493. dumpsrunning++; /* parent */
  494. }
  495. }
  496. for(est = est_list; est != NULL; est = est->next) {
  497. run_client_scripts(EXECUTE_ON_POST_HOST_ESTIMATE, g_options, est->dle,
  498. stdout);
  499. }
  500. est_prev = NULL;
  501. for(est = est_list; est != NULL; est = est->next) {
  502. free_estimates(est);
  503. amfree(est_prev);
  504. est_prev = est;
  505. }
  506. amfree(est_prev);
  507. amfree(our_feature_string);
  508. am_release_feature_set(our_features);
  509. our_features = NULL;
  510. free_g_options(g_options);
  511. dbclose();
  512. return 0;
  513. err:
  514. if (err_extra) {
  515. g_printf(_("ERROR FORMAT ERROR IN REQUEST PACKET '%s'\n"), err_extra);
  516. dbprintf(_("REQ packet is bogus: %s\n"), err_extra);
  517. amfree(err_extra);
  518. } else {
  519. g_printf(_("ERROR FORMAT ERROR IN REQUEST PACKET\n"));
  520. dbprintf(_("REQ packet is bogus\n"));
  521. }
  522. free_g_options(g_options);
  523. dbclose();
  524. return 1;
  525. }
  526. void
  527. dle_add_diskest(
  528. dle_t *dle)
  529. {
  530. disk_estimates_t *newp, *curp;
  531. amandates_t *amdp;
  532. int dumplev, estlev;
  533. time_t dumpdate;
  534. levellist_t levellist;
  535. char *amandates_file;
  536. gboolean need_amandates = FALSE;
  537. estimatelist_t el;
  538. if (dle->levellist == NULL) {
  539. g_printf(_("ERROR Missing level in request\n"));
  540. return;
  541. }
  542. /* should we use amandates for this? */
  543. for (el = dle->estimatelist; el != NULL; el=el->next) {
  544. estimate_t estimate = (estimate_t)GPOINTER_TO_INT(el->data);
  545. if (estimate == ES_CALCSIZE)
  546. need_amandates = TRUE;
  547. }
  548. if (strcmp(dle->program, "GNUTAR") == 0) {
  549. /* GNUTAR only needs amandates if gnutar_list_dir is NULL */
  550. char *gnutar_list_dir = getconf_str(CNF_GNUTAR_LIST_DIR);
  551. if (!gnutar_list_dir || !*gnutar_list_dir)
  552. need_amandates = TRUE;
  553. }
  554. /* start amandates here, before adding this DLE to est_list, in case
  555. * we encounter an error. */
  556. if (need_amandates) {
  557. if (!amandates_started) {
  558. amandates_file = getconf_str(CNF_AMANDATES);
  559. if(!start_amandates(amandates_file, 0)) {
  560. char *errstr = strerror(errno);
  561. char *qamname = quote_string(dle->disk);
  562. char *errmsg = vstrallocf(_("could not open %s: %s"), amandates_file, errstr);
  563. char *qerrmsg = quote_string(errmsg);
  564. g_printf(_("%s %d ERROR %s\n"), qamname, 0, qerrmsg);
  565. amfree(qamname);
  566. amfree(errmsg);
  567. amfree(qerrmsg);
  568. return;
  569. }
  570. amandates_started = TRUE;
  571. }
  572. }
  573. levellist = dle->levellist;
  574. while (levellist != NULL) {
  575. level_t *alevel = (level_t *)levellist->data;
  576. if (alevel->level < 0)
  577. alevel->level = 0;
  578. if (alevel->level >= DUMP_LEVELS)
  579. alevel->level = DUMP_LEVELS - 1;
  580. levellist = g_slist_next(levellist);
  581. }
  582. for(curp = est_list; curp != NULL; curp = curp->next) {
  583. if(strcmp(curp->dle->disk, dle->disk) == 0) {
  584. /* already have disk info, just note the level request */
  585. levellist = dle->levellist;
  586. while (levellist != NULL) {
  587. level_t *alevel = (level_t *)levellist->data;
  588. int level = alevel->level;
  589. curp->est[level].needestimate = 1;
  590. curp->est[level].server = alevel->server;
  591. levellist = g_slist_next(levellist);
  592. }
  593. return;
  594. }
  595. }
  596. newp = (disk_estimates_t *) alloc(SIZEOF(disk_estimates_t));
  597. memset(newp, 0, SIZEOF(*newp));
  598. newp->next = est_list;
  599. est_list = newp;
  600. newp->qamname = quote_string(dle->disk);
  601. if (dle->device) {
  602. newp->qamdevice = quote_string(dle->device);
  603. newp->dirname = amname_to_dirname(dle->device);
  604. newp->qdirname = quote_string(newp->dirname);
  605. } else {
  606. newp->qamdevice = stralloc("");
  607. newp->dirname = stralloc("");
  608. newp->qdirname = stralloc("");
  609. }
  610. levellist = dle->levellist;
  611. while (levellist != NULL) {
  612. level_t *alevel = (level_t *)levellist->data;
  613. newp->est[alevel->level].needestimate = 1;
  614. newp->est[alevel->level].server = alevel->server;
  615. levellist = g_slist_next(levellist);
  616. }
  617. newp->dle = dle;
  618. /* fill in dump-since dates */
  619. if (need_amandates) {
  620. amdp = amandates_lookup(newp->dle->disk);
  621. newp->est[0].dumpsince = EPOCH;
  622. for(dumplev = 0; dumplev < DUMP_LEVELS; dumplev++) {
  623. dumpdate = amdp->dates[dumplev];
  624. for(estlev = dumplev+1; estlev < DUMP_LEVELS; estlev++) {
  625. if(dumpdate > newp->est[estlev].dumpsince)
  626. newp->est[estlev].dumpsince = dumpdate;
  627. }
  628. }
  629. } else {
  630. /* just zero everything out */
  631. for(dumplev = 0; dumplev < DUMP_LEVELS; dumplev++) {
  632. newp->est[dumplev].dumpsince = 0;
  633. }
  634. }
  635. }
  636. void
  637. free_estimates(
  638. disk_estimates_t * est)
  639. {
  640. amfree(est->qamname);
  641. amfree(est->qamdevice);
  642. amfree(est->dirname);
  643. amfree(est->qdirname);
  644. if (est->dle) {
  645. free_dle(est->dle);
  646. }
  647. }
  648. /*
  649. * ------------------------------------------------------------------------
  650. *
  651. */
  652. void
  653. calc_estimates(
  654. disk_estimates_t * est)
  655. {
  656. dbprintf(_("calculating for amname %s, dirname %s, spindle %d %s\n"),
  657. est->qamname, est->qdirname, est->dle->spindle, est->dle->program);
  658. if(est->dle->program_is_application_api == 1)
  659. application_api_calc_estimate(est);
  660. else {
  661. estimatelist_t el;
  662. estimate_t estimate;
  663. int level;
  664. estimate_t estimate_method = ES_ES;
  665. estimate_t client_method = ES_ES;
  666. /* find estimate method to use */
  667. for (el = est->dle->estimatelist; el != NULL; el = el->next) {
  668. estimate = (estimate_t)GPOINTER_TO_INT(el->data);
  669. if (estimate == ES_SERVER) {
  670. if (estimate_method == ES_ES)
  671. estimate_method = ES_SERVER;
  672. }
  673. if (estimate == ES_CLIENT ||
  674. (estimate == ES_CALCSIZE &&
  675. (est->dle->device[0] != '/' || est->dle->device[1] != '/'))) {
  676. if (client_method == ES_ES)
  677. client_method = estimate;
  678. if (estimate_method == ES_ES)
  679. estimate_method = estimate;
  680. }
  681. }
  682. /* do server estimate */
  683. if (estimate_method == ES_SERVER) {
  684. for (level = 0; level < DUMP_LEVELS; level++) {
  685. if (est->est[level].needestimate) {
  686. if (est->est[level].server || client_method == ES_ES) {
  687. g_printf(_("%s %d SIZE -1\n"), est->qamname, level);
  688. est->est[level].needestimate = 0;
  689. }
  690. }
  691. }
  692. }
  693. if (client_method == ES_ES && estimate_method != ES_SERVER) {
  694. g_printf(_("%s %d SIZE -2\n"), est->qamname, 0);
  695. dbprintf(_("Can't use CALCSIZE for samba estimate: %s %s\n"),
  696. est->qamname, est->qdirname);
  697. } else if (client_method == ES_CALCSIZE) {
  698. generic_calc_estimates(est);
  699. } else if (client_method == ES_CLIENT) {
  700. #ifndef USE_GENERIC_CALCSIZE
  701. if (strcmp(est->dle->program, "DUMP") == 0)
  702. dump_calc_estimates(est);
  703. else
  704. #endif
  705. #ifdef SAMBA_CLIENT
  706. if (strcmp(est->dle->program, "GNUTAR") == 0 &&
  707. est->dle->device[0] == '/' && est->dle->device[1] == '/')
  708. smbtar_calc_estimates(est);
  709. else
  710. #endif
  711. #ifdef GNUTAR
  712. if (strcmp(est->dle->program, "GNUTAR") == 0)
  713. gnutar_calc_estimates(est);
  714. else
  715. #endif
  716. dbprintf(_("Invalid program: %s %s %s\n"),
  717. est->qamname, est->qdirname, est->dle->program);
  718. }
  719. }
  720. dbprintf(_("done with amname %s dirname %s spindle %d\n"),
  721. est->qamname, est->qdirname, est->dle->spindle);
  722. }
  723. /*
  724. * ------------------------------------------------------------------------
  725. *
  726. */
  727. /* local functions */
  728. off_t getsize_dump(dle_t *dle, int level, char **errmsg);
  729. off_t getsize_smbtar(dle_t *dle, int level, char **errmsg);
  730. off_t getsize_gnutar(dle_t *dle, int level, time_t dumpsince, char **errmsg);
  731. off_t getsize_application_api(disk_estimates_t *est, int nb_level,
  732. int *levels, backup_support_option_t *bsu);
  733. off_t handle_dumpline(char *str);
  734. double first_num(char *str);
  735. void
  736. application_api_calc_estimate(
  737. disk_estimates_t * est)
  738. {
  739. int level;
  740. int i;
  741. int levels[DUMP_LEVELS];
  742. int nb_level = 0;
  743. backup_support_option_t *bsu;
  744. GPtrArray *errarray;
  745. estimatelist_t el;
  746. estimate_t estimate;
  747. estimate_t estimate_method = ES_ES;
  748. estimate_t client_method = ES_ES;
  749. int has_calcsize = 0;
  750. int has_client = 0;
  751. bsu = backup_support_option(est->dle->program, g_options, est->dle->disk,
  752. est->dle->device, &errarray);
  753. if (!bsu) {
  754. guint i;
  755. for (i=0; i < errarray->len; i++) {
  756. char *line;
  757. char *errmsg;
  758. char *qerrmsg;
  759. line = g_ptr_array_index(errarray, i);
  760. if(am_has_feature(g_options->features,
  761. fe_rep_sendsize_quoted_error)) {
  762. errmsg = g_strdup_printf(_("Application '%s': %s"),
  763. est->dle->program, line);
  764. qerrmsg = quote_string(errmsg);
  765. for (level = 0; level < DUMP_LEVELS; level++) {
  766. if (est->est[level].needestimate) {
  767. g_printf(_("%s %d ERROR %s\n"),
  768. est->dle->disk, level, qerrmsg);
  769. dbprintf(_("%s %d ERROR %s\n"),
  770. est->qamname, level, qerrmsg);
  771. }
  772. }
  773. amfree(errmsg);
  774. amfree(qerrmsg);
  775. }
  776. }
  777. if (i == 0) { /* nothing in errarray */
  778. char *errmsg;
  779. char *qerrmsg;
  780. errmsg = g_strdup_printf(
  781. _("Application '%s': cannon execute support command"),
  782. est->dle->program);
  783. qerrmsg = quote_string(errmsg);
  784. for (level = 0; level < DUMP_LEVELS; level++) {
  785. if (est->est[level].needestimate) {
  786. g_printf(_("%s %d ERROR %s\n"),
  787. est->dle->disk, level, qerrmsg);
  788. dbprintf(_("%s %d ERROR %s\n"),
  789. est->qamname, level, qerrmsg);
  790. }
  791. }
  792. amfree(errmsg);
  793. amfree(qerrmsg);
  794. }
  795. for (level = 0; level < DUMP_LEVELS; level++) {
  796. est->est[level].needestimate = 0;
  797. }
  798. g_ptr_array_free(errarray, TRUE);
  799. }
  800. if (est->dle->data_path == DATA_PATH_AMANDA &&
  801. (bsu->data_path_set & DATA_PATH_AMANDA)==0) {
  802. g_printf("%s %d ERROR application %s doesn't support amanda data-path\n", est->qamname, 0, est->dle->program);
  803. amfree(bsu);
  804. return;
  805. }
  806. if (est->dle->data_path == DATA_PATH_DIRECTTCP &&
  807. (bsu->data_path_set & DATA_PATH_DIRECTTCP)==0) {
  808. g_printf("%s %d ERROR application %s doesn't support directtcp data-path\n", est->qamname, 0, est->dle->program);
  809. amfree(bsu);
  810. return;
  811. }
  812. /* find estimate method to use */
  813. for (el = est->dle->estimatelist; el != NULL; el = el->next) {
  814. estimate = (estimate_t)GPOINTER_TO_INT(el->data);
  815. if (estimate == ES_CLIENT)
  816. has_client = 1;
  817. if (estimate == ES_CALCSIZE)
  818. has_calcsize = 1;
  819. if (estimate == ES_SERVER) {
  820. if (estimate_method == ES_ES)
  821. estimate_method = ES_SERVER;
  822. }
  823. if ((estimate == ES_CLIENT && bsu->client_estimate) ||
  824. (estimate == ES_CALCSIZE && bsu->calcsize)) {
  825. if (client_method == ES_ES)
  826. client_method = estimate;
  827. if (estimate_method == ES_ES)
  828. estimate_method = estimate;
  829. }
  830. }
  831. for(level = 0; level < DUMP_LEVELS; level++) {
  832. if (est->est[level].needestimate) {
  833. if (level > bsu->max_level) {
  834. /* planner will not even consider this level */
  835. g_printf("%s %d SIZE %lld\n", est->qamname, level,
  836. (long long)-2);
  837. est->est[level].needestimate = 0;
  838. dbprintf(_("Application '%s' can't estimate level %d\n"),
  839. est->dle->program, level);
  840. } else if (estimate_method == ES_ES) {
  841. g_printf("%s %d SIZE %lld\n", est->qamname, level,
  842. (long long)-2);
  843. est->est[level].needestimate = 0;
  844. if (am_has_feature(g_options->features,
  845. fe_rep_sendsize_quoted_error)) {
  846. char *errmsg, *qerrmsg;
  847. if (has_client && !bsu->client_estimate &&
  848. has_calcsize && !bsu->calcsize) {
  849. errmsg = vstrallocf(_("Application '%s' can't do CLIENT or CALCSIZE estimate"),
  850. est->dle->program);
  851. } else if (has_client && !bsu->client_estimate) {
  852. errmsg = vstrallocf(_("Application '%s' can't do CLIENT estimate"),
  853. est->dle->program);
  854. } else if (has_calcsize && !bsu->calcsize) {
  855. errmsg = vstrallocf(_("Application '%s' can't do CALCSIZE estimate"),
  856. est->dle->program);
  857. } else {
  858. errmsg = vstrallocf(_("Application '%s' can't do estimate"),
  859. est->dle->program);
  860. }
  861. qerrmsg = quote_string(errmsg);
  862. dbprintf(_("errmsg is %s\n"), errmsg);
  863. g_printf("%s %d ERROR %s\n",
  864. est->qamname, 0, qerrmsg);
  865. amfree(errmsg);
  866. amfree(qerrmsg);
  867. }
  868. } else if (estimate_method == ES_SERVER &&
  869. (est->est[level].server || client_method == ES_ES)) {
  870. /* planner will consider this level, */
  871. /* but use a server-side estimate */
  872. g_printf("%s %d SIZE -1\n", est->qamname, level);
  873. est->est[level].needestimate = 0;
  874. } else if (client_method == ES_CLIENT) {
  875. levels[nb_level++] = level;
  876. } else if (client_method == ES_CALCSIZE) {
  877. levels[nb_level++] = level;
  878. }
  879. }
  880. }
  881. if (nb_level == 0) {
  882. amfree(bsu);
  883. return;
  884. }
  885. if (bsu->multi_estimate) {
  886. for (i=0;i<nb_level;i++) {
  887. dbprintf(_("getting size via application API for %s %s level %d\n"),
  888. est->qamname, est->qamdevice, levels[i]);
  889. }
  890. getsize_application_api(est, nb_level, levels, bsu);
  891. } else {
  892. for(level = 0; level < DUMP_LEVELS; level++) {
  893. if (est->est[level].needestimate) {
  894. dbprintf(
  895. _("getting size via application API for %s %s level %d\n"),
  896. est->qamname, est->qamdevice, level);
  897. levels[0] = level;
  898. getsize_application_api(est, 1, levels, bsu);
  899. }
  900. }
  901. }
  902. amfree(bsu);
  903. }
  904. void
  905. generic_calc_estimates(
  906. disk_estimates_t * est)
  907. {
  908. int pipefd = -1, nullfd = -1;
  909. char *cmd;
  910. char *cmdline;
  911. char *command;
  912. GPtrArray *argv_ptr = g_ptr_array_new();
  913. char number[NUM_STR_SIZE];
  914. unsigned int i;
  915. int level;
  916. pid_t calcpid;
  917. int nb_exclude = 0;
  918. int nb_include = 0;
  919. char *file_exclude = NULL;
  920. char *file_include = NULL;
  921. times_t start_time;
  922. FILE *dumpout = NULL;
  923. char *line = NULL;
  924. char *match_expr;
  925. amwait_t wait_status;
  926. char *errmsg = NULL, *qerrmsg;
  927. char tmppath[PATH_MAX];
  928. int len;
  929. cmd = vstralloc(amlibexecdir, "/", "calcsize", NULL);
  930. g_ptr_array_add(argv_ptr, stralloc("calcsize"));
  931. if (g_options->config)
  932. g_ptr_array_add(argv_ptr, stralloc(g_options->config));
  933. else
  934. g_ptr_array_add(argv_ptr, stralloc("NOCONFIG"));
  935. g_ptr_array_add(argv_ptr, stralloc(est->dle->program));
  936. canonicalize_pathname(est->dle->disk, tmppath);
  937. g_ptr_array_add(argv_ptr, stralloc(tmppath));
  938. canonicalize_pathname(est->dirname, tmppath);
  939. g_ptr_array_add(argv_ptr, stralloc(tmppath));
  940. if (est->dle->exclude_file)
  941. nb_exclude += est->dle->exclude_file->nb_element;
  942. if (est->dle->exclude_list)
  943. nb_exclude += est->dle->exclude_list->nb_element;
  944. if (est->dle->include_file)
  945. nb_include += est->dle->include_file->nb_element;
  946. if (est->dle->include_list)
  947. nb_include += est->dle->include_list->nb_element;
  948. if (nb_exclude > 0)
  949. file_exclude = build_exclude(est->dle, 0);
  950. if (nb_include > 0)
  951. file_include = build_include(est->dle, 0);
  952. if(file_exclude) {
  953. g_ptr_array_add(argv_ptr, stralloc("-X"));
  954. g_ptr_array_add(argv_ptr, stralloc(file_exclude));
  955. }
  956. if(file_include) {
  957. g_ptr_array_add(argv_ptr, stralloc("-I"));
  958. g_ptr_array_add(argv_ptr, stralloc(file_include));
  959. }
  960. start_time = curclock();
  961. command = (char *)g_ptr_array_index(argv_ptr, 0);
  962. cmdline = stralloc(command);
  963. for(i = 1; i < argv_ptr->len-1; i++) {
  964. cmdline = vstrextend(&cmdline, " ",
  965. (char *)g_ptr_array_index(argv_ptr, i), NULL);
  966. }
  967. dbprintf(_("running: \"%s\"\n"), cmdline);
  968. amfree(cmdline);
  969. for(level = 0; level < DUMP_LEVELS; level++) {
  970. if(est->est[level].needestimate) {
  971. g_snprintf(number, SIZEOF(number), "%d", level);
  972. g_ptr_array_add(argv_ptr, stralloc(number));
  973. dbprintf(" %s", number);
  974. g_snprintf(number, SIZEOF(number),
  975. "%ld", (long)est->est[level].dumpsince);
  976. g_ptr_array_add(argv_ptr, stralloc(number));
  977. dbprintf(" %s", number);
  978. }
  979. }
  980. g_ptr_array_add(argv_ptr, NULL);
  981. dbprintf("\n");
  982. fflush(stderr); fflush(stdout);
  983. if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
  984. errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
  985. strerror(errno));
  986. dbprintf("%s\n", errmsg);
  987. goto common_exit;
  988. }
  989. calcpid = pipespawnv(cmd, STDERR_PIPE, 0,
  990. &nullfd, &nullfd, &pipefd, (char **)argv_ptr->pdata);
  991. amfree(cmd);
  992. dumpout = fdopen(pipefd,"r");
  993. if (!dumpout) {
  994. error(_("Can't fdopen: %s"), strerror(errno));
  995. /*NOTREACHED*/
  996. }
  997. match_expr = vstralloc(" %d SIZE %lld", NULL);
  998. len = strlen(est->qamname);
  999. for(; (line = agets(dumpout)) != NULL; free(line)) {
  1000. long long size_ = (long long)0;
  1001. if (line[0] == '\0' || (int)strlen(line) <= len)
  1002. continue;
  1003. /* Don't use sscanf for est->qamname because it can have a '%'. */
  1004. if (strncmp(line, est->qamname, len) == 0 &&
  1005. sscanf(line+len, match_expr, &level, &size_) == 2) {
  1006. g_printf("%s\n", line); /* write to amandad */
  1007. dbprintf(_("estimate size for %s level %d: %lld KB\n"),
  1008. est->qamname,
  1009. level,
  1010. size_);
  1011. }
  1012. }
  1013. amfree(match_expr);
  1014. dbprintf(_("waiting for %s %s child (pid=%d)\n"),
  1015. command, est->qamdevice, (int)calcpid);
  1016. waitpid(calcpid, &wait_status, 0);
  1017. if (WIFSIGNALED(wait_status)) {
  1018. errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
  1019. "calcsize", WTERMSIG(wait_status),
  1020. dbfn());
  1021. } else if (WIFEXITED(wait_status)) {
  1022. if (WEXITSTATUS(wait_status) != 0) {
  1023. errmsg = vstrallocf(_("%s exited with status %d: see %s"),
  1024. "calcsize", WEXITSTATUS(wait_status),
  1025. dbfn());
  1026. } else {
  1027. /* Normal exit */
  1028. }
  1029. } else {
  1030. errmsg = vstrallocf(_("%s got bad exit: see %s"),
  1031. "calcsize", dbfn());
  1032. }
  1033. dbprintf(_("after %s %s wait: child pid=%d status=%d\n"),
  1034. command, est->qamdevice,
  1035. (int)calcpid, WEXITSTATUS(wait_status));
  1036. dbprintf(_(".....\n"));
  1037. dbprintf(_("estimate time for %s: %s\n"),
  1038. est->qamname,
  1039. walltime_str(timessub(curclock(), start_time)));
  1040. common_exit:
  1041. if (errmsg && errmsg[0] != '\0') {
  1042. if(am_has_feature(g_options->features, fe_rep_sendsize_quoted_error)) {
  1043. qerrmsg = quote_string(errmsg);
  1044. dbprintf(_("errmsg is %s\n"), errmsg);
  1045. g_printf("%s %d ERROR %s\n",
  1046. est->qamname, 0, qerrmsg);
  1047. amfree(qerrmsg);
  1048. }
  1049. }
  1050. amfree(errmsg);
  1051. g_ptr_array_free_full(argv_ptr);
  1052. amfree(cmd);
  1053. }
  1054. void
  1055. dump_calc_estimates(
  1056. disk_estimates_t * est)
  1057. {
  1058. int level;
  1059. off_t size;
  1060. char *errmsg=NULL, *qerrmsg;
  1061. for(level = 0; level < DUMP_LEVELS; level++) {
  1062. if(est->est[level].needestimate) {
  1063. dbprintf(_("getting size via dump for %s level %d\n"),
  1064. est->qamname, level);
  1065. size = getsize_dump(est->dle, level, &errmsg);
  1066. amflock(1, "size");
  1067. g_printf(_("%s %d SIZE %lld\n"),
  1068. est->qamname, level, (long long)size);
  1069. if (errmsg && errmsg[0] != '\0') {
  1070. if(am_has_feature(g_options->features,
  1071. fe_rep_sendsize_quoted_error)) {
  1072. qerrmsg = quote_string(errmsg);
  1073. dbprintf(_("errmsg is %s\n"), errmsg);
  1074. g_printf("%s %d ERROR %s\n",
  1075. est->qamname, level, qerrmsg);
  1076. amfree(qerrmsg);
  1077. }
  1078. }
  1079. amfree(errmsg);
  1080. fflush(stdout);
  1081. amfunlock(1, "size");
  1082. }
  1083. }
  1084. }
  1085. #ifdef SAMBA_CLIENT
  1086. void
  1087. smbtar_calc_estimates(
  1088. disk_estimates_t * est)
  1089. {
  1090. int level;
  1091. off_t size;
  1092. char *errmsg = NULL, *qerrmsg;
  1093. for(level = 0; level < DUMP_LEVELS; level++) {
  1094. if(est->est[level].needestimate) {
  1095. dbprintf(_("getting size via smbclient for %s level %d\n"),
  1096. est->qamname, level);
  1097. size = getsize_smbtar(est->dle, level, &errmsg);
  1098. amflock(1, "size");
  1099. g_printf(_("%s %d SIZE %lld\n"),
  1100. est->qamname, level, (long long)size);
  1101. if (errmsg && errmsg[0] != '\0') {
  1102. if(am_has_feature(g_options->features,
  1103. fe_rep_sendsize_quoted_error)) {
  1104. qerrmsg = quote_string(errmsg);
  1105. dbprintf(_("errmsg is %s\n"), errmsg);
  1106. g_printf("%s %d ERROR %s\n",
  1107. est->qamname, level, qerrmsg);
  1108. amfree(qerrmsg);
  1109. }
  1110. }
  1111. amfree(errmsg);
  1112. fflush(stdout);
  1113. amfunlock(1, "size");
  1114. }
  1115. }
  1116. }
  1117. #endif
  1118. #ifdef GNUTAR
  1119. void
  1120. gnutar_calc_estimates(
  1121. disk_estimates_t * est)
  1122. {
  1123. int level;
  1124. off_t size;
  1125. char *errmsg = NULL, *qerrmsg;
  1126. for(level = 0; level < DUMP_LEVELS; level++) {
  1127. if (est->est[level].needestimate) {
  1128. dbprintf(_("getting size via gnutar for %s level %d\n"),
  1129. est->qamname, level);
  1130. size = getsize_gnutar(est->dle, level,
  1131. est->est[level].dumpsince,
  1132. &errmsg);
  1133. amflock(1, "size");
  1134. g_printf(_("%s %d SIZE %lld\n"),
  1135. est->qamname, level, (long long)size);
  1136. if (errmsg && errmsg[0] != '\0') {
  1137. if(am_has_feature(g_options->features,
  1138. fe_rep_sendsize_quoted_error)) {
  1139. qerrmsg = quote_string(errmsg);
  1140. dbprintf(_("errmsg is %s\n"), errmsg);
  1141. g_printf(_("%s %d ERROR %s\n"),
  1142. est->qamname, level, qerrmsg);
  1143. amfree(qerrmsg);
  1144. }
  1145. }
  1146. amfree(errmsg);
  1147. fflush(stdout);
  1148. amfunlock(1, "size");
  1149. }
  1150. }
  1151. }
  1152. #endif
  1153. typedef struct regex_scale_s {
  1154. char *regex;
  1155. int scale;
  1156. } regex_scale_t;
  1157. /*@ignore@*/
  1158. regex_scale_t re_size[] = {
  1159. #ifdef DUMP
  1160. {" DUMP: estimated -*[0-9][0-9]* tape blocks", 1024},
  1161. {" DUMP: [Ee]stimated [0-9][0-9]* blocks", 512},
  1162. {" DUMP: [Ee]stimated [0-9][0-9]* bytes", 1}, /* Ultrix 4.4 */
  1163. {" UFSDUMP: estimated [0-9][0-9]* blocks", 512}, /* NEC EWS-UX */
  1164. {"dump: Estimate: [0-9][0-9]* tape blocks", 1024}, /* OSF/1 */
  1165. {"backup: There are an estimated [0-9][0-9]* tape blocks.",1024}, /* AIX */
  1166. {"backup: estimated [0-9][0-9]* 1k blocks", 1024}, /* AIX */
  1167. {"backup: estimated [0-9][0-9]* tape blocks", 1024}, /* AIX */
  1168. {"backup: [0-9][0-9]* tape blocks on [0-9][0-9]* tape(s)",1024}, /* AIX */
  1169. {"backup: [0-9][0-9]* 1k blocks on [0-9][0-9]* volume(s)",1024}, /* AIX */
  1170. {"dump: Estimate: [0-9][0-9]* blocks being output to pipe",1024},
  1171. /* DU 4.0 dump */
  1172. {"dump: Dumping [0-9][0-9]* bytes, ", 1}, /* DU 4.0 vdump */
  1173. {"DUMP: estimated [0-9][0-9]* KB output", 1024}, /* HPUX */
  1174. {"DUMP: estimated [0-9][0-9]* KB\\.", 1024}, /* NetApp */
  1175. {" UFSDUMP: estimated [0-9][0-9]* blocks", 512}, /* Sinix */
  1176. #ifdef HAVE_DUMP_ESTIMATE
  1177. {"[0-9][0-9]* blocks, [0-9][0-9]*.[0-9][0-9]* volumes", 1024},
  1178. /* DU 3.2g dump -E */
  1179. {"^[0-9][0-9]* blocks$", 1024}, /* DU 4.0 dump -E */
  1180. {"^[0-9][0-9]*$", 1}, /* Solaris ufsdump -S */
  1181. #endif
  1182. #endif
  1183. #ifdef VDUMP
  1184. {"vdump: Dumping [0-9][0-9]* bytes, ", 1}, /* OSF/1 vdump */
  1185. #endif
  1186. #ifdef VXDUMP
  1187. {"vxdump: estimated [0-9][0-9]* blocks", 512}, /* HPUX's vxdump */
  1188. {" VXDUMP: estimated [0-9][0-9]* blocks", 512}, /* Sinix */
  1189. #endif
  1190. #ifdef XFSDUMP
  1191. {"xfsdump: estimated dump size: [0-9][0-9]* bytes", 1}, /* Irix 6.2 xfs */
  1192. #endif
  1193. #ifdef GNUTAR
  1194. {"Total bytes written: [0-9][0-9]*", 1}, /* Gnutar client */
  1195. #endif
  1196. #ifdef SAMBA_CLIENT
  1197. #if SAMBA_VERSION >= 2
  1198. #define SAMBA_DEBUG_LEVEL "0"
  1199. {"Total number of bytes: [0-9][0-9]*", 1}, /* Samba du */
  1200. #else
  1201. #define SAMBA_DEBUG_LEVEL "3"
  1202. {"Total bytes listed: [0-9][0-9]*", 1}, /* Samba dir */
  1203. #endif
  1204. #endif
  1205. { NULL, 0 }
  1206. };
  1207. /*@end@*/
  1208. off_t
  1209. getsize_dump(
  1210. dle_t *dle,
  1211. int level,
  1212. char **errmsg)
  1213. {
  1214. int pipefd[2], nullfd, stdoutfd, killctl[2];
  1215. pid_t dumppid;
  1216. off_t size;
  1217. FILE *dumpout;
  1218. char *dumpkeys = NULL;
  1219. char *device = NULL;
  1220. char *fstype = NULL;
  1221. char *cmd = NULL;
  1222. char *name = NULL;
  1223. char *line = NULL;
  1224. char *rundump_cmd = NULL;
  1225. char level_str[NUM_STR_SIZE];
  1226. int s;
  1227. times_t start_time;
  1228. char *qdisk = quote_string(dle->disk);
  1229. char *qdevice;
  1230. char *config;
  1231. amwait_t wait_status;
  1232. #if defined(DUMP) || defined(VDUMP) || defined(VXDUMP) || defined(XFSDUMP)
  1233. int is_rundump = 1;
  1234. #endif
  1235. if (level > 9)
  1236. return -2; /* planner will not even consider this level */
  1237. g_snprintf(level_str, SIZEOF(level_str), "%d", level);
  1238. device = amname_to_devname(dle->device);
  1239. qdevice = quote_string(device);
  1240. fstype = amname_to_fstype(dle->device);
  1241. dbprintf(_("calculating for device %s with %s\n"),
  1242. qdevice, fstype);
  1243. cmd = vstralloc(amlibexecdir, "/rundump", NULL);
  1244. rundump_cmd = stralloc(cmd);
  1245. if (g_options->config)
  1246. config = g_options->config;
  1247. else
  1248. config = "NOCONFIG";
  1249. if ((stdoutfd = nullfd = open("/dev/null", O_RDWR)) == -1) {
  1250. *errmsg = vstrallocf(_("getsize_dump could not open /dev/null: %s"),
  1251. strerror(errno));
  1252. dbprintf("%s\n", *errmsg);
  1253. amfree(cmd);
  1254. amfree(rundump_cmd);
  1255. amfree(fstype);
  1256. amfree(device);
  1257. amfree(qdevice);
  1258. amfree(qdisk);
  1259. return(-1);
  1260. }
  1261. pipefd[0] = pipefd[1] = killctl[0] = killctl[1] = -1;
  1262. if (pipe(pipefd) < 0) {
  1263. *errmsg = vstrallocf(_("getsize_dump could create data pipes: %s"),
  1264. strerror(errno));
  1265. dbprintf("%s\n", *errmsg);
  1266. amfree(cmd);
  1267. amfree(rundump_cmd);
  1268. amfree(fstype);
  1269. amfree(device);
  1270. amfree(qdevice);
  1271. amfree(qdisk);
  1272. return(-1);
  1273. }
  1274. #ifdef XFSDUMP /* { */
  1275. #ifdef DUMP /* { */
  1276. if (strcmp(fstype, "xfs") == 0)
  1277. #else /* } { */
  1278. if (1)
  1279. #endif /* } */
  1280. {
  1281. name = stralloc(" (xfsdump)");
  1282. dbprintf(_("running \"%s%s -F -J -l %s - %s\"\n"),
  1283. cmd, name, level_str, qdevice);
  1284. }
  1285. else
  1286. #endif /* } */
  1287. #ifdef VXDUMP /* { */
  1288. #ifdef DUMP /* { */
  1289. if (strcmp(fstype, "vxfs") == 0)
  1290. #else /* } { */
  1291. if (1)
  1292. #endif /* } */
  1293. {
  1294. #ifdef USE_RUNDUMP
  1295. name = stralloc(" (vxdump)");
  1296. #else
  1297. name = stralloc("");
  1298. cmd = newstralloc(cmd, VXDUMP);
  1299. config = skip_argument;
  1300. is_rundump = 0;
  1301. #endif
  1302. dumpkeys = vstralloc(level_str, "s", "f", NULL);
  1303. dbprintf(_("running \"%s%s %s 1048576 - %s\"\n"),
  1304. cmd, name, dumpkeys, qdevice);
  1305. }
  1306. else
  1307. #endif /* } */
  1308. #ifdef VDUMP /* { */
  1309. #ifdef DUMP /* { */
  1310. if (strcmp(fstype, "advfs") == 0)
  1311. #else /* } { */
  1312. if (1)
  1313. #endif /* } */
  1314. {
  1315. name = stralloc(" (vdump)");
  1316. dumpkeys = vstralloc(level_str, "b", "f", NULL);
  1317. dbprintf(_("running \"%s%s %s 60 - %s\"\n"),
  1318. cmd, name, dumpkeys, qdevice);
  1319. }
  1320. else
  1321. #endif /* } */
  1322. #ifdef DUMP /* { */
  1323. if (1) {
  1324. # ifdef USE_RUNDUMP /* { */
  1325. # ifdef AIX_BACKUP /* { */
  1326. name = stralloc(" (backup)");
  1327. # else /* } { */
  1328. name = vstralloc(" (", DUMP, ")", NULL);
  1329. # endif /* } */
  1330. # else /* } { */
  1331. name = stralloc("");
  1332. cmd = newstralloc(cmd, DUMP);
  1333. config = skip_argument;
  1334. is_rundump = 0;
  1335. # endif /* } */
  1336. # ifdef AIX_BACKUP /* { */
  1337. dumpkeys = vstralloc("-", level_str, "f", NULL);
  1338. dbprintf(_("running \"%s%s %s - %s\"\n"),
  1339. cmd, name, dumpkeys, qdevice);
  1340. # else /* } { */
  1341. # ifdef HAVE_DUMP_ESTIMATE
  1342. # define PARAM_DUMP_ESTIMATE HAVE_DUMP_ESTIMATE
  1343. # else
  1344. # define PARAM_DUMP_ESTIMATE ""
  1345. # endif
  1346. # ifdef HAVE_HONOR_NODUMP
  1347. # define PARAM_HONOR_NODUMP "h"
  1348. # else
  1349. # define PARAM_HONOR_NODUMP ""
  1350. # endif
  1351. dumpkeys = vstralloc(level_str,
  1352. PARAM_DUMP_ESTIMATE,
  1353. PARAM_HONOR_NODUMP,
  1354. "s", "f", NULL);
  1355. # ifdef HAVE_DUMP_ESTIMATE
  1356. stdoutfd = pipefd[1];
  1357. # endif
  1358. # ifdef HAVE_HONOR_NODUMP /* { */
  1359. dbprintf(_("running \"%s%s %s 0 1048576 - %s\"\n"),
  1360. cmd, name, dumpkeys, qdevice);
  1361. # else /* } { */
  1362. dbprintf(_("running \"%s%s %s 1048576 - %s\"\n"),
  1363. cmd, name, dumpkeys, qdevice);
  1364. # endif /* } */
  1365. # endif /* } */
  1366. }
  1367. else
  1368. #endif /* } */
  1369. {
  1370. error(_("no dump program available"));
  1371. /*NOTREACHED*/
  1372. }
  1373. if (pipe(killctl) < 0) {
  1374. dbprintf(_("Could not create pipe: %s\n"), strerror(errno));
  1375. /* Message will be printed later... */
  1376. killctl[0] = killctl[1] = -1;
  1377. }
  1378. start_time = curclock();
  1379. switch(dumppid = fork()) {
  1380. case -1:
  1381. *errmsg = vstrallocf(_("cannot fork for killpgrp: %s"),
  1382. strerror(errno));
  1383. dbprintf("%s\n", *errmsg);
  1384. amfree(dumpkeys);
  1385. amfree(cmd);
  1386. amfree(rundump_cmd);
  1387. amfree(device);
  1388. amfree(qdevice);
  1389. amfree(qdisk);
  1390. amfree(name);
  1391. amfree(fstype);
  1392. return -1;
  1393. default:
  1394. break;
  1395. case 0: /* child process */
  1396. if(SETPGRP == -1)
  1397. SETPGRP_FAILED();
  1398. else if (killctl[0] == -1 || killctl[1] == -1)
  1399. dbprintf(_("Trying without killpgrp\n"));
  1400. else {
  1401. switch(fork()) {
  1402. case -1:
  1403. dbprintf(_("fork failed, trying without killpgrp\n"));
  1404. break;
  1405. default:
  1406. {
  1407. char *config;
  1408. char *killpgrp_cmd = vstralloc(amlibexecdir, "/killpgrp", NULL);
  1409. dbprintf(_("running %s\n"), killpgrp_cmd);
  1410. dup2(killctl[0], 0);
  1411. dup2(nullfd, 1);
  1412. dup2(nullfd, 2);
  1413. close(pipefd[0]);
  1414. close(pipefd[1]);
  1415. close(killctl[1]);
  1416. close(nullfd);
  1417. if (g_options->config)
  1418. config = g_options->config;
  1419. else
  1420. config = "NOCONFIG";
  1421. safe_fd(-1, 0);
  1422. execle(killpgrp_cmd, killpgrp_cmd, config, (char *)0,
  1423. safe_env());
  1424. dbprintf(_("cannot execute %s: %s\n"),
  1425. killpgrp_cmd, strerror(errno));
  1426. exit(-1);
  1427. }
  1428. case 0: /* child process */
  1429. break;
  1430. }
  1431. }
  1432. dup2(nullfd, 0);
  1433. dup2(stdoutfd, 1);
  1434. dup2(pipefd[1], 2);
  1435. aclose(pipefd[0]);
  1436. if (killctl[0] != -1)
  1437. aclose(killctl[0]);
  1438. if (killctl[1] != -1)
  1439. aclose(killctl[1]);
  1440. safe_fd(-1, 0);
  1441. #ifdef XFSDUMP
  1442. #ifdef DUMP
  1443. if (strcmp(fstype, "xfs") == 0)
  1444. #else
  1445. if (1)
  1446. #endif
  1447. if (is_rundump)
  1448. execle(cmd, "rundump", config, "xfsdump", "-F", "-J", "-l",
  1449. level_str, "-", device, (char *)0, safe_env());
  1450. else
  1451. execle(cmd, "xfsdump", "-F", "-J", "-l",
  1452. level_str, "-", device, (char *)0, safe_env());
  1453. else
  1454. #endif
  1455. #ifdef VXDUMP
  1456. #ifdef DUMP
  1457. if (strcmp(fstype, "vxfs") == 0)
  1458. #else
  1459. if (1)
  1460. #endif
  1461. if (is_rundump)
  1462. execle(cmd, "rundump", config, "vxdump", dumpkeys, "1048576",
  1463. "-", device, (char *)0, safe_env());
  1464. else
  1465. execle(cmd, "vxdump", dumpkeys, "1048576", "-",
  1466. device, (char *)0, safe_env());
  1467. else
  1468. #endif
  1469. #ifdef VDUMP
  1470. #ifdef DUMP
  1471. if (strcmp(fstype, "advfs") == 0)
  1472. #else
  1473. if (1)
  1474. #endif
  1475. if (is_rundump)
  1476. execle(cmd, "rundump", config, "vdump", dumpkeys, "60", "-",
  1477. device, (char *)0, safe_env());
  1478. else
  1479. execle(cmd, "vdump", dumpkeys, "60", "-",
  1480. device, (char *)0, safe_env());
  1481. else
  1482. #endif
  1483. #ifdef DUMP
  1484. # ifdef AIX_BACKUP
  1485. if (is_rundump)
  1486. execle(cmd, "rundump", config, "backup", dumpkeys, "-",
  1487. device, (char *)0, safe_env());
  1488. else
  1489. execle(cmd, "backup", dumpkeys, "-",
  1490. device, (char *)0, safe_env());
  1491. # else
  1492. if (is_rundump) {
  1493. execle(cmd, "rundump", config, "dump", dumpkeys,
  1494. #ifdef HAVE_HONOR_NODUMP
  1495. "0",
  1496. #endif
  1497. "1048576", "-", device, (char *)0, safe_env());
  1498. } else {
  1499. execle(cmd, "dump", dumpkeys,
  1500. #ifdef HAVE_HONOR_NODUMP
  1501. "0",
  1502. #endif
  1503. "1048576", "-", device, (char *)0, safe_env());
  1504. }
  1505. # endif
  1506. #endif
  1507. {
  1508. error(_("exec %s failed or no dump program available: %s"),
  1509. cmd, strerror(errno));
  1510. /*NOTREACHED*/
  1511. }
  1512. }
  1513. amfree(dumpkeys);
  1514. amfree(rundump_cmd);
  1515. aclose(pipefd[1]);
  1516. if (killctl[0] != -1)
  1517. aclose(killctl[0]);
  1518. dumpout = fdopen(pipefd[0],"r");
  1519. if (!dumpout) {
  1520. error(_("Can't fdopen: %s"), strerror(errno));
  1521. /*NOTREACHED*/
  1522. }
  1523. for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
  1524. if (line[0] == '\0')
  1525. continue;
  1526. dbprintf("%s\n", line);
  1527. size = handle_dumpline(line);
  1528. if(size > (off_t)-1) {
  1529. amfree(line);
  1530. while ((line = agets(dumpout)) != NULL) {
  1531. if (line[0] != '\0')
  1532. break;
  1533. amfree(line);
  1534. }
  1535. if (line != NULL) {
  1536. dbprintf("%s\n", line);
  1537. }
  1538. break;
  1539. }
  1540. }
  1541. amfree(line);
  1542. dbprintf(".....\n");
  1543. dbprintf(_("estimate time for %s level %d: %s\n"),
  1544. qdisk,
  1545. level,
  1546. walltime_str(timessub(curclock(), start_time)));
  1547. if(size == (off_t)-1) {
  1548. *errmsg = vstrallocf(_("no size line match in %s%s output"),
  1549. cmd, name);
  1550. dbprintf(_("%s for %s\n"),
  1551. *errmsg, qdisk);
  1552. dbprintf(".....\n");
  1553. dbprintf(_("Run %s%s manually to check for errors\n"),
  1554. cmd, name);
  1555. } else if(size == (off_t)0 && level == 0) {
  1556. dbprintf(_("possible %s%s problem -- is \"%s\" really empty?\n"),
  1557. cmd, name, dle->disk);
  1558. dbprintf(".....\n");
  1559. } else {
  1560. dbprintf(_("estimate size for %s level %d: %lld KB\n"),
  1561. qdisk,
  1562. level,
  1563. (long long)size);
  1564. }
  1565. if (killctl[1] != -1) {
  1566. dbprintf(_("asking killpgrp to terminate\n"));
  1567. aclose(killctl[1]);
  1568. for(s = 5; s > 0; --s) {
  1569. sleep(1);
  1570. if (waitpid(dumppid, NULL, WNOHANG) != -1)
  1571. goto terminated;
  1572. }
  1573. }
  1574. /*
  1575. * First, try to kill the dump process nicely. If it ignores us
  1576. * for several seconds, hit it harder.
  1577. */
  1578. dbprintf(_("sending SIGTERM to process group %ld\n"), (long)dumppid);
  1579. if (kill(-dumppid, SIGTERM) == -1) {
  1580. dbprintf(_("kill failed: %s\n"), strerror(errno));
  1581. }
  1582. /* Now check whether it dies */
  1583. for(s = 5; s > 0; --s) {
  1584. sleep(1);
  1585. if (waitpid(dumppid, NULL, WNOHANG) != -1)
  1586. goto terminated;
  1587. }
  1588. dbprintf(_("sending SIGKILL to process group %ld\n"), (long)dumppid);
  1589. if (kill(-dumppid, SIGKILL) == -1) {
  1590. dbprintf(_("kill failed: %s\n"), strerror(errno));
  1591. }
  1592. for(s = 5; s > 0; --s) {
  1593. sleep(1);
  1594. if (waitpid(dumppid, NULL, WNOHANG) != -1)
  1595. goto terminated;
  1596. }
  1597. dbprintf(_("waiting for %s%s \"%s\" child\n"), cmd, name, qdisk);
  1598. waitpid(dumppid, &wait_status, 0);
  1599. if (WIFSIGNALED(wait_status)) {
  1600. *errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
  1601. cmd, WTERMSIG(wait_status), dbfn());
  1602. } else if (WIFEXITED(wait_status)) {
  1603. if (WEXITSTATUS(wait_status) != 0) {
  1604. *errmsg = vstrallocf(_("%s exited with status %d: see %s"),
  1605. cmd, WEXITSTATUS(wait_status), dbfn());
  1606. } else {
  1607. /* Normal exit */
  1608. }
  1609. } else {
  1610. *errmsg = vstrallocf(_("%s got bad exit: see %s"),
  1611. cmd, dbfn());
  1612. }
  1613. dbprintf(_("after %s%s %s wait\n"), cmd, name, qdisk);
  1614. terminated:
  1615. aclose(nullfd);
  1616. afclose(dumpout);
  1617. amfree(device);
  1618. amfree(qdevice);
  1619. amfree(qdisk);
  1620. amfree(fstype);
  1621. amfree(cmd);
  1622. amfree(name);
  1623. return size;
  1624. }
  1625. #ifdef SAMBA_CLIENT
  1626. off_t
  1627. getsize_smbtar(
  1628. dle_t *dle,
  1629. int level,
  1630. char **errmsg)
  1631. {
  1632. int pipefd = -1, nullfd = -1, passwdfd = -1;
  1633. pid_t dumppid;
  1634. off_t size;
  1635. FILE *dumpout;
  1636. char *tarkeys, *sharename, *user_and_password = NULL, *domain = NULL;
  1637. char *share = NULL, *subdir = NULL;
  1638. size_t lpass;
  1639. char *pwtext;
  1640. size_t pwtext_len;
  1641. char *line;
  1642. char *pw_fd_env;
  1643. times_t start_time;
  1644. char *error_pn = NULL;
  1645. char *qdisk = quote_string(dle->disk);
  1646. amwait_t wait_status;
  1647. error_pn = stralloc2(get_pname(), "-smbclient");
  1648. if (level > 1)
  1649. return -2; /* planner will not even consider this level */
  1650. parsesharename(dle->device, &share, &subdir);
  1651. if (!share) {
  1652. amfree(share);
  1653. amfree(subdir);
  1654. set_pname(error_pn);
  1655. amfree(error_pn);
  1656. error(_("cannot parse disk entry %s for share/subdir"), qdisk);
  1657. /*NOTREACHED*/
  1658. }
  1659. if ((subdir) && (SAMBA_VERSION < 2)) {
  1660. amfree(share);
  1661. amfree(subdir);
  1662. set_pname(error_pn);
  1663. amfree(error_pn);
  1664. error(_("subdirectory specified for share %s but samba not v2 or better"), qdisk);
  1665. /*NOTREACHED*/
  1666. }
  1667. if ((user_and_password = findpass(share, &domain)) == NULL) {
  1668. if(domain) {
  1669. memset(domain, '\0', strlen(domain));
  1670. amfree(domain);
  1671. }
  1672. set_pname(error_pn);
  1673. amfree(error_pn);
  1674. error(_("cannot find password for %s"), dle->disk);
  1675. /*NOTREACHED*/
  1676. }
  1677. lpass = strlen(user_and_password);

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