PageRenderTime 224ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/amanda/tags/amanda261p2/application-src/amgtar.c

#
C | 1214 lines | 985 code | 130 blank | 99 comment | 217 complexity | 1435e456bdfb531fc058a39f1ea2feb0 MD5 | raw file
  1. /*
  2. * Amanda, The Advanced Maryland Automatic Network Disk Archiver
  3. * Copyright (c) 1991-1998 University of Maryland at College Park
  4. * All Rights Reserved.
  5. *
  6. * Permission to use, copy, modify, distribute, and sell this software and its
  7. * documentation for any purpose is hereby granted without fee, provided that
  8. * the above copyright notice appear in all copies and that both that
  9. * copyright notice and this permission notice appear in supporting
  10. * documentation, and that the name of U.M. not be used in advertising or
  11. * publicity pertaining to distribution of the software without specific,
  12. * written prior permission. U.M. makes no representations about the
  13. * suitability of this software for any purpose. It is provided "as is"
  14. * without express or implied warranty.
  15. *
  16. * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
  18. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  21. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22. *
  23. * Authors: the Amanda Development Team. Its members are listed in a
  24. * file named AUTHORS, in the root directory of this distribution.
  25. */
  26. /*
  27. * $Id: amgtar.c 8888 2007-10-02 13:40:42Z martineau $
  28. *
  29. * send estimated backup sizes using dump
  30. */
  31. /* PROPERTY:
  32. *
  33. * GNUTAR-PATH (default GNUTAR)
  34. * GNUTAR-LISTDIR (default CNF_GNUTAR_LIST_DIR)
  35. * DIRECTORY (no default, if set, the backup will be from that directory
  36. * instead of from the --device)
  37. * ONE-FILE-SYSTEM (default YES)
  38. * SPARSE (default YES)
  39. * ATIME-PRESERVE (default YES)
  40. * CHECK-DEVICE (default YES)
  41. * INCLUDE-FILE
  42. * INCLUDE-LIST
  43. * INCLUDE-OPTIONAL
  44. * EXCLUDE-FILE
  45. * EXCLUDE-LIST
  46. * EXCLUDE-OPTIONAL
  47. * NORMAL
  48. * IGNORE
  49. * STRANGE
  50. * EXIT-HANDLING (1=GOOD 2=BAD)
  51. * TAR-BLOCKSIZE (default does not add --blocking-factor option,
  52. * using tar's default)
  53. */
  54. #include "amanda.h"
  55. #include "pipespawn.h"
  56. #include "amfeatures.h"
  57. #include "clock.h"
  58. #include "util.h"
  59. #include "getfsent.h"
  60. #include "version.h"
  61. #include "client_util.h"
  62. #include "conffile.h"
  63. #include "amandad.h"
  64. #include "getopt.h"
  65. #include "sendbackup.h"
  66. int debug_application = 1;
  67. #define application_debug(i, ...) do { \
  68. if ((i) <= debug_application) { \
  69. dbprintf(__VA_ARGS__); \
  70. } \
  71. } while (0)
  72. static amregex_t init_re_table[] = {
  73. /* tar prints the size in bytes */
  74. AM_SIZE_RE("^ *Total bytes written: [0-9][0-9]*", 1, 1),
  75. AM_NORMAL_RE("^could not open conf file"),
  76. AM_NORMAL_RE("^Elapsed time:"),
  77. AM_NORMAL_RE("^Throughput"),
  78. AM_IGNORE_RE(": Directory is new$"),
  79. AM_IGNORE_RE(": Directory has been renamed"),
  80. /* GNU tar 1.13.17 will print this warning when (not) backing up a
  81. Unix named socket. */
  82. AM_NORMAL_RE(": socket ignored$"),
  83. /* GNUTAR produces a few error messages when files are modified or
  84. removed while it is running. They may cause data to be lost, but
  85. then they may not. We shouldn't consider them NORMAL until
  86. further investigation. */
  87. AM_NORMAL_RE(": File .* shrunk by [0-9][0-9]* bytes, padding with zeros"),
  88. AM_NORMAL_RE(": Cannot add file .*: No such file or directory$"),
  89. AM_NORMAL_RE(": Error exit delayed from previous errors"),
  90. /* catch-all: DMP_STRANGE is returned for all other lines */
  91. AM_STRANGE_RE(NULL)
  92. };
  93. static amregex_t *re_table;
  94. /* local functions */
  95. int main(int argc, char **argv);
  96. typedef struct application_argument_s {
  97. char *config;
  98. char *host;
  99. int message;
  100. int collection;
  101. int calcsize;
  102. char *tar_blocksize;
  103. GSList *level;
  104. dle_t dle;
  105. int argc;
  106. char **argv;
  107. } application_argument_t;
  108. enum { CMD_ESTIMATE, CMD_BACKUP };
  109. static void amgtar_support(application_argument_t *argument);
  110. static void amgtar_selfcheck(application_argument_t *argument);
  111. static void amgtar_estimate(application_argument_t *argument);
  112. static void amgtar_backup(application_argument_t *argument);
  113. static void amgtar_restore(application_argument_t *argument);
  114. static void amgtar_validate(application_argument_t *argument);
  115. static void amgtar_build_exinclude(dle_t *dle, int verbose,
  116. int *nb_exclude, char **file_exclude,
  117. int *nb_include, char **file_include);
  118. static char *amgtar_get_incrname(application_argument_t *argument, int level);
  119. static char **amgtar_build_argv(application_argument_t *argument,
  120. char *incrname, int command);
  121. static amregex_t *build_re_table(amregex_t *orig_re_table,
  122. GSList *normal_message,
  123. GSList *ignore_message,
  124. GSList *strange_message);
  125. static void add_type_table(dmpline_t typ,
  126. amregex_t **re_table, amregex_t *orig_re_table,
  127. GSList *normal_message, GSList *ignore_message,
  128. GSList *strange_message);
  129. static void add_list_table(dmpline_t typ, amregex_t **re_table,
  130. GSList *message);
  131. static char *gnutar_path;
  132. static char *gnutar_listdir;
  133. static char *gnutar_directory;
  134. static int gnutar_onefilesystem;
  135. static int gnutar_atimepreserve;
  136. static int gnutar_checkdevice;
  137. static int gnutar_sparse;
  138. static GSList *normal_message = NULL;
  139. static GSList *ignore_message = NULL;
  140. static GSList *strange_message = NULL;
  141. static char *exit_handling;
  142. static int exit_value[256];
  143. static struct option long_options[] = {
  144. {"config" , 1, NULL, 1},
  145. {"host" , 1, NULL, 2},
  146. {"disk" , 1, NULL, 3},
  147. {"device" , 1, NULL, 4},
  148. {"level" , 1, NULL, 5},
  149. {"index" , 1, NULL, 6},
  150. {"message" , 1, NULL, 7},
  151. {"collection" , 0, NULL, 8},
  152. {"record" , 0, NULL, 9},
  153. {"gnutar-path" , 1, NULL, 10},
  154. {"gnutar-listdir" , 1, NULL, 11},
  155. {"one-file-system" , 1, NULL, 12},
  156. {"sparse" , 1, NULL, 13},
  157. {"atime-preserve" , 1, NULL, 14},
  158. {"check-device" , 1, NULL, 15},
  159. {"include-file" , 1, NULL, 16},
  160. {"include-list" , 1, NULL, 17},
  161. {"include-optional", 1, NULL, 18},
  162. {"exclude-file" , 1, NULL, 19},
  163. {"exclude-list" , 1, NULL, 20},
  164. {"exclude-optional", 1, NULL, 21},
  165. {"directory" , 1, NULL, 22},
  166. {"normal" , 1, NULL, 23},
  167. {"ignore" , 1, NULL, 24},
  168. {"strange" , 1, NULL, 25},
  169. {"exit-handling" , 1, NULL, 26},
  170. {"calcsize" , 0, NULL, 27},
  171. {"tar-blocksize" , 1, NULL, 28},
  172. {NULL, 0, NULL, 0}
  173. };
  174. void
  175. add_type_table(
  176. dmpline_t typ,
  177. amregex_t **re_table,
  178. amregex_t *orig_re_table,
  179. GSList *normal_message,
  180. GSList *ignore_message,
  181. GSList *strange_message)
  182. {
  183. amregex_t *rp;
  184. for(rp = orig_re_table; rp->regex != NULL; rp++) {
  185. if (rp->typ == typ) {
  186. int found = 0;
  187. GSList *mes;
  188. for (mes = normal_message; mes != NULL; mes = mes->next) {
  189. if (strcmp(rp->regex, (char *)mes->data) == 0)
  190. found = 1;
  191. }
  192. for (mes = ignore_message; mes != NULL; mes = mes->next) {
  193. if (strcmp(rp->regex, (char *)mes->data) == 0)
  194. found = 1;
  195. }
  196. for (mes = strange_message; mes != NULL; mes = mes->next) {
  197. if (strcmp(rp->regex, (char *)mes->data) == 0)
  198. found = 1;
  199. }
  200. if (found == 0) {
  201. (*re_table)->regex = rp->regex;
  202. (*re_table)->srcline = rp->srcline;
  203. (*re_table)->scale = rp->scale;
  204. (*re_table)->field = rp->field;
  205. (*re_table)->typ = rp->typ;
  206. (*re_table)++;
  207. }
  208. }
  209. }
  210. }
  211. void
  212. add_list_table(
  213. dmpline_t typ,
  214. amregex_t **re_table,
  215. GSList *message)
  216. {
  217. GSList *mes;
  218. for (mes = message; mes != NULL; mes = mes->next) {
  219. (*re_table)->regex = (char *)mes->data;
  220. (*re_table)->srcline = 0;
  221. (*re_table)->scale = 0;
  222. (*re_table)->field = 0;
  223. (*re_table)->typ = typ;
  224. (*re_table)++;
  225. }
  226. }
  227. amregex_t *
  228. build_re_table(
  229. amregex_t *orig_re_table,
  230. GSList *normal_message,
  231. GSList *ignore_message,
  232. GSList *strange_message)
  233. {
  234. int nb = 0;
  235. amregex_t *rp;
  236. amregex_t *re_table, *new_re_table;
  237. for(rp = orig_re_table; rp->regex != NULL; rp++) {
  238. nb++;
  239. }
  240. nb += g_slist_length(normal_message);
  241. nb += g_slist_length(ignore_message);
  242. nb += g_slist_length(strange_message);
  243. nb ++;
  244. re_table = new_re_table = malloc(nb * sizeof(amregex_t));
  245. /* add SIZE from orig_re_table */
  246. add_type_table(DMP_SIZE, &re_table, orig_re_table,
  247. normal_message, ignore_message, strange_message);
  248. /* add ignore_message */
  249. add_list_table(DMP_IGNORE, &re_table, ignore_message);
  250. /* add IGNORE from orig_re_table */
  251. add_type_table(DMP_IGNORE, &re_table, orig_re_table,
  252. normal_message, ignore_message, strange_message);
  253. /* add normal_message */
  254. add_list_table(DMP_NORMAL, &re_table, normal_message);
  255. /* add NORMAL from orig_re_table */
  256. add_type_table(DMP_NORMAL, &re_table, orig_re_table,
  257. normal_message, ignore_message, strange_message);
  258. /* add strange_message */
  259. add_list_table(DMP_STRANGE, &re_table, strange_message);
  260. /* add STRANGE from orig_re_table */
  261. add_type_table(DMP_STRANGE, &re_table, orig_re_table,
  262. normal_message, ignore_message, strange_message);
  263. /* Add DMP_STRANGE with NULL regex, */
  264. /* it is not copied by previous statement */
  265. re_table->regex = NULL;
  266. re_table->srcline = 0;
  267. re_table->scale = 0;
  268. re_table->field = 0;
  269. re_table->typ = DMP_STRANGE;
  270. return new_re_table;
  271. }
  272. int
  273. main(
  274. int argc,
  275. char ** argv)
  276. {
  277. int c;
  278. char *command;
  279. application_argument_t argument;
  280. int i;
  281. #ifdef GNUTAR
  282. gnutar_path = GNUTAR;
  283. #else
  284. gnutar_path = NULL;
  285. #endif
  286. gnutar_directory = NULL;
  287. gnutar_onefilesystem = 1;
  288. gnutar_atimepreserve = 1;
  289. gnutar_checkdevice = 1;
  290. gnutar_sparse = 1;
  291. exit_handling = NULL;
  292. /* initialize */
  293. /*
  294. * Configure program for internationalization:
  295. * 1) Only set the message locale for now.
  296. * 2) Set textdomain for all amanda related programs to "amanda"
  297. * We don't want to be forced to support dozens of message catalogs.
  298. */
  299. setlocale(LC_MESSAGES, "C");
  300. textdomain("amanda");
  301. /* drop root privileges */
  302. if (!set_root_privs(0)) {
  303. error(_("amgtar must be run setuid root"));
  304. }
  305. safe_fd(3, 2);
  306. set_pname("amgtar");
  307. /* Don't die when child closes pipe */
  308. signal(SIGPIPE, SIG_IGN);
  309. #if defined(USE_DBMALLOC)
  310. malloc_size_1 = malloc_inuse(&malloc_hist_1);
  311. #endif
  312. erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
  313. dbopen(DBG_SUBDIR_CLIENT);
  314. startclock();
  315. dbprintf(_("version %s\n"), version());
  316. config_init(CONFIG_INIT_CLIENT, NULL);
  317. //check_running_as(RUNNING_AS_DUMPUSER_PREFERRED);
  318. //root for amrecover
  319. //RUNNING_AS_CLIENT_LOGIN from selfcheck, sendsize, sendbackup
  320. /* parse argument */
  321. command = argv[1];
  322. argument.config = NULL;
  323. argument.host = NULL;
  324. argument.message = 0;
  325. argument.collection = 0;
  326. argument.calcsize = 0;
  327. argument.tar_blocksize = NULL;
  328. argument.level = NULL;
  329. init_dle(&argument.dle);
  330. while (1) {
  331. int option_index = 0;
  332. c = getopt_long (argc, argv, "", long_options, &option_index);
  333. if (c == -1) {
  334. break;
  335. }
  336. switch (c) {
  337. case 1: argument.config = stralloc(optarg);
  338. break;
  339. case 2: argument.host = stralloc(optarg);
  340. break;
  341. case 3: argument.dle.disk = stralloc(optarg);
  342. break;
  343. case 4: argument.dle.device = stralloc(optarg);
  344. break;
  345. case 5: argument.level = g_slist_append(argument.level,
  346. GINT_TO_POINTER(atoi(optarg)));
  347. break;
  348. case 6: argument.dle.create_index = 1;
  349. break;
  350. case 7: argument.message = 1;
  351. break;
  352. case 8: argument.collection = 1;
  353. break;
  354. case 9: argument.dle.record = 1;
  355. break;
  356. case 10: gnutar_path = stralloc(optarg);
  357. break;
  358. case 11: gnutar_listdir = stralloc(optarg);
  359. break;
  360. case 12: if (optarg && strcasecmp(optarg, "YES") != 0)
  361. gnutar_onefilesystem = 0;
  362. break;
  363. case 13: if (optarg && strcasecmp(optarg, "YES") != 0)
  364. gnutar_sparse = 0;
  365. break;
  366. case 14: if (optarg && strcasecmp(optarg, "YES") != 0)
  367. gnutar_atimepreserve = 0;
  368. break;
  369. case 15: if (optarg && strcasecmp(optarg, "YES") != 0)
  370. gnutar_checkdevice = 0;
  371. break;
  372. case 16: if (optarg)
  373. argument.dle.include_file =
  374. append_sl(argument.dle.include_file, optarg);
  375. break;
  376. case 17: if (optarg)
  377. argument.dle.include_list =
  378. append_sl(argument.dle.include_list, optarg);
  379. break;
  380. case 18: argument.dle.include_optional = 1;
  381. break;
  382. case 19: if (optarg)
  383. argument.dle.exclude_file =
  384. append_sl(argument.dle.exclude_file, optarg);
  385. break;
  386. case 20: if (optarg)
  387. argument.dle.exclude_list =
  388. append_sl(argument.dle.exclude_list, optarg);
  389. break;
  390. case 21: argument.dle.exclude_optional = 1;
  391. break;
  392. case 22: gnutar_directory = stralloc(optarg);
  393. break;
  394. case 23: if (optarg)
  395. normal_message =
  396. g_slist_append(normal_message, optarg);
  397. break;
  398. case 24: if (optarg)
  399. ignore_message =
  400. g_slist_append(ignore_message, optarg);
  401. break;
  402. case 25: if (optarg)
  403. strange_message =
  404. g_slist_append(strange_message, optarg);
  405. break;
  406. case 26: if (optarg)
  407. exit_handling = stralloc(optarg);
  408. break;
  409. case 27: argument.calcsize = 1;
  410. break;
  411. case 28: argument.tar_blocksize = stralloc(optarg);
  412. case ':':
  413. case '?':
  414. break;
  415. }
  416. }
  417. argument.argc = argc - optind;
  418. argument.argv = argv + optind;
  419. if (argument.config) {
  420. config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
  421. argument.config);
  422. dbrename(get_config_name(), DBG_SUBDIR_CLIENT);
  423. }
  424. if (config_errors(NULL) >= CFGERR_ERRORS) {
  425. g_critical(_("errors processing config file"));
  426. }
  427. re_table = build_re_table(init_re_table, normal_message, ignore_message,
  428. strange_message);
  429. for(i=0;i<256;i++)
  430. exit_value[i] = 1; /* BAD */
  431. exit_value[0] = 0; /* GOOD */
  432. exit_value[1] = 0; /* GOOD */
  433. if (exit_handling) {
  434. char *s = exit_handling;
  435. while (s) {
  436. char *r = strchr(s, '=');
  437. if (r) {
  438. int j = atoi(s);
  439. if (j >= 0 && j < 256) {
  440. r++;
  441. if (strncasecmp(r, "GOOD", 4) == 0) {
  442. exit_value[j] = 0;
  443. }
  444. }
  445. }
  446. s = strchr(s+1, ' ');
  447. }
  448. }
  449. gnutar_listdir = getconf_str(CNF_GNUTAR_LIST_DIR);
  450. if (strlen(gnutar_listdir) == 0)
  451. gnutar_listdir = NULL;
  452. if (gnutar_path) {
  453. dbprintf("GNUTAR-PATH %s\n", gnutar_path);
  454. } else {
  455. dbprintf("GNUTAR-PATH is not set\n");
  456. }
  457. if (gnutar_listdir) {
  458. dbprintf("GNUTAR-LISTDIR %s\n", gnutar_listdir);
  459. } else {
  460. dbprintf("GNUTAR-LISTDIR is not set\n");
  461. }
  462. if (gnutar_directory) {
  463. dbprintf("DIRECTORY %s\n", gnutar_directory);
  464. }
  465. dbprintf("ONE-FILE-SYSTEM %s\n", gnutar_onefilesystem? "yes":"no");
  466. dbprintf("SPARSE %s\n", gnutar_sparse? "yes":"no");
  467. dbprintf("ATIME-PRESERVE %s\n", gnutar_atimepreserve? "yes":"no");
  468. dbprintf("CHECK-DEVICE %s\n", gnutar_checkdevice? "yes":"no");
  469. {
  470. amregex_t *rp;
  471. for (rp = re_table; rp->regex != NULL; rp++) {
  472. switch (rp->typ) {
  473. case DMP_NORMAL : dbprintf("NORMAL %s\n", rp->regex); break;
  474. case DMP_IGNORE : dbprintf("IGNORE %s\n", rp->regex); break;
  475. case DMP_STRANGE: dbprintf("STRANGE %s\n", rp->regex); break;
  476. case DMP_SIZE : dbprintf("SIZE %s\n", rp->regex); break;
  477. case DMP_ERROR : dbprintf("ERROR %s\n", rp->regex); break;
  478. }
  479. }
  480. }
  481. if (strcmp(command, "support") == 0) {
  482. amgtar_support(&argument);
  483. } else if (strcmp(command, "selfcheck") == 0) {
  484. amgtar_selfcheck(&argument);
  485. } else if (strcmp(command, "estimate") == 0) {
  486. amgtar_estimate(&argument);
  487. } else if (strcmp(command, "backup") == 0) {
  488. amgtar_backup(&argument);
  489. } else if (strcmp(command, "restore") == 0) {
  490. amgtar_restore(&argument);
  491. } else if (strcmp(command, "validate") == 0) {
  492. amgtar_validate(&argument);
  493. } else {
  494. dbprintf("Unknown command `%s'.\n", command);
  495. fprintf(stderr, "Unknown command `%s'.\n", command);
  496. exit (1);
  497. }
  498. return 0;
  499. }
  500. static void
  501. amgtar_support(
  502. application_argument_t *argument)
  503. {
  504. (void)argument;
  505. fprintf(stdout, "CONFIG YES\n");
  506. fprintf(stdout, "HOST YES\n");
  507. fprintf(stdout, "DISK YES\n");
  508. fprintf(stdout, "MAX-LEVEL 9\n");
  509. fprintf(stdout, "INDEX-LINE YES\n");
  510. fprintf(stdout, "INDEX-XML NO\n");
  511. fprintf(stdout, "MESSAGE-LINE YES\n");
  512. fprintf(stdout, "MESSAGE-XML NO\n");
  513. fprintf(stdout, "RECORD YES\n");
  514. fprintf(stdout, "INCLUDE-FILE YES\n");
  515. fprintf(stdout, "INCLUDE-LIST YES\n");
  516. fprintf(stdout, "INCLUDE-OPTIONAL YES\n");
  517. fprintf(stdout, "EXCLUDE-FILE YES\n");
  518. fprintf(stdout, "EXCLUDE-LIST YES\n");
  519. fprintf(stdout, "EXCLUDE-OPTIONAL YES\n");
  520. fprintf(stdout, "COLLECTION NO\n");
  521. fprintf(stdout, "MULTI-ESTIMATE YES\n");
  522. fprintf(stdout, "CALCSIZE YES\n");
  523. }
  524. static void
  525. amgtar_selfcheck(
  526. application_argument_t *argument)
  527. {
  528. amgtar_build_exinclude(&argument->dle, 1, NULL, NULL, NULL, NULL);
  529. if (gnutar_path) {
  530. check_file(gnutar_path, X_OK);
  531. } else {
  532. printf(_("ERROR [GNUTAR program not available]\n"));
  533. }
  534. set_root_privs(1);
  535. if (gnutar_listdir && strlen(gnutar_listdir) == 0)
  536. gnutar_listdir = NULL;
  537. if (gnutar_listdir) {
  538. check_dir(gnutar_listdir, R_OK|W_OK);
  539. } else {
  540. printf(_("ERROR [No GNUTAR-LISTDIR]\n"));
  541. }
  542. fprintf(stdout, "OK %s\n", argument->dle.disk);
  543. if (gnutar_directory) {
  544. check_dir(gnutar_directory, R_OK);
  545. } else {
  546. check_dir(argument->dle.device, R_OK);
  547. }
  548. set_root_privs(0);
  549. }
  550. static void
  551. amgtar_estimate(
  552. application_argument_t *argument)
  553. {
  554. char *incrname = NULL;
  555. char **my_argv = NULL;
  556. char *cmd = NULL;
  557. int nullfd = -1;
  558. int pipefd = -1;
  559. FILE *dumpout = NULL;
  560. off_t size = -1;
  561. char line[32768];
  562. char *errmsg = NULL;
  563. char *qerrmsg = NULL;
  564. char *qdisk;
  565. amwait_t wait_status;
  566. int tarpid;
  567. amregex_t *rp;
  568. times_t start_time;
  569. int level;
  570. GSList *levels;
  571. qdisk = quote_string(argument->dle.disk);
  572. if (argument->calcsize) {
  573. char *dirname;
  574. char *file_exclude;
  575. char *file_include;
  576. int nb_exclude;
  577. int nb_include;
  578. if (gnutar_directory) {
  579. dirname = gnutar_directory;
  580. } else {
  581. dirname = amname_to_dirname(argument->dle.device);
  582. }
  583. amgtar_build_exinclude(&argument->dle, 1,
  584. &nb_exclude, &file_exclude,
  585. &nb_include, &file_include);
  586. run_calcsize(argument->config, "GNUTAR", argument->dle.disk, dirname,
  587. argument->level, file_exclude, file_include);
  588. return;
  589. }
  590. if (!gnutar_path) {
  591. errmsg = vstrallocf(_("GNUTAR-PATH not defined"));
  592. goto common_error;
  593. }
  594. if (!gnutar_listdir) {
  595. errmsg = vstrallocf(_("GNUTAR-LISTDIR not defined"));
  596. goto common_error;
  597. }
  598. for (levels = argument->level; levels != NULL; levels = levels->next) {
  599. level = GPOINTER_TO_INT(levels->data);
  600. incrname = amgtar_get_incrname(argument, level);
  601. cmd = stralloc(gnutar_path);
  602. my_argv = amgtar_build_argv(argument, incrname, CMD_ESTIMATE);
  603. start_time = curclock();
  604. if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
  605. errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
  606. strerror(errno));
  607. goto common_exit;
  608. }
  609. tarpid = pipespawnv(cmd, STDERR_PIPE, 1,
  610. &nullfd, &nullfd, &pipefd, my_argv);
  611. dumpout = fdopen(pipefd,"r");
  612. if (!dumpout) {
  613. error(_("Can't fdopen: %s"), strerror(errno));
  614. /*NOTREACHED*/
  615. }
  616. size = (off_t)-1;
  617. while (size < 0 && (fgets(line, sizeof(line), dumpout) != NULL)) {
  618. if (line[strlen(line)-1] == '\n') /* remove trailling \n */
  619. line[strlen(line)-1] = '\0';
  620. if (line[0] == '\0')
  621. continue;
  622. dbprintf("%s\n", line);
  623. /* check for size match */
  624. /*@ignore@*/
  625. for(rp = re_table; rp->regex != NULL; rp++) {
  626. if(match(rp->regex, line)) {
  627. if (rp->typ == DMP_SIZE) {
  628. size = ((the_num(line, rp->field)*rp->scale+1023.0)/1024.0);
  629. if(size < 0.0)
  630. size = 1.0; /* found on NeXT -- sigh */
  631. }
  632. break;
  633. }
  634. }
  635. /*@end@*/
  636. }
  637. while (fgets(line, sizeof(line), dumpout) != NULL) {
  638. dbprintf("%s", line);
  639. }
  640. dbprintf(".....\n");
  641. dbprintf(_("estimate time for %s level %d: %s\n"),
  642. qdisk,
  643. level,
  644. walltime_str(timessub(curclock(), start_time)));
  645. if(size == (off_t)-1) {
  646. errmsg = vstrallocf(_("no size line match in %s output"),
  647. my_argv[0]);
  648. dbprintf(_("%s for %s\n"), errmsg, qdisk);
  649. dbprintf(".....\n");
  650. } else if(size == (off_t)0 && argument->level == 0) {
  651. dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"),
  652. my_argv[0], argument->dle.disk);
  653. dbprintf(".....\n");
  654. }
  655. dbprintf(_("estimate size for %s level %d: %lld KB\n"),
  656. qdisk,
  657. level,
  658. (long long)size);
  659. kill(-tarpid, SIGTERM);
  660. dbprintf(_("waiting for %s \"%s\" child\n"), my_argv[0], qdisk);
  661. waitpid(tarpid, &wait_status, 0);
  662. if (WIFSIGNALED(wait_status)) {
  663. errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
  664. cmd, WTERMSIG(wait_status), dbfn());
  665. } else if (WIFEXITED(wait_status)) {
  666. if (exit_value[WEXITSTATUS(wait_status)] == 1) {
  667. errmsg = vstrallocf(_("%s exited with status %d: see %s"),
  668. cmd, WEXITSTATUS(wait_status), dbfn());
  669. } else {
  670. /* Normal exit */
  671. }
  672. } else {
  673. errmsg = vstrallocf(_("%s got bad exit: see %s"),
  674. cmd, dbfn());
  675. }
  676. dbprintf(_("after %s %s wait\n"), my_argv[0], qdisk);
  677. common_exit:
  678. if (errmsg) {
  679. dbprintf("%s", errmsg);
  680. fprintf(stdout, "ERROR %s\n", errmsg);
  681. }
  682. if (incrname) {
  683. unlink(incrname);
  684. }
  685. amfree(my_argv);
  686. amfree(cmd);
  687. aclose(nullfd);
  688. afclose(dumpout);
  689. fprintf(stdout, "%d %lld 1\n", level, (long long)size);
  690. }
  691. amfree(qdisk);
  692. return;
  693. common_error:
  694. qerrmsg = quote_string(errmsg);
  695. amfree(qdisk);
  696. dbprintf("%s", errmsg);
  697. fprintf(stdout, "ERROR %s\n", qerrmsg);
  698. amfree(errmsg);
  699. amfree(qerrmsg);
  700. return;
  701. }
  702. static void
  703. amgtar_backup(
  704. application_argument_t *argument)
  705. {
  706. int dumpin;
  707. char *cmd = NULL;
  708. char *qdisk;
  709. char *incrname;
  710. char line[32768];
  711. amregex_t *rp;
  712. off_t dump_size = -1;
  713. char *type;
  714. char startchr;
  715. int dataf = 1;
  716. int mesgf = 3;
  717. int indexf = 4;
  718. int outf;
  719. FILE *mesgstream;
  720. FILE *indexstream = NULL;
  721. FILE *outstream;
  722. char *errmsg = NULL;
  723. amwait_t wait_status;
  724. char **my_argv;
  725. int tarpid;
  726. if (!gnutar_path) {
  727. error(_("GNUTAR-PATH not defined"));
  728. }
  729. if (!gnutar_listdir) {
  730. error(_("GNUTAR-LISTDIR not defined"));
  731. }
  732. qdisk = quote_string(argument->dle.disk);
  733. incrname = amgtar_get_incrname(argument,
  734. GPOINTER_TO_INT(argument->level->data));
  735. cmd = stralloc(gnutar_path);
  736. my_argv = amgtar_build_argv(argument, incrname, CMD_BACKUP);
  737. tarpid = pipespawnv(cmd, STDIN_PIPE|STDERR_PIPE, 1,
  738. &dumpin, &dataf, &outf, my_argv);
  739. /* close the write ends of the pipes */
  740. aclose(dumpin);
  741. aclose(dataf);
  742. if (argument->dle.create_index) {
  743. indexstream = fdopen(indexf, "w");
  744. if (!indexstream) {
  745. error(_("error indexstream(%d): %s\n"), indexf, strerror(errno));
  746. }
  747. }
  748. mesgstream = fdopen(mesgf, "w");
  749. if (!mesgstream) {
  750. error(_("error mesgstream(%d): %s\n"), mesgf, strerror(errno));
  751. }
  752. outstream = fdopen(outf, "r");
  753. if (!outstream) {
  754. error(_("error outstream(%d): %s\n"), outf, strerror(errno));
  755. }
  756. while (fgets(line, sizeof(line), outstream) != NULL) {
  757. if (line[strlen(line)-1] == '\n') /* remove trailling \n */
  758. line[strlen(line)-1] = '\0';
  759. if (*line == '.' && *(line+1) == '/') { /* filename */
  760. if (argument->dle.create_index) {
  761. fprintf(indexstream, "%s\n", &line[1]); /* remove . */
  762. }
  763. } else { /* message */
  764. for(rp = re_table; rp->regex != NULL; rp++) {
  765. if(match(rp->regex, line)) {
  766. break;
  767. }
  768. }
  769. if(rp->typ == DMP_SIZE) {
  770. dump_size = (long)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0);
  771. }
  772. switch(rp->typ) {
  773. case DMP_NORMAL:
  774. type = "normal";
  775. startchr = '|';
  776. break;
  777. case DMP_IGNORE:
  778. continue;
  779. case DMP_STRANGE:
  780. type = "strange";
  781. startchr = '?';
  782. break;
  783. case DMP_SIZE:
  784. type = "size";
  785. startchr = '|';
  786. break;
  787. case DMP_ERROR:
  788. type = "error";
  789. startchr = '?';
  790. break;
  791. default:
  792. type = "unknown";
  793. startchr = '!';
  794. break;
  795. }
  796. dbprintf("%3d: %7s(%c): %s\n", rp->srcline, type, startchr, line);
  797. fprintf(mesgstream,"%c %s\n", startchr, line);
  798. }
  799. }
  800. waitpid(tarpid, &wait_status, 0);
  801. if (WIFSIGNALED(wait_status)) {
  802. errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
  803. cmd, WTERMSIG(wait_status), dbfn());
  804. } else if (WIFEXITED(wait_status)) {
  805. if (exit_value[WEXITSTATUS(wait_status)] == 1) {
  806. errmsg = vstrallocf(_("%s exited with status %d: see %s"),
  807. cmd, WEXITSTATUS(wait_status), dbfn());
  808. } else {
  809. /* Normal exit */
  810. }
  811. } else {
  812. errmsg = vstrallocf(_("%s got bad exit: see %s"),
  813. cmd, dbfn());
  814. }
  815. dbprintf(_("after %s %s wait\n"), my_argv[0], qdisk);
  816. dbprintf(_("amgtar: %s: pid %ld\n"), cmd, (long)tarpid);
  817. if (errmsg) {
  818. dbprintf("%s", errmsg);
  819. g_fprintf(mesgstream, "sendbackup: error [%s]\n", errmsg);
  820. }
  821. if (!errmsg && incrname && strlen(incrname) > 4) {
  822. char *nodotnew;
  823. nodotnew = stralloc(incrname);
  824. nodotnew[strlen(nodotnew)-4] = '\0';
  825. if (rename(incrname, nodotnew)) {
  826. dbprintf(_("%s: warning [renaming %s to %s: %s]\n"),
  827. get_pname(), incrname, nodotnew, strerror(errno));
  828. g_fprintf(mesgstream, _("? warning [renaming %s to %s: %s]\n"),
  829. incrname, nodotnew, strerror(errno));
  830. }
  831. amfree(nodotnew);
  832. }
  833. dbprintf("sendbackup: size %lld\n", (long long)dump_size);
  834. fprintf(mesgstream, "sendbackup: size %lld\n", (long long)dump_size);
  835. dbprintf("sendbackup: end\n");
  836. fprintf(mesgstream, "sendbackup: end\n");
  837. if (argument->dle.create_index)
  838. fclose(indexstream);
  839. fclose(mesgstream);
  840. amfree(incrname);
  841. amfree(qdisk);
  842. amfree(cmd);
  843. }
  844. static void
  845. amgtar_restore(
  846. application_argument_t *argument)
  847. {
  848. char *cmd;
  849. char **my_argv;
  850. char **env;
  851. int i, j;
  852. char *e;
  853. if (!gnutar_path) {
  854. error(_("GNUTAR-PATH not defined"));
  855. }
  856. cmd = stralloc(gnutar_path);
  857. my_argv = alloc(SIZEOF(char *) * (6 + argument->argc));
  858. i = 0;
  859. my_argv[i++] = stralloc(gnutar_path);
  860. my_argv[i++] = stralloc("--numeric-owner");
  861. my_argv[i++] = stralloc("-xpGvf");
  862. my_argv[i++] = stralloc("-");
  863. for (j=1; j< argument->argc; j++) {
  864. my_argv[i++] = stralloc(argument->argv[j]);
  865. }
  866. my_argv[i++] = NULL;
  867. env = safe_env();
  868. become_root();
  869. execve(cmd, my_argv, env);
  870. e = strerror(errno);
  871. error(_("error [exec %s: %s]"), cmd, e);
  872. }
  873. static void
  874. amgtar_validate(
  875. application_argument_t *argument G_GNUC_UNUSED)
  876. {
  877. char *cmd;
  878. char **my_argv;
  879. char **env;
  880. int i;
  881. char *e;
  882. if (!gnutar_path) {
  883. error(_("GNUTAR-PATH not defined"));
  884. }
  885. cmd = stralloc(gnutar_path);
  886. my_argv = alloc(SIZEOF(char *) * 4);
  887. i = 0;
  888. my_argv[i++] = stralloc(gnutar_path);
  889. my_argv[i++] = stralloc("-tf");
  890. my_argv[i++] = stralloc("-");
  891. my_argv[i++] = NULL;
  892. env = safe_env();
  893. execve(cmd, my_argv, env);
  894. e = strerror(errno);
  895. error(_("error [exec %s: %s]"), cmd, e);
  896. }
  897. static void
  898. amgtar_build_exinclude(
  899. dle_t *dle,
  900. int verbose,
  901. int *nb_exclude,
  902. char **file_exclude,
  903. int *nb_include,
  904. char **file_include)
  905. {
  906. int n_exclude = 0;
  907. int n_include = 0;
  908. char *exclude = NULL;
  909. char *include = NULL;
  910. if (dle->exclude_file) n_exclude += dle->exclude_file->nb_element;
  911. if (dle->exclude_list) n_exclude += dle->exclude_list->nb_element;
  912. if (dle->include_file) n_include += dle->include_file->nb_element;
  913. if (dle->include_list) n_include += dle->include_list->nb_element;
  914. if (n_exclude > 0) exclude = build_exclude(dle, verbose);
  915. if (n_include > 0) include = build_include(dle, verbose);
  916. if (nb_exclude)
  917. *nb_exclude = n_exclude;
  918. if (file_exclude)
  919. *file_exclude = exclude;
  920. else
  921. amfree(exclude);
  922. if (nb_include)
  923. *nb_include = n_include;
  924. if (file_include)
  925. *file_include = include;
  926. else
  927. amfree(include);
  928. }
  929. static char *
  930. amgtar_get_incrname(
  931. application_argument_t *argument,
  932. int level)
  933. {
  934. char *basename = NULL;
  935. char *incrname = NULL;
  936. int infd, outfd;
  937. ssize_t nb;
  938. char *inputname = NULL;
  939. char *errmsg = NULL;
  940. char *buf;
  941. if (gnutar_listdir) {
  942. char number[NUM_STR_SIZE];
  943. int baselevel;
  944. char *sdisk = sanitise_filename(argument->dle.disk);
  945. basename = vstralloc(gnutar_listdir,
  946. "/",
  947. argument->host,
  948. sdisk,
  949. NULL);
  950. amfree(sdisk);
  951. snprintf(number, SIZEOF(number), "%d", level);
  952. incrname = vstralloc(basename, "_", number, ".new", NULL);
  953. unlink(incrname);
  954. /*
  955. * Open the listed incremental file from the previous level. Search
  956. * backward until one is found. If none are found (which will also
  957. * be true for a level 0), arrange to read from /dev/null.
  958. */
  959. baselevel = level;
  960. infd = -1;
  961. while (infd == -1) {
  962. if (--baselevel >= 0) {
  963. snprintf(number, SIZEOF(number), "%d", baselevel);
  964. inputname = newvstralloc(inputname,
  965. basename, "_", number, NULL);
  966. } else {
  967. inputname = newstralloc(inputname, "/dev/null");
  968. }
  969. if ((infd = open(inputname, O_RDONLY)) == -1) {
  970. errmsg = vstrallocf(_("amgtar: error opening %s: %s"),
  971. inputname, strerror(errno));
  972. dbprintf("%s\n", errmsg);
  973. if (baselevel < 0) {
  974. return NULL;
  975. }
  976. amfree(errmsg);
  977. }
  978. }
  979. /*
  980. * Copy the previous listed incremental file to the new one.
  981. */
  982. if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) {
  983. errmsg = vstrallocf(_("opening %s: %s"),
  984. incrname, strerror(errno));
  985. dbprintf("%s\n", errmsg);
  986. return NULL;
  987. }
  988. while ((nb = read(infd, &buf, SIZEOF(buf))) > 0) {
  989. if (full_write(outfd, &buf, (size_t)nb) < (size_t)nb) {
  990. errmsg = vstrallocf(_("writing to %s: %s"),
  991. incrname, strerror(errno));
  992. dbprintf("%s\n", errmsg);
  993. return NULL;
  994. }
  995. }
  996. if (nb < 0) {
  997. errmsg = vstrallocf(_("reading from %s: %s"),
  998. inputname, strerror(errno));
  999. dbprintf("%s\n", errmsg);
  1000. return NULL;
  1001. }
  1002. if (close(infd) != 0) {
  1003. errmsg = vstrallocf(_("closing %s: %s"),
  1004. inputname, strerror(errno));
  1005. dbprintf("%s\n", errmsg);
  1006. return NULL;
  1007. }
  1008. if (close(outfd) != 0) {
  1009. errmsg = vstrallocf(_("closing %s: %s"),
  1010. incrname, strerror(errno));
  1011. dbprintf("%s\n", errmsg);
  1012. return NULL;
  1013. }
  1014. amfree(inputname);
  1015. amfree(basename);
  1016. }
  1017. return incrname;
  1018. }
  1019. char **amgtar_build_argv(
  1020. application_argument_t *argument,
  1021. char *incrname,
  1022. int command)
  1023. {
  1024. int i;
  1025. int nb_exclude;
  1026. int nb_include;
  1027. char *file_exclude;
  1028. char *file_include;
  1029. char *dirname;
  1030. char tmppath[PATH_MAX];
  1031. char **my_argv;
  1032. amgtar_build_exinclude(&argument->dle, 1,
  1033. &nb_exclude, &file_exclude,
  1034. &nb_include, &file_include);
  1035. if (gnutar_directory) {
  1036. dirname = gnutar_directory;
  1037. } else {
  1038. dirname = amname_to_dirname(argument->dle.device);
  1039. }
  1040. my_argv = alloc(SIZEOF(char *) * 23);
  1041. i = 0;
  1042. my_argv[i++] = gnutar_path;
  1043. my_argv[i++] = "--create";
  1044. if (command == CMD_BACKUP && argument->dle.create_index)
  1045. my_argv[i++] = "--verbose";
  1046. my_argv[i++] = "--file";
  1047. if (command == CMD_ESTIMATE) {
  1048. my_argv[i++] = "/dev/null";
  1049. } else {
  1050. my_argv[i++] = "-";
  1051. }
  1052. my_argv[i++] = "--directory";
  1053. canonicalize_pathname(dirname, tmppath);
  1054. my_argv[i++] = stralloc(tmppath);
  1055. if (gnutar_onefilesystem)
  1056. my_argv[i++] = "--one-file-system";
  1057. if (gnutar_atimepreserve)
  1058. my_argv[i++] = "--atime-preserve=system";
  1059. if (!gnutar_checkdevice)
  1060. my_argv[i++] = "--no-check-device";
  1061. my_argv[i++] = "--listed-incremental";
  1062. my_argv[i++] = incrname;
  1063. if (gnutar_sparse)
  1064. my_argv[i++] = "--sparse";
  1065. if (argument->tar_blocksize) {
  1066. my_argv[i++] = "--blocking-factor";
  1067. my_argv[i++] = argument->tar_blocksize;
  1068. }
  1069. my_argv[i++] = "--ignore-failed-read";
  1070. my_argv[i++] = "--totals";
  1071. if(file_exclude) {
  1072. my_argv[i++] = "--exclude-from";
  1073. my_argv[i++] = file_exclude;
  1074. }
  1075. if(file_include) {
  1076. my_argv[i++] = "--files-from";
  1077. my_argv[i++] = file_include;
  1078. }
  1079. else {
  1080. my_argv[i++] = ".";
  1081. }
  1082. my_argv[i++] = NULL;
  1083. return(my_argv);
  1084. }