PageRenderTime 52ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/amanda/trunk/application-src/amstar.c

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