PageRenderTime 50ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/amanda/tags/3_2_3/application-src/amstar.c

#
C | 1053 lines | 866 code | 119 blank | 68 comment | 213 complexity | 504bcd2090adedf85894ff66e94dd786 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: amstar.c 8888 2007-10-02 13:40:42Z martineau $
  28. *
  29. * send estimated backup sizes using dump
  30. */
  31. /* PROPERTY:
  32. *
  33. * STAR-PATH (default STAR)
  34. * STAR-TARDUMP
  35. * STAR-DLE-TARDUMP
  36. * ONE-FILE-SYSTEM
  37. * SPARSE
  38. * NORMAL
  39. * IGNORE
  40. * STRANGE
  41. * INCLUDE-LIST (for restore only)
  42. * EXCLUDE-LIST (for restore only)
  43. * DIRECTORY
  44. */
  45. #include "amanda.h"
  46. #include "match.h"
  47. #include "pipespawn.h"
  48. #include "amfeatures.h"
  49. #include "amandates.h"
  50. #include "clock.h"
  51. #include "util.h"
  52. #include "getfsent.h"
  53. #include "client_util.h"
  54. #include "conffile.h"
  55. #include "getopt.h"
  56. #include "sendbackup.h"
  57. int debug_application = 1;
  58. #define application_debug(i, ...) do { \
  59. if ((i) <= debug_application) { \
  60. dbprintf(__VA_ARGS__); \
  61. } \
  62. } while (0)
  63. static amregex_t init_re_table[] = {
  64. /* tar prints the size in bytes */
  65. AM_SIZE_RE("star: [0-9][0-9]* blocks", 10240, 1),
  66. AM_NORMAL_RE("^could not open conf file"),
  67. AM_NORMAL_RE("^Type of this level "),
  68. AM_NORMAL_RE("^Date of this level "),
  69. AM_NORMAL_RE("^Date of last level "),
  70. AM_NORMAL_RE("^Dump record level "),
  71. AM_NORMAL_RE("^Throughput"),
  72. AM_NORMAL_RE("^.*is sparse$"),
  73. #ifdef IGNORE_TAR_ERRORS
  74. AM_NORMAL_RE("^.*shrunk*$"),
  75. AM_NORMAL_RE("^.*changed size.*$"),
  76. AM_NORMAL_RE("^.*Cannot listxattr for.*$"),
  77. AM_NORMAL_RE("^.Cannot: stat .*$"),
  78. AM_NORMAL_RE("^.Missing links .*$"),
  79. AM_NORMAL_RE("^.Cannot get xattr.*$"),
  80. AM_NORMAL_RE("^.Cannot.*acl.*$"),
  81. #endif
  82. AM_NORMAL_RE("^star: dumped [0-9][0-9]* (tar )?files"),
  83. AM_NORMAL_RE("^.*The following problems occurred during .* processing.*$"),
  84. AM_NORMAL_RE("^.*Processed all possible files, despite earlier errors.*$"),
  85. AM_NORMAL_RE("^.*not written due to problems during backup.*$"),
  86. AM_STRANGE_RE("^Perform a level 0 dump first.*$"),
  87. /* catch-all: DMP_STRANGE is returned for all other lines */
  88. AM_STRANGE_RE(NULL)
  89. };
  90. static amregex_t *re_table;
  91. /* local functions */
  92. int main(int argc, char **argv);
  93. typedef struct application_argument_s {
  94. char *config;
  95. char *host;
  96. int message;
  97. int collection;
  98. int calcsize;
  99. GSList *level;
  100. GSList *command_options;
  101. dle_t dle;
  102. int argc;
  103. char **argv;
  104. } application_argument_t;
  105. enum { CMD_ESTIMATE, CMD_BACKUP };
  106. static void amstar_support(application_argument_t *argument);
  107. static void amstar_selfcheck(application_argument_t *argument);
  108. static void amstar_estimate(application_argument_t *argument);
  109. static void amstar_backup(application_argument_t *argument);
  110. static void amstar_restore(application_argument_t *argument);
  111. static void amstar_validate(application_argument_t *argument);
  112. static GPtrArray *amstar_build_argv(application_argument_t *argument,
  113. int level,
  114. int command);
  115. static int check_device(application_argument_t *argument);
  116. static char *star_path;
  117. static char *star_tardumps;
  118. static int star_dle_tardumps;
  119. static int star_onefilesystem;
  120. static int star_sparse;
  121. static int star_acl;
  122. static char *star_directory;
  123. static GSList *normal_message = NULL;
  124. static GSList *ignore_message = NULL;
  125. static GSList *strange_message = NULL;
  126. static struct option long_options[] = {
  127. {"config" , 1, NULL, 1},
  128. {"host" , 1, NULL, 2},
  129. {"disk" , 1, NULL, 3},
  130. {"device" , 1, NULL, 4},
  131. {"level" , 1, NULL, 5},
  132. {"index" , 1, NULL, 6},
  133. {"message" , 1, NULL, 7},
  134. {"collection" , 0, NULL, 8},
  135. {"record" , 0, NULL, 9},
  136. {"star-path" , 1, NULL, 10},
  137. {"star-tardump" , 1, NULL, 11},
  138. {"star-dle-tardump", 1, NULL, 12},
  139. {"one-file-system" , 1, NULL, 13},
  140. {"sparse" , 1, NULL, 14},
  141. {"calcsize" , 0, NULL, 15},
  142. {"normal" , 1, NULL, 16},
  143. {"ignore" , 1, NULL, 17},
  144. {"strange" , 1, NULL, 18},
  145. {"include-list" , 1, NULL, 19},
  146. {"exclude-list" , 1, NULL, 20},
  147. {"directory" , 1, NULL, 21},
  148. {"command-options" , 1, NULL, 22},
  149. {"acl" , 1, NULL, 24},
  150. { NULL, 0, NULL, 0}
  151. };
  152. int
  153. main(
  154. int argc,
  155. char ** argv)
  156. {
  157. int c;
  158. char *command;
  159. application_argument_t argument;
  160. #ifdef STAR
  161. star_path = STAR;
  162. #else
  163. star_path = NULL;
  164. #endif
  165. star_tardumps = "/etc/tardumps";
  166. star_dle_tardumps = 0;
  167. star_onefilesystem = 1;
  168. star_sparse = 1;
  169. star_acl = 1;
  170. star_directory = NULL;
  171. /* initialize */
  172. /*
  173. * Configure program for internationalization:
  174. * 1) Only set the message locale for now.
  175. * 2) Set textdomain for all amanda related programs to "amanda"
  176. * We don't want to be forced to support dozens of message catalogs.
  177. */
  178. setlocale(LC_MESSAGES, "C");
  179. textdomain("amanda");
  180. if (argc < 2) {
  181. printf("ERROR no command given to amstar\n");
  182. error(_("No command given to amstar"));
  183. }
  184. /* drop root privileges */
  185. if (!set_root_privs(0)) {
  186. if (strcmp(argv[1], "selfcheck") == 0) {
  187. printf("ERROR amstar must be run setuid root\n");
  188. }
  189. error(_("amstar must be run setuid root"));
  190. }
  191. safe_fd(3, 2);
  192. set_pname("amstar");
  193. /* Don't die when child closes pipe */
  194. signal(SIGPIPE, SIG_IGN);
  195. #if defined(USE_DBMALLOC)
  196. malloc_size_1 = malloc_inuse(&malloc_hist_1);
  197. #endif
  198. add_amanda_log_handler(amanda_log_stderr);
  199. add_amanda_log_handler(amanda_log_syslog);
  200. dbopen(DBG_SUBDIR_CLIENT);
  201. startclock();
  202. dbprintf(_("version %s\n"), VERSION);
  203. config_init(CONFIG_INIT_CLIENT, NULL);
  204. //check_running_as(RUNNING_AS_DUMPUSER_PREFERRED);
  205. //root for amrecover
  206. //RUNNING_AS_CLIENT_LOGIN from selfcheck, sendsize, sendbackup
  207. /* parse argument */
  208. command = argv[1];
  209. argument.config = NULL;
  210. argument.host = NULL;
  211. argument.message = 0;
  212. argument.collection = 0;
  213. argument.calcsize = 0;
  214. argument.level = NULL;
  215. argument.command_options = NULL;
  216. init_dle(&argument.dle);
  217. opterr = 0;
  218. while (1) {
  219. int option_index = 0;
  220. c = getopt_long (argc, argv, "", long_options, &option_index);
  221. if (c == -1)
  222. break;
  223. switch (c) {
  224. case 1: argument.config = stralloc(optarg);
  225. break;
  226. case 2: argument.host = stralloc(optarg);
  227. break;
  228. case 3: argument.dle.disk = stralloc(optarg);
  229. break;
  230. case 4: argument.dle.device = stralloc(optarg);
  231. break;
  232. case 5: argument.level = g_slist_append(argument.level,
  233. GINT_TO_POINTER(atoi(optarg)));
  234. break;
  235. case 6: argument.dle.create_index = 1;
  236. break;
  237. case 7: argument.message = 1;
  238. break;
  239. case 8: argument.collection = 1;
  240. break;
  241. case 9: argument.dle.record = 1;
  242. break;
  243. case 10: star_path = stralloc(optarg);
  244. break;
  245. case 11: star_tardumps = stralloc(optarg);
  246. break;
  247. case 12: if (optarg && strcasecmp(optarg, "NO") == 0)
  248. star_dle_tardumps = 0;
  249. else if (optarg && strcasecmp(optarg, "YES") == 0)
  250. star_dle_tardumps = 1;
  251. else if (strcasecmp(command, "selfcheck") == 0)
  252. printf(_("ERROR [%s: bad STAR-DLE-TARDUMP property value (%s)]\n"), get_pname(), optarg);
  253. break;
  254. case 13: if (optarg && strcasecmp(optarg, "YES") != 0) {
  255. /* This option is required to be YES */
  256. /* star_onefilesystem = 0; */
  257. }
  258. break;
  259. case 14: if (optarg && strcasecmp(optarg, "NO") == 0)
  260. star_sparse = 0;
  261. else if (optarg && strcasecmp(optarg, "YES") == 0)
  262. star_sparse = 1;
  263. else if (strcasecmp(command, "selfcheck") == 0)
  264. printf(_("ERROR [%s: bad SPARSE property value (%s)]\n"), get_pname(), optarg);
  265. break;
  266. case 15: argument.calcsize = 1;
  267. break;
  268. case 16: if (optarg)
  269. normal_message =
  270. g_slist_append(normal_message, optarg);
  271. break;
  272. case 17: if (optarg)
  273. ignore_message =
  274. g_slist_append(ignore_message, optarg);
  275. break;
  276. case 18: if (optarg)
  277. strange_message =
  278. g_slist_append(strange_message, optarg);
  279. break;
  280. case 19: if (optarg)
  281. argument.dle.include_list =
  282. append_sl(argument.dle.include_list, optarg);
  283. break;
  284. case 20: if (optarg)
  285. argument.dle.exclude_list =
  286. append_sl(argument.dle.exclude_list, optarg);
  287. break;
  288. case 21: if (optarg)
  289. star_directory = stralloc(optarg);
  290. break;
  291. case 22: argument.command_options =
  292. g_slist_append(argument.command_options,
  293. stralloc(optarg));
  294. case 24: if (optarg && strcasecmp(optarg, "NO") == 0)
  295. star_acl = 0;
  296. else if (optarg && strcasecmp(optarg, "YES") == 0)
  297. star_acl = 1;
  298. else if (strcasecmp(command, "selfcheck") == 0)
  299. printf(_("ERROR [%s: bad ACL property value (%s)]\n"), get_pname(), optarg);
  300. break;
  301. case ':':
  302. case '?':
  303. break;
  304. }
  305. }
  306. if (!argument.dle.disk && argument.dle.device)
  307. argument.dle.disk = stralloc(argument.dle.device);
  308. if (!argument.dle.device && argument.dle.disk)
  309. argument.dle.device = stralloc(argument.dle.disk);
  310. argument.argc = argc - optind;
  311. argument.argv = argv + optind;
  312. if (argument.config) {
  313. /* overlay this configuration on the existing (nameless) configuration */
  314. config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
  315. argument.config);
  316. dbrename(get_config_name(), DBG_SUBDIR_CLIENT);
  317. }
  318. if (config_errors(NULL) >= CFGERR_ERRORS) {
  319. g_critical(_("errors processing config file"));
  320. }
  321. re_table = build_re_table(init_re_table, normal_message, ignore_message,
  322. strange_message);
  323. if (strcmp(command, "support") == 0) {
  324. amstar_support(&argument);
  325. } else if (strcmp(command, "selfcheck") == 0) {
  326. amstar_selfcheck(&argument);
  327. } else if (strcmp(command, "estimate") == 0) {
  328. amstar_estimate(&argument);
  329. } else if (strcmp(command, "backup") == 0) {
  330. amstar_backup(&argument);
  331. } else if (strcmp(command, "restore") == 0) {
  332. amstar_restore(&argument);
  333. } else if (strcmp(command, "validate") == 0) {
  334. amstar_validate(&argument);
  335. } else {
  336. fprintf(stderr, "Unknown command `%s'.\n", command);
  337. exit (1);
  338. }
  339. return 0;
  340. }
  341. static void
  342. amstar_support(
  343. application_argument_t *argument)
  344. {
  345. (void)argument;
  346. fprintf(stdout, "CONFIG YES\n");
  347. fprintf(stdout, "HOST YES\n");
  348. fprintf(stdout, "DISK YES\n");
  349. fprintf(stdout, "MAX-LEVEL 9\n");
  350. fprintf(stdout, "INDEX-LINE YES\n");
  351. fprintf(stdout, "INDEX-XML NO\n");
  352. fprintf(stdout, "MESSAGE-LINE YES\n");
  353. fprintf(stdout, "MESSAGE-XML NO\n");
  354. fprintf(stdout, "RECORD YES\n");
  355. fprintf(stdout, "INCLUDE-FILE NO\n");
  356. fprintf(stdout, "INCLUDE-LIST YES\n");
  357. fprintf(stdout, "EXCLUDE-FILE YES\n");
  358. fprintf(stdout, "EXCLUDE-LIST YES\n");
  359. fprintf(stdout, "COLLECTION NO\n");
  360. fprintf(stdout, "MULTI-ESTIMATE YES\n");
  361. fprintf(stdout, "CALCSIZE YES\n");
  362. fprintf(stdout, "CLIENT-ESTIMATE YES\n");
  363. }
  364. static void
  365. amstar_selfcheck(
  366. application_argument_t *argument)
  367. {
  368. fprintf(stdout, "OK amstar\n");
  369. if (argument->dle.disk) {
  370. char *qdisk = quote_string(argument->dle.disk);
  371. fprintf(stdout, "OK %s\n", qdisk);
  372. amfree(qdisk);
  373. }
  374. if (argument->dle.device) {
  375. char *qdevice = quote_string(argument->dle.device);
  376. fprintf(stdout, "OK %s\n", qdevice);
  377. amfree(qdevice);
  378. }
  379. if (star_directory) {
  380. char *qdirectory = quote_string(star_directory);
  381. fprintf(stdout, "OK %s\n", qdirectory);
  382. amfree(qdirectory);
  383. }
  384. if (argument->dle.include_list &&
  385. argument->dle.include_list->nb_element >= 0) {
  386. fprintf(stdout, "ERROR include-list not supported for backup\n");
  387. }
  388. if (argument->dle.exclude_list &&
  389. argument->dle.exclude_list->nb_element >= 0) {
  390. fprintf(stdout, "ERROR exclude-list not supported for backup\n");
  391. }
  392. if (!star_path) {
  393. fprintf(stdout, "ERROR STAR-PATH not defined\n");
  394. } else {
  395. check_file(star_path, X_OK);
  396. }
  397. if (argument->calcsize) {
  398. char *calcsize = vstralloc(amlibexecdir, "/", "calcsize", NULL);
  399. check_file(calcsize, X_OK);
  400. check_suid(calcsize);
  401. amfree(calcsize);
  402. }
  403. {
  404. char *amandates_file;
  405. amandates_file = getconf_str(CNF_AMANDATES);
  406. check_file(amandates_file, R_OK|W_OK);
  407. }
  408. set_root_privs(1);
  409. if (argument->dle.device) {
  410. check_dir(argument->dle.device, R_OK);
  411. }
  412. set_root_privs(0);
  413. }
  414. static void
  415. amstar_estimate(
  416. application_argument_t *argument)
  417. {
  418. GPtrArray *argv_ptr;
  419. char *cmd = NULL;
  420. int nullfd;
  421. int pipefd;
  422. FILE *dumpout = NULL;
  423. off_t size = -1;
  424. char line[32768];
  425. char *errmsg = NULL;
  426. char *qerrmsg;
  427. char *qdisk;
  428. amwait_t wait_status;
  429. int starpid;
  430. amregex_t *rp;
  431. times_t start_time;
  432. int level = 0;
  433. GSList *levels = NULL;
  434. if (!argument->level) {
  435. fprintf(stderr, "ERROR No level argument\n");
  436. error(_("No level argument"));
  437. }
  438. if (!argument->dle.disk) {
  439. fprintf(stderr, "ERROR No disk argument\n");
  440. error(_("No disk argument"));
  441. }
  442. if (!argument->dle.device) {
  443. fprintf(stderr, "ERROR No device argument\n");
  444. error(_("No device argument"));
  445. }
  446. if (argument->dle.include_list &&
  447. argument->dle.include_list->nb_element >= 0) {
  448. fprintf(stderr, "ERROR include-list not supported for backup\n");
  449. }
  450. if (argument->dle.exclude_list &&
  451. argument->dle.exclude_list->nb_element >= 0) {
  452. fprintf(stderr, "ERROR exclude-list not supported for backup\n");
  453. }
  454. if (check_device(argument) == 0) {
  455. return;
  456. }
  457. qdisk = quote_string(argument->dle.disk);
  458. if (argument->calcsize) {
  459. char *dirname;
  460. if (star_directory) {
  461. dirname = amname_to_dirname(star_directory);
  462. } else {
  463. dirname = amname_to_dirname(argument->dle.device);
  464. }
  465. run_calcsize(argument->config, "STAR", argument->dle.disk, dirname,
  466. argument->level, NULL, NULL);
  467. return;
  468. }
  469. if (!star_path) {
  470. errmsg = vstrallocf(_("STAR-PATH not defined"));
  471. goto common_error;
  472. }
  473. cmd = stralloc(star_path);
  474. start_time = curclock();
  475. for (levels = argument->level; levels != NULL; levels = levels->next) {
  476. level = GPOINTER_TO_INT(levels->data);
  477. argv_ptr = amstar_build_argv(argument, level, CMD_ESTIMATE);
  478. if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
  479. errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
  480. strerror(errno));
  481. goto common_error;
  482. }
  483. starpid = pipespawnv(cmd, STDERR_PIPE, 1,
  484. &nullfd, &nullfd, &pipefd,
  485. (char **)argv_ptr->pdata);
  486. dumpout = fdopen(pipefd,"r");
  487. if (!dumpout) {
  488. errmsg = vstrallocf(_("Can't fdopen: %s"), strerror(errno));
  489. goto common_error;
  490. }
  491. size = (off_t)-1;
  492. while (size < 0 && (fgets(line, sizeof(line), dumpout)) != NULL) {
  493. if (line[strlen(line)-1] == '\n') /* remove trailling \n */
  494. line[strlen(line)-1] = '\0';
  495. if (line[0] == '\0')
  496. continue;
  497. dbprintf("%s\n", line);
  498. /* check for size match */
  499. /*@ignore@*/
  500. for(rp = re_table; rp->regex != NULL; rp++) {
  501. if(match(rp->regex, line)) {
  502. if (rp->typ == DMP_SIZE) {
  503. size = ((the_num(line, rp->field)*rp->scale+1023.0)/1024.0);
  504. if(size < 0.0)
  505. size = 1.0; /* found on NeXT -- sigh */
  506. }
  507. break;
  508. }
  509. }
  510. /*@end@*/
  511. }
  512. while ((fgets(line, sizeof(line), dumpout)) != NULL) {
  513. dbprintf("%s", line);
  514. }
  515. dbprintf(".....\n");
  516. dbprintf(_("estimate time for %s level %d: %s\n"),
  517. qdisk,
  518. level,
  519. walltime_str(timessub(curclock(), start_time)));
  520. if(size == (off_t)-1) {
  521. errmsg = vstrallocf(_("no size line match in %s output"),
  522. cmd);
  523. dbprintf(_("%s for %s\n"), errmsg, qdisk);
  524. dbprintf(".....\n");
  525. } else if(size == (off_t)0 && argument->level == 0) {
  526. dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"),
  527. cmd, argument->dle.disk);
  528. dbprintf(".....\n");
  529. }
  530. dbprintf(_("estimate size for %s level %d: %lld KB\n"),
  531. qdisk,
  532. level,
  533. (long long)size);
  534. kill(-starpid, SIGTERM);
  535. dbprintf(_("waiting for %s \"%s\" child\n"), cmd, qdisk);
  536. waitpid(starpid, &wait_status, 0);
  537. if (WIFSIGNALED(wait_status)) {
  538. errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
  539. cmd, WTERMSIG(wait_status), dbfn());
  540. } else if (WIFEXITED(wait_status)) {
  541. if (WEXITSTATUS(wait_status) != 0) {
  542. errmsg = vstrallocf(_("%s exited with status %d: see %s"),
  543. cmd, WEXITSTATUS(wait_status), dbfn());
  544. } else {
  545. /* Normal exit */
  546. }
  547. } else {
  548. errmsg = vstrallocf(_("%s got bad exit: see %s"), cmd, dbfn());
  549. }
  550. dbprintf(_("after %s %s wait\n"), cmd, qdisk);
  551. g_ptr_array_free_full(argv_ptr);
  552. aclose(nullfd);
  553. afclose(dumpout);
  554. fprintf(stdout, "%d %lld 1\n", level, (long long)size);
  555. }
  556. amfree(qdisk);
  557. amfree(cmd);
  558. return;
  559. common_error:
  560. dbprintf("%s\n", errmsg);
  561. qerrmsg = quote_string(errmsg);
  562. amfree(qdisk);
  563. dbprintf("%s", errmsg);
  564. fprintf(stdout, "ERROR %s\n", qerrmsg);
  565. amfree(errmsg);
  566. amfree(qerrmsg);
  567. amfree(cmd);
  568. }
  569. static void
  570. amstar_backup(
  571. application_argument_t *argument)
  572. {
  573. int dumpin;
  574. char *cmd = NULL;
  575. char *qdisk;
  576. char line[32768];
  577. amregex_t *rp;
  578. off_t dump_size = -1;
  579. char *type;
  580. char startchr;
  581. GPtrArray *argv_ptr;
  582. int starpid;
  583. int dataf = 1;
  584. int mesgf = 3;
  585. int indexf = 4;
  586. int outf;
  587. FILE *mesgstream;
  588. FILE *indexstream = NULL;
  589. FILE *outstream;
  590. int level;
  591. regex_t regex_root;
  592. regex_t regex_dir;
  593. regex_t regex_file;
  594. regex_t regex_special;
  595. regex_t regex_symbolic;
  596. regex_t regex_hard;
  597. mesgstream = fdopen(mesgf, "w");
  598. if (!mesgstream) {
  599. error(_("error mesgstream(%d): %s\n"), mesgf, strerror(errno));
  600. }
  601. if (!argument->level) {
  602. fprintf(mesgstream, "? No level argument\n");
  603. error(_("No level argument"));
  604. }
  605. if (!argument->dle.disk) {
  606. fprintf(mesgstream, "? No disk argument\n");
  607. error(_("No disk argument"));
  608. }
  609. if (!argument->dle.device) {
  610. fprintf(mesgstream, "? No device argument\n");
  611. error(_("No device argument"));
  612. }
  613. if (argument->dle.include_list &&
  614. argument->dle.include_list->nb_element >= 0) {
  615. fprintf(mesgstream, "? include-list not supported for backup\n");
  616. }
  617. if (argument->dle.exclude_list &&
  618. argument->dle.exclude_list->nb_element >= 0) {
  619. fprintf(mesgstream, "? exclude-list not supported for backup\n");
  620. }
  621. level = GPOINTER_TO_INT(argument->level->data);
  622. qdisk = quote_string(argument->dle.disk);
  623. argv_ptr = amstar_build_argv(argument, level, CMD_BACKUP);
  624. cmd = stralloc(star_path);
  625. starpid = pipespawnv(cmd, STDIN_PIPE|STDERR_PIPE, 1,
  626. &dumpin, &dataf, &outf, (char **)argv_ptr->pdata);
  627. g_ptr_array_free_full(argv_ptr);
  628. /* close the write ends of the pipes */
  629. aclose(dumpin);
  630. aclose(dataf);
  631. if (argument->dle.create_index) {
  632. indexstream = fdopen(indexf, "w");
  633. if (!indexstream) {
  634. error(_("error indexstream(%d): %s\n"), indexf, strerror(errno));
  635. }
  636. }
  637. outstream = fdopen(outf, "r");
  638. if (!outstream) {
  639. error(_("error outstream(%d): %s\n"), outf, strerror(errno));
  640. }
  641. regcomp(&regex_root, "^a \\.\\/ directory$", REG_EXTENDED|REG_NEWLINE);
  642. regcomp(&regex_dir, "^a (.*) directory$", REG_EXTENDED|REG_NEWLINE);
  643. regcomp(&regex_file, "^a (.*) (.*) bytes", REG_EXTENDED|REG_NEWLINE);
  644. regcomp(&regex_special, "^a (.*) special", REG_EXTENDED|REG_NEWLINE);
  645. regcomp(&regex_symbolic, "^a (.*) symbolic", REG_EXTENDED|REG_NEWLINE);
  646. regcomp(&regex_hard, "^a (.*) link to", REG_EXTENDED|REG_NEWLINE);
  647. while ((fgets(line, sizeof(line), outstream)) != NULL) {
  648. regmatch_t regmatch[3];
  649. if (line[strlen(line)-1] == '\n') /* remove trailling \n */
  650. line[strlen(line)-1] = '\0';
  651. if (regexec(&regex_root, line, 1, regmatch, 0) == 0) {
  652. if (argument->dle.create_index)
  653. fprintf(indexstream, "%s\n", "/");
  654. continue;
  655. }
  656. if (regexec(&regex_dir, line, 3, regmatch, 0) == 0) {
  657. if (argument->dle.create_index && regmatch[1].rm_so == 2) {
  658. line[regmatch[1].rm_eo+1]='\0';
  659. fprintf(indexstream, "/%s\n", &line[regmatch[1].rm_so]);
  660. }
  661. continue;
  662. }
  663. if (regexec(&regex_file, line, 3, regmatch, 0) == 0 ||
  664. regexec(&regex_special, line, 3, regmatch, 0) == 0 ||
  665. regexec(&regex_symbolic, line, 3, regmatch, 0) == 0 ||
  666. regexec(&regex_hard, line, 3, regmatch, 0) == 0) {
  667. if (argument->dle.create_index && regmatch[1].rm_so == 2) {
  668. line[regmatch[1].rm_eo]='\0';
  669. fprintf(indexstream, "/%s\n", &line[regmatch[1].rm_so]);
  670. }
  671. continue;
  672. }
  673. for (rp = re_table; rp->regex != NULL; rp++) {
  674. if (match(rp->regex, line)) {
  675. break;
  676. }
  677. }
  678. if (rp->typ == DMP_SIZE) {
  679. dump_size = (off_t)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0);
  680. }
  681. switch (rp->typ) {
  682. case DMP_IGNORE:
  683. continue;
  684. case DMP_NORMAL:
  685. type = "normal";
  686. startchr = '|';
  687. break;
  688. case DMP_STRANGE:
  689. type = "strange";
  690. startchr = '?';
  691. break;
  692. case DMP_SIZE:
  693. type = "size";
  694. startchr = '|';
  695. break;
  696. case DMP_ERROR:
  697. type = "error";
  698. startchr = '?';
  699. break;
  700. default:
  701. type = "unknown";
  702. startchr = '!';
  703. break;
  704. }
  705. dbprintf("%3d: %7s(%c): %s\n", rp->srcline, type, startchr, line);
  706. fprintf(mesgstream,"%c %s\n", startchr, line);
  707. }
  708. regfree(&regex_root);
  709. regfree(&regex_dir);
  710. regfree(&regex_file);
  711. regfree(&regex_special);
  712. regfree(&regex_symbolic);
  713. regfree(&regex_hard);
  714. dbprintf(_("gnutar: %s: pid %ld\n"), cmd, (long)starpid);
  715. dbprintf("sendbackup: size %lld\n", (long long)dump_size);
  716. fprintf(mesgstream, "sendbackup: size %lld\n", (long long)dump_size);
  717. dbprintf("sendbackup: end\n");
  718. fprintf(mesgstream, "sendbackup: end\n");
  719. fclose(mesgstream);
  720. if (argument->dle.create_index)
  721. fclose(indexstream);
  722. amfree(qdisk);
  723. amfree(cmd);
  724. }
  725. static void
  726. amstar_restore(
  727. application_argument_t *argument)
  728. {
  729. char *cmd;
  730. GPtrArray *argv_ptr = g_ptr_array_new();
  731. char **env;
  732. int j;
  733. char *e;
  734. if (!star_path) {
  735. error(_("STAR-PATH not defined"));
  736. }
  737. cmd = stralloc(star_path);
  738. g_ptr_array_add(argv_ptr, stralloc(star_path));
  739. if (star_directory) {
  740. struct stat stat_buf;
  741. if(stat(star_directory, &stat_buf) != 0) {
  742. fprintf(stderr,"can not stat directory %s: %s\n", star_directory, strerror(errno));
  743. exit(1);
  744. }
  745. if (!S_ISDIR(stat_buf.st_mode)) {
  746. fprintf(stderr,"%s is not a directory\n", star_directory);
  747. exit(1);
  748. }
  749. if (access(star_directory, W_OK) != 0 ) {
  750. fprintf(stderr, "Can't write to %s: %s\n", star_directory, strerror(errno));
  751. exit(1);
  752. }
  753. g_ptr_array_add(argv_ptr, stralloc("-C"));
  754. g_ptr_array_add(argv_ptr, stralloc(star_directory));
  755. }
  756. g_ptr_array_add(argv_ptr, stralloc("-x"));
  757. g_ptr_array_add(argv_ptr, stralloc("-v"));
  758. g_ptr_array_add(argv_ptr, stralloc("-xattr"));
  759. g_ptr_array_add(argv_ptr, stralloc("-acl"));
  760. g_ptr_array_add(argv_ptr, stralloc("errctl=WARN|SAMEFILE|SETTIME|DIFF|SETACL|SETXATTR|SETMODE|BADACL *"));
  761. g_ptr_array_add(argv_ptr, stralloc("-no-fifo"));
  762. g_ptr_array_add(argv_ptr, stralloc("-f"));
  763. g_ptr_array_add(argv_ptr, stralloc("-"));
  764. if (argument->dle.exclude_list &&
  765. argument->dle.exclude_list->nb_element == 1) {
  766. g_ptr_array_add(argv_ptr, stralloc("-exclude-from"));
  767. g_ptr_array_add(argv_ptr,
  768. stralloc(argument->dle.exclude_list->first->name));
  769. }
  770. if (argument->dle.include_list &&
  771. argument->dle.include_list->nb_element == 1) {
  772. FILE *include_list = fopen(argument->dle.include_list->first->name, "r");
  773. char line[2*PATH_MAX+2];
  774. while (fgets(line, 2*PATH_MAX, include_list)) {
  775. line[strlen(line)-1] = '\0'; /* remove '\n' */
  776. if (strncmp(line, "./", 2) == 0)
  777. g_ptr_array_add(argv_ptr, stralloc(line+2)); /* remove ./ */
  778. else if (strcmp(line, ".") != 0)
  779. g_ptr_array_add(argv_ptr, stralloc(line));
  780. }
  781. fclose(include_list);
  782. }
  783. for (j=1; j< argument->argc; j++) {
  784. if (strncmp(argument->argv[j], "./", 2) == 0)
  785. g_ptr_array_add(argv_ptr, stralloc(argument->argv[j]+2));/*remove ./ */
  786. else if (strcmp(argument->argv[j], ".") != 0)
  787. g_ptr_array_add(argv_ptr, stralloc(argument->argv[j]));
  788. }
  789. g_ptr_array_add(argv_ptr, NULL);
  790. debug_executing(argv_ptr);
  791. env = safe_env();
  792. become_root();
  793. execve(cmd, (char **)argv_ptr->pdata, env);
  794. e = strerror(errno);
  795. error(_("error [exec %s: %s]"), cmd, e);
  796. }
  797. static void
  798. amstar_validate(
  799. application_argument_t *argument G_GNUC_UNUSED)
  800. {
  801. char *cmd;
  802. GPtrArray *argv_ptr = g_ptr_array_new();
  803. char **env;
  804. char *e;
  805. char buf[32768];
  806. if (!star_path) {
  807. dbprintf("STAR-PATH not set; Piping to /dev/null\n");
  808. fprintf(stderr,"STAR-PATH not set; Piping to /dev/null\n");
  809. goto pipe_to_null;
  810. }
  811. cmd = stralloc(star_path);
  812. g_ptr_array_add(argv_ptr, stralloc(star_path));
  813. g_ptr_array_add(argv_ptr, stralloc("-t"));
  814. g_ptr_array_add(argv_ptr, stralloc("-f"));
  815. g_ptr_array_add(argv_ptr, stralloc("-"));
  816. g_ptr_array_add(argv_ptr, NULL);
  817. debug_executing(argv_ptr);
  818. env = safe_env();
  819. execve(cmd, (char **)argv_ptr->pdata, env);
  820. e = strerror(errno);
  821. dbprintf("failed to execute %s: %s; Piping to /dev/null\n", cmd, e);
  822. fprintf(stderr,"failed to execute %s: %s; Piping to /dev/null\n", cmd, e);
  823. pipe_to_null:
  824. while (read(0, buf, 32768) > 0) {
  825. }
  826. }
  827. static GPtrArray *amstar_build_argv(
  828. application_argument_t *argument,
  829. int level,
  830. int command)
  831. {
  832. char *dirname;
  833. char *fsname;
  834. char levelstr[NUM_STR_SIZE+7];
  835. GPtrArray *argv_ptr = g_ptr_array_new();
  836. char *s;
  837. char *tardumpfile;
  838. GSList *copt;
  839. if (star_directory) {
  840. dirname = amname_to_dirname(star_directory);
  841. } else {
  842. dirname = amname_to_dirname(argument->dle.device);
  843. }
  844. fsname = vstralloc("fs-name=", dirname, NULL);
  845. for (s = fsname; *s != '\0'; s++) {
  846. if (iscntrl((int)*s))
  847. *s = '-';
  848. }
  849. snprintf(levelstr, SIZEOF(levelstr), "-level=%d", level);
  850. if (star_dle_tardumps) {
  851. char *sdisk = sanitise_filename(argument->dle.disk);
  852. tardumpfile = vstralloc(star_tardumps, sdisk, NULL);
  853. amfree(sdisk);
  854. } else {
  855. tardumpfile = stralloc(star_tardumps);
  856. }
  857. g_ptr_array_add(argv_ptr, stralloc(star_path));
  858. g_ptr_array_add(argv_ptr, stralloc("-c"));
  859. g_ptr_array_add(argv_ptr, stralloc("-f"));
  860. if (command == CMD_ESTIMATE) {
  861. g_ptr_array_add(argv_ptr, stralloc("/dev/null"));
  862. } else {
  863. g_ptr_array_add(argv_ptr, stralloc("-"));
  864. }
  865. g_ptr_array_add(argv_ptr, stralloc("-C"));
  866. #if defined(__CYGWIN__)
  867. {
  868. char tmppath[PATH_MAX];
  869. cygwin_conv_to_full_posix_path(dirname, tmppath);
  870. g_ptr_array_add(argv_ptr, stralloc(tmppath));
  871. }
  872. #else
  873. g_ptr_array_add(argv_ptr, stralloc(dirname));
  874. #endif
  875. g_ptr_array_add(argv_ptr, stralloc(fsname));
  876. if (star_onefilesystem)
  877. g_ptr_array_add(argv_ptr, stralloc("-xdev"));
  878. g_ptr_array_add(argv_ptr, stralloc("-link-dirs"));
  879. g_ptr_array_add(argv_ptr, stralloc(levelstr));
  880. g_ptr_array_add(argv_ptr, stralloc2("tardumps=", tardumpfile));
  881. if (command == CMD_BACKUP)
  882. g_ptr_array_add(argv_ptr, stralloc("-wtardumps"));
  883. g_ptr_array_add(argv_ptr, stralloc("-xattr"));
  884. if (star_acl)
  885. g_ptr_array_add(argv_ptr, stralloc("-acl"));
  886. g_ptr_array_add(argv_ptr, stralloc("H=exustar"));
  887. g_ptr_array_add(argv_ptr, stralloc("errctl=WARN|SAMEFILE|DIFF|GROW|SHRINK|SPECIALFILE|GETXATTR|BADACL *"));
  888. if (star_sparse)
  889. g_ptr_array_add(argv_ptr, stralloc("-sparse"));
  890. g_ptr_array_add(argv_ptr, stralloc("-dodesc"));
  891. for (copt = argument->command_options; copt != NULL; copt = copt->next) {
  892. g_ptr_array_add(argv_ptr, stralloc((char *)copt->data));
  893. }
  894. if (command == CMD_BACKUP && argument->dle.create_index)
  895. g_ptr_array_add(argv_ptr, stralloc("-v"));
  896. g_ptr_array_add(argv_ptr, stralloc("."));
  897. g_ptr_array_add(argv_ptr, NULL);
  898. amfree(tardumpfile);
  899. amfree(fsname);
  900. return(argv_ptr);
  901. }
  902. static int
  903. check_device(
  904. application_argument_t *argument)
  905. {
  906. char *qdevice;
  907. struct stat stat_buf;
  908. qdevice = quote_string(argument->dle.device);
  909. set_root_privs(1);
  910. if(!stat(argument->dle.device, &stat_buf)) {
  911. if (!S_ISDIR(stat_buf.st_mode)) {
  912. set_root_privs(0);
  913. g_fprintf(stderr, _("ERROR %s is not a directory\n"), qdevice);
  914. amfree(qdevice);
  915. return 0;
  916. }
  917. } else {
  918. set_root_privs(0);
  919. g_fprintf(stderr, _("ERROR can not stat %s: %s\n"), qdevice,
  920. strerror(errno));
  921. amfree(qdevice);
  922. return 0;
  923. }
  924. if (access(argument->dle.device, R_OK|X_OK) == -1) {
  925. set_root_privs(0);
  926. g_fprintf(stderr, _("ERROR can not access %s: %s\n"),
  927. argument->dle.device, strerror(errno));
  928. amfree(qdevice);
  929. return 0;
  930. }
  931. set_root_privs(0);
  932. amfree(qdevice);
  933. return 1;
  934. }