PageRenderTime 54ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/amanda/trunk/client-src/sendsize.c

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

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