2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
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.
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.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: amgtar.c 8888 2007-10-02 13:40:42Z martineau $
29 * send estimated backup sizes using dump
34 * GNUTAR-PATH (default GNUTAR)
35 * GNUTAR-LISTDIR (default CNF_GNUTAR_LIST_DIR)
36 * DIRECTORY (no default, if set, the backup will be from that directory
37 * instead of from the --device)
38 * ONE-FILE-SYSTEM (default YES)
39 * SPARSE (default YES)
40 * ATIME-PRESERVE (default YES)
41 * CHECK-DEVICE (default YES)
42 * NO-UNQUOTE (default NO)
44 * SELINUX (default NO)
57 * EXIT-HANDLING (1=GOOD 2=BAD)
58 * TAR-BLOCKSIZE (default does not add --blocking-factor option,
59 * using tar's default)
65 #include "pipespawn.h"
66 #include "amfeatures.h"
70 #include "client_util.h"
74 int debug_application = 1;
75 #define application_debug(i, ...) do { \
76 if ((i) <= debug_application) { \
77 dbprintf(__VA_ARGS__); \
81 static amregex_t init_re_table[] = {
82 /* tar prints the size in bytes */
83 AM_SIZE_RE("^ *Total bytes written: [0-9][0-9]*", 1, 1),
84 AM_NORMAL_RE("^could not open conf file"),
85 AM_NORMAL_RE("^Elapsed time:"),
86 AM_NORMAL_RE("^Throughput"),
87 AM_IGNORE_RE(": Directory is new$"),
88 AM_IGNORE_RE(": Directory has been renamed"),
90 /* GNU tar 1.13.17 will print this warning when (not) backing up a
92 AM_NORMAL_RE(": socket ignored$"),
94 /* GNUTAR produces a few error messages when files are modified or
95 removed while it is running. They may cause data to be lost, but
96 then they may not. We shouldn't consider them NORMAL until
97 further investigation. */
98 AM_NORMAL_RE(": File .* shrunk by [0-9][0-9]* bytes, padding with zeros"),
99 AM_NORMAL_RE(": Cannot add file .*: No such file or directory$"),
100 AM_NORMAL_RE(": Error exit delayed from previous errors"),
102 /* catch-all: DMP_STRANGE is returned for all other lines */
105 static amregex_t *re_table;
107 /* local functions */
108 int main(int argc, char **argv);
110 typedef struct application_argument_s {
118 GSList *command_options;
119 char *include_list_glob;
120 char *exclude_list_glob;
126 } application_argument_t;
128 enum { CMD_ESTIMATE, CMD_BACKUP };
130 static void amgtar_support(application_argument_t *argument);
131 static void amgtar_selfcheck(application_argument_t *argument);
132 static void amgtar_estimate(application_argument_t *argument);
133 static void amgtar_backup(application_argument_t *argument);
134 static void amgtar_restore(application_argument_t *argument);
135 static void amgtar_validate(application_argument_t *argument);
136 static void amgtar_build_exinclude(dle_t *dle, int verbose,
137 int *nb_exclude, char **file_exclude,
138 int *nb_include, char **file_include);
139 static char *amgtar_get_incrname(application_argument_t *argument, int level,
140 FILE *mesgstream, int command);
141 static void check_no_check_device(void);
142 static GPtrArray *amgtar_build_argv(application_argument_t *argument,
143 char *incrname, char **file_exclude,
144 char **file_include, int command);
145 static char *gnutar_path;
146 static char *gnutar_listdir;
147 static char *gnutar_directory;
148 static int gnutar_onefilesystem;
149 static int gnutar_atimepreserve;
150 static int gnutar_acls;
151 static int gnutar_selinux;
152 static int gnutar_xattrs;
153 static int gnutar_checkdevice;
154 static int gnutar_no_unquote;
155 static int gnutar_sparse;
156 static GSList *normal_message = NULL;
157 static GSList *ignore_message = NULL;
158 static GSList *strange_message = NULL;
159 static char *exit_handling;
160 static int exit_value[256];
162 static struct option long_options[] = {
163 {"config" , 1, NULL, 1},
164 {"host" , 1, NULL, 2},
165 {"disk" , 1, NULL, 3},
166 {"device" , 1, NULL, 4},
167 {"level" , 1, NULL, 5},
168 {"index" , 1, NULL, 6},
169 {"message" , 1, NULL, 7},
170 {"collection" , 0, NULL, 8},
171 {"record" , 0, NULL, 9},
172 {"gnutar-path" , 1, NULL, 10},
173 {"gnutar-listdir" , 1, NULL, 11},
174 {"one-file-system" , 1, NULL, 12},
175 {"sparse" , 1, NULL, 13},
176 {"atime-preserve" , 1, NULL, 14},
177 {"check-device" , 1, NULL, 15},
178 {"include-file" , 1, NULL, 16},
179 {"include-list" , 1, NULL, 17},
180 {"include-optional", 1, NULL, 18},
181 {"exclude-file" , 1, NULL, 19},
182 {"exclude-list" , 1, NULL, 20},
183 {"exclude-optional", 1, NULL, 21},
184 {"directory" , 1, NULL, 22},
185 {"normal" , 1, NULL, 23},
186 {"ignore" , 1, NULL, 24},
187 {"strange" , 1, NULL, 25},
188 {"exit-handling" , 1, NULL, 26},
189 {"calcsize" , 0, NULL, 27},
190 {"tar-blocksize" , 1, NULL, 28},
191 {"no-unquote" , 1, NULL, 29},
192 {"acls" , 1, NULL, 30},
193 {"selinux" , 1, NULL, 31},
194 {"xattrs" , 1, NULL, 32},
195 {"command-options" , 1, NULL, 33},
196 {"include-list-glob", 1, NULL, 34},
197 {"exclude-list-glob", 1, NULL, 35},
198 {"verbose" , 1, NULL, 36},
199 {"ignore-zeros" , 1, NULL, 37},
208 char *result = malloc(4*strlen(str)+1);
213 for (s = str; *s != '\0'; s++) {
221 } else if (c == '?') {
225 } else if (c == 'a') {
229 } else if (c == 'b') {
233 } else if (c == 'f') {
237 } else if (c == 'n') {
242 } else if (c == 'r') {
247 } else if (c == 't') {
251 } else if (c == 'v') {
255 } else if (c >= '0' && c <= '9') {
259 if (c >= '0' && c <= '9') {
263 if (c >= '0' && c <= '9') {
273 } else if (*s == '?') {
276 } else if (*s == '*' || *s == '[') {
294 application_argument_t argument;
298 gnutar_path = GNUTAR;
302 gnutar_listdir = NULL;
303 gnutar_directory = NULL;
304 gnutar_onefilesystem = 1;
305 gnutar_atimepreserve = 1;
309 gnutar_checkdevice = 1;
311 gnutar_no_unquote = 0;
312 exit_handling = NULL;
317 * Configure program for internationalization:
318 * 1) Only set the message locale for now.
319 * 2) Set textdomain for all amanda related programs to "amanda"
320 * We don't want to be forced to support dozens of message catalogs.
322 setlocale(LC_MESSAGES, "C");
323 textdomain("amanda");
326 printf("ERROR no command given to amgtar\n");
327 error(_("No command given to amgtar"));
330 /* drop root privileges */
331 if (!set_root_privs(0)) {
332 if (strcmp(argv[1], "selfcheck") == 0) {
333 printf("ERROR amgtar must be run setuid root\n");
335 error(_("amgtar must be run setuid root"));
342 /* Don't die when child closes pipe */
343 signal(SIGPIPE, SIG_IGN);
345 #if defined(USE_DBMALLOC)
346 malloc_size_1 = malloc_inuse(&malloc_hist_1);
349 add_amanda_log_handler(amanda_log_stderr);
350 add_amanda_log_handler(amanda_log_syslog);
351 dbopen(DBG_SUBDIR_CLIENT);
353 dbprintf(_("version %s\n"), VERSION);
355 config_init(CONFIG_INIT_CLIENT, NULL);
357 //check_running_as(RUNNING_AS_DUMPUSER_PREFERRED);
359 //RUNNING_AS_CLIENT_LOGIN from selfcheck, sendsize, sendbackup
364 gnutar_listdir = stralloc(getconf_str(CNF_GNUTAR_LIST_DIR));
365 argument.config = NULL;
366 argument.host = NULL;
367 argument.message = 0;
368 argument.collection = 0;
369 argument.calcsize = 0;
370 argument.tar_blocksize = NULL;
371 argument.level = NULL;
372 argument.command_options = NULL;
373 argument.include_list_glob = NULL;
374 argument.exclude_list_glob = NULL;
375 argument.verbose = 0;
376 argument.ignore_zeros = 1;
377 init_dle(&argument.dle);
378 argument.dle.record = 0;
381 int option_index = 0;
382 c = getopt_long (argc, argv, "", long_options, &option_index);
387 case 1: argument.config = stralloc(optarg);
389 case 2: argument.host = stralloc(optarg);
391 case 3: argument.dle.disk = stralloc(optarg);
393 case 4: argument.dle.device = stralloc(optarg);
395 case 5: argument.level = g_slist_append(argument.level,
396 GINT_TO_POINTER(atoi(optarg)));
398 case 6: argument.dle.create_index = 1;
400 case 7: argument.message = 1;
402 case 8: argument.collection = 1;
404 case 9: argument.dle.record = 1;
406 case 10: gnutar_path = stralloc(optarg);
408 case 11: gnutar_listdir = stralloc(optarg);
410 case 12: if (optarg && strcasecmp(optarg, "NO") == 0)
411 gnutar_onefilesystem = 0;
412 else if (optarg && strcasecmp(optarg, "YES") == 0)
413 gnutar_onefilesystem = 1;
414 else if (strcasecmp(command, "selfcheck") == 0)
415 printf(_("ERROR [%s: bad ONE-FILE-SYSTEM property value (%s)]\n"), get_pname(), optarg);
417 case 13: if (optarg && strcasecmp(optarg, "NO") == 0)
419 else if (optarg && strcasecmp(optarg, "YES") == 0)
421 else if (strcasecmp(command, "selfcheck") == 0)
422 printf(_("ERROR [%s: bad SPARSE property value (%s)]\n"), get_pname(), optarg);
424 case 14: if (optarg && strcasecmp(optarg, "NO") == 0)
425 gnutar_atimepreserve = 0;
426 else if (optarg && strcasecmp(optarg, "YES") == 0)
427 gnutar_atimepreserve = 1;
428 else if (strcasecmp(command, "selfcheck") == 0)
429 printf(_("ERROR [%s: bad ATIME-PRESERVE property value (%s)]\n"), get_pname(), optarg);
431 case 15: if (optarg && strcasecmp(optarg, "NO") == 0)
432 gnutar_checkdevice = 0;
433 else if (optarg && strcasecmp(optarg, "YES") == 0)
434 gnutar_checkdevice = 1;
435 else if (strcasecmp(command, "selfcheck") == 0)
436 printf(_("ERROR [%s: bad CHECK-DEVICE property value (%s)]\n"), get_pname(), optarg);
439 argument.dle.include_file =
440 append_sl(argument.dle.include_file, optarg);
443 argument.dle.include_list =
444 append_sl(argument.dle.include_list, optarg);
446 case 18: argument.dle.include_optional = 1;
449 argument.dle.exclude_file =
450 append_sl(argument.dle.exclude_file, optarg);
453 argument.dle.exclude_list =
454 append_sl(argument.dle.exclude_list, optarg);
456 case 21: argument.dle.exclude_optional = 1;
458 case 22: gnutar_directory = stralloc(optarg);
462 g_slist_append(normal_message, optarg);
466 g_slist_append(ignore_message, optarg);
470 g_slist_append(strange_message, optarg);
473 exit_handling = stralloc(optarg);
475 case 27: argument.calcsize = 1;
477 case 28: argument.tar_blocksize = stralloc(optarg);
479 case 29: if (optarg && strcasecmp(optarg, "NO") == 0)
480 gnutar_no_unquote = 0;
481 else if (optarg && strcasecmp(optarg, "YES") == 0)
482 gnutar_no_unquote = 1;
483 else if (strcasecmp(command, "selfcheck") == 0)
484 printf(_("ERROR [%s: bad No_UNQUOTE property value (%s)]\n"), get_pname(), optarg);
486 case 30: if (optarg && strcasecmp(optarg, "YES") == 0)
489 case 31: if (optarg && strcasecmp(optarg, "YES") == 0)
492 case 32: if (optarg && strcasecmp(optarg, "YES") == 0)
495 case 33: argument.command_options =
496 g_slist_append(argument.command_options,
500 argument.include_list_glob = stralloc(optarg);
503 argument.exclude_list_glob = stralloc(optarg);
505 case 36: if (optarg && strcasecmp(optarg, "YES") == 0)
506 argument.verbose = 1;
508 case 37: if (strcasecmp(optarg, "YES") != 0)
509 argument.ignore_zeros = 0;
517 if (!argument.dle.disk && argument.dle.device)
518 argument.dle.disk = stralloc(argument.dle.device);
519 if (!argument.dle.device && argument.dle.disk)
520 argument.dle.device = stralloc(argument.dle.disk);
522 argument.argc = argc - optind;
523 argument.argv = argv + optind;
525 if (argument.config) {
526 config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
528 dbrename(get_config_name(), DBG_SUBDIR_CLIENT);
531 if (config_errors(NULL) >= CFGERR_ERRORS) {
532 g_critical(_("errors processing config file"));
535 re_table = build_re_table(init_re_table, normal_message, ignore_message,
539 exit_value[i] = 1; /* BAD */
540 exit_value[0] = 0; /* GOOD */
541 exit_value[1] = 0; /* GOOD */
543 char *s = exit_handling;
545 char *r = strchr(s, '=');
548 if (j >= 0 && j < 256) {
550 if (strncasecmp(r, "GOOD", 4) == 0) {
555 s = strchr(s+1, ' ');
559 if (strlen(gnutar_listdir) == 0)
560 gnutar_listdir = NULL;
563 dbprintf("GNUTAR-PATH %s\n", gnutar_path);
565 dbprintf("GNUTAR-PATH is not set\n");
567 if (gnutar_listdir) {
568 dbprintf("GNUTAR-LISTDIR %s\n", gnutar_listdir);
570 dbprintf("GNUTAR-LISTDIR is not set\n");
572 if (gnutar_directory) {
573 dbprintf("DIRECTORY %s\n", gnutar_directory);
575 dbprintf("ONE-FILE-SYSTEM %s\n", gnutar_onefilesystem? "yes":"no");
576 dbprintf("SPARSE %s\n", gnutar_sparse? "yes":"no");
577 dbprintf("NO-UNQUOTE %s\n", gnutar_no_unquote? "yes":"no");
578 dbprintf("ATIME-PRESERVE %s\n", gnutar_atimepreserve? "yes":"no");
579 dbprintf("ACLS %s\n", gnutar_acls? "yes":"no");
580 dbprintf("SELINUX %s\n", gnutar_selinux? "yes":"no");
581 dbprintf("XATTRS %s\n", gnutar_xattrs? "yes":"no");
582 dbprintf("CHECK-DEVICE %s\n", gnutar_checkdevice? "yes":"no");
585 for (rp = re_table; rp->regex != NULL; rp++) {
587 case DMP_NORMAL : dbprintf("NORMAL %s\n", rp->regex); break;
588 case DMP_IGNORE : dbprintf("IGNORE %s\n", rp->regex); break;
589 case DMP_STRANGE: dbprintf("STRANGE %s\n", rp->regex); break;
590 case DMP_SIZE : dbprintf("SIZE %s\n", rp->regex); break;
591 case DMP_ERROR : dbprintf("ERROR %s\n", rp->regex); break;
596 if (strcmp(command, "support") == 0) {
597 amgtar_support(&argument);
598 } else if (strcmp(command, "selfcheck") == 0) {
599 amgtar_selfcheck(&argument);
600 } else if (strcmp(command, "estimate") == 0) {
601 amgtar_estimate(&argument);
602 } else if (strcmp(command, "backup") == 0) {
603 amgtar_backup(&argument);
604 } else if (strcmp(command, "restore") == 0) {
605 amgtar_restore(&argument);
606 } else if (strcmp(command, "validate") == 0) {
607 amgtar_validate(&argument);
609 dbprintf("Unknown command `%s'.\n", command);
610 fprintf(stderr, "Unknown command `%s'.\n", command);
618 application_argument_t *argument)
621 fprintf(stdout, "CONFIG YES\n");
622 fprintf(stdout, "HOST YES\n");
623 fprintf(stdout, "DISK YES\n");
624 fprintf(stdout, "MAX-LEVEL 399\n");
625 fprintf(stdout, "INDEX-LINE YES\n");
626 fprintf(stdout, "INDEX-XML NO\n");
627 fprintf(stdout, "MESSAGE-LINE YES\n");
628 fprintf(stdout, "MESSAGE-XML NO\n");
629 fprintf(stdout, "RECORD YES\n");
630 fprintf(stdout, "INCLUDE-FILE YES\n");
631 fprintf(stdout, "INCLUDE-LIST YES\n");
632 fprintf(stdout, "INCLUDE-LIST-GLOB YES\n");
633 fprintf(stdout, "INCLUDE-OPTIONAL YES\n");
634 fprintf(stdout, "EXCLUDE-FILE YES\n");
635 fprintf(stdout, "EXCLUDE-LIST YES\n");
636 fprintf(stdout, "EXCLUDE-LIST-GLOB YES\n");
637 fprintf(stdout, "EXCLUDE-OPTIONAL YES\n");
638 fprintf(stdout, "COLLECTION NO\n");
639 fprintf(stdout, "MULTI-ESTIMATE YES\n");
640 fprintf(stdout, "CALCSIZE YES\n");
641 fprintf(stdout, "CLIENT-ESTIMATE YES\n");
646 application_argument_t *argument)
648 if (argument->dle.disk) {
649 char *qdisk = quote_string(argument->dle.disk);
650 fprintf(stdout, "OK disk %s\n", qdisk);
654 printf("OK amgtar version %s\n", VERSION);
655 amgtar_build_exinclude(&argument->dle, 1, NULL, NULL, NULL, NULL);
657 printf("OK amgtar\n");
659 if (check_file(gnutar_path, X_OK)) {
661 GPtrArray *argv_ptr = g_ptr_array_new();
663 g_ptr_array_add(argv_ptr, gnutar_path);
664 g_ptr_array_add(argv_ptr, "--version");
665 g_ptr_array_add(argv_ptr, NULL);
667 gtar_version = get_first_line(argv_ptr);
670 for (gv = gtar_version; *gv && !g_ascii_isdigit(*gv); gv++);
671 printf("OK amgtar gtar-version %s\n", gv);
673 printf(_("ERROR [Can't get %s version]\n"), gnutar_path);
676 g_ptr_array_free(argv_ptr, TRUE);
677 amfree(gtar_version);
680 printf(_("ERROR [GNUTAR program not available]\n"));
684 if (gnutar_listdir && strlen(gnutar_listdir) == 0)
685 gnutar_listdir = NULL;
686 if (gnutar_listdir) {
687 check_dir(gnutar_listdir, R_OK|W_OK);
689 printf(_("ERROR [No GNUTAR-LISTDIR]\n"));
692 if (gnutar_directory) {
693 check_dir(gnutar_directory, R_OK);
694 } else if (argument->dle.device) {
695 check_dir(argument->dle.device, R_OK);
697 if (argument->calcsize) {
698 char *calcsize = vstralloc(amlibexecdir, "/", "calcsize", NULL);
699 check_file(calcsize, X_OK);
700 check_suid(calcsize);
708 application_argument_t *argument)
710 char *incrname = NULL;
715 FILE *dumpout = NULL;
719 char *qerrmsg = NULL;
721 amwait_t wait_status;
730 if (!argument->level) {
731 fprintf(stderr, "ERROR No level argument\n");
732 error(_("No level argument"));
734 if (!argument->dle.disk) {
735 fprintf(stderr, "ERROR No disk argument\n");
736 error(_("No disk argument"));
738 if (!argument->dle.device) {
739 fprintf(stderr, "ERROR No device argument\n");
740 error(_("No device argument"));
743 qdisk = quote_string(argument->dle.disk);
745 if (argument->calcsize) {
750 if (gnutar_directory) {
751 dirname = gnutar_directory;
753 dirname = argument->dle.device;
755 amgtar_build_exinclude(&argument->dle, 1,
756 &nb_exclude, &file_exclude,
757 &nb_include, &file_include);
759 run_calcsize(argument->config, "GNUTAR", argument->dle.disk, dirname,
760 argument->level, file_exclude, file_include);
762 if (argument->verbose == 0) {
764 unlink(file_exclude);
766 unlink(file_include);
772 errmsg = vstrallocf(_("GNUTAR-PATH not defined"));
776 if (!gnutar_listdir) {
777 errmsg = vstrallocf(_("GNUTAR-LISTDIR not defined"));
781 for (levels = argument->level; levels != NULL; levels = levels->next) {
782 level = GPOINTER_TO_INT(levels->data);
783 incrname = amgtar_get_incrname(argument, level, stdout, CMD_ESTIMATE);
784 cmd = stralloc(gnutar_path);
785 argv_ptr = amgtar_build_argv(argument, incrname, &file_exclude,
786 &file_include, CMD_ESTIMATE);
788 start_time = curclock();
790 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
791 errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
796 tarpid = pipespawnv(cmd, STDERR_PIPE, 1,
797 &nullfd, &nullfd, &pipefd,
798 (char **)argv_ptr->pdata);
800 dumpout = fdopen(pipefd,"r");
802 error(_("Can't fdopen: %s"), strerror(errno));
807 while (size < 0 && (fgets(line, sizeof(line), dumpout) != NULL)) {
808 if (line[strlen(line)-1] == '\n') /* remove trailling \n */
809 line[strlen(line)-1] = '\0';
812 dbprintf("%s\n", line);
813 /* check for size match */
815 for(rp = re_table; rp->regex != NULL; rp++) {
816 if(match(rp->regex, line)) {
817 if (rp->typ == DMP_SIZE) {
818 size = ((the_num(line, rp->field)*rp->scale+1023.0)/1024.0);
820 size = 1.0; /* found on NeXT -- sigh */
828 while (fgets(line, sizeof(line), dumpout) != NULL) {
829 dbprintf("%s", line);
833 dbprintf(_("estimate time for %s level %d: %s\n"),
836 walltime_str(timessub(curclock(), start_time)));
837 if(size == (off_t)-1) {
838 errmsg = vstrallocf(_("no size line match in %s output"), cmd);
839 dbprintf(_("%s for %s\n"), errmsg, qdisk);
841 } else if(size == (off_t)0 && argument->level == 0) {
842 dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"),
843 cmd, argument->dle.disk);
846 dbprintf(_("estimate size for %s level %d: %lld KB\n"),
851 kill(-tarpid, SIGTERM);
853 dbprintf(_("waiting for %s \"%s\" child\n"), cmd, qdisk);
854 waitpid(tarpid, &wait_status, 0);
855 if (WIFSIGNALED(wait_status)) {
856 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
857 cmd, WTERMSIG(wait_status), dbfn());
858 } else if (WIFEXITED(wait_status)) {
859 if (exit_value[WEXITSTATUS(wait_status)] == 1) {
860 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
861 cmd, WEXITSTATUS(wait_status), dbfn());
866 errmsg = vstrallocf(_("%s got bad exit: see %s"),
869 dbprintf(_("after %s %s wait\n"), cmd, qdisk);
873 dbprintf("%s", errmsg);
874 fprintf(stdout, "ERROR %s\n", errmsg);
881 if (argument->verbose == 0) {
883 unlink(file_exclude);
885 unlink(file_include);
888 g_ptr_array_free_full(argv_ptr);
894 fprintf(stdout, "%d %lld 1\n", level, (long long)size);
900 qerrmsg = quote_string(errmsg);
902 dbprintf("%s", errmsg);
903 fprintf(stdout, "ERROR %s\n", qerrmsg);
911 application_argument_t *argument)
919 off_t dump_size = -1;
927 FILE *indexstream = NULL;
930 amwait_t wait_status;
936 mesgstream = fdopen(mesgf, "w");
938 error(_("error mesgstream(%d): %s\n"), mesgf, strerror(errno));
942 error(_("GNUTAR-PATH not defined"));
944 if (!gnutar_listdir) {
945 error(_("GNUTAR-LISTDIR not defined"));
948 if (!argument->level) {
949 fprintf(mesgstream, "? No level argument\n");
950 error(_("No level argument"));
952 if (!argument->dle.disk) {
953 fprintf(mesgstream, "? No disk argument\n");
954 error(_("No disk argument"));
956 if (!argument->dle.device) {
957 fprintf(mesgstream, "? No device argument\n");
958 error(_("No device argument"));
961 qdisk = quote_string(argument->dle.disk);
963 incrname = amgtar_get_incrname(argument,
964 GPOINTER_TO_INT(argument->level->data),
965 mesgstream, CMD_BACKUP);
966 cmd = stralloc(gnutar_path);
967 argv_ptr = amgtar_build_argv(argument, incrname, &file_exclude,
968 &file_include, CMD_BACKUP);
970 tarpid = pipespawnv(cmd, STDIN_PIPE|STDERR_PIPE, 1,
971 &dumpin, &dataf, &outf, (char **)argv_ptr->pdata);
972 /* close the write ends of the pipes */
976 if (argument->dle.create_index) {
977 indexstream = fdopen(indexf, "w");
979 error(_("error indexstream(%d): %s\n"), indexf, strerror(errno));
982 outstream = fdopen(outf, "r");
984 error(_("error outstream(%d): %s\n"), outf, strerror(errno));
987 while (fgets(line, sizeof(line), outstream) != NULL) {
988 if (line[strlen(line)-1] == '\n') /* remove trailling \n */
989 line[strlen(line)-1] = '\0';
990 if (*line == '.' && *(line+1) == '/') { /* filename */
991 if (argument->dle.create_index) {
992 fprintf(indexstream, "%s\n", &line[1]); /* remove . */
994 } else { /* message */
995 for(rp = re_table; rp->regex != NULL; rp++) {
996 if(match(rp->regex, line)) {
1000 if(rp->typ == DMP_SIZE) {
1001 dump_size = (off_t)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0);
1027 dbprintf("%3d: %7s(%c): %s\n", rp->srcline, type, startchr, line);
1028 fprintf(mesgstream,"%c %s\n", startchr, line);
1032 waitpid(tarpid, &wait_status, 0);
1033 if (WIFSIGNALED(wait_status)) {
1034 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
1035 cmd, WTERMSIG(wait_status), dbfn());
1036 } else if (WIFEXITED(wait_status)) {
1037 if (exit_value[WEXITSTATUS(wait_status)] == 1) {
1038 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
1039 cmd, WEXITSTATUS(wait_status), dbfn());
1044 errmsg = vstrallocf(_("%s got bad exit: see %s"),
1047 dbprintf(_("after %s %s wait\n"), cmd, qdisk);
1048 dbprintf(_("amgtar: %s: pid %ld\n"), cmd, (long)tarpid);
1050 dbprintf("%s", errmsg);
1051 g_fprintf(mesgstream, "sendbackup: error [%s]\n", errmsg);
1054 if (!errmsg && incrname && strlen(incrname) > 4) {
1055 if (argument->dle.record) {
1057 nodotnew = stralloc(incrname);
1058 nodotnew[strlen(nodotnew)-4] = '\0';
1059 if (rename(incrname, nodotnew)) {
1060 dbprintf(_("%s: warning [renaming %s to %s: %s]\n"),
1061 get_pname(), incrname, nodotnew, strerror(errno));
1062 g_fprintf(mesgstream, _("? warning [renaming %s to %s: %s]\n"),
1063 incrname, nodotnew, strerror(errno));
1067 if (unlink(incrname) == -1) {
1068 dbprintf(_("%s: warning [unlink %s: %s]\n"),
1069 get_pname(), incrname, strerror(errno));
1070 g_fprintf(mesgstream, _("? warning [unlink %s: %s]\n"),
1071 incrname, strerror(errno));
1076 dbprintf("sendbackup: size %lld\n", (long long)dump_size);
1077 fprintf(mesgstream, "sendbackup: size %lld\n", (long long)dump_size);
1078 dbprintf("sendbackup: end\n");
1079 fprintf(mesgstream, "sendbackup: end\n");
1081 if (argument->dle.create_index)
1082 fclose(indexstream);
1086 if (argument->verbose == 0) {
1088 unlink(file_exclude);
1090 unlink(file_include);
1096 g_ptr_array_free_full(argv_ptr);
1101 application_argument_t *argument)
1104 GPtrArray *argv_ptr = g_ptr_array_new();
1108 char *include_filename = NULL;
1109 char *exclude_filename = NULL;
1113 error(_("GNUTAR-PATH not defined"));
1116 cmd = stralloc(gnutar_path);
1117 g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1118 g_ptr_array_add(argv_ptr, stralloc("--numeric-owner"));
1119 if (gnutar_no_unquote)
1120 g_ptr_array_add(argv_ptr, stralloc("--no-unquote"));
1122 g_ptr_array_add(argv_ptr, stralloc("--acls"));
1124 g_ptr_array_add(argv_ptr, stralloc("--selinux"));
1126 g_ptr_array_add(argv_ptr, stralloc("--xattrs"));
1127 /* ignore trailing zero blocks on input (this was the default until tar-1.21) */
1128 if (argument->ignore_zeros) {
1129 g_ptr_array_add(argv_ptr, stralloc("--ignore-zeros"));
1131 if (argument->tar_blocksize) {
1132 g_ptr_array_add(argv_ptr, stralloc("--blocking-factor"));
1133 g_ptr_array_add(argv_ptr, stralloc(argument->tar_blocksize));
1135 g_ptr_array_add(argv_ptr, stralloc("-xpGvf"));
1136 g_ptr_array_add(argv_ptr, stralloc("-"));
1137 if (gnutar_directory) {
1138 struct stat stat_buf;
1139 if(stat(gnutar_directory, &stat_buf) != 0) {
1140 fprintf(stderr,"can not stat directory %s: %s\n", gnutar_directory, strerror(errno));
1143 if (!S_ISDIR(stat_buf.st_mode)) {
1144 fprintf(stderr,"%s is not a directory\n", gnutar_directory);
1147 if (access(gnutar_directory, W_OK) != 0) {
1148 fprintf(stderr, "Can't write to %s: %s\n", gnutar_directory, strerror(errno));
1151 g_ptr_array_add(argv_ptr, stralloc("--directory"));
1152 g_ptr_array_add(argv_ptr, stralloc(gnutar_directory));
1155 g_ptr_array_add(argv_ptr, stralloc("--wildcards"));
1156 if (argument->dle.exclude_list &&
1157 argument->dle.exclude_list->nb_element == 1) {
1161 int entry_in_exclude = 0;
1162 char line[2*PATH_MAX];
1165 if (argument->dle.disk) {
1166 sdisk = sanitise_filename(argument->dle.disk);
1168 sdisk = g_strdup_printf("no_dle-%d", getpid());
1170 exclude_filename= vstralloc(AMANDA_TMPDIR, "/", "exclude-", sdisk, NULL);
1171 exclude_list = fopen(argument->dle.exclude_list->first->name, "r");
1173 exclude = fopen(exclude_filename, "w");
1174 while (fgets(line, 2*PATH_MAX, exclude_list)) {
1176 line[strlen(line)-1] = '\0'; /* remove '\n' */
1177 escaped = escape_tar_glob(line, &in_argv);
1179 g_ptr_array_add(argv_ptr, "--exclude");
1180 g_ptr_array_add(argv_ptr, escaped);
1182 fprintf(exclude,"%s\n", escaped);
1188 g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1189 g_ptr_array_add(argv_ptr, exclude_filename);
1192 if (argument->exclude_list_glob) {
1193 g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1194 g_ptr_array_add(argv_ptr, stralloc(argument->exclude_list_glob));
1198 GPtrArray *argv_include = g_ptr_array_new();
1203 int entry_in_include = 0;
1205 if (argument->dle.disk) {
1206 sdisk = sanitise_filename(argument->dle.disk);
1208 sdisk = g_strdup_printf("no_dle-%d", getpid());
1210 include_filename = vstralloc(AMANDA_TMPDIR, "/", "include-", sdisk, NULL);
1211 include = fopen(include_filename, "w");
1212 if (argument->dle.include_list &&
1213 argument->dle.include_list->nb_element == 1) {
1214 char line[2*PATH_MAX];
1215 FILE *include_list = fopen(argument->dle.include_list->first->name, "r");
1216 while (fgets(line, 2*PATH_MAX, include_list)) {
1218 line[strlen(line)-1] = '\0'; /* remove '\n' */
1219 escaped = escape_tar_glob(line, &in_argv);
1221 g_ptr_array_add(argv_include, escaped);
1223 fprintf(include,"%s\n", escaped);
1230 for (j=1; j< argument->argc; j++) {
1231 char *escaped = escape_tar_glob(argument->argv[j], &in_argv);
1233 g_ptr_array_add(argv_include, escaped);
1235 fprintf(include,"%s\n", escaped);
1242 if (entry_in_include) {
1243 g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1244 g_ptr_array_add(argv_ptr, include_filename);
1247 if (argument->include_list_glob) {
1248 g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1249 g_ptr_array_add(argv_ptr, stralloc(argument->include_list_glob));
1252 for (i = 0; i < argv_include->len; i++) {
1253 g_ptr_array_add(argv_ptr, (char *)g_ptr_array_index(argv_include,i));
1256 g_ptr_array_add(argv_ptr, NULL);
1258 debug_executing(argv_ptr);
1262 case -1: error(_("%s: fork returned: %s"), get_pname(), strerror(errno));
1266 execve(cmd, (char **)argv_ptr->pdata, env);
1267 e = strerror(errno);
1268 error(_("error [exec %s: %s]"), cmd, e);
1273 waitpid(tarpid, NULL, 0);
1274 if (argument->verbose == 0) {
1275 if (exclude_filename)
1276 unlink(exclude_filename);
1277 if (include_filename)
1278 unlink(include_filename);
1284 application_argument_t *argument G_GNUC_UNUSED)
1287 GPtrArray *argv_ptr = g_ptr_array_new();
1293 dbprintf("GNUTAR-PATH not set; Piping to /dev/null\n");
1294 fprintf(stderr,"GNUTAR-PATH not set; Piping to /dev/null\n");
1298 cmd = stralloc(gnutar_path);
1299 g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1300 /* ignore trailing zero blocks on input (this was the default until tar-1.21) */
1301 g_ptr_array_add(argv_ptr, stralloc("--ignore-zeros"));
1302 g_ptr_array_add(argv_ptr, stralloc("-tf"));
1303 g_ptr_array_add(argv_ptr, stralloc("-"));
1304 g_ptr_array_add(argv_ptr, NULL);
1306 debug_executing(argv_ptr);
1308 execve(cmd, (char **)argv_ptr->pdata, env);
1309 e = strerror(errno);
1310 dbprintf("failed to execute %s: %s; Piping to /dev/null\n", cmd, e);
1311 fprintf(stderr,"failed to execute %s: %s; Piping to /dev/null\n", cmd, e);
1313 while (read(0, buf, 32768) > 0) {
1318 amgtar_build_exinclude(
1322 char **file_exclude,
1324 char **file_include)
1328 char *exclude = NULL;
1329 char *include = NULL;
1331 if (dle->exclude_file) n_exclude += dle->exclude_file->nb_element;
1332 if (dle->exclude_list) n_exclude += dle->exclude_list->nb_element;
1333 if (dle->include_file) n_include += dle->include_file->nb_element;
1334 if (dle->include_list) n_include += dle->include_list->nb_element;
1336 if (n_exclude > 0) exclude = build_exclude(dle, verbose);
1337 if (n_include > 0) include = build_include(dle, verbose);
1340 *nb_exclude = n_exclude;
1342 *file_exclude = exclude;
1347 *nb_include = n_include;
1349 *file_include = include;
1355 amgtar_get_incrname(
1356 application_argument_t *argument,
1361 char *basename = NULL;
1362 char *incrname = NULL;
1365 char *inputname = NULL;
1366 char *errmsg = NULL;
1369 if (gnutar_listdir) {
1370 char number[NUM_STR_SIZE];
1372 char *sdisk = sanitise_filename(argument->dle.disk);
1374 basename = vstralloc(gnutar_listdir,
1381 snprintf(number, SIZEOF(number), "%d", level);
1382 incrname = vstralloc(basename, "_", number, ".new", NULL);
1386 * Open the listed incremental file from the previous level. Search
1387 * backward until one is found. If none are found (which will also
1388 * be true for a level 0), arrange to read from /dev/null.
1392 while (infd == -1) {
1393 if (--baselevel >= 0) {
1394 snprintf(number, SIZEOF(number), "%d", baselevel);
1395 inputname = newvstralloc(inputname,
1396 basename, "_", number, NULL);
1398 inputname = newstralloc(inputname, "/dev/null");
1400 if ((infd = open(inputname, O_RDONLY)) == -1) {
1402 errmsg = vstrallocf(_("amgtar: error opening %s: %s"),
1403 inputname, strerror(errno));
1404 dbprintf("%s\n", errmsg);
1405 if (baselevel < 0) {
1406 if (command == CMD_ESTIMATE) {
1407 fprintf(mesgstream, "ERROR %s\n", errmsg);
1409 fprintf(mesgstream, "? %s\n", errmsg);
1418 * Copy the previous listed incremental file to the new one.
1420 if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) {
1421 errmsg = vstrallocf(_("error opening %s: %s"),
1422 incrname, strerror(errno));
1423 dbprintf("%s\n", errmsg);
1424 if (command == CMD_ESTIMATE) {
1425 fprintf(mesgstream, "ERROR %s\n", errmsg);
1427 fprintf(mesgstream, "? %s\n", errmsg);
1432 while ((nb = read(infd, &buf, SIZEOF(buf))) > 0) {
1433 if (full_write(outfd, &buf, (size_t)nb) < (size_t)nb) {
1434 errmsg = vstrallocf(_("writing to %s: %s"),
1435 incrname, strerror(errno));
1436 dbprintf("%s\n", errmsg);
1442 errmsg = vstrallocf(_("reading from %s: %s"),
1443 inputname, strerror(errno));
1444 dbprintf("%s\n", errmsg);
1448 if (close(infd) != 0) {
1449 errmsg = vstrallocf(_("closing %s: %s"),
1450 inputname, strerror(errno));
1451 dbprintf("%s\n", errmsg);
1454 if (close(outfd) != 0) {
1455 errmsg = vstrallocf(_("closing %s: %s"),
1456 incrname, strerror(errno));
1457 dbprintf("%s\n", errmsg);
1468 check_no_check_device(void)
1470 if (gnutar_checkdevice == 0) {
1471 GPtrArray *argv_ptr = g_ptr_array_new();
1478 g_ptr_array_add(argv_ptr, gnutar_path);
1479 g_ptr_array_add(argv_ptr, "-x");
1480 g_ptr_array_add(argv_ptr, "--no-check-device");
1481 g_ptr_array_add(argv_ptr, "-f");
1482 g_ptr_array_add(argv_ptr, "-");
1483 g_ptr_array_add(argv_ptr, NULL);
1485 pipespawnv(gnutar_path, STDIN_PIPE|STDOUT_PIPE|STDERR_PIPE, 0,
1486 &dumpin, &dataf, &outf, (char **)argv_ptr->pdata);
1489 size = read(outf, buf, 32767);
1492 if (strstr(buf, "--no-check-device")) {
1493 g_debug("disabling --no-check-device since '%s' doesn't support it", gnutar_path);
1494 gnutar_checkdevice = 1;
1498 g_ptr_array_free(argv_ptr, TRUE);
1502 GPtrArray *amgtar_build_argv(
1503 application_argument_t *argument,
1505 char **file_exclude,
1506 char **file_include,
1512 char tmppath[PATH_MAX];
1513 GPtrArray *argv_ptr = g_ptr_array_new();
1516 check_no_check_device();
1517 amgtar_build_exinclude(&argument->dle, 1,
1518 &nb_exclude, file_exclude,
1519 &nb_include, file_include);
1521 if (gnutar_directory) {
1522 dirname = gnutar_directory;
1524 dirname = argument->dle.device;
1527 g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1529 g_ptr_array_add(argv_ptr, stralloc("--create"));
1530 if (command == CMD_BACKUP && argument->dle.create_index)
1531 g_ptr_array_add(argv_ptr, stralloc("--verbose"));
1532 g_ptr_array_add(argv_ptr, stralloc("--file"));
1533 if (command == CMD_ESTIMATE) {
1534 g_ptr_array_add(argv_ptr, stralloc("/dev/null"));
1536 g_ptr_array_add(argv_ptr, stralloc("-"));
1538 if (gnutar_no_unquote)
1539 g_ptr_array_add(argv_ptr, stralloc("--no-unquote"));
1540 g_ptr_array_add(argv_ptr, stralloc("--directory"));
1541 canonicalize_pathname(dirname, tmppath);
1542 g_ptr_array_add(argv_ptr, stralloc(tmppath));
1543 if (gnutar_onefilesystem)
1544 g_ptr_array_add(argv_ptr, stralloc("--one-file-system"));
1545 if (gnutar_atimepreserve)
1546 g_ptr_array_add(argv_ptr, stralloc("--atime-preserve=system"));
1547 if (!gnutar_checkdevice)
1548 g_ptr_array_add(argv_ptr, stralloc("--no-check-device"));
1550 g_ptr_array_add(argv_ptr, stralloc("--acls"));
1552 g_ptr_array_add(argv_ptr, stralloc("--selinux"));
1554 g_ptr_array_add(argv_ptr, stralloc("--xattrs"));
1555 g_ptr_array_add(argv_ptr, stralloc("--listed-incremental"));
1556 g_ptr_array_add(argv_ptr, stralloc(incrname));
1558 g_ptr_array_add(argv_ptr, stralloc("--sparse"));
1559 if (argument->tar_blocksize) {
1560 g_ptr_array_add(argv_ptr, stralloc("--blocking-factor"));
1561 g_ptr_array_add(argv_ptr, stralloc(argument->tar_blocksize));
1563 g_ptr_array_add(argv_ptr, stralloc("--ignore-failed-read"));
1564 g_ptr_array_add(argv_ptr, stralloc("--totals"));
1566 for (copt = argument->command_options; copt != NULL; copt = copt->next) {
1567 g_ptr_array_add(argv_ptr, stralloc((char *)copt->data));
1570 if (*file_exclude) {
1571 g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1572 g_ptr_array_add(argv_ptr, stralloc(*file_exclude));
1575 if (*file_include) {
1576 g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1577 g_ptr_array_add(argv_ptr, stralloc(*file_include));
1580 g_ptr_array_add(argv_ptr, stralloc("."));
1582 g_ptr_array_add(argv_ptr, NULL);