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)
51 * EXIT-HANDLING (1=GOOD 2=BAD)
52 * TAR-BLOCKSIZE (default does not add --blocking-factor option,
53 * using tar's default)
57 #include "pipespawn.h"
58 #include "amfeatures.h"
63 #include "client_util.h"
67 #include "sendbackup.h"
69 int debug_application = 1;
70 #define application_debug(i, ...) do { \
71 if ((i) <= debug_application) { \
72 dbprintf(__VA_ARGS__); \
76 static amregex_t init_re_table[] = {
77 /* tar prints the size in bytes */
78 AM_SIZE_RE("^ *Total bytes written: [0-9][0-9]*", 1, 1),
79 AM_NORMAL_RE("^could not open conf file"),
80 AM_NORMAL_RE("^Elapsed time:"),
81 AM_NORMAL_RE("^Throughput"),
82 AM_IGNORE_RE(": Directory is new$"),
83 AM_IGNORE_RE(": Directory has been renamed"),
85 /* GNU tar 1.13.17 will print this warning when (not) backing up a
87 AM_NORMAL_RE(": socket ignored$"),
89 /* GNUTAR produces a few error messages when files are modified or
90 removed while it is running. They may cause data to be lost, but
91 then they may not. We shouldn't consider them NORMAL until
92 further investigation. */
93 AM_NORMAL_RE(": File .* shrunk by [0-9][0-9]* bytes, padding with zeros"),
94 AM_NORMAL_RE(": Cannot add file .*: No such file or directory$"),
95 AM_NORMAL_RE(": Error exit delayed from previous errors"),
97 /* catch-all: DMP_STRANGE is returned for all other lines */
100 static amregex_t *re_table;
102 /* local functions */
103 int main(int argc, char **argv);
105 typedef struct application_argument_s {
116 } application_argument_t;
118 enum { CMD_ESTIMATE, CMD_BACKUP };
120 static void amgtar_support(application_argument_t *argument);
121 static void amgtar_selfcheck(application_argument_t *argument);
122 static void amgtar_estimate(application_argument_t *argument);
123 static void amgtar_backup(application_argument_t *argument);
124 static void amgtar_restore(application_argument_t *argument);
125 static void amgtar_validate(application_argument_t *argument);
126 static void amgtar_build_exinclude(dle_t *dle, int verbose,
127 int *nb_exclude, char **file_exclude,
128 int *nb_include, char **file_include);
129 static char *amgtar_get_incrname(application_argument_t *argument, int level);
130 static char **amgtar_build_argv(application_argument_t *argument,
131 char *incrname, int command);
132 static amregex_t *build_re_table(amregex_t *orig_re_table,
133 GSList *normal_message,
134 GSList *ignore_message,
135 GSList *strange_message);
136 static void add_type_table(dmpline_t typ,
137 amregex_t **re_table, amregex_t *orig_re_table,
138 GSList *normal_message, GSList *ignore_message,
139 GSList *strange_message);
140 static void add_list_table(dmpline_t typ, amregex_t **re_table,
142 static char *gnutar_path;
143 static char *gnutar_listdir;
144 static char *gnutar_directory;
145 static int gnutar_onefilesystem;
146 static int gnutar_atimepreserve;
147 static int gnutar_checkdevice;
148 static int gnutar_sparse;
149 static GSList *normal_message = NULL;
150 static GSList *ignore_message = NULL;
151 static GSList *strange_message = NULL;
152 static char *exit_handling;
153 static int exit_value[256];
155 static struct option long_options[] = {
156 {"config" , 1, NULL, 1},
157 {"host" , 1, NULL, 2},
158 {"disk" , 1, NULL, 3},
159 {"device" , 1, NULL, 4},
160 {"level" , 1, NULL, 5},
161 {"index" , 1, NULL, 6},
162 {"message" , 1, NULL, 7},
163 {"collection" , 0, NULL, 8},
164 {"record" , 0, NULL, 9},
165 {"gnutar-path" , 1, NULL, 10},
166 {"gnutar-listdir" , 1, NULL, 11},
167 {"one-file-system" , 1, NULL, 12},
168 {"sparse" , 1, NULL, 13},
169 {"atime-preserve" , 1, NULL, 14},
170 {"check-device" , 1, NULL, 15},
171 {"include-file" , 1, NULL, 16},
172 {"include-list" , 1, NULL, 17},
173 {"include-optional", 1, NULL, 18},
174 {"exclude-file" , 1, NULL, 19},
175 {"exclude-list" , 1, NULL, 20},
176 {"exclude-optional", 1, NULL, 21},
177 {"directory" , 1, NULL, 22},
178 {"normal" , 1, NULL, 23},
179 {"ignore" , 1, NULL, 24},
180 {"strange" , 1, NULL, 25},
181 {"exit-handling" , 1, NULL, 26},
182 {"calcsize" , 0, NULL, 27},
183 {"tar-blocksize" , 1, NULL, 28},
191 amregex_t **re_table,
192 amregex_t *orig_re_table,
193 GSList *normal_message,
194 GSList *ignore_message,
195 GSList *strange_message)
199 for(rp = orig_re_table; rp->regex != NULL; rp++) {
200 if (rp->typ == typ) {
204 for (mes = normal_message; mes != NULL; mes = mes->next) {
205 if (strcmp(rp->regex, (char *)mes->data) == 0)
208 for (mes = ignore_message; mes != NULL; mes = mes->next) {
209 if (strcmp(rp->regex, (char *)mes->data) == 0)
212 for (mes = strange_message; mes != NULL; mes = mes->next) {
213 if (strcmp(rp->regex, (char *)mes->data) == 0)
217 (*re_table)->regex = rp->regex;
218 (*re_table)->srcline = rp->srcline;
219 (*re_table)->scale = rp->scale;
220 (*re_table)->field = rp->field;
221 (*re_table)->typ = rp->typ;
231 amregex_t **re_table,
236 for (mes = message; mes != NULL; mes = mes->next) {
237 (*re_table)->regex = (char *)mes->data;
238 (*re_table)->srcline = 0;
239 (*re_table)->scale = 0;
240 (*re_table)->field = 0;
241 (*re_table)->typ = typ;
248 amregex_t *orig_re_table,
249 GSList *normal_message,
250 GSList *ignore_message,
251 GSList *strange_message)
255 amregex_t *re_table, *new_re_table;
257 for(rp = orig_re_table; rp->regex != NULL; rp++) {
260 nb += g_slist_length(normal_message);
261 nb += g_slist_length(ignore_message);
262 nb += g_slist_length(strange_message);
265 re_table = new_re_table = malloc(nb * sizeof(amregex_t));
267 /* add SIZE from orig_re_table */
268 add_type_table(DMP_SIZE, &re_table, orig_re_table,
269 normal_message, ignore_message, strange_message);
271 /* add ignore_message */
272 add_list_table(DMP_IGNORE, &re_table, ignore_message);
274 /* add IGNORE from orig_re_table */
275 add_type_table(DMP_IGNORE, &re_table, orig_re_table,
276 normal_message, ignore_message, strange_message);
278 /* add normal_message */
279 add_list_table(DMP_NORMAL, &re_table, normal_message);
281 /* add NORMAL from orig_re_table */
282 add_type_table(DMP_NORMAL, &re_table, orig_re_table,
283 normal_message, ignore_message, strange_message);
285 /* add strange_message */
286 add_list_table(DMP_STRANGE, &re_table, strange_message);
288 /* add STRANGE from orig_re_table */
289 add_type_table(DMP_STRANGE, &re_table, orig_re_table,
290 normal_message, ignore_message, strange_message);
292 /* Add DMP_STRANGE with NULL regex, */
293 /* it is not copied by previous statement */
294 re_table->regex = NULL;
295 re_table->srcline = 0;
298 re_table->typ = DMP_STRANGE;
310 application_argument_t argument;
314 gnutar_path = GNUTAR;
318 gnutar_directory = NULL;
319 gnutar_onefilesystem = 1;
320 gnutar_atimepreserve = 1;
321 gnutar_checkdevice = 1;
323 exit_handling = NULL;
328 * Configure program for internationalization:
329 * 1) Only set the message locale for now.
330 * 2) Set textdomain for all amanda related programs to "amanda"
331 * We don't want to be forced to support dozens of message catalogs.
333 setlocale(LC_MESSAGES, "C");
334 textdomain("amanda");
336 /* drop root privileges */
337 if (!set_root_privs(0)) {
338 error(_("amgtar must be run setuid root"));
345 /* Don't die when child closes pipe */
346 signal(SIGPIPE, SIG_IGN);
348 #if defined(USE_DBMALLOC)
349 malloc_size_1 = malloc_inuse(&malloc_hist_1);
352 erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
353 dbopen(DBG_SUBDIR_CLIENT);
355 dbprintf(_("version %s\n"), version());
357 config_init(CONFIG_INIT_CLIENT, NULL);
359 //check_running_as(RUNNING_AS_DUMPUSER_PREFERRED);
361 //RUNNING_AS_CLIENT_LOGIN from selfcheck, sendsize, sendbackup
366 argument.config = NULL;
367 argument.host = NULL;
368 argument.message = 0;
369 argument.collection = 0;
370 argument.calcsize = 0;
371 argument.tar_blocksize = NULL;
372 argument.level = NULL;
373 init_dle(&argument.dle);
376 int option_index = 0;
377 c = getopt_long (argc, argv, "", long_options, &option_index);
382 case 1: argument.config = stralloc(optarg);
384 case 2: argument.host = stralloc(optarg);
386 case 3: argument.dle.disk = stralloc(optarg);
388 case 4: argument.dle.device = stralloc(optarg);
390 case 5: argument.level = g_slist_append(argument.level,
391 GINT_TO_POINTER(atoi(optarg)));
393 case 6: argument.dle.create_index = 1;
395 case 7: argument.message = 1;
397 case 8: argument.collection = 1;
399 case 9: argument.dle.record = 1;
401 case 10: gnutar_path = stralloc(optarg);
403 case 11: gnutar_listdir = stralloc(optarg);
405 case 12: if (optarg && strcasecmp(optarg, "YES") != 0)
406 gnutar_onefilesystem = 0;
408 case 13: if (optarg && strcasecmp(optarg, "YES") != 0)
411 case 14: if (optarg && strcasecmp(optarg, "YES") != 0)
412 gnutar_atimepreserve = 0;
414 case 15: if (optarg && strcasecmp(optarg, "YES") != 0)
415 gnutar_checkdevice = 0;
418 argument.dle.include_file =
419 append_sl(argument.dle.include_file, optarg);
422 argument.dle.include_list =
423 append_sl(argument.dle.include_list, optarg);
425 case 18: argument.dle.include_optional = 1;
428 argument.dle.exclude_file =
429 append_sl(argument.dle.exclude_file, optarg);
432 argument.dle.exclude_list =
433 append_sl(argument.dle.exclude_list, optarg);
435 case 21: argument.dle.exclude_optional = 1;
437 case 22: gnutar_directory = stralloc(optarg);
441 g_slist_append(normal_message, optarg);
445 g_slist_append(ignore_message, optarg);
449 g_slist_append(strange_message, optarg);
452 exit_handling = stralloc(optarg);
454 case 27: argument.calcsize = 1;
456 case 28: argument.tar_blocksize = stralloc(optarg);
463 argument.argc = argc - optind;
464 argument.argv = argv + optind;
466 if (argument.config) {
467 config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
469 dbrename(get_config_name(), DBG_SUBDIR_CLIENT);
472 if (config_errors(NULL) >= CFGERR_ERRORS) {
473 g_critical(_("errors processing config file"));
476 re_table = build_re_table(init_re_table, normal_message, ignore_message,
480 exit_value[i] = 1; /* BAD */
481 exit_value[0] = 0; /* GOOD */
482 exit_value[1] = 0; /* GOOD */
484 char *s = exit_handling;
486 char *r = strchr(s, '=');
489 if (j >= 0 && j < 256) {
491 if (strncasecmp(r, "GOOD", 4) == 0) {
496 s = strchr(s+1, ' ');
500 gnutar_listdir = getconf_str(CNF_GNUTAR_LIST_DIR);
501 if (strlen(gnutar_listdir) == 0)
502 gnutar_listdir = NULL;
505 dbprintf("GNUTAR-PATH %s\n", gnutar_path);
507 dbprintf("GNUTAR-PATH is not set\n");
509 if (gnutar_listdir) {
510 dbprintf("GNUTAR-LISTDIR %s\n", gnutar_listdir);
512 dbprintf("GNUTAR-LISTDIR is not set\n");
514 if (gnutar_directory) {
515 dbprintf("DIRECTORY %s\n", gnutar_directory);
517 dbprintf("ONE-FILE-SYSTEM %s\n", gnutar_onefilesystem? "yes":"no");
518 dbprintf("SPARSE %s\n", gnutar_sparse? "yes":"no");
519 dbprintf("ATIME-PRESERVE %s\n", gnutar_atimepreserve? "yes":"no");
520 dbprintf("CHECK-DEVICE %s\n", gnutar_checkdevice? "yes":"no");
523 for (rp = re_table; rp->regex != NULL; rp++) {
525 case DMP_NORMAL : dbprintf("NORMAL %s\n", rp->regex); break;
526 case DMP_IGNORE : dbprintf("IGNORE %s\n", rp->regex); break;
527 case DMP_STRANGE: dbprintf("STRANGE %s\n", rp->regex); break;
528 case DMP_SIZE : dbprintf("SIZE %s\n", rp->regex); break;
529 case DMP_ERROR : dbprintf("ERROR %s\n", rp->regex); break;
534 if (strcmp(command, "support") == 0) {
535 amgtar_support(&argument);
536 } else if (strcmp(command, "selfcheck") == 0) {
537 amgtar_selfcheck(&argument);
538 } else if (strcmp(command, "estimate") == 0) {
539 amgtar_estimate(&argument);
540 } else if (strcmp(command, "backup") == 0) {
541 amgtar_backup(&argument);
542 } else if (strcmp(command, "restore") == 0) {
543 amgtar_restore(&argument);
544 } else if (strcmp(command, "validate") == 0) {
545 amgtar_validate(&argument);
547 dbprintf("Unknown command `%s'.\n", command);
548 fprintf(stderr, "Unknown command `%s'.\n", command);
556 application_argument_t *argument)
559 fprintf(stdout, "CONFIG YES\n");
560 fprintf(stdout, "HOST YES\n");
561 fprintf(stdout, "DISK YES\n");
562 fprintf(stdout, "MAX-LEVEL 9\n");
563 fprintf(stdout, "INDEX-LINE YES\n");
564 fprintf(stdout, "INDEX-XML NO\n");
565 fprintf(stdout, "MESSAGE-LINE YES\n");
566 fprintf(stdout, "MESSAGE-XML NO\n");
567 fprintf(stdout, "RECORD YES\n");
568 fprintf(stdout, "INCLUDE-FILE YES\n");
569 fprintf(stdout, "INCLUDE-LIST YES\n");
570 fprintf(stdout, "INCLUDE-OPTIONAL YES\n");
571 fprintf(stdout, "EXCLUDE-FILE YES\n");
572 fprintf(stdout, "EXCLUDE-LIST YES\n");
573 fprintf(stdout, "EXCLUDE-OPTIONAL YES\n");
574 fprintf(stdout, "COLLECTION NO\n");
575 fprintf(stdout, "MULTI-ESTIMATE YES\n");
576 fprintf(stdout, "CALCSIZE YES\n");
581 application_argument_t *argument)
583 amgtar_build_exinclude(&argument->dle, 1, NULL, NULL, NULL, NULL);
586 check_file(gnutar_path, X_OK);
588 printf(_("ERROR [GNUTAR program not available]\n"));
592 if (gnutar_listdir && strlen(gnutar_listdir) == 0)
593 gnutar_listdir = NULL;
594 if (gnutar_listdir) {
595 check_dir(gnutar_listdir, R_OK|W_OK);
597 printf(_("ERROR [No GNUTAR-LISTDIR]\n"));
600 fprintf(stdout, "OK %s\n", argument->dle.disk);
601 if (gnutar_directory) {
602 check_dir(gnutar_directory, R_OK);
604 check_dir(argument->dle.device, R_OK);
611 application_argument_t *argument)
613 char *incrname = NULL;
614 char **my_argv = NULL;
618 FILE *dumpout = NULL;
622 char *qerrmsg = NULL;
624 amwait_t wait_status;
631 qdisk = quote_string(argument->dle.disk);
633 if (argument->calcsize) {
640 if (gnutar_directory) {
641 dirname = gnutar_directory;
643 dirname = amname_to_dirname(argument->dle.device);
645 amgtar_build_exinclude(&argument->dle, 1,
646 &nb_exclude, &file_exclude,
647 &nb_include, &file_include);
649 run_calcsize(argument->config, "GNUTAR", argument->dle.disk, dirname,
650 argument->level, file_exclude, file_include);
655 errmsg = vstrallocf(_("GNUTAR-PATH not defined"));
659 if (!gnutar_listdir) {
660 errmsg = vstrallocf(_("GNUTAR-LISTDIR not defined"));
664 for (levels = argument->level; levels != NULL; levels = levels->next) {
665 level = GPOINTER_TO_INT(levels->data);
666 incrname = amgtar_get_incrname(argument, level);
667 cmd = stralloc(gnutar_path);
668 my_argv = amgtar_build_argv(argument, incrname, CMD_ESTIMATE);
670 start_time = curclock();
672 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
673 errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
678 tarpid = pipespawnv(cmd, STDERR_PIPE, 1,
679 &nullfd, &nullfd, &pipefd, my_argv);
681 dumpout = fdopen(pipefd,"r");
683 error(_("Can't fdopen: %s"), strerror(errno));
688 while (size < 0 && (fgets(line, sizeof(line), dumpout) != NULL)) {
689 if (line[strlen(line)-1] == '\n') /* remove trailling \n */
690 line[strlen(line)-1] = '\0';
693 dbprintf("%s\n", line);
694 /* check for size match */
696 for(rp = re_table; rp->regex != NULL; rp++) {
697 if(match(rp->regex, line)) {
698 if (rp->typ == DMP_SIZE) {
699 size = ((the_num(line, rp->field)*rp->scale+1023.0)/1024.0);
701 size = 1.0; /* found on NeXT -- sigh */
709 while (fgets(line, sizeof(line), dumpout) != NULL) {
710 dbprintf("%s", line);
714 dbprintf(_("estimate time for %s level %d: %s\n"),
717 walltime_str(timessub(curclock(), start_time)));
718 if(size == (off_t)-1) {
719 errmsg = vstrallocf(_("no size line match in %s output"),
721 dbprintf(_("%s for %s\n"), errmsg, qdisk);
723 } else if(size == (off_t)0 && argument->level == 0) {
724 dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"),
725 my_argv[0], argument->dle.disk);
728 dbprintf(_("estimate size for %s level %d: %lld KB\n"),
733 kill(-tarpid, SIGTERM);
735 dbprintf(_("waiting for %s \"%s\" child\n"), my_argv[0], qdisk);
736 waitpid(tarpid, &wait_status, 0);
737 if (WIFSIGNALED(wait_status)) {
738 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
739 cmd, WTERMSIG(wait_status), dbfn());
740 } else if (WIFEXITED(wait_status)) {
741 if (exit_value[WEXITSTATUS(wait_status)] == 1) {
742 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
743 cmd, WEXITSTATUS(wait_status), dbfn());
748 errmsg = vstrallocf(_("%s got bad exit: see %s"),
751 dbprintf(_("after %s %s wait\n"), my_argv[0], qdisk);
755 dbprintf("%s", errmsg);
756 fprintf(stdout, "ERROR %s\n", errmsg);
768 fprintf(stdout, "%d %lld 1\n", level, (long long)size);
774 qerrmsg = quote_string(errmsg);
776 dbprintf("%s", errmsg);
777 fprintf(stdout, "ERROR %s\n", qerrmsg);
785 application_argument_t *argument)
793 off_t dump_size = -1;
802 FILE *indexstream = NULL;
805 amwait_t wait_status;
811 error(_("GNUTAR-PATH not defined"));
813 if (!gnutar_listdir) {
814 error(_("GNUTAR-LISTDIR not defined"));
817 qdisk = quote_string(argument->dle.disk);
819 incrname = amgtar_get_incrname(argument,
820 GPOINTER_TO_INT(argument->level->data));
821 cmd = stralloc(gnutar_path);
822 my_argv = amgtar_build_argv(argument, incrname, CMD_BACKUP);
824 tarpid = pipespawnv(cmd, STDIN_PIPE|STDERR_PIPE, 1,
825 &dumpin, &dataf, &outf, my_argv);
826 /* close the write ends of the pipes */
830 if (argument->dle.create_index) {
831 indexstream = fdopen(indexf, "w");
833 error(_("error indexstream(%d): %s\n"), indexf, strerror(errno));
836 mesgstream = fdopen(mesgf, "w");
838 error(_("error mesgstream(%d): %s\n"), mesgf, strerror(errno));
840 outstream = fdopen(outf, "r");
842 error(_("error outstream(%d): %s\n"), outf, strerror(errno));
845 while (fgets(line, sizeof(line), outstream) != NULL) {
846 if (line[strlen(line)-1] == '\n') /* remove trailling \n */
847 line[strlen(line)-1] = '\0';
848 if (*line == '.' && *(line+1) == '/') { /* filename */
849 if (argument->dle.create_index) {
850 fprintf(indexstream, "%s\n", &line[1]); /* remove . */
852 } else { /* message */
853 for(rp = re_table; rp->regex != NULL; rp++) {
854 if(match(rp->regex, line)) {
858 if(rp->typ == DMP_SIZE) {
859 dump_size = (long)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0);
885 dbprintf("%3d: %7s(%c): %s\n", rp->srcline, type, startchr, line);
886 fprintf(mesgstream,"%c %s\n", startchr, line);
890 waitpid(tarpid, &wait_status, 0);
891 if (WIFSIGNALED(wait_status)) {
892 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
893 cmd, WTERMSIG(wait_status), dbfn());
894 } else if (WIFEXITED(wait_status)) {
895 if (exit_value[WEXITSTATUS(wait_status)] == 1) {
896 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
897 cmd, WEXITSTATUS(wait_status), dbfn());
902 errmsg = vstrallocf(_("%s got bad exit: see %s"),
905 dbprintf(_("after %s %s wait\n"), my_argv[0], qdisk);
906 dbprintf(_("amgtar: %s: pid %ld\n"), cmd, (long)tarpid);
908 dbprintf("%s", errmsg);
909 g_fprintf(mesgstream, "sendbackup: error [%s]\n", errmsg);
912 if (!errmsg && incrname && strlen(incrname) > 4) {
914 nodotnew = stralloc(incrname);
915 nodotnew[strlen(nodotnew)-4] = '\0';
916 if (rename(incrname, nodotnew)) {
917 dbprintf(_("%s: warning [renaming %s to %s: %s]\n"),
918 get_pname(), incrname, nodotnew, strerror(errno));
919 g_fprintf(mesgstream, _("? warning [renaming %s to %s: %s]\n"),
920 incrname, nodotnew, strerror(errno));
925 dbprintf("sendbackup: size %lld\n", (long long)dump_size);
926 fprintf(mesgstream, "sendbackup: size %lld\n", (long long)dump_size);
927 dbprintf("sendbackup: end\n");
928 fprintf(mesgstream, "sendbackup: end\n");
930 if (argument->dle.create_index)
942 application_argument_t *argument)
951 error(_("GNUTAR-PATH not defined"));
954 cmd = stralloc(gnutar_path);
955 my_argv = alloc(SIZEOF(char *) * (6 + argument->argc));
957 my_argv[i++] = stralloc(gnutar_path);
958 my_argv[i++] = stralloc("--numeric-owner");
959 my_argv[i++] = stralloc("-xpGvf");
960 my_argv[i++] = stralloc("-");
962 for (j=1; j< argument->argc; j++) {
963 my_argv[i++] = stralloc(argument->argv[j]);
969 execve(cmd, my_argv, env);
971 error(_("error [exec %s: %s]"), cmd, e);
976 application_argument_t *argument G_GNUC_UNUSED)
985 error(_("GNUTAR-PATH not defined"));
988 cmd = stralloc(gnutar_path);
989 my_argv = alloc(SIZEOF(char *) * 4);
991 my_argv[i++] = stralloc(gnutar_path);
992 my_argv[i++] = stralloc("-tf");
993 my_argv[i++] = stralloc("-");
997 execve(cmd, my_argv, env);
999 error(_("error [exec %s: %s]"), cmd, e);
1003 amgtar_build_exinclude(
1007 char **file_exclude,
1009 char **file_include)
1013 char *exclude = NULL;
1014 char *include = NULL;
1016 if (dle->exclude_file) n_exclude += dle->exclude_file->nb_element;
1017 if (dle->exclude_list) n_exclude += dle->exclude_list->nb_element;
1018 if (dle->include_file) n_include += dle->include_file->nb_element;
1019 if (dle->include_list) n_include += dle->include_list->nb_element;
1021 if (n_exclude > 0) exclude = build_exclude(dle, verbose);
1022 if (n_include > 0) include = build_include(dle, verbose);
1025 *nb_exclude = n_exclude;
1027 *file_exclude = exclude;
1032 *nb_include = n_include;
1034 *file_include = include;
1040 amgtar_get_incrname(
1041 application_argument_t *argument,
1044 char *basename = NULL;
1045 char *incrname = NULL;
1048 char *inputname = NULL;
1049 char *errmsg = NULL;
1052 if (gnutar_listdir) {
1053 char number[NUM_STR_SIZE];
1055 char *sdisk = sanitise_filename(argument->dle.disk);
1057 basename = vstralloc(gnutar_listdir,
1064 snprintf(number, SIZEOF(number), "%d", level);
1065 incrname = vstralloc(basename, "_", number, ".new", NULL);
1069 * Open the listed incremental file from the previous level. Search
1070 * backward until one is found. If none are found (which will also
1071 * be true for a level 0), arrange to read from /dev/null.
1075 while (infd == -1) {
1076 if (--baselevel >= 0) {
1077 snprintf(number, SIZEOF(number), "%d", baselevel);
1078 inputname = newvstralloc(inputname,
1079 basename, "_", number, NULL);
1081 inputname = newstralloc(inputname, "/dev/null");
1083 if ((infd = open(inputname, O_RDONLY)) == -1) {
1085 errmsg = vstrallocf(_("amgtar: error opening %s: %s"),
1086 inputname, strerror(errno));
1087 dbprintf("%s\n", errmsg);
1088 if (baselevel < 0) {
1096 * Copy the previous listed incremental file to the new one.
1098 if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) {
1099 errmsg = vstrallocf(_("opening %s: %s"),
1100 incrname, strerror(errno));
1101 dbprintf("%s\n", errmsg);
1105 while ((nb = read(infd, &buf, SIZEOF(buf))) > 0) {
1106 if (full_write(outfd, &buf, (size_t)nb) < (size_t)nb) {
1107 errmsg = vstrallocf(_("writing to %s: %s"),
1108 incrname, strerror(errno));
1109 dbprintf("%s\n", errmsg);
1115 errmsg = vstrallocf(_("reading from %s: %s"),
1116 inputname, strerror(errno));
1117 dbprintf("%s\n", errmsg);
1121 if (close(infd) != 0) {
1122 errmsg = vstrallocf(_("closing %s: %s"),
1123 inputname, strerror(errno));
1124 dbprintf("%s\n", errmsg);
1127 if (close(outfd) != 0) {
1128 errmsg = vstrallocf(_("closing %s: %s"),
1129 incrname, strerror(errno));
1130 dbprintf("%s\n", errmsg);
1140 char **amgtar_build_argv(
1141 application_argument_t *argument,
1151 char tmppath[PATH_MAX];
1154 amgtar_build_exinclude(&argument->dle, 1,
1155 &nb_exclude, &file_exclude,
1156 &nb_include, &file_include);
1158 if (gnutar_directory) {
1159 dirname = gnutar_directory;
1161 dirname = amname_to_dirname(argument->dle.device);
1164 my_argv = alloc(SIZEOF(char *) * 23);
1167 my_argv[i++] = gnutar_path;
1169 my_argv[i++] = "--create";
1170 if (command == CMD_BACKUP && argument->dle.create_index)
1171 my_argv[i++] = "--verbose";
1172 my_argv[i++] = "--file";
1173 if (command == CMD_ESTIMATE) {
1174 my_argv[i++] = "/dev/null";
1178 my_argv[i++] = "--directory";
1179 canonicalize_pathname(dirname, tmppath);
1180 my_argv[i++] = stralloc(tmppath);
1181 if (gnutar_onefilesystem)
1182 my_argv[i++] = "--one-file-system";
1183 if (gnutar_atimepreserve)
1184 my_argv[i++] = "--atime-preserve=system";
1185 if (!gnutar_checkdevice)
1186 my_argv[i++] = "--no-check-device";
1187 my_argv[i++] = "--listed-incremental";
1188 my_argv[i++] = incrname;
1190 my_argv[i++] = "--sparse";
1191 if (argument->tar_blocksize) {
1192 my_argv[i++] = "--blocking-factor";
1193 my_argv[i++] = argument->tar_blocksize;
1195 my_argv[i++] = "--ignore-failed-read";
1196 my_argv[i++] = "--totals";
1199 my_argv[i++] = "--exclude-from";
1200 my_argv[i++] = file_exclude;
1204 my_argv[i++] = "--files-from";
1205 my_argv[i++] = file_include;
1210 my_argv[i++] = NULL;