7cf28a1ffce292a70c68b0bd3a31d4f1036eb130
[debian/amanda] / application-src / amgtar.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /* 
27  * $Id: amgtar.c 8888 2007-10-02 13:40:42Z martineau $
28  *
29  * send estimated backup sizes using dump
30  */
31
32 /* PROPERTY:
33  *
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)
43  * ACLS            (default NO)
44  * SELINUX         (default NO)
45  * XATTRS          (default NO)
46  * INCLUDE-FILE
47  * INCLUDE-LIST
48  * INCLUDE-LIST-GLOB
49  * INCLUDE-OPTIONAL
50  * EXCLUDE-FILE
51  * EXCLUDE-LIST
52  * EXCLUDE-LIST-GLOB
53  * EXCLUDE-OPTIONAL
54  * NORMAL
55  * IGNORE
56  * STRANGE
57  * EXIT-HANDLING   (1=GOOD 2=BAD)
58  * TAR-BLOCKSIZE   (default does not add --blocking-factor option,
59  *                  using tar's default)
60  * VERBOSE
61  */
62
63 #include "amanda.h"
64 #include "match.h"
65 #include "pipespawn.h"
66 #include "amfeatures.h"
67 #include "clock.h"
68 #include "util.h"
69 #include "getfsent.h"
70 #include "client_util.h"
71 #include "conffile.h"
72 #include "getopt.h"
73
74 int debug_application = 1;
75 #define application_debug(i, ...) do {  \
76         if ((i) <= debug_application) { \
77             dbprintf(__VA_ARGS__);      \
78         }                               \
79 } while (0)
80
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"),
89
90   /* GNU tar 1.13.17 will print this warning when (not) backing up a
91      Unix named socket.  */
92   AM_NORMAL_RE(": socket ignored$"),
93
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"),
101   
102   /* catch-all: DMP_STRANGE is returned for all other lines */
103   AM_STRANGE_RE(NULL)
104 };
105 static amregex_t *re_table;
106
107 /* local functions */
108 int main(int argc, char **argv);
109
110 typedef struct application_argument_s {
111     char      *config;
112     char      *host;
113     int        message;
114     int        collection;
115     int        calcsize;
116     char      *tar_blocksize;
117     GSList    *level;
118     GSList    *command_options;
119     char      *include_list_glob;
120     char      *exclude_list_glob;
121     dle_t      dle;
122     int        argc;
123     char     **argv;
124     int        verbose;
125 } application_argument_t;
126
127 enum { CMD_ESTIMATE, CMD_BACKUP };
128
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];
159
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},
197     {NULL, 0, NULL, 0}
198 };
199
200 static char *
201 escape_tar_glob(
202     char *str,
203     int  *in_argv)
204 {
205     char *result = malloc(4*strlen(str)+1);
206     char *r = result;
207     char *s;
208
209     *in_argv = 0;
210     for (s = str; *s != '\0'; s++) {
211         if (*s == '\\') {
212             char c = *(s+1);
213             if (c == '\\') {
214                 *r++ = '\\';
215                 *r++ = '\\';
216                 *r++ = '\\';
217                 s++;
218             } else if (c == '?') {
219                 *r++ = 127;
220                 s++;
221                 continue;
222             } else if (c == 'a') {
223                 *r++ = 7;
224                 s++;
225                 continue;
226             } else if (c == 'b') {
227                 *r++ = 8;
228                 s++;
229                 continue;
230             } else if (c == 'f') {
231                 *r++ = 12;
232                 s++;
233                 continue;
234             } else if (c == 'n') {
235                 *r++ = 10;
236                 s++;
237                 *in_argv = 1;
238                 continue;
239             } else if (c == 'r') {
240                 *r++ = 13;
241                 s++;
242                 *in_argv = 1;
243                 continue;
244             } else if (c == 't') {
245                 *r++ = 9;
246                 s++;
247                 continue;
248             } else if (c == 'v') {
249                 *r++ = 11;
250                 s++;
251                 continue;
252             } else if (c >= '0' && c <= '9') {
253                 char d = c-'0';
254                 s++;
255                 c = *(s+1);
256                 if (c >= '0' && c <= '9') {
257                     d = (d*8)+(c-'0');
258                     s++;
259                     c = *(s+1);
260                     if (c >= '0' && c <= '9') {
261                         d = (d*8)+(c-'0');
262                         s++;
263                     }
264                 }
265                 *r++ = d;
266                 continue;
267             } else {
268                 *r++ = '\\';
269             }
270         } else if (*s == '?') {
271             *r++ = '\\';
272             *r++ = '\\';
273         } else if (*s == '*' || *s == '[') {
274             *r++ = '\\';
275         }
276         *r++ = *s;
277     }
278     *r = '\0';
279
280     return result;
281 }
282
283
284 int
285 main(
286     int         argc,
287     char **     argv)
288 {
289     int c;
290     char *command;
291     application_argument_t argument;
292     int i;
293
294 #ifdef GNUTAR
295     gnutar_path = GNUTAR;
296 #else
297     gnutar_path = NULL;
298 #endif
299     gnutar_listdir = NULL;
300     gnutar_directory = NULL;
301     gnutar_onefilesystem = 1;
302     gnutar_atimepreserve = 1;
303     gnutar_acls = 0;
304     gnutar_selinux = 0;
305     gnutar_xattrs = 0;
306     gnutar_checkdevice = 1;
307     gnutar_sparse = 1;
308     gnutar_no_unquote = 0;
309     exit_handling = NULL;
310
311     /* initialize */
312
313     /*
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.
318      */
319     setlocale(LC_MESSAGES, "C");
320     textdomain("amanda");
321
322     if (argc < 2) {
323         printf("ERROR no command given to amgtar\n");
324         error(_("No command given to amgtar"));
325     }
326
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");
331         }
332         error(_("amgtar must be run setuid root"));
333     }
334
335     safe_fd(3, 2);
336
337     set_pname("amgtar");
338
339     /* Don't die when child closes pipe */
340     signal(SIGPIPE, SIG_IGN);
341
342 #if defined(USE_DBMALLOC)
343     malloc_size_1 = malloc_inuse(&malloc_hist_1);
344 #endif
345
346     add_amanda_log_handler(amanda_log_stderr);
347     add_amanda_log_handler(amanda_log_syslog);
348     dbopen(DBG_SUBDIR_CLIENT);
349     startclock();
350     dbprintf(_("version %s\n"), VERSION);
351
352     config_init(CONFIG_INIT_CLIENT, NULL);
353
354     //check_running_as(RUNNING_AS_DUMPUSER_PREFERRED);
355     //root for amrecover
356     //RUNNING_AS_CLIENT_LOGIN from selfcheck, sendsize, sendbackup
357
358     /* parse argument */
359     command = argv[1];
360
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;
375
376     while (1) {
377         int option_index = 0;
378         c = getopt_long (argc, argv, "", long_options, &option_index);
379         if (c == -1) {
380             break;
381         }
382         switch (c) {
383         case 1: argument.config = stralloc(optarg);
384                 break;
385         case 2: argument.host = stralloc(optarg);
386                 break;
387         case 3: argument.dle.disk = stralloc(optarg);
388                 break;
389         case 4: argument.dle.device = stralloc(optarg);
390                 break;
391         case 5: argument.level = g_slist_append(argument.level,
392                                                 GINT_TO_POINTER(atoi(optarg)));
393                 break;
394         case 6: argument.dle.create_index = 1;
395                 break;
396         case 7: argument.message = 1;
397                 break;
398         case 8: argument.collection = 1;
399                 break;
400         case 9: argument.dle.record = 1;
401                 break;
402         case 10: gnutar_path = stralloc(optarg);
403                  break;
404         case 11: gnutar_listdir = stralloc(optarg);
405                  break;
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);
412                  break;
413         case 13: if (optarg && strcasecmp(optarg, "NO") == 0)
414                      gnutar_sparse = 0;
415                  else if (optarg && strcasecmp(optarg, "YES") == 0)
416                      gnutar_sparse = 1;
417                  else if (strcasecmp(command, "selfcheck") == 0)
418                      printf(_("ERROR [%s: bad SPARSE property value (%s)]\n"), get_pname(), optarg);
419                  break;
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);
426                  break;
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);
433                  break;
434         case 16: if (optarg)
435                      argument.dle.include_file =
436                          append_sl(argument.dle.include_file, optarg);
437                  break;
438         case 17: if (optarg)
439                      argument.dle.include_list =
440                          append_sl(argument.dle.include_list, optarg);
441                  break;
442         case 18: argument.dle.include_optional = 1;
443                  break;
444         case 19: if (optarg)
445                      argument.dle.exclude_file =
446                          append_sl(argument.dle.exclude_file, optarg);
447                  break;
448         case 20: if (optarg)
449                      argument.dle.exclude_list =
450                          append_sl(argument.dle.exclude_list, optarg);
451                  break;
452         case 21: argument.dle.exclude_optional = 1;
453                  break;
454         case 22: gnutar_directory = stralloc(optarg);
455                  break;
456         case 23: if (optarg)
457                      normal_message = 
458                          g_slist_append(normal_message, optarg);
459                  break;
460         case 24: if (optarg)
461                      ignore_message = 
462                          g_slist_append(ignore_message, optarg);
463                  break;
464         case 25: if (optarg)
465                      strange_message = 
466                          g_slist_append(strange_message, optarg);
467                  break;
468         case 26: if (optarg)
469                      exit_handling = stralloc(optarg);
470                  break;
471         case 27: argument.calcsize = 1;
472                  break;
473         case 28: argument.tar_blocksize = stralloc(optarg);
474                  break;
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);
481                  break;
482         case 30: if (optarg && strcasecmp(optarg, "YES") == 0)
483                    gnutar_acls = 1;
484                  break;
485         case 31: if (optarg && strcasecmp(optarg, "YES") == 0)
486                    gnutar_selinux = 1;
487                  break;
488         case 32: if (optarg && strcasecmp(optarg, "YES") == 0)
489                    gnutar_xattrs = 1;
490                  break;
491         case 33: argument.command_options =
492                         g_slist_append(argument.command_options,
493                                        stralloc(optarg));
494                  break;
495         case 34: if (optarg)
496                      argument.include_list_glob = stralloc(optarg);
497                  break;
498         case 35: if (optarg)
499                      argument.exclude_list_glob = stralloc(optarg);
500                  break;
501         case 36: if (optarg  && strcasecmp(optarg, "YES") == 0)
502                      argument.verbose = 1;
503                  break;
504         case ':':
505         case '?':
506                 break;
507         }
508     }
509
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);
514
515     argument.argc = argc - optind;
516     argument.argv = argv + optind;
517
518     if (argument.config) {
519         config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
520                     argument.config);
521         dbrename(get_config_name(), DBG_SUBDIR_CLIENT);
522     }
523
524     if (config_errors(NULL) >= CFGERR_ERRORS) {
525         g_critical(_("errors processing config file"));
526     }
527
528     re_table = build_re_table(init_re_table, normal_message, ignore_message,
529                               strange_message);
530
531     for(i=0;i<256;i++)
532         exit_value[i] = 1; /* BAD  */
533     exit_value[0] = 0;     /* GOOD */
534     exit_value[1] = 0;     /* GOOD */
535     if (exit_handling) {
536         char *s = exit_handling;
537         while (s) {
538             char *r = strchr(s, '=');
539             if (r) {
540                 int j = atoi(s);
541                 if (j >= 0 && j < 256) {
542                     r++;
543                     if (strncasecmp(r, "GOOD", 4) == 0) {
544                         exit_value[j] = 0;
545                     }
546                 }
547             }
548             s = strchr(s+1, ' ');
549         }
550     }
551
552     if (strlen(gnutar_listdir) == 0)
553         gnutar_listdir = NULL;
554
555     if (gnutar_path) {
556         dbprintf("GNUTAR-PATH %s\n", gnutar_path);
557     } else {
558         dbprintf("GNUTAR-PATH is not set\n");
559     }
560     if (gnutar_listdir) {
561             dbprintf("GNUTAR-LISTDIR %s\n", gnutar_listdir);
562     } else {
563         dbprintf("GNUTAR-LISTDIR is not set\n");
564     }
565     if (gnutar_directory) {
566         dbprintf("DIRECTORY %s\n", gnutar_directory);
567     }
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");
576     {
577         amregex_t *rp;
578         for (rp = re_table; rp->regex != NULL; rp++) {
579             switch (rp->typ) {
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;
585             }
586         }
587     }
588
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);
601     } else {
602         dbprintf("Unknown command `%s'.\n", command);
603         fprintf(stderr, "Unknown command `%s'.\n", command);
604         exit (1);
605     }
606     return 0;
607 }
608
609 static void
610 amgtar_support(
611     application_argument_t *argument)
612 {
613     (void)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");
635 }
636
637 static void
638 amgtar_selfcheck(
639     application_argument_t *argument)
640 {
641     if (argument->dle.disk) {
642         char *qdisk = quote_string(argument->dle.disk);
643         fprintf(stdout, "OK disk %s\n", qdisk);
644         amfree(qdisk);
645     }
646
647     printf("OK amgtar version %s\n", VERSION);
648     amgtar_build_exinclude(&argument->dle, 1, NULL, NULL, NULL, NULL);
649
650     printf("OK amgtar\n");
651     if (gnutar_path) {
652         if (check_file(gnutar_path, X_OK)) {
653             char *gtar_version;
654             GPtrArray *argv_ptr = g_ptr_array_new();
655
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);
659
660             gtar_version = get_first_line(argv_ptr);
661             if (gtar_version) {
662                 char *gv;
663                 for (gv = gtar_version; *gv && !g_ascii_isdigit(*gv); gv++);
664                 printf("OK amgtar gtar-version %s\n", gv);
665             } else {
666                 printf(_("ERROR [Can't get %s version]\n"), gnutar_path);
667             }
668
669             g_ptr_array_free(argv_ptr, TRUE);
670             amfree(gtar_version);
671         }
672     } else {
673         printf(_("ERROR [GNUTAR program not available]\n"));
674     }
675
676     set_root_privs(1);
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);
681     } else {
682         printf(_("ERROR [No GNUTAR-LISTDIR]\n"));
683     }
684
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);
689     }
690     if (argument->calcsize) {
691         char *calcsize = vstralloc(amlibexecdir, "/", "calcsize", NULL);
692         check_file(calcsize, X_OK);
693         check_suid(calcsize);
694         amfree(calcsize);
695     }
696     set_root_privs(0);
697 }
698
699 static void
700 amgtar_estimate(
701     application_argument_t *argument)
702 {
703     char      *incrname = NULL;
704     GPtrArray *argv_ptr;
705     char      *cmd = NULL;
706     int        nullfd = -1;
707     int        pipefd = -1;
708     FILE      *dumpout = NULL;
709     off_t      size = -1;
710     char       line[32768];
711     char      *errmsg = NULL;
712     char      *qerrmsg = NULL;
713     char      *qdisk;
714     amwait_t   wait_status;
715     int        tarpid;
716     amregex_t *rp;
717     times_t    start_time;
718     int        level;
719     GSList    *levels;
720     char      *file_exclude;
721     char      *file_include;
722
723     if (!argument->level) {
724         fprintf(stderr, "ERROR No level argument\n");
725         error(_("No level argument"));
726     }
727     if (!argument->dle.disk) {
728         fprintf(stderr, "ERROR No disk argument\n");
729         error(_("No disk argument"));
730     }
731     if (!argument->dle.device) {
732         fprintf(stderr, "ERROR No device argument\n");
733         error(_("No device argument"));
734     }
735
736     qdisk = quote_string(argument->dle.disk);
737
738     if (argument->calcsize) {
739         char *dirname;
740         int   nb_exclude;
741         int   nb_include;
742
743         if (gnutar_directory) {
744             dirname = gnutar_directory;
745         } else {
746             dirname = argument->dle.device;
747         }
748         amgtar_build_exinclude(&argument->dle, 1,
749                                &nb_exclude, &file_exclude,
750                                &nb_include, &file_include);
751
752         run_calcsize(argument->config, "GNUTAR", argument->dle.disk, dirname,
753                      argument->level, file_exclude, file_include);
754
755         if (argument->verbose == 0) {
756             if (file_exclude)
757                 unlink(file_exclude);
758             if (file_include)
759                 unlink(file_include);
760         }
761         return;
762     }
763
764     if (!gnutar_path) {
765         errmsg = vstrallocf(_("GNUTAR-PATH not defined"));
766         goto common_error;
767     }
768
769     if (!gnutar_listdir) {
770         errmsg = vstrallocf(_("GNUTAR-LISTDIR not defined"));
771         goto common_error;
772     }
773
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);
780
781         start_time = curclock();
782
783         if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
784             errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
785                                 strerror(errno));
786             goto common_exit;
787         }
788
789         tarpid = pipespawnv(cmd, STDERR_PIPE, 1,
790                             &nullfd, &nullfd, &pipefd,
791                             (char **)argv_ptr->pdata);
792
793         dumpout = fdopen(pipefd,"r");
794         if (!dumpout) {
795             error(_("Can't fdopen: %s"), strerror(errno));
796             /*NOTREACHED*/
797         }
798
799         size = (off_t)-1;
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';
803             if (line[0] == '\0')
804                 continue;
805             dbprintf("%s\n", line);
806             /* check for size match */
807             /*@ignore@*/
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);
812                         if(size < 0.0)
813                             size = 1.0;             /* found on NeXT -- sigh */
814                     }
815                     break;
816                 }
817             }
818             /*@end@*/
819         }
820
821         while (fgets(line, sizeof(line), dumpout) != NULL) {
822             dbprintf("%s", line);
823         }
824
825         dbprintf(".....\n");
826         dbprintf(_("estimate time for %s level %d: %s\n"),
827                  qdisk,
828                  level,
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);
833             dbprintf(".....\n");
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);
837             dbprintf(".....\n");
838         }
839         dbprintf(_("estimate size for %s level %d: %lld KB\n"),
840                  qdisk,
841                  level,
842                  (long long)size);
843
844         kill(-tarpid, SIGTERM);
845
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());
855             } else {
856                 /* Normal exit */
857             }
858         } else {
859             errmsg = vstrallocf(_("%s got bad exit: see %s"),
860                                 cmd, dbfn());
861         }
862         dbprintf(_("after %s %s wait\n"), cmd, qdisk);
863
864 common_exit:
865         if (errmsg) {
866             dbprintf("%s", errmsg);
867             fprintf(stdout, "ERROR %s\n", errmsg);
868         }
869
870         if (incrname) {
871             unlink(incrname);
872         }
873
874         if (argument->verbose == 0) {
875             if (file_exclude)
876                 unlink(file_exclude);
877             if (file_include)
878                 unlink(file_include);
879         }
880
881         g_ptr_array_free_full(argv_ptr);
882         amfree(cmd);
883
884         aclose(nullfd);
885         afclose(dumpout);
886
887         fprintf(stdout, "%d %lld 1\n", level, (long long)size);
888     }
889     amfree(qdisk);
890     return;
891
892 common_error:
893     qerrmsg = quote_string(errmsg);
894     amfree(qdisk);
895     dbprintf("%s", errmsg);
896     fprintf(stdout, "ERROR %s\n", qerrmsg);
897     amfree(errmsg);
898     amfree(qerrmsg);
899     return;
900 }
901
902 static void
903 amgtar_backup(
904     application_argument_t *argument)
905 {
906     int         dumpin;
907     char      *cmd = NULL;
908     char      *qdisk;
909     char      *incrname;
910     char       line[32768];
911     amregex_t *rp;
912     off_t      dump_size = -1;
913     char      *type;
914     char       startchr;
915     int        dataf = 1;
916     int        mesgf = 3;
917     int        indexf = 4;
918     int        outf;
919     FILE      *mesgstream;
920     FILE      *indexstream = NULL;
921     FILE      *outstream;
922     char      *errmsg = NULL;
923     amwait_t   wait_status;
924     GPtrArray *argv_ptr;
925     int        tarpid;
926     char      *file_exclude;
927     char      *file_include;
928
929     mesgstream = fdopen(mesgf, "w");
930     if (!mesgstream) {
931         error(_("error mesgstream(%d): %s\n"), mesgf, strerror(errno));
932     }
933
934     if (!gnutar_path) {
935         error(_("GNUTAR-PATH not defined"));
936     }
937     if (!gnutar_listdir) {
938         error(_("GNUTAR-LISTDIR not defined"));
939     }
940
941     if (!argument->level) {
942         fprintf(mesgstream, "? No level argument\n");
943         error(_("No level argument"));
944     }
945     if (!argument->dle.disk) {
946         fprintf(mesgstream, "? No disk argument\n");
947         error(_("No disk argument"));
948     }
949     if (!argument->dle.device) {
950         fprintf(mesgstream, "? No device argument\n");
951         error(_("No device argument"));
952     }
953
954     qdisk = quote_string(argument->dle.disk);
955
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);
962
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 */
966
967     aclose(dumpin);
968     aclose(dataf);
969     if (argument->dle.create_index) {
970         indexstream = fdopen(indexf, "w");
971         if (!indexstream) {
972             error(_("error indexstream(%d): %s\n"), indexf, strerror(errno));
973         }
974     }
975     outstream = fdopen(outf, "r");
976     if (!outstream) {
977         error(_("error outstream(%d): %s\n"), outf, strerror(errno));
978     }
979
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 . */
986             }
987         } else { /* message */
988             for(rp = re_table; rp->regex != NULL; rp++) {
989                 if(match(rp->regex, line)) {
990                     break;
991                 }
992             }
993             if(rp->typ == DMP_SIZE) {
994                 dump_size = (off_t)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0);
995             }
996             switch(rp->typ) {
997             case DMP_NORMAL:
998                 type = "normal";
999                 startchr = '|';
1000                 break;
1001             case DMP_IGNORE:
1002                 continue;
1003             case DMP_STRANGE:
1004                 type = "strange";
1005                 startchr = '?';
1006                 break;
1007             case DMP_SIZE:
1008                 type = "size";
1009                 startchr = '|';
1010                 break;
1011             case DMP_ERROR:
1012                 type = "error";
1013                 startchr = '?';
1014                 break;
1015             default:
1016                 type = "unknown";
1017                 startchr = '!';
1018                 break;
1019             }
1020             dbprintf("%3d: %7s(%c): %s\n", rp->srcline, type, startchr, line);
1021             fprintf(mesgstream,"%c %s\n", startchr, line);
1022         }
1023     }
1024
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());
1033         } else {
1034             /* Normal exit */
1035         }
1036     } else {
1037         errmsg = vstrallocf(_("%s got bad exit: see %s"),
1038                             cmd, dbfn());
1039     }
1040     dbprintf(_("after %s %s wait\n"), cmd, qdisk);
1041     dbprintf(_("amgtar: %s: pid %ld\n"), cmd, (long)tarpid);
1042     if (errmsg) {
1043         dbprintf("%s", errmsg);
1044         g_fprintf(mesgstream, "sendbackup: error [%s]\n", errmsg);
1045     }
1046
1047     if (!errmsg && incrname && strlen(incrname) > 4) {
1048         if (argument->dle.record) {
1049             char *nodotnew;
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));
1057             }
1058             amfree(nodotnew);
1059         } else {
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));
1065             }
1066         }
1067     }
1068
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");
1073
1074     if (argument->dle.create_index)
1075         fclose(indexstream);
1076
1077     fclose(mesgstream);
1078
1079     if (argument->verbose == 0) {
1080         if (file_exclude)
1081             unlink(file_exclude);
1082         if (file_include)
1083             unlink(file_include);
1084     }
1085
1086     amfree(incrname);
1087     amfree(qdisk);
1088     amfree(cmd);
1089     g_ptr_array_free_full(argv_ptr);
1090 }
1091
1092 static void
1093 amgtar_restore(
1094     application_argument_t *argument)
1095 {
1096     char       *cmd;
1097     GPtrArray  *argv_ptr = g_ptr_array_new();
1098     char      **env;
1099     int         j;
1100     char       *e;
1101     char       *include_filename = NULL;
1102     char       *exclude_filename = NULL;
1103     int         tarpid;
1104
1105     if (!gnutar_path) {
1106         error(_("GNUTAR-PATH not defined"));
1107     }
1108
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"));
1114     if (gnutar_acls)
1115         g_ptr_array_add(argv_ptr, stralloc("--acls"));
1116     if (gnutar_selinux)
1117         g_ptr_array_add(argv_ptr, stralloc("--selinux"));
1118     if (gnutar_xattrs)
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));
1128             exit(1);
1129         }
1130         if (!S_ISDIR(stat_buf.st_mode)) {
1131             fprintf(stderr,"%s is not a directory\n", gnutar_directory);
1132             exit(1);
1133         }
1134         if (access(gnutar_directory, W_OK) != 0) {
1135             fprintf(stderr, "Can't write to %s: %s\n", gnutar_directory, strerror(errno));
1136             exit(1);
1137         }
1138         g_ptr_array_add(argv_ptr, stralloc("--directory"));
1139         g_ptr_array_add(argv_ptr, stralloc(gnutar_directory));
1140     }
1141
1142     g_ptr_array_add(argv_ptr, stralloc("--wildcards"));
1143     if (argument->dle.exclude_list &&
1144         argument->dle.exclude_list->nb_element == 1) {
1145         FILE      *exclude;
1146         char      *sdisk;
1147         int        in_argv;
1148         int        entry_in_exclude = 0;
1149         char       line[2*PATH_MAX];
1150         FILE      *exclude_list;
1151
1152         if (argument->dle.disk) {
1153             sdisk = sanitise_filename(argument->dle.disk);
1154         } else {
1155             sdisk = g_strdup_printf("no_dle-%d", getpid());
1156         }
1157         exclude_filename= vstralloc(AMANDA_TMPDIR, "/", "exclude-", sdisk,  NULL);
1158         exclude_list = fopen(argument->dle.exclude_list->first->name, "r");
1159
1160         exclude = fopen(exclude_filename, "w");
1161         while (fgets(line, 2*PATH_MAX, exclude_list)) {
1162             char *escaped;
1163             line[strlen(line)-1] = '\0'; /* remove '\n' */
1164             escaped = escape_tar_glob(line, &in_argv);
1165             if (in_argv) {
1166                 g_ptr_array_add(argv_ptr, "--exclude");
1167                 g_ptr_array_add(argv_ptr, escaped);
1168             } else {
1169                 fprintf(exclude,"%s\n", escaped);
1170                 entry_in_exclude++;
1171                 amfree(escaped);
1172             }
1173         }
1174         fclose(exclude);
1175         g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1176         g_ptr_array_add(argv_ptr, exclude_filename);
1177     }
1178
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));
1182     }
1183
1184     {
1185         GPtrArray *argv_include = g_ptr_array_new();
1186         FILE      *include;
1187         char      *sdisk;
1188         int        in_argv;
1189         guint      i;
1190         int        entry_in_include = 0;
1191
1192         if (argument->dle.disk) {
1193             sdisk = sanitise_filename(argument->dle.disk);
1194         } else {
1195             sdisk = g_strdup_printf("no_dle-%d", getpid());
1196         }
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)) {
1204                 char *escaped;
1205                 line[strlen(line)-1] = '\0'; /* remove '\n' */
1206                 escaped = escape_tar_glob(line, &in_argv);
1207                 if (in_argv) {
1208                     g_ptr_array_add(argv_include, escaped);
1209                 } else {
1210                     fprintf(include,"%s\n", escaped);
1211                     entry_in_include++;
1212                     amfree(escaped);
1213                 }
1214             }
1215         }
1216
1217         for (j=1; j< argument->argc; j++) {
1218             char *escaped = escape_tar_glob(argument->argv[j], &in_argv);
1219             if (in_argv) {
1220                 g_ptr_array_add(argv_include, escaped);
1221             } else {
1222                 fprintf(include,"%s\n", escaped);
1223                 entry_in_include++;
1224                 amfree(escaped);
1225             }
1226         }
1227         fclose(include);
1228
1229         if (entry_in_include) {
1230             g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1231             g_ptr_array_add(argv_ptr, include_filename);
1232         }
1233
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));
1237         }
1238
1239         for (i = 0; i < argv_include->len; i++) {
1240             g_ptr_array_add(argv_ptr, (char *)g_ptr_array_index(argv_include,i));
1241         }
1242     }
1243     g_ptr_array_add(argv_ptr, NULL);
1244
1245     debug_executing(argv_ptr);
1246
1247     tarpid = fork();
1248     switch (tarpid) {
1249     case -1: error(_("%s: fork returned: %s"), get_pname(), strerror(errno));
1250     case 0:
1251         env = safe_env();
1252         become_root();
1253         execve(cmd, (char **)argv_ptr->pdata, env);
1254         e = strerror(errno);
1255         error(_("error [exec %s: %s]"), cmd, e);
1256         break;
1257     default: break;
1258     }
1259
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);
1266     }
1267 }
1268
1269 static void
1270 amgtar_validate(
1271     application_argument_t *argument G_GNUC_UNUSED)
1272 {
1273     char       *cmd;
1274     GPtrArray  *argv_ptr = g_ptr_array_new();
1275     char      **env;
1276     char       *e;
1277     char        buf[32768];
1278
1279     if (!gnutar_path) {
1280         dbprintf("GNUTAR-PATH not set; Piping to /dev/null\n");
1281         fprintf(stderr,"GNUTAR-PATH not set; Piping to /dev/null\n");
1282         goto pipe_to_null;
1283     }
1284
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);
1292
1293     debug_executing(argv_ptr);
1294     env = safe_env();
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);
1299 pipe_to_null:
1300     while (read(0, buf, 32768) > 0) {
1301     }
1302 }
1303
1304 static void
1305 amgtar_build_exinclude(
1306     dle_t  *dle,
1307     int     verbose,
1308     int    *nb_exclude,
1309     char  **file_exclude,
1310     int    *nb_include,
1311     char  **file_include)
1312 {
1313     int n_exclude = 0;
1314     int n_include = 0;
1315     char *exclude = NULL;
1316     char *include = NULL;
1317
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;
1322
1323     if (n_exclude > 0) exclude = build_exclude(dle, verbose);
1324     if (n_include > 0) include = build_include(dle, verbose);
1325
1326     if (nb_exclude)
1327         *nb_exclude = n_exclude;
1328     if (file_exclude)
1329         *file_exclude = exclude;
1330     else
1331         amfree(exclude);
1332
1333     if (nb_include)
1334         *nb_include = n_include;
1335     if (file_include)
1336         *file_include = include;
1337     else
1338         amfree(include);
1339 }
1340
1341 static char *
1342 amgtar_get_incrname(
1343     application_argument_t *argument,
1344     int                     level,
1345     FILE                   *mesgstream,
1346     int                     command)
1347 {
1348     char *basename = NULL;
1349     char *incrname = NULL;
1350     int   infd, outfd;
1351     ssize_t   nb;
1352     char *inputname = NULL;
1353     char *errmsg = NULL;
1354     char *buf;
1355
1356     if (gnutar_listdir) {
1357         char number[NUM_STR_SIZE];
1358         int baselevel;
1359         char *sdisk = sanitise_filename(argument->dle.disk);
1360
1361         basename = vstralloc(gnutar_listdir,
1362                              "/",
1363                              argument->host,
1364                              sdisk,
1365                              NULL);
1366         amfree(sdisk);
1367
1368         snprintf(number, SIZEOF(number), "%d", level);
1369         incrname = vstralloc(basename, "_", number, ".new", NULL);
1370         unlink(incrname);
1371
1372         /*
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.
1376          */
1377         baselevel = level;
1378         infd = -1;
1379         while (infd == -1) {
1380             if (--baselevel >= 0) {
1381                 snprintf(number, SIZEOF(number), "%d", baselevel);
1382                 inputname = newvstralloc(inputname,
1383                                          basename, "_", number, NULL);
1384             } else {
1385                 inputname = newstralloc(inputname, "/dev/null");
1386             }
1387             if ((infd = open(inputname, O_RDONLY)) == -1) {
1388
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);
1395                     } else {
1396                         fprintf(mesgstream, "? %s\n", errmsg);
1397                     }
1398                     exit(1);
1399                 }
1400                 amfree(errmsg);
1401             }
1402         }
1403
1404         /*
1405          * Copy the previous listed incremental file to the new one.
1406          */
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);
1413             } else {
1414                 fprintf(mesgstream, "? %s\n", errmsg);
1415             }
1416             exit(1);
1417         }
1418
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);
1424                 return NULL;
1425             }
1426         }
1427
1428         if (nb < 0) {
1429             errmsg = vstrallocf(_("reading from %s: %s"),
1430                                  inputname, strerror(errno));
1431             dbprintf("%s\n", errmsg);
1432             return NULL;
1433         }
1434
1435         if (close(infd) != 0) {
1436             errmsg = vstrallocf(_("closing %s: %s"),
1437                                  inputname, strerror(errno));
1438             dbprintf("%s\n", errmsg);
1439             return NULL;
1440         }
1441         if (close(outfd) != 0) {
1442             errmsg = vstrallocf(_("closing %s: %s"),
1443                                  incrname, strerror(errno));
1444             dbprintf("%s\n", errmsg);
1445             return NULL;
1446         }
1447
1448         amfree(inputname);
1449         amfree(basename);
1450     }
1451     return incrname;
1452 }
1453
1454 GPtrArray *amgtar_build_argv(
1455     application_argument_t *argument,
1456     char  *incrname,
1457     char **file_exclude,
1458     char **file_include,
1459     int    command)
1460 {
1461     int    nb_exclude;
1462     int    nb_include;
1463     char  *dirname;
1464     char   tmppath[PATH_MAX];
1465     GPtrArray *argv_ptr = g_ptr_array_new();
1466     GSList    *copt;
1467
1468     amgtar_build_exinclude(&argument->dle, 1,
1469                            &nb_exclude, file_exclude,
1470                            &nb_include, file_include);
1471
1472     if (gnutar_directory) {
1473         dirname = gnutar_directory;
1474     } else {
1475         dirname = argument->dle.device;
1476     }
1477
1478     g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1479
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"));
1486     } else {
1487         g_ptr_array_add(argv_ptr, stralloc("-"));
1488     }
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"));
1500     if (gnutar_acls)
1501         g_ptr_array_add(argv_ptr, stralloc("--acls"));
1502     if (gnutar_selinux)
1503         g_ptr_array_add(argv_ptr, stralloc("--selinux"));
1504     if (gnutar_xattrs)
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));
1508     if (gnutar_sparse)
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));
1513     }
1514     g_ptr_array_add(argv_ptr, stralloc("--ignore-failed-read"));
1515     g_ptr_array_add(argv_ptr, stralloc("--totals"));
1516
1517     for (copt = argument->command_options; copt != NULL; copt = copt->next) {
1518         g_ptr_array_add(argv_ptr, stralloc((char *)copt->data));
1519     }
1520
1521     if (*file_exclude) {
1522         g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1523         g_ptr_array_add(argv_ptr, stralloc(*file_exclude));
1524     }
1525
1526     if (*file_include) {
1527         g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1528         g_ptr_array_add(argv_ptr, stralloc(*file_include));
1529     }
1530     else {
1531         g_ptr_array_add(argv_ptr, stralloc("."));
1532     }
1533     g_ptr_array_add(argv_ptr, NULL);
1534
1535     return(argv_ptr);
1536 }
1537