PageRenderTime 56ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

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

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

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