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_directory = NULL;
300 gnutar_onefilesystem = 1;
301 gnutar_atimepreserve = 1;
305 gnutar_checkdevice = 1;
307 gnutar_no_unquote = 0;
308 exit_handling = NULL;
313 * Configure program for internationalization:
314 * 1) Only set the message locale for now.
315 * 2) Set textdomain for all amanda related programs to "amanda"
316 * We don't want to be forced to support dozens of message catalogs.
318 setlocale(LC_MESSAGES, "C");
319 textdomain("amanda");
322 printf("ERROR no command given to amgtar\n");
323 error(_("No command given to amgtar"));
326 /* drop root privileges */
327 if (!set_root_privs(0)) {
328 if (strcmp(argv[1], "selfcheck") == 0) {
329 printf("ERROR amgtar must be run setuid root\n");
331 error(_("amgtar must be run setuid root"));
338 /* Don't die when child closes pipe */
339 signal(SIGPIPE, SIG_IGN);
341 #if defined(USE_DBMALLOC)
342 malloc_size_1 = malloc_inuse(&malloc_hist_1);
345 add_amanda_log_handler(amanda_log_stderr);
346 add_amanda_log_handler(amanda_log_syslog);
347 dbopen(DBG_SUBDIR_CLIENT);
349 dbprintf(_("version %s\n"), VERSION);
351 config_init(CONFIG_INIT_CLIENT, NULL);
353 //check_running_as(RUNNING_AS_DUMPUSER_PREFERRED);
355 //RUNNING_AS_CLIENT_LOGIN from selfcheck, sendsize, sendbackup
360 argument.config = NULL;
361 argument.host = NULL;
362 argument.message = 0;
363 argument.collection = 0;
364 argument.calcsize = 0;
365 argument.tar_blocksize = NULL;
366 argument.level = NULL;
367 argument.command_options = NULL;
368 argument.include_list_glob = NULL;
369 argument.exclude_list_glob = NULL;
370 argument.verbose = 0;
371 init_dle(&argument.dle);
374 int option_index = 0;
375 c = getopt_long (argc, argv, "", long_options, &option_index);
380 case 1: argument.config = stralloc(optarg);
382 case 2: argument.host = stralloc(optarg);
384 case 3: argument.dle.disk = stralloc(optarg);
386 case 4: argument.dle.device = stralloc(optarg);
388 case 5: argument.level = g_slist_append(argument.level,
389 GINT_TO_POINTER(atoi(optarg)));
391 case 6: argument.dle.create_index = 1;
393 case 7: argument.message = 1;
395 case 8: argument.collection = 1;
397 case 9: argument.dle.record = 1;
399 case 10: gnutar_path = stralloc(optarg);
401 case 11: gnutar_listdir = stralloc(optarg);
403 case 12: if (optarg && strcasecmp(optarg, "NO") == 0)
404 gnutar_onefilesystem = 0;
405 else if (optarg && strcasecmp(optarg, "YES") == 0)
406 gnutar_onefilesystem = 1;
407 else if (strcasecmp(command, "selfcheck") == 0)
408 printf(_("ERROR [%s: bad ONE-FILE-SYSTEM property value (%s)]\n"), get_pname(), optarg);
410 case 13: if (optarg && strcasecmp(optarg, "NO") == 0)
412 else if (optarg && strcasecmp(optarg, "YES") == 0)
414 else if (strcasecmp(command, "selfcheck") == 0)
415 printf(_("ERROR [%s: bad SPARSE property value (%s)]\n"), get_pname(), optarg);
417 case 14: if (optarg && strcasecmp(optarg, "NO") == 0)
418 gnutar_atimepreserve = 0;
419 else if (optarg && strcasecmp(optarg, "YES") == 0)
420 gnutar_atimepreserve = 1;
421 else if (strcasecmp(command, "selfcheck") == 0)
422 printf(_("ERROR [%s: bad ATIME-PRESERVE property value (%s)]\n"), get_pname(), optarg);
424 case 15: if (optarg && strcasecmp(optarg, "NO") == 0)
425 gnutar_checkdevice = 0;
426 else if (optarg && strcasecmp(optarg, "YES") == 0)
427 gnutar_checkdevice = 1;
428 else if (strcasecmp(command, "selfcheck") == 0)
429 printf(_("ERROR [%s: bad CHECK-DEVICE property value (%s)]\n"), get_pname(), optarg);
432 argument.dle.include_file =
433 append_sl(argument.dle.include_file, optarg);
436 argument.dle.include_list =
437 append_sl(argument.dle.include_list, optarg);
439 case 18: argument.dle.include_optional = 1;
442 argument.dle.exclude_file =
443 append_sl(argument.dle.exclude_file, optarg);
446 argument.dle.exclude_list =
447 append_sl(argument.dle.exclude_list, optarg);
449 case 21: argument.dle.exclude_optional = 1;
451 case 22: gnutar_directory = stralloc(optarg);
455 g_slist_append(normal_message, optarg);
459 g_slist_append(ignore_message, optarg);
463 g_slist_append(strange_message, optarg);
466 exit_handling = stralloc(optarg);
468 case 27: argument.calcsize = 1;
470 case 28: argument.tar_blocksize = stralloc(optarg);
472 case 29: if (optarg && strcasecmp(optarg, "NO") == 0)
473 gnutar_no_unquote = 0;
474 else if (optarg && strcasecmp(optarg, "YES") == 0)
475 gnutar_no_unquote = 1;
476 else if (strcasecmp(command, "selfcheck") == 0)
477 printf(_("ERROR [%s: bad No_UNQUOTE property value (%s)]\n"), get_pname(), optarg);
479 case 30: if (optarg && strcasecmp(optarg, "YES") == 0)
482 case 31: if (optarg && strcasecmp(optarg, "YES") == 0)
485 case 32: if (optarg && strcasecmp(optarg, "YES") == 0)
488 case 33: argument.command_options =
489 g_slist_append(argument.command_options,
493 argument.include_list_glob = stralloc(optarg);
496 argument.exclude_list_glob = stralloc(optarg);
498 case 36: if (optarg && strcasecmp(optarg, "YES") == 0)
499 argument.verbose = 1;
507 if (!argument.dle.disk && argument.dle.device)
508 argument.dle.disk = stralloc(argument.dle.device);
509 if (!argument.dle.device && argument.dle.disk)
510 argument.dle.device = stralloc(argument.dle.disk);
512 argument.argc = argc - optind;
513 argument.argv = argv + optind;
515 if (argument.config) {
516 config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
518 dbrename(get_config_name(), DBG_SUBDIR_CLIENT);
521 if (config_errors(NULL) >= CFGERR_ERRORS) {
522 g_critical(_("errors processing config file"));
525 re_table = build_re_table(init_re_table, normal_message, ignore_message,
529 exit_value[i] = 1; /* BAD */
530 exit_value[0] = 0; /* GOOD */
531 exit_value[1] = 0; /* GOOD */
533 char *s = exit_handling;
535 char *r = strchr(s, '=');
538 if (j >= 0 && j < 256) {
540 if (strncasecmp(r, "GOOD", 4) == 0) {
545 s = strchr(s+1, ' ');
549 gnutar_listdir = getconf_str(CNF_GNUTAR_LIST_DIR);
550 if (strlen(gnutar_listdir) == 0)
551 gnutar_listdir = NULL;
554 dbprintf("GNUTAR-PATH %s\n", gnutar_path);
556 dbprintf("GNUTAR-PATH is not set\n");
558 if (gnutar_listdir) {
559 dbprintf("GNUTAR-LISTDIR %s\n", gnutar_listdir);
561 dbprintf("GNUTAR-LISTDIR is not set\n");
563 if (gnutar_directory) {
564 dbprintf("DIRECTORY %s\n", gnutar_directory);
566 dbprintf("ONE-FILE-SYSTEM %s\n", gnutar_onefilesystem? "yes":"no");
567 dbprintf("SPARSE %s\n", gnutar_sparse? "yes":"no");
568 dbprintf("NO-UNQUOTE %s\n", gnutar_no_unquote? "yes":"no");
569 dbprintf("ATIME-PRESERVE %s\n", gnutar_atimepreserve? "yes":"no");
570 dbprintf("ACLS %s\n", gnutar_acls? "yes":"no");
571 dbprintf("SELINUX %s\n", gnutar_selinux? "yes":"no");
572 dbprintf("XATTRS %s\n", gnutar_xattrs? "yes":"no");
573 dbprintf("CHECK-DEVICE %s\n", gnutar_checkdevice? "yes":"no");
576 for (rp = re_table; rp->regex != NULL; rp++) {
578 case DMP_NORMAL : dbprintf("NORMAL %s\n", rp->regex); break;
579 case DMP_IGNORE : dbprintf("IGNORE %s\n", rp->regex); break;
580 case DMP_STRANGE: dbprintf("STRANGE %s\n", rp->regex); break;
581 case DMP_SIZE : dbprintf("SIZE %s\n", rp->regex); break;
582 case DMP_ERROR : dbprintf("ERROR %s\n", rp->regex); break;
587 if (strcmp(command, "support") == 0) {
588 amgtar_support(&argument);
589 } else if (strcmp(command, "selfcheck") == 0) {
590 amgtar_selfcheck(&argument);
591 } else if (strcmp(command, "estimate") == 0) {
592 amgtar_estimate(&argument);
593 } else if (strcmp(command, "backup") == 0) {
594 amgtar_backup(&argument);
595 } else if (strcmp(command, "restore") == 0) {
596 amgtar_restore(&argument);
597 } else if (strcmp(command, "validate") == 0) {
598 amgtar_validate(&argument);
600 dbprintf("Unknown command `%s'.\n", command);
601 fprintf(stderr, "Unknown command `%s'.\n", command);
609 application_argument_t *argument)
612 fprintf(stdout, "CONFIG YES\n");
613 fprintf(stdout, "HOST YES\n");
614 fprintf(stdout, "DISK YES\n");
615 fprintf(stdout, "MAX-LEVEL 399\n");
616 fprintf(stdout, "INDEX-LINE YES\n");
617 fprintf(stdout, "INDEX-XML NO\n");
618 fprintf(stdout, "MESSAGE-LINE YES\n");
619 fprintf(stdout, "MESSAGE-XML NO\n");
620 fprintf(stdout, "RECORD YES\n");
621 fprintf(stdout, "INCLUDE-FILE YES\n");
622 fprintf(stdout, "INCLUDE-LIST YES\n");
623 fprintf(stdout, "INCLUDE-LIST-GLOB YES\n");
624 fprintf(stdout, "INCLUDE-OPTIONAL YES\n");
625 fprintf(stdout, "EXCLUDE-FILE YES\n");
626 fprintf(stdout, "EXCLUDE-LIST YES\n");
627 fprintf(stdout, "EXCLUDE-LIST-GLOB YES\n");
628 fprintf(stdout, "EXCLUDE-OPTIONAL YES\n");
629 fprintf(stdout, "COLLECTION NO\n");
630 fprintf(stdout, "MULTI-ESTIMATE YES\n");
631 fprintf(stdout, "CALCSIZE YES\n");
632 fprintf(stdout, "CLIENT-ESTIMATE YES\n");
637 application_argument_t *argument)
639 amgtar_build_exinclude(&argument->dle, 1, NULL, NULL, NULL, NULL);
641 printf("OK amgtar\n");
643 check_file(gnutar_path, X_OK);
645 printf(_("ERROR [GNUTAR program not available]\n"));
649 if (gnutar_listdir && strlen(gnutar_listdir) == 0)
650 gnutar_listdir = NULL;
651 if (gnutar_listdir) {
652 check_dir(gnutar_listdir, R_OK|W_OK);
654 printf(_("ERROR [No GNUTAR-LISTDIR]\n"));
657 if (argument->dle.disk) {
658 char *qdisk = quote_string(argument->dle.disk);
659 fprintf(stdout, "OK %s\n", qdisk);
662 if (gnutar_directory) {
663 check_dir(gnutar_directory, R_OK);
664 } else if (argument->dle.device) {
665 check_dir(argument->dle.device, R_OK);
667 if (argument->calcsize) {
668 char *calcsize = vstralloc(amlibexecdir, "/", "calcsize", NULL);
669 check_file(calcsize, X_OK);
670 check_suid(calcsize);
678 application_argument_t *argument)
680 char *incrname = NULL;
685 FILE *dumpout = NULL;
689 char *qerrmsg = NULL;
691 amwait_t wait_status;
700 if (!argument->level) {
701 fprintf(stderr, "ERROR No level argument\n");
702 error(_("No level argument"));
704 if (!argument->dle.disk) {
705 fprintf(stderr, "ERROR No disk argument\n");
706 error(_("No disk argument"));
708 if (!argument->dle.device) {
709 fprintf(stderr, "ERROR No device argument\n");
710 error(_("No device argument"));
713 qdisk = quote_string(argument->dle.disk);
715 if (argument->calcsize) {
720 if (gnutar_directory) {
721 dirname = gnutar_directory;
723 dirname = amname_to_dirname(argument->dle.device);
725 amgtar_build_exinclude(&argument->dle, 1,
726 &nb_exclude, &file_exclude,
727 &nb_include, &file_include);
729 run_calcsize(argument->config, "GNUTAR", argument->dle.disk, dirname,
730 argument->level, file_exclude, file_include);
732 if (argument->verbose == 0) {
734 unlink(file_exclude);
736 unlink(file_include);
742 errmsg = vstrallocf(_("GNUTAR-PATH not defined"));
746 if (!gnutar_listdir) {
747 errmsg = vstrallocf(_("GNUTAR-LISTDIR not defined"));
751 for (levels = argument->level; levels != NULL; levels = levels->next) {
752 level = GPOINTER_TO_INT(levels->data);
753 incrname = amgtar_get_incrname(argument, level, stdout, CMD_ESTIMATE);
754 cmd = stralloc(gnutar_path);
755 argv_ptr = amgtar_build_argv(argument, incrname, &file_exclude,
756 &file_include, CMD_ESTIMATE);
758 start_time = curclock();
760 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
761 errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
766 tarpid = pipespawnv(cmd, STDERR_PIPE, 1,
767 &nullfd, &nullfd, &pipefd,
768 (char **)argv_ptr->pdata);
770 dumpout = fdopen(pipefd,"r");
772 error(_("Can't fdopen: %s"), strerror(errno));
777 while (size < 0 && (fgets(line, sizeof(line), dumpout) != NULL)) {
778 if (line[strlen(line)-1] == '\n') /* remove trailling \n */
779 line[strlen(line)-1] = '\0';
782 dbprintf("%s\n", line);
783 /* check for size match */
785 for(rp = re_table; rp->regex != NULL; rp++) {
786 if(match(rp->regex, line)) {
787 if (rp->typ == DMP_SIZE) {
788 size = ((the_num(line, rp->field)*rp->scale+1023.0)/1024.0);
790 size = 1.0; /* found on NeXT -- sigh */
798 while (fgets(line, sizeof(line), dumpout) != NULL) {
799 dbprintf("%s", line);
803 dbprintf(_("estimate time for %s level %d: %s\n"),
806 walltime_str(timessub(curclock(), start_time)));
807 if(size == (off_t)-1) {
808 errmsg = vstrallocf(_("no size line match in %s output"), cmd);
809 dbprintf(_("%s for %s\n"), errmsg, qdisk);
811 } else if(size == (off_t)0 && argument->level == 0) {
812 dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"),
813 cmd, argument->dle.disk);
816 dbprintf(_("estimate size for %s level %d: %lld KB\n"),
821 kill(-tarpid, SIGTERM);
823 dbprintf(_("waiting for %s \"%s\" child\n"), cmd, qdisk);
824 waitpid(tarpid, &wait_status, 0);
825 if (WIFSIGNALED(wait_status)) {
826 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
827 cmd, WTERMSIG(wait_status), dbfn());
828 } else if (WIFEXITED(wait_status)) {
829 if (exit_value[WEXITSTATUS(wait_status)] == 1) {
830 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
831 cmd, WEXITSTATUS(wait_status), dbfn());
836 errmsg = vstrallocf(_("%s got bad exit: see %s"),
839 dbprintf(_("after %s %s wait\n"), cmd, qdisk);
843 dbprintf("%s", errmsg);
844 fprintf(stdout, "ERROR %s\n", errmsg);
851 if (argument->verbose == 0) {
853 unlink(file_exclude);
855 unlink(file_include);
858 g_ptr_array_free_full(argv_ptr);
864 fprintf(stdout, "%d %lld 1\n", level, (long long)size);
870 qerrmsg = quote_string(errmsg);
872 dbprintf("%s", errmsg);
873 fprintf(stdout, "ERROR %s\n", qerrmsg);
881 application_argument_t *argument)
889 off_t dump_size = -1;
897 FILE *indexstream = NULL;
900 amwait_t wait_status;
906 mesgstream = fdopen(mesgf, "w");
908 error(_("error mesgstream(%d): %s\n"), mesgf, strerror(errno));
912 error(_("GNUTAR-PATH not defined"));
914 if (!gnutar_listdir) {
915 error(_("GNUTAR-LISTDIR not defined"));
918 if (!argument->level) {
919 fprintf(mesgstream, "? No level argument\n");
920 error(_("No level argument"));
922 if (!argument->dle.disk) {
923 fprintf(mesgstream, "? No disk argument\n");
924 error(_("No disk argument"));
926 if (!argument->dle.device) {
927 fprintf(mesgstream, "? No device argument\n");
928 error(_("No device argument"));
931 qdisk = quote_string(argument->dle.disk);
933 incrname = amgtar_get_incrname(argument,
934 GPOINTER_TO_INT(argument->level->data),
935 mesgstream, CMD_BACKUP);
936 cmd = stralloc(gnutar_path);
937 argv_ptr = amgtar_build_argv(argument, incrname, &file_exclude,
938 &file_include, CMD_BACKUP);
940 tarpid = pipespawnv(cmd, STDIN_PIPE|STDERR_PIPE, 1,
941 &dumpin, &dataf, &outf, (char **)argv_ptr->pdata);
942 /* close the write ends of the pipes */
946 if (argument->dle.create_index) {
947 indexstream = fdopen(indexf, "w");
949 error(_("error indexstream(%d): %s\n"), indexf, strerror(errno));
952 outstream = fdopen(outf, "r");
954 error(_("error outstream(%d): %s\n"), outf, strerror(errno));
957 while (fgets(line, sizeof(line), outstream) != NULL) {
958 if (line[strlen(line)-1] == '\n') /* remove trailling \n */
959 line[strlen(line)-1] = '\0';
960 if (*line == '.' && *(line+1) == '/') { /* filename */
961 if (argument->dle.create_index) {
962 fprintf(indexstream, "%s\n", &line[1]); /* remove . */
964 } else { /* message */
965 for(rp = re_table; rp->regex != NULL; rp++) {
966 if(match(rp->regex, line)) {
970 if(rp->typ == DMP_SIZE) {
971 dump_size = (long)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0);
997 dbprintf("%3d: %7s(%c): %s\n", rp->srcline, type, startchr, line);
998 fprintf(mesgstream,"%c %s\n", startchr, line);
1002 waitpid(tarpid, &wait_status, 0);
1003 if (WIFSIGNALED(wait_status)) {
1004 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
1005 cmd, WTERMSIG(wait_status), dbfn());
1006 } else if (WIFEXITED(wait_status)) {
1007 if (exit_value[WEXITSTATUS(wait_status)] == 1) {
1008 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
1009 cmd, WEXITSTATUS(wait_status), dbfn());
1014 errmsg = vstrallocf(_("%s got bad exit: see %s"),
1017 dbprintf(_("after %s %s wait\n"), cmd, qdisk);
1018 dbprintf(_("amgtar: %s: pid %ld\n"), cmd, (long)tarpid);
1020 dbprintf("%s", errmsg);
1021 g_fprintf(mesgstream, "sendbackup: error [%s]\n", errmsg);
1024 if (!errmsg && incrname && strlen(incrname) > 4) {
1026 nodotnew = stralloc(incrname);
1027 nodotnew[strlen(nodotnew)-4] = '\0';
1028 if (rename(incrname, nodotnew)) {
1029 dbprintf(_("%s: warning [renaming %s to %s: %s]\n"),
1030 get_pname(), incrname, nodotnew, strerror(errno));
1031 g_fprintf(mesgstream, _("? warning [renaming %s to %s: %s]\n"),
1032 incrname, nodotnew, strerror(errno));
1037 dbprintf("sendbackup: size %lld\n", (long long)dump_size);
1038 fprintf(mesgstream, "sendbackup: size %lld\n", (long long)dump_size);
1039 dbprintf("sendbackup: end\n");
1040 fprintf(mesgstream, "sendbackup: end\n");
1042 if (argument->dle.create_index)
1043 fclose(indexstream);
1047 if (argument->verbose == 0) {
1049 unlink(file_exclude);
1051 unlink(file_include);
1057 g_ptr_array_free_full(argv_ptr);
1062 application_argument_t *argument)
1065 GPtrArray *argv_ptr = g_ptr_array_new();
1069 char *include_filename = NULL;
1070 char *exclude_filename = NULL;
1074 error(_("GNUTAR-PATH not defined"));
1077 cmd = stralloc(gnutar_path);
1078 g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1079 g_ptr_array_add(argv_ptr, stralloc("--numeric-owner"));
1080 if (gnutar_no_unquote)
1081 g_ptr_array_add(argv_ptr, stralloc("--no-unquote"));
1083 g_ptr_array_add(argv_ptr, stralloc("--acls"));
1085 g_ptr_array_add(argv_ptr, stralloc("--selinux"));
1087 g_ptr_array_add(argv_ptr, stralloc("--xattrs"));
1088 /* ignore trailing zero blocks on input (this was the default until tar-1.21) */
1089 g_ptr_array_add(argv_ptr, stralloc("--ignore-zeros"));
1090 g_ptr_array_add(argv_ptr, stralloc("-xpGvf"));
1091 g_ptr_array_add(argv_ptr, stralloc("-"));
1092 if (gnutar_directory) {
1093 struct stat stat_buf;
1094 if(stat(gnutar_directory, &stat_buf) != 0) {
1095 fprintf(stderr,"can not stat directory %s: %s\n", gnutar_directory, strerror(errno));
1098 if (!S_ISDIR(stat_buf.st_mode)) {
1099 fprintf(stderr,"%s is not a directory\n", gnutar_directory);
1102 if (access(gnutar_directory, W_OK) != 0) {
1103 fprintf(stderr, "Can't write to %s: %s\n", gnutar_directory, strerror(errno));
1106 g_ptr_array_add(argv_ptr, stralloc("--directory"));
1107 g_ptr_array_add(argv_ptr, stralloc(gnutar_directory));
1110 g_ptr_array_add(argv_ptr, stralloc("--wildcards"));
1111 if (argument->dle.exclude_list &&
1112 argument->dle.exclude_list->nb_element == 1) {
1116 int entry_in_exclude = 0;
1117 char line[2*PATH_MAX];
1120 if (argument->dle.disk) {
1121 sdisk = sanitise_filename(argument->dle.disk);
1123 sdisk = g_strdup_printf("no_dle-%d", getpid());
1125 exclude_filename= vstralloc(AMANDA_TMPDIR, "/", "exclude-", sdisk, NULL);
1126 exclude_list = fopen(argument->dle.exclude_list->first->name, "r");
1128 exclude = fopen(exclude_filename, "w");
1129 while (fgets(line, 2*PATH_MAX, exclude_list)) {
1131 line[strlen(line)-1] = '\0'; /* remove '\n' */
1132 escaped = escape_tar_glob(line, &in_argv);
1134 g_ptr_array_add(argv_ptr, "--exclude");
1135 g_ptr_array_add(argv_ptr, escaped);
1137 fprintf(exclude,"%s\n", escaped);
1143 g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1144 g_ptr_array_add(argv_ptr, exclude_filename);
1147 if (argument->exclude_list_glob) {
1148 g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1149 g_ptr_array_add(argv_ptr, stralloc(argument->exclude_list_glob));
1153 GPtrArray *argv_include = g_ptr_array_new();
1158 int entry_in_include = 0;
1160 if (argument->dle.disk) {
1161 sdisk = sanitise_filename(argument->dle.disk);
1163 sdisk = g_strdup_printf("no_dle-%d", getpid());
1165 include_filename = vstralloc(AMANDA_TMPDIR, "/", "include-", sdisk, NULL);
1166 include = fopen(include_filename, "w");
1167 if (argument->dle.include_list &&
1168 argument->dle.include_list->nb_element == 1) {
1169 char line[2*PATH_MAX];
1170 FILE *include_list = fopen(argument->dle.include_list->first->name, "r");
1171 while (fgets(line, 2*PATH_MAX, include_list)) {
1173 line[strlen(line)-1] = '\0'; /* remove '\n' */
1174 escaped = escape_tar_glob(line, &in_argv);
1176 g_ptr_array_add(argv_include, escaped);
1178 fprintf(include,"%s\n", escaped);
1185 for (j=1; j< argument->argc; j++) {
1186 char *escaped = escape_tar_glob(argument->argv[j], &in_argv);
1188 g_ptr_array_add(argv_include, escaped);
1190 fprintf(include,"%s\n", escaped);
1197 if (entry_in_include) {
1198 g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1199 g_ptr_array_add(argv_ptr, include_filename);
1202 if (argument->include_list_glob) {
1203 g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1204 g_ptr_array_add(argv_ptr, stralloc(argument->include_list_glob));
1207 for (i = 0; i < argv_include->len; i++) {
1208 g_ptr_array_add(argv_ptr, (char *)g_ptr_array_index(argv_include,i));
1211 g_ptr_array_add(argv_ptr, NULL);
1213 debug_executing(argv_ptr);
1217 case -1: error(_("%s: fork returned: %s"), get_pname(), strerror(errno));
1221 execve(cmd, (char **)argv_ptr->pdata, env);
1222 e = strerror(errno);
1223 error(_("error [exec %s: %s]"), cmd, e);
1228 waitpid(tarpid, NULL, 0);
1229 if (argument->verbose == 0) {
1230 if (exclude_filename)
1231 unlink(exclude_filename);
1232 if (include_filename)
1233 unlink(include_filename);
1239 application_argument_t *argument G_GNUC_UNUSED)
1242 GPtrArray *argv_ptr = g_ptr_array_new();
1248 dbprintf("GNUTAR-PATH not set; Piping to /dev/null\n");
1249 fprintf(stderr,"GNUTAR-PATH not set; Piping to /dev/null\n");
1253 cmd = stralloc(gnutar_path);
1254 g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1255 /* ignore trailing zero blocks on input (this was the default until tar-1.21) */
1256 g_ptr_array_add(argv_ptr, stralloc("--ignore-zeros"));
1257 g_ptr_array_add(argv_ptr, stralloc("-tf"));
1258 g_ptr_array_add(argv_ptr, stralloc("-"));
1259 g_ptr_array_add(argv_ptr, NULL);
1261 debug_executing(argv_ptr);
1263 execve(cmd, (char **)argv_ptr->pdata, env);
1264 e = strerror(errno);
1265 dbprintf("failed to execute %s: %s; Piping to /dev/null\n", cmd, e);
1266 fprintf(stderr,"failed to execute %s: %s; Piping to /dev/null\n", cmd, e);
1268 while (read(0, buf, 32768) > 0) {
1273 amgtar_build_exinclude(
1277 char **file_exclude,
1279 char **file_include)
1283 char *exclude = NULL;
1284 char *include = NULL;
1286 if (dle->exclude_file) n_exclude += dle->exclude_file->nb_element;
1287 if (dle->exclude_list) n_exclude += dle->exclude_list->nb_element;
1288 if (dle->include_file) n_include += dle->include_file->nb_element;
1289 if (dle->include_list) n_include += dle->include_list->nb_element;
1291 if (n_exclude > 0) exclude = build_exclude(dle, verbose);
1292 if (n_include > 0) include = build_include(dle, verbose);
1295 *nb_exclude = n_exclude;
1297 *file_exclude = exclude;
1302 *nb_include = n_include;
1304 *file_include = include;
1310 amgtar_get_incrname(
1311 application_argument_t *argument,
1316 char *basename = NULL;
1317 char *incrname = NULL;
1320 char *inputname = NULL;
1321 char *errmsg = NULL;
1324 if (gnutar_listdir) {
1325 char number[NUM_STR_SIZE];
1327 char *sdisk = sanitise_filename(argument->dle.disk);
1329 basename = vstralloc(gnutar_listdir,
1336 snprintf(number, SIZEOF(number), "%d", level);
1337 incrname = vstralloc(basename, "_", number, ".new", NULL);
1341 * Open the listed incremental file from the previous level. Search
1342 * backward until one is found. If none are found (which will also
1343 * be true for a level 0), arrange to read from /dev/null.
1347 while (infd == -1) {
1348 if (--baselevel >= 0) {
1349 snprintf(number, SIZEOF(number), "%d", baselevel);
1350 inputname = newvstralloc(inputname,
1351 basename, "_", number, NULL);
1353 inputname = newstralloc(inputname, "/dev/null");
1355 if ((infd = open(inputname, O_RDONLY)) == -1) {
1357 errmsg = vstrallocf(_("amgtar: error opening %s: %s"),
1358 inputname, strerror(errno));
1359 dbprintf("%s\n", errmsg);
1360 if (baselevel < 0) {
1361 if (command == CMD_ESTIMATE) {
1362 fprintf(mesgstream, "ERROR %s\n", errmsg);
1364 fprintf(mesgstream, "? %s\n", errmsg);
1373 * Copy the previous listed incremental file to the new one.
1375 if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) {
1376 errmsg = vstrallocf(_("error opening %s: %s"),
1377 incrname, strerror(errno));
1378 dbprintf("%s\n", errmsg);
1379 if (command == CMD_ESTIMATE) {
1380 fprintf(mesgstream, "ERROR %s\n", errmsg);
1382 fprintf(mesgstream, "? %s\n", errmsg);
1387 while ((nb = read(infd, &buf, SIZEOF(buf))) > 0) {
1388 if (full_write(outfd, &buf, (size_t)nb) < (size_t)nb) {
1389 errmsg = vstrallocf(_("writing to %s: %s"),
1390 incrname, strerror(errno));
1391 dbprintf("%s\n", errmsg);
1397 errmsg = vstrallocf(_("reading from %s: %s"),
1398 inputname, strerror(errno));
1399 dbprintf("%s\n", errmsg);
1403 if (close(infd) != 0) {
1404 errmsg = vstrallocf(_("closing %s: %s"),
1405 inputname, strerror(errno));
1406 dbprintf("%s\n", errmsg);
1409 if (close(outfd) != 0) {
1410 errmsg = vstrallocf(_("closing %s: %s"),
1411 incrname, strerror(errno));
1412 dbprintf("%s\n", errmsg);
1422 GPtrArray *amgtar_build_argv(
1423 application_argument_t *argument,
1425 char **file_exclude,
1426 char **file_include,
1432 char tmppath[PATH_MAX];
1433 GPtrArray *argv_ptr = g_ptr_array_new();
1436 amgtar_build_exinclude(&argument->dle, 1,
1437 &nb_exclude, file_exclude,
1438 &nb_include, file_include);
1440 if (gnutar_directory) {
1441 dirname = gnutar_directory;
1443 dirname = amname_to_dirname(argument->dle.device);
1446 g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1448 g_ptr_array_add(argv_ptr, stralloc("--create"));
1449 if (command == CMD_BACKUP && argument->dle.create_index)
1450 g_ptr_array_add(argv_ptr, stralloc("--verbose"));
1451 g_ptr_array_add(argv_ptr, stralloc("--file"));
1452 if (command == CMD_ESTIMATE) {
1453 g_ptr_array_add(argv_ptr, stralloc("/dev/null"));
1455 g_ptr_array_add(argv_ptr, stralloc("-"));
1457 if (gnutar_no_unquote)
1458 g_ptr_array_add(argv_ptr, stralloc("--no-unquote"));
1459 g_ptr_array_add(argv_ptr, stralloc("--directory"));
1460 canonicalize_pathname(dirname, tmppath);
1461 g_ptr_array_add(argv_ptr, stralloc(tmppath));
1462 if (gnutar_onefilesystem)
1463 g_ptr_array_add(argv_ptr, stralloc("--one-file-system"));
1464 if (gnutar_atimepreserve)
1465 g_ptr_array_add(argv_ptr, stralloc("--atime-preserve=system"));
1466 if (!gnutar_checkdevice)
1467 g_ptr_array_add(argv_ptr, stralloc("--no-check-device"));
1469 g_ptr_array_add(argv_ptr, stralloc("--acls"));
1471 g_ptr_array_add(argv_ptr, stralloc("--selinux"));
1473 g_ptr_array_add(argv_ptr, stralloc("--xattrs"));
1474 g_ptr_array_add(argv_ptr, stralloc("--listed-incremental"));
1475 g_ptr_array_add(argv_ptr, stralloc(incrname));
1477 g_ptr_array_add(argv_ptr, stralloc("--sparse"));
1478 if (argument->tar_blocksize) {
1479 g_ptr_array_add(argv_ptr, stralloc("--blocking-factor"));
1480 g_ptr_array_add(argv_ptr, stralloc(argument->tar_blocksize));
1482 g_ptr_array_add(argv_ptr, stralloc("--ignore-failed-read"));
1483 g_ptr_array_add(argv_ptr, stralloc("--totals"));
1485 for (copt = argument->command_options; copt != NULL; copt = copt->next) {
1486 g_ptr_array_add(argv_ptr, stralloc((char *)copt->data));
1489 if (*file_exclude) {
1490 g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1491 g_ptr_array_add(argv_ptr, stralloc(*file_exclude));
1494 if (*file_include) {
1495 g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1496 g_ptr_array_add(argv_ptr, stralloc(*file_include));
1499 g_ptr_array_add(argv_ptr, stralloc("."));
1501 g_ptr_array_add(argv_ptr, NULL);