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;
125 } application_argument_t;
127 enum { CMD_ESTIMATE, CMD_BACKUP };
129 static void amgtar_support(application_argument_t *argument);
130 static void amgtar_selfcheck(application_argument_t *argument);
131 static void amgtar_estimate(application_argument_t *argument);
132 static void amgtar_backup(application_argument_t *argument);
133 static void amgtar_restore(application_argument_t *argument);
134 static void amgtar_validate(application_argument_t *argument);
135 static void amgtar_build_exinclude(dle_t *dle, int verbose,
136 int *nb_exclude, char **file_exclude,
137 int *nb_include, char **file_include);
138 static char *amgtar_get_incrname(application_argument_t *argument, int level,
139 FILE *mesgstream, int command);
140 static GPtrArray *amgtar_build_argv(application_argument_t *argument,
141 char *incrname, char **file_exclude,
142 char **file_include, int command);
143 static char *gnutar_path;
144 static char *gnutar_listdir;
145 static char *gnutar_directory;
146 static int gnutar_onefilesystem;
147 static int gnutar_atimepreserve;
148 static int gnutar_acls;
149 static int gnutar_selinux;
150 static int gnutar_xattrs;
151 static int gnutar_checkdevice;
152 static int gnutar_no_unquote;
153 static int gnutar_sparse;
154 static GSList *normal_message = NULL;
155 static GSList *ignore_message = NULL;
156 static GSList *strange_message = NULL;
157 static char *exit_handling;
158 static int exit_value[256];
160 static struct option long_options[] = {
161 {"config" , 1, NULL, 1},
162 {"host" , 1, NULL, 2},
163 {"disk" , 1, NULL, 3},
164 {"device" , 1, NULL, 4},
165 {"level" , 1, NULL, 5},
166 {"index" , 1, NULL, 6},
167 {"message" , 1, NULL, 7},
168 {"collection" , 0, NULL, 8},
169 {"record" , 0, NULL, 9},
170 {"gnutar-path" , 1, NULL, 10},
171 {"gnutar-listdir" , 1, NULL, 11},
172 {"one-file-system" , 1, NULL, 12},
173 {"sparse" , 1, NULL, 13},
174 {"atime-preserve" , 1, NULL, 14},
175 {"check-device" , 1, NULL, 15},
176 {"include-file" , 1, NULL, 16},
177 {"include-list" , 1, NULL, 17},
178 {"include-optional", 1, NULL, 18},
179 {"exclude-file" , 1, NULL, 19},
180 {"exclude-list" , 1, NULL, 20},
181 {"exclude-optional", 1, NULL, 21},
182 {"directory" , 1, NULL, 22},
183 {"normal" , 1, NULL, 23},
184 {"ignore" , 1, NULL, 24},
185 {"strange" , 1, NULL, 25},
186 {"exit-handling" , 1, NULL, 26},
187 {"calcsize" , 0, NULL, 27},
188 {"tar-blocksize" , 1, NULL, 28},
189 {"no-unquote" , 1, NULL, 29},
190 {"acls" , 1, NULL, 30},
191 {"selinux" , 1, NULL, 31},
192 {"xattrs" , 1, NULL, 32},
193 {"command-options" , 1, NULL, 33},
194 {"include-list-glob", 1, NULL, 34},
195 {"exclude-list-glob", 1, NULL, 35},
196 {"verbose" , 1, NULL, 36},
205 char *result = malloc(4*strlen(str)+1);
210 for (s = str; *s != '\0'; s++) {
218 } else if (c == '?') {
222 } else if (c == 'a') {
226 } else if (c == 'b') {
230 } else if (c == 'f') {
234 } else if (c == 'n') {
239 } else if (c == 'r') {
244 } else if (c == 't') {
248 } else if (c == 'v') {
252 } else if (c >= '0' && c <= '9') {
256 if (c >= '0' && c <= '9') {
260 if (c >= '0' && c <= '9') {
270 } else if (*s == '?') {
273 } else if (*s == '*' || *s == '[') {
291 application_argument_t argument;
295 gnutar_path = GNUTAR;
299 gnutar_listdir = NULL;
300 gnutar_directory = NULL;
301 gnutar_onefilesystem = 1;
302 gnutar_atimepreserve = 1;
306 gnutar_checkdevice = 1;
308 gnutar_no_unquote = 0;
309 exit_handling = NULL;
314 * Configure program for internationalization:
315 * 1) Only set the message locale for now.
316 * 2) Set textdomain for all amanda related programs to "amanda"
317 * We don't want to be forced to support dozens of message catalogs.
319 setlocale(LC_MESSAGES, "C");
320 textdomain("amanda");
323 printf("ERROR no command given to amgtar\n");
324 error(_("No command given to amgtar"));
327 /* drop root privileges */
328 if (!set_root_privs(0)) {
329 if (strcmp(argv[1], "selfcheck") == 0) {
330 printf("ERROR amgtar must be run setuid root\n");
332 error(_("amgtar must be run setuid root"));
339 /* Don't die when child closes pipe */
340 signal(SIGPIPE, SIG_IGN);
342 #if defined(USE_DBMALLOC)
343 malloc_size_1 = malloc_inuse(&malloc_hist_1);
346 add_amanda_log_handler(amanda_log_stderr);
347 add_amanda_log_handler(amanda_log_syslog);
348 dbopen(DBG_SUBDIR_CLIENT);
350 dbprintf(_("version %s\n"), VERSION);
352 config_init(CONFIG_INIT_CLIENT, NULL);
354 //check_running_as(RUNNING_AS_DUMPUSER_PREFERRED);
356 //RUNNING_AS_CLIENT_LOGIN from selfcheck, sendsize, sendbackup
361 gnutar_listdir = stralloc(getconf_str(CNF_GNUTAR_LIST_DIR));
362 argument.config = NULL;
363 argument.host = NULL;
364 argument.message = 0;
365 argument.collection = 0;
366 argument.calcsize = 0;
367 argument.tar_blocksize = NULL;
368 argument.level = NULL;
369 argument.command_options = NULL;
370 argument.include_list_glob = NULL;
371 argument.exclude_list_glob = NULL;
372 argument.verbose = 0;
373 init_dle(&argument.dle);
374 argument.dle.record = 0;
377 int option_index = 0;
378 c = getopt_long (argc, argv, "", long_options, &option_index);
383 case 1: argument.config = stralloc(optarg);
385 case 2: argument.host = stralloc(optarg);
387 case 3: argument.dle.disk = stralloc(optarg);
389 case 4: argument.dle.device = stralloc(optarg);
391 case 5: argument.level = g_slist_append(argument.level,
392 GINT_TO_POINTER(atoi(optarg)));
394 case 6: argument.dle.create_index = 1;
396 case 7: argument.message = 1;
398 case 8: argument.collection = 1;
400 case 9: argument.dle.record = 1;
402 case 10: gnutar_path = stralloc(optarg);
404 case 11: gnutar_listdir = stralloc(optarg);
406 case 12: if (optarg && strcasecmp(optarg, "NO") == 0)
407 gnutar_onefilesystem = 0;
408 else if (optarg && strcasecmp(optarg, "YES") == 0)
409 gnutar_onefilesystem = 1;
410 else if (strcasecmp(command, "selfcheck") == 0)
411 printf(_("ERROR [%s: bad ONE-FILE-SYSTEM property value (%s)]\n"), get_pname(), optarg);
413 case 13: if (optarg && strcasecmp(optarg, "NO") == 0)
415 else if (optarg && strcasecmp(optarg, "YES") == 0)
417 else if (strcasecmp(command, "selfcheck") == 0)
418 printf(_("ERROR [%s: bad SPARSE property value (%s)]\n"), get_pname(), optarg);
420 case 14: if (optarg && strcasecmp(optarg, "NO") == 0)
421 gnutar_atimepreserve = 0;
422 else if (optarg && strcasecmp(optarg, "YES") == 0)
423 gnutar_atimepreserve = 1;
424 else if (strcasecmp(command, "selfcheck") == 0)
425 printf(_("ERROR [%s: bad ATIME-PRESERVE property value (%s)]\n"), get_pname(), optarg);
427 case 15: if (optarg && strcasecmp(optarg, "NO") == 0)
428 gnutar_checkdevice = 0;
429 else if (optarg && strcasecmp(optarg, "YES") == 0)
430 gnutar_checkdevice = 1;
431 else if (strcasecmp(command, "selfcheck") == 0)
432 printf(_("ERROR [%s: bad CHECK-DEVICE property value (%s)]\n"), get_pname(), optarg);
435 argument.dle.include_file =
436 append_sl(argument.dle.include_file, optarg);
439 argument.dle.include_list =
440 append_sl(argument.dle.include_list, optarg);
442 case 18: argument.dle.include_optional = 1;
445 argument.dle.exclude_file =
446 append_sl(argument.dle.exclude_file, optarg);
449 argument.dle.exclude_list =
450 append_sl(argument.dle.exclude_list, optarg);
452 case 21: argument.dle.exclude_optional = 1;
454 case 22: gnutar_directory = stralloc(optarg);
458 g_slist_append(normal_message, optarg);
462 g_slist_append(ignore_message, optarg);
466 g_slist_append(strange_message, optarg);
469 exit_handling = stralloc(optarg);
471 case 27: argument.calcsize = 1;
473 case 28: argument.tar_blocksize = stralloc(optarg);
475 case 29: if (optarg && strcasecmp(optarg, "NO") == 0)
476 gnutar_no_unquote = 0;
477 else if (optarg && strcasecmp(optarg, "YES") == 0)
478 gnutar_no_unquote = 1;
479 else if (strcasecmp(command, "selfcheck") == 0)
480 printf(_("ERROR [%s: bad No_UNQUOTE property value (%s)]\n"), get_pname(), optarg);
482 case 30: if (optarg && strcasecmp(optarg, "YES") == 0)
485 case 31: if (optarg && strcasecmp(optarg, "YES") == 0)
488 case 32: if (optarg && strcasecmp(optarg, "YES") == 0)
491 case 33: argument.command_options =
492 g_slist_append(argument.command_options,
496 argument.include_list_glob = stralloc(optarg);
499 argument.exclude_list_glob = stralloc(optarg);
501 case 36: if (optarg && strcasecmp(optarg, "YES") == 0)
502 argument.verbose = 1;
510 if (!argument.dle.disk && argument.dle.device)
511 argument.dle.disk = stralloc(argument.dle.device);
512 if (!argument.dle.device && argument.dle.disk)
513 argument.dle.device = stralloc(argument.dle.disk);
515 argument.argc = argc - optind;
516 argument.argv = argv + optind;
518 if (argument.config) {
519 config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
521 dbrename(get_config_name(), DBG_SUBDIR_CLIENT);
524 if (config_errors(NULL) >= CFGERR_ERRORS) {
525 g_critical(_("errors processing config file"));
528 re_table = build_re_table(init_re_table, normal_message, ignore_message,
532 exit_value[i] = 1; /* BAD */
533 exit_value[0] = 0; /* GOOD */
534 exit_value[1] = 0; /* GOOD */
536 char *s = exit_handling;
538 char *r = strchr(s, '=');
541 if (j >= 0 && j < 256) {
543 if (strncasecmp(r, "GOOD", 4) == 0) {
548 s = strchr(s+1, ' ');
552 if (strlen(gnutar_listdir) == 0)
553 gnutar_listdir = NULL;
556 dbprintf("GNUTAR-PATH %s\n", gnutar_path);
558 dbprintf("GNUTAR-PATH is not set\n");
560 if (gnutar_listdir) {
561 dbprintf("GNUTAR-LISTDIR %s\n", gnutar_listdir);
563 dbprintf("GNUTAR-LISTDIR is not set\n");
565 if (gnutar_directory) {
566 dbprintf("DIRECTORY %s\n", gnutar_directory);
568 dbprintf("ONE-FILE-SYSTEM %s\n", gnutar_onefilesystem? "yes":"no");
569 dbprintf("SPARSE %s\n", gnutar_sparse? "yes":"no");
570 dbprintf("NO-UNQUOTE %s\n", gnutar_no_unquote? "yes":"no");
571 dbprintf("ATIME-PRESERVE %s\n", gnutar_atimepreserve? "yes":"no");
572 dbprintf("ACLS %s\n", gnutar_acls? "yes":"no");
573 dbprintf("SELINUX %s\n", gnutar_selinux? "yes":"no");
574 dbprintf("XATTRS %s\n", gnutar_xattrs? "yes":"no");
575 dbprintf("CHECK-DEVICE %s\n", gnutar_checkdevice? "yes":"no");
578 for (rp = re_table; rp->regex != NULL; rp++) {
580 case DMP_NORMAL : dbprintf("NORMAL %s\n", rp->regex); break;
581 case DMP_IGNORE : dbprintf("IGNORE %s\n", rp->regex); break;
582 case DMP_STRANGE: dbprintf("STRANGE %s\n", rp->regex); break;
583 case DMP_SIZE : dbprintf("SIZE %s\n", rp->regex); break;
584 case DMP_ERROR : dbprintf("ERROR %s\n", rp->regex); break;
589 if (strcmp(command, "support") == 0) {
590 amgtar_support(&argument);
591 } else if (strcmp(command, "selfcheck") == 0) {
592 amgtar_selfcheck(&argument);
593 } else if (strcmp(command, "estimate") == 0) {
594 amgtar_estimate(&argument);
595 } else if (strcmp(command, "backup") == 0) {
596 amgtar_backup(&argument);
597 } else if (strcmp(command, "restore") == 0) {
598 amgtar_restore(&argument);
599 } else if (strcmp(command, "validate") == 0) {
600 amgtar_validate(&argument);
602 dbprintf("Unknown command `%s'.\n", command);
603 fprintf(stderr, "Unknown command `%s'.\n", command);
611 application_argument_t *argument)
614 fprintf(stdout, "CONFIG YES\n");
615 fprintf(stdout, "HOST YES\n");
616 fprintf(stdout, "DISK YES\n");
617 fprintf(stdout, "MAX-LEVEL 399\n");
618 fprintf(stdout, "INDEX-LINE YES\n");
619 fprintf(stdout, "INDEX-XML NO\n");
620 fprintf(stdout, "MESSAGE-LINE YES\n");
621 fprintf(stdout, "MESSAGE-XML NO\n");
622 fprintf(stdout, "RECORD YES\n");
623 fprintf(stdout, "INCLUDE-FILE YES\n");
624 fprintf(stdout, "INCLUDE-LIST YES\n");
625 fprintf(stdout, "INCLUDE-LIST-GLOB YES\n");
626 fprintf(stdout, "INCLUDE-OPTIONAL YES\n");
627 fprintf(stdout, "EXCLUDE-FILE YES\n");
628 fprintf(stdout, "EXCLUDE-LIST YES\n");
629 fprintf(stdout, "EXCLUDE-LIST-GLOB YES\n");
630 fprintf(stdout, "EXCLUDE-OPTIONAL YES\n");
631 fprintf(stdout, "COLLECTION NO\n");
632 fprintf(stdout, "MULTI-ESTIMATE YES\n");
633 fprintf(stdout, "CALCSIZE YES\n");
634 fprintf(stdout, "CLIENT-ESTIMATE YES\n");
639 application_argument_t *argument)
641 if (argument->dle.disk) {
642 char *qdisk = quote_string(argument->dle.disk);
643 fprintf(stdout, "OK disk %s\n", qdisk);
647 printf("OK amgtar version %s\n", VERSION);
648 amgtar_build_exinclude(&argument->dle, 1, NULL, NULL, NULL, NULL);
650 printf("OK amgtar\n");
652 if (check_file(gnutar_path, X_OK)) {
654 GPtrArray *argv_ptr = g_ptr_array_new();
656 g_ptr_array_add(argv_ptr, gnutar_path);
657 g_ptr_array_add(argv_ptr, "--version");
658 g_ptr_array_add(argv_ptr, NULL);
660 gtar_version = get_first_line(argv_ptr);
663 for (gv = gtar_version; *gv && !g_ascii_isdigit(*gv); gv++);
664 printf("OK amgtar gtar-version %s\n", gv);
666 printf(_("ERROR [Can't get %s version]\n"), gnutar_path);
669 g_ptr_array_free(argv_ptr, TRUE);
670 amfree(gtar_version);
673 printf(_("ERROR [GNUTAR program not available]\n"));
677 if (gnutar_listdir && strlen(gnutar_listdir) == 0)
678 gnutar_listdir = NULL;
679 if (gnutar_listdir) {
680 check_dir(gnutar_listdir, R_OK|W_OK);
682 printf(_("ERROR [No GNUTAR-LISTDIR]\n"));
685 if (gnutar_directory) {
686 check_dir(gnutar_directory, R_OK);
687 } else if (argument->dle.device) {
688 check_dir(argument->dle.device, R_OK);
690 if (argument->calcsize) {
691 char *calcsize = vstralloc(amlibexecdir, "/", "calcsize", NULL);
692 check_file(calcsize, X_OK);
693 check_suid(calcsize);
701 application_argument_t *argument)
703 char *incrname = NULL;
708 FILE *dumpout = NULL;
712 char *qerrmsg = NULL;
714 amwait_t wait_status;
723 if (!argument->level) {
724 fprintf(stderr, "ERROR No level argument\n");
725 error(_("No level argument"));
727 if (!argument->dle.disk) {
728 fprintf(stderr, "ERROR No disk argument\n");
729 error(_("No disk argument"));
731 if (!argument->dle.device) {
732 fprintf(stderr, "ERROR No device argument\n");
733 error(_("No device argument"));
736 qdisk = quote_string(argument->dle.disk);
738 if (argument->calcsize) {
743 if (gnutar_directory) {
744 dirname = gnutar_directory;
746 dirname = argument->dle.device;
748 amgtar_build_exinclude(&argument->dle, 1,
749 &nb_exclude, &file_exclude,
750 &nb_include, &file_include);
752 run_calcsize(argument->config, "GNUTAR", argument->dle.disk, dirname,
753 argument->level, file_exclude, file_include);
755 if (argument->verbose == 0) {
757 unlink(file_exclude);
759 unlink(file_include);
765 errmsg = vstrallocf(_("GNUTAR-PATH not defined"));
769 if (!gnutar_listdir) {
770 errmsg = vstrallocf(_("GNUTAR-LISTDIR not defined"));
774 for (levels = argument->level; levels != NULL; levels = levels->next) {
775 level = GPOINTER_TO_INT(levels->data);
776 incrname = amgtar_get_incrname(argument, level, stdout, CMD_ESTIMATE);
777 cmd = stralloc(gnutar_path);
778 argv_ptr = amgtar_build_argv(argument, incrname, &file_exclude,
779 &file_include, CMD_ESTIMATE);
781 start_time = curclock();
783 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
784 errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
789 tarpid = pipespawnv(cmd, STDERR_PIPE, 1,
790 &nullfd, &nullfd, &pipefd,
791 (char **)argv_ptr->pdata);
793 dumpout = fdopen(pipefd,"r");
795 error(_("Can't fdopen: %s"), strerror(errno));
800 while (size < 0 && (fgets(line, sizeof(line), dumpout) != NULL)) {
801 if (line[strlen(line)-1] == '\n') /* remove trailling \n */
802 line[strlen(line)-1] = '\0';
805 dbprintf("%s\n", line);
806 /* check for size match */
808 for(rp = re_table; rp->regex != NULL; rp++) {
809 if(match(rp->regex, line)) {
810 if (rp->typ == DMP_SIZE) {
811 size = ((the_num(line, rp->field)*rp->scale+1023.0)/1024.0);
813 size = 1.0; /* found on NeXT -- sigh */
821 while (fgets(line, sizeof(line), dumpout) != NULL) {
822 dbprintf("%s", line);
826 dbprintf(_("estimate time for %s level %d: %s\n"),
829 walltime_str(timessub(curclock(), start_time)));
830 if(size == (off_t)-1) {
831 errmsg = vstrallocf(_("no size line match in %s output"), cmd);
832 dbprintf(_("%s for %s\n"), errmsg, qdisk);
834 } else if(size == (off_t)0 && argument->level == 0) {
835 dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"),
836 cmd, argument->dle.disk);
839 dbprintf(_("estimate size for %s level %d: %lld KB\n"),
844 kill(-tarpid, SIGTERM);
846 dbprintf(_("waiting for %s \"%s\" child\n"), cmd, qdisk);
847 waitpid(tarpid, &wait_status, 0);
848 if (WIFSIGNALED(wait_status)) {
849 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
850 cmd, WTERMSIG(wait_status), dbfn());
851 } else if (WIFEXITED(wait_status)) {
852 if (exit_value[WEXITSTATUS(wait_status)] == 1) {
853 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
854 cmd, WEXITSTATUS(wait_status), dbfn());
859 errmsg = vstrallocf(_("%s got bad exit: see %s"),
862 dbprintf(_("after %s %s wait\n"), cmd, qdisk);
866 dbprintf("%s", errmsg);
867 fprintf(stdout, "ERROR %s\n", errmsg);
874 if (argument->verbose == 0) {
876 unlink(file_exclude);
878 unlink(file_include);
881 g_ptr_array_free_full(argv_ptr);
887 fprintf(stdout, "%d %lld 1\n", level, (long long)size);
893 qerrmsg = quote_string(errmsg);
895 dbprintf("%s", errmsg);
896 fprintf(stdout, "ERROR %s\n", qerrmsg);
904 application_argument_t *argument)
912 off_t dump_size = -1;
920 FILE *indexstream = NULL;
923 amwait_t wait_status;
929 mesgstream = fdopen(mesgf, "w");
931 error(_("error mesgstream(%d): %s\n"), mesgf, strerror(errno));
935 error(_("GNUTAR-PATH not defined"));
937 if (!gnutar_listdir) {
938 error(_("GNUTAR-LISTDIR not defined"));
941 if (!argument->level) {
942 fprintf(mesgstream, "? No level argument\n");
943 error(_("No level argument"));
945 if (!argument->dle.disk) {
946 fprintf(mesgstream, "? No disk argument\n");
947 error(_("No disk argument"));
949 if (!argument->dle.device) {
950 fprintf(mesgstream, "? No device argument\n");
951 error(_("No device argument"));
954 qdisk = quote_string(argument->dle.disk);
956 incrname = amgtar_get_incrname(argument,
957 GPOINTER_TO_INT(argument->level->data),
958 mesgstream, CMD_BACKUP);
959 cmd = stralloc(gnutar_path);
960 argv_ptr = amgtar_build_argv(argument, incrname, &file_exclude,
961 &file_include, CMD_BACKUP);
963 tarpid = pipespawnv(cmd, STDIN_PIPE|STDERR_PIPE, 1,
964 &dumpin, &dataf, &outf, (char **)argv_ptr->pdata);
965 /* close the write ends of the pipes */
969 if (argument->dle.create_index) {
970 indexstream = fdopen(indexf, "w");
972 error(_("error indexstream(%d): %s\n"), indexf, strerror(errno));
975 outstream = fdopen(outf, "r");
977 error(_("error outstream(%d): %s\n"), outf, strerror(errno));
980 while (fgets(line, sizeof(line), outstream) != NULL) {
981 if (line[strlen(line)-1] == '\n') /* remove trailling \n */
982 line[strlen(line)-1] = '\0';
983 if (*line == '.' && *(line+1) == '/') { /* filename */
984 if (argument->dle.create_index) {
985 fprintf(indexstream, "%s\n", &line[1]); /* remove . */
987 } else { /* message */
988 for(rp = re_table; rp->regex != NULL; rp++) {
989 if(match(rp->regex, line)) {
993 if(rp->typ == DMP_SIZE) {
994 dump_size = (off_t)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0);
1020 dbprintf("%3d: %7s(%c): %s\n", rp->srcline, type, startchr, line);
1021 fprintf(mesgstream,"%c %s\n", startchr, line);
1025 waitpid(tarpid, &wait_status, 0);
1026 if (WIFSIGNALED(wait_status)) {
1027 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
1028 cmd, WTERMSIG(wait_status), dbfn());
1029 } else if (WIFEXITED(wait_status)) {
1030 if (exit_value[WEXITSTATUS(wait_status)] == 1) {
1031 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
1032 cmd, WEXITSTATUS(wait_status), dbfn());
1037 errmsg = vstrallocf(_("%s got bad exit: see %s"),
1040 dbprintf(_("after %s %s wait\n"), cmd, qdisk);
1041 dbprintf(_("amgtar: %s: pid %ld\n"), cmd, (long)tarpid);
1043 dbprintf("%s", errmsg);
1044 g_fprintf(mesgstream, "sendbackup: error [%s]\n", errmsg);
1047 if (!errmsg && incrname && strlen(incrname) > 4) {
1048 if (argument->dle.record) {
1050 nodotnew = stralloc(incrname);
1051 nodotnew[strlen(nodotnew)-4] = '\0';
1052 if (rename(incrname, nodotnew)) {
1053 dbprintf(_("%s: warning [renaming %s to %s: %s]\n"),
1054 get_pname(), incrname, nodotnew, strerror(errno));
1055 g_fprintf(mesgstream, _("? warning [renaming %s to %s: %s]\n"),
1056 incrname, nodotnew, strerror(errno));
1060 if (unlink(incrname) == -1) {
1061 dbprintf(_("%s: warning [unlink %s: %s]\n"),
1062 get_pname(), incrname, strerror(errno));
1063 g_fprintf(mesgstream, _("? warning [unlink %s: %s]\n"),
1064 incrname, strerror(errno));
1069 dbprintf("sendbackup: size %lld\n", (long long)dump_size);
1070 fprintf(mesgstream, "sendbackup: size %lld\n", (long long)dump_size);
1071 dbprintf("sendbackup: end\n");
1072 fprintf(mesgstream, "sendbackup: end\n");
1074 if (argument->dle.create_index)
1075 fclose(indexstream);
1079 if (argument->verbose == 0) {
1081 unlink(file_exclude);
1083 unlink(file_include);
1089 g_ptr_array_free_full(argv_ptr);
1094 application_argument_t *argument)
1097 GPtrArray *argv_ptr = g_ptr_array_new();
1101 char *include_filename = NULL;
1102 char *exclude_filename = NULL;
1106 error(_("GNUTAR-PATH not defined"));
1109 cmd = stralloc(gnutar_path);
1110 g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1111 g_ptr_array_add(argv_ptr, stralloc("--numeric-owner"));
1112 if (gnutar_no_unquote)
1113 g_ptr_array_add(argv_ptr, stralloc("--no-unquote"));
1115 g_ptr_array_add(argv_ptr, stralloc("--acls"));
1117 g_ptr_array_add(argv_ptr, stralloc("--selinux"));
1119 g_ptr_array_add(argv_ptr, stralloc("--xattrs"));
1120 /* ignore trailing zero blocks on input (this was the default until tar-1.21) */
1121 g_ptr_array_add(argv_ptr, stralloc("--ignore-zeros"));
1122 g_ptr_array_add(argv_ptr, stralloc("-xpGvf"));
1123 g_ptr_array_add(argv_ptr, stralloc("-"));
1124 if (gnutar_directory) {
1125 struct stat stat_buf;
1126 if(stat(gnutar_directory, &stat_buf) != 0) {
1127 fprintf(stderr,"can not stat directory %s: %s\n", gnutar_directory, strerror(errno));
1130 if (!S_ISDIR(stat_buf.st_mode)) {
1131 fprintf(stderr,"%s is not a directory\n", gnutar_directory);
1134 if (access(gnutar_directory, W_OK) != 0) {
1135 fprintf(stderr, "Can't write to %s: %s\n", gnutar_directory, strerror(errno));
1138 g_ptr_array_add(argv_ptr, stralloc("--directory"));
1139 g_ptr_array_add(argv_ptr, stralloc(gnutar_directory));
1142 g_ptr_array_add(argv_ptr, stralloc("--wildcards"));
1143 if (argument->dle.exclude_list &&
1144 argument->dle.exclude_list->nb_element == 1) {
1148 int entry_in_exclude = 0;
1149 char line[2*PATH_MAX];
1152 if (argument->dle.disk) {
1153 sdisk = sanitise_filename(argument->dle.disk);
1155 sdisk = g_strdup_printf("no_dle-%d", getpid());
1157 exclude_filename= vstralloc(AMANDA_TMPDIR, "/", "exclude-", sdisk, NULL);
1158 exclude_list = fopen(argument->dle.exclude_list->first->name, "r");
1160 exclude = fopen(exclude_filename, "w");
1161 while (fgets(line, 2*PATH_MAX, exclude_list)) {
1163 line[strlen(line)-1] = '\0'; /* remove '\n' */
1164 escaped = escape_tar_glob(line, &in_argv);
1166 g_ptr_array_add(argv_ptr, "--exclude");
1167 g_ptr_array_add(argv_ptr, escaped);
1169 fprintf(exclude,"%s\n", escaped);
1175 g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1176 g_ptr_array_add(argv_ptr, exclude_filename);
1179 if (argument->exclude_list_glob) {
1180 g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1181 g_ptr_array_add(argv_ptr, stralloc(argument->exclude_list_glob));
1185 GPtrArray *argv_include = g_ptr_array_new();
1190 int entry_in_include = 0;
1192 if (argument->dle.disk) {
1193 sdisk = sanitise_filename(argument->dle.disk);
1195 sdisk = g_strdup_printf("no_dle-%d", getpid());
1197 include_filename = vstralloc(AMANDA_TMPDIR, "/", "include-", sdisk, NULL);
1198 include = fopen(include_filename, "w");
1199 if (argument->dle.include_list &&
1200 argument->dle.include_list->nb_element == 1) {
1201 char line[2*PATH_MAX];
1202 FILE *include_list = fopen(argument->dle.include_list->first->name, "r");
1203 while (fgets(line, 2*PATH_MAX, include_list)) {
1205 line[strlen(line)-1] = '\0'; /* remove '\n' */
1206 escaped = escape_tar_glob(line, &in_argv);
1208 g_ptr_array_add(argv_include, escaped);
1210 fprintf(include,"%s\n", escaped);
1217 for (j=1; j< argument->argc; j++) {
1218 char *escaped = escape_tar_glob(argument->argv[j], &in_argv);
1220 g_ptr_array_add(argv_include, escaped);
1222 fprintf(include,"%s\n", escaped);
1229 if (entry_in_include) {
1230 g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1231 g_ptr_array_add(argv_ptr, include_filename);
1234 if (argument->include_list_glob) {
1235 g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1236 g_ptr_array_add(argv_ptr, stralloc(argument->include_list_glob));
1239 for (i = 0; i < argv_include->len; i++) {
1240 g_ptr_array_add(argv_ptr, (char *)g_ptr_array_index(argv_include,i));
1243 g_ptr_array_add(argv_ptr, NULL);
1245 debug_executing(argv_ptr);
1249 case -1: error(_("%s: fork returned: %s"), get_pname(), strerror(errno));
1253 execve(cmd, (char **)argv_ptr->pdata, env);
1254 e = strerror(errno);
1255 error(_("error [exec %s: %s]"), cmd, e);
1260 waitpid(tarpid, NULL, 0);
1261 if (argument->verbose == 0) {
1262 if (exclude_filename)
1263 unlink(exclude_filename);
1264 if (include_filename)
1265 unlink(include_filename);
1271 application_argument_t *argument G_GNUC_UNUSED)
1274 GPtrArray *argv_ptr = g_ptr_array_new();
1280 dbprintf("GNUTAR-PATH not set; Piping to /dev/null\n");
1281 fprintf(stderr,"GNUTAR-PATH not set; Piping to /dev/null\n");
1285 cmd = stralloc(gnutar_path);
1286 g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1287 /* ignore trailing zero blocks on input (this was the default until tar-1.21) */
1288 g_ptr_array_add(argv_ptr, stralloc("--ignore-zeros"));
1289 g_ptr_array_add(argv_ptr, stralloc("-tf"));
1290 g_ptr_array_add(argv_ptr, stralloc("-"));
1291 g_ptr_array_add(argv_ptr, NULL);
1293 debug_executing(argv_ptr);
1295 execve(cmd, (char **)argv_ptr->pdata, env);
1296 e = strerror(errno);
1297 dbprintf("failed to execute %s: %s; Piping to /dev/null\n", cmd, e);
1298 fprintf(stderr,"failed to execute %s: %s; Piping to /dev/null\n", cmd, e);
1300 while (read(0, buf, 32768) > 0) {
1305 amgtar_build_exinclude(
1309 char **file_exclude,
1311 char **file_include)
1315 char *exclude = NULL;
1316 char *include = NULL;
1318 if (dle->exclude_file) n_exclude += dle->exclude_file->nb_element;
1319 if (dle->exclude_list) n_exclude += dle->exclude_list->nb_element;
1320 if (dle->include_file) n_include += dle->include_file->nb_element;
1321 if (dle->include_list) n_include += dle->include_list->nb_element;
1323 if (n_exclude > 0) exclude = build_exclude(dle, verbose);
1324 if (n_include > 0) include = build_include(dle, verbose);
1327 *nb_exclude = n_exclude;
1329 *file_exclude = exclude;
1334 *nb_include = n_include;
1336 *file_include = include;
1342 amgtar_get_incrname(
1343 application_argument_t *argument,
1348 char *basename = NULL;
1349 char *incrname = NULL;
1352 char *inputname = NULL;
1353 char *errmsg = NULL;
1356 if (gnutar_listdir) {
1357 char number[NUM_STR_SIZE];
1359 char *sdisk = sanitise_filename(argument->dle.disk);
1361 basename = vstralloc(gnutar_listdir,
1368 snprintf(number, SIZEOF(number), "%d", level);
1369 incrname = vstralloc(basename, "_", number, ".new", NULL);
1373 * Open the listed incremental file from the previous level. Search
1374 * backward until one is found. If none are found (which will also
1375 * be true for a level 0), arrange to read from /dev/null.
1379 while (infd == -1) {
1380 if (--baselevel >= 0) {
1381 snprintf(number, SIZEOF(number), "%d", baselevel);
1382 inputname = newvstralloc(inputname,
1383 basename, "_", number, NULL);
1385 inputname = newstralloc(inputname, "/dev/null");
1387 if ((infd = open(inputname, O_RDONLY)) == -1) {
1389 errmsg = vstrallocf(_("amgtar: error opening %s: %s"),
1390 inputname, strerror(errno));
1391 dbprintf("%s\n", errmsg);
1392 if (baselevel < 0) {
1393 if (command == CMD_ESTIMATE) {
1394 fprintf(mesgstream, "ERROR %s\n", errmsg);
1396 fprintf(mesgstream, "? %s\n", errmsg);
1405 * Copy the previous listed incremental file to the new one.
1407 if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) {
1408 errmsg = vstrallocf(_("error opening %s: %s"),
1409 incrname, strerror(errno));
1410 dbprintf("%s\n", errmsg);
1411 if (command == CMD_ESTIMATE) {
1412 fprintf(mesgstream, "ERROR %s\n", errmsg);
1414 fprintf(mesgstream, "? %s\n", errmsg);
1419 while ((nb = read(infd, &buf, SIZEOF(buf))) > 0) {
1420 if (full_write(outfd, &buf, (size_t)nb) < (size_t)nb) {
1421 errmsg = vstrallocf(_("writing to %s: %s"),
1422 incrname, strerror(errno));
1423 dbprintf("%s\n", errmsg);
1429 errmsg = vstrallocf(_("reading from %s: %s"),
1430 inputname, strerror(errno));
1431 dbprintf("%s\n", errmsg);
1435 if (close(infd) != 0) {
1436 errmsg = vstrallocf(_("closing %s: %s"),
1437 inputname, strerror(errno));
1438 dbprintf("%s\n", errmsg);
1441 if (close(outfd) != 0) {
1442 errmsg = vstrallocf(_("closing %s: %s"),
1443 incrname, strerror(errno));
1444 dbprintf("%s\n", errmsg);
1454 GPtrArray *amgtar_build_argv(
1455 application_argument_t *argument,
1457 char **file_exclude,
1458 char **file_include,
1464 char tmppath[PATH_MAX];
1465 GPtrArray *argv_ptr = g_ptr_array_new();
1468 amgtar_build_exinclude(&argument->dle, 1,
1469 &nb_exclude, file_exclude,
1470 &nb_include, file_include);
1472 if (gnutar_directory) {
1473 dirname = gnutar_directory;
1475 dirname = argument->dle.device;
1478 g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1480 g_ptr_array_add(argv_ptr, stralloc("--create"));
1481 if (command == CMD_BACKUP && argument->dle.create_index)
1482 g_ptr_array_add(argv_ptr, stralloc("--verbose"));
1483 g_ptr_array_add(argv_ptr, stralloc("--file"));
1484 if (command == CMD_ESTIMATE) {
1485 g_ptr_array_add(argv_ptr, stralloc("/dev/null"));
1487 g_ptr_array_add(argv_ptr, stralloc("-"));
1489 if (gnutar_no_unquote)
1490 g_ptr_array_add(argv_ptr, stralloc("--no-unquote"));
1491 g_ptr_array_add(argv_ptr, stralloc("--directory"));
1492 canonicalize_pathname(dirname, tmppath);
1493 g_ptr_array_add(argv_ptr, stralloc(tmppath));
1494 if (gnutar_onefilesystem)
1495 g_ptr_array_add(argv_ptr, stralloc("--one-file-system"));
1496 if (gnutar_atimepreserve)
1497 g_ptr_array_add(argv_ptr, stralloc("--atime-preserve=system"));
1498 if (!gnutar_checkdevice)
1499 g_ptr_array_add(argv_ptr, stralloc("--no-check-device"));
1501 g_ptr_array_add(argv_ptr, stralloc("--acls"));
1503 g_ptr_array_add(argv_ptr, stralloc("--selinux"));
1505 g_ptr_array_add(argv_ptr, stralloc("--xattrs"));
1506 g_ptr_array_add(argv_ptr, stralloc("--listed-incremental"));
1507 g_ptr_array_add(argv_ptr, stralloc(incrname));
1509 g_ptr_array_add(argv_ptr, stralloc("--sparse"));
1510 if (argument->tar_blocksize) {
1511 g_ptr_array_add(argv_ptr, stralloc("--blocking-factor"));
1512 g_ptr_array_add(argv_ptr, stralloc(argument->tar_blocksize));
1514 g_ptr_array_add(argv_ptr, stralloc("--ignore-failed-read"));
1515 g_ptr_array_add(argv_ptr, stralloc("--totals"));
1517 for (copt = argument->command_options; copt != NULL; copt = copt->next) {
1518 g_ptr_array_add(argv_ptr, stralloc((char *)copt->data));
1521 if (*file_exclude) {
1522 g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1523 g_ptr_array_add(argv_ptr, stralloc(*file_exclude));
1526 if (*file_include) {
1527 g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1528 g_ptr_array_add(argv_ptr, stralloc(*file_include));
1531 g_ptr_array_add(argv_ptr, stralloc("."));
1533 g_ptr_array_add(argv_ptr, NULL);