PageRenderTime 64ms CodeModel.GetById 5ms RepoModel.GetById 1ms app.codeStats 0ms

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

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

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