Imported Upstream version 3.2.0
[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_directory = NULL;
300     gnutar_onefilesystem = 1;
301     gnutar_atimepreserve = 1;
302     gnutar_acls = 0;
303     gnutar_selinux = 0;
304     gnutar_xattrs = 0;
305     gnutar_checkdevice = 1;
306     gnutar_sparse = 1;
307     gnutar_no_unquote = 0;
308     exit_handling = NULL;
309
310     /* initialize */
311
312     /*
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.
317      */
318     setlocale(LC_MESSAGES, "C");
319     textdomain("amanda");
320
321     if (argc < 2) {
322         printf("ERROR no command given to amgtar\n");
323         error(_("No command given to amgtar"));
324     }
325
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");
330         }
331         error(_("amgtar must be run setuid root"));
332     }
333
334     safe_fd(3, 2);
335
336     set_pname("amgtar");
337
338     /* Don't die when child closes pipe */
339     signal(SIGPIPE, SIG_IGN);
340
341 #if defined(USE_DBMALLOC)
342     malloc_size_1 = malloc_inuse(&malloc_hist_1);
343 #endif
344
345     add_amanda_log_handler(amanda_log_stderr);
346     add_amanda_log_handler(amanda_log_syslog);
347     dbopen(DBG_SUBDIR_CLIENT);
348     startclock();
349     dbprintf(_("version %s\n"), VERSION);
350
351     config_init(CONFIG_INIT_CLIENT, NULL);
352
353     //check_running_as(RUNNING_AS_DUMPUSER_PREFERRED);
354     //root for amrecover
355     //RUNNING_AS_CLIENT_LOGIN from selfcheck, sendsize, sendbackup
356
357     /* parse argument */
358     command = argv[1];
359
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);
372
373     while (1) {
374         int option_index = 0;
375         c = getopt_long (argc, argv, "", long_options, &option_index);
376         if (c == -1) {
377             break;
378         }
379         switch (c) {
380         case 1: argument.config = stralloc(optarg);
381                 break;
382         case 2: argument.host = stralloc(optarg);
383                 break;
384         case 3: argument.dle.disk = stralloc(optarg);
385                 break;
386         case 4: argument.dle.device = stralloc(optarg);
387                 break;
388         case 5: argument.level = g_slist_append(argument.level,
389                                                 GINT_TO_POINTER(atoi(optarg)));
390                 break;
391         case 6: argument.dle.create_index = 1;
392                 break;
393         case 7: argument.message = 1;
394                 break;
395         case 8: argument.collection = 1;
396                 break;
397         case 9: argument.dle.record = 1;
398                 break;
399         case 10: gnutar_path = stralloc(optarg);
400                  break;
401         case 11: gnutar_listdir = stralloc(optarg);
402                  break;
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);
409                  break;
410         case 13: if (optarg && strcasecmp(optarg, "NO") == 0)
411                      gnutar_sparse = 0;
412                  else if (optarg && strcasecmp(optarg, "YES") == 0)
413                      gnutar_sparse = 1;
414                  else if (strcasecmp(command, "selfcheck") == 0)
415                      printf(_("ERROR [%s: bad SPARSE property value (%s)]\n"), get_pname(), optarg);
416                  break;
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);
423                  break;
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);
430                  break;
431         case 16: if (optarg)
432                      argument.dle.include_file =
433                          append_sl(argument.dle.include_file, optarg);
434                  break;
435         case 17: if (optarg)
436                      argument.dle.include_list =
437                          append_sl(argument.dle.include_list, optarg);
438                  break;
439         case 18: argument.dle.include_optional = 1;
440                  break;
441         case 19: if (optarg)
442                      argument.dle.exclude_file =
443                          append_sl(argument.dle.exclude_file, optarg);
444                  break;
445         case 20: if (optarg)
446                      argument.dle.exclude_list =
447                          append_sl(argument.dle.exclude_list, optarg);
448                  break;
449         case 21: argument.dle.exclude_optional = 1;
450                  break;
451         case 22: gnutar_directory = stralloc(optarg);
452                  break;
453         case 23: if (optarg)
454                      normal_message = 
455                          g_slist_append(normal_message, optarg);
456                  break;
457         case 24: if (optarg)
458                      ignore_message = 
459                          g_slist_append(ignore_message, optarg);
460                  break;
461         case 25: if (optarg)
462                      strange_message = 
463                          g_slist_append(strange_message, optarg);
464                  break;
465         case 26: if (optarg)
466                      exit_handling = stralloc(optarg);
467                  break;
468         case 27: argument.calcsize = 1;
469                  break;
470         case 28: argument.tar_blocksize = stralloc(optarg);
471                  break;
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);
478                  break;
479         case 30: if (optarg && strcasecmp(optarg, "YES") == 0)
480                    gnutar_acls = 1;
481                  break;
482         case 31: if (optarg && strcasecmp(optarg, "YES") == 0)
483                    gnutar_selinux = 1;
484                  break;
485         case 32: if (optarg && strcasecmp(optarg, "YES") == 0)
486                    gnutar_xattrs = 1;
487                  break;
488         case 33: argument.command_options =
489                         g_slist_append(argument.command_options,
490                                        stralloc(optarg));
491                  break;
492         case 34: if (optarg)
493                      argument.include_list_glob = stralloc(optarg);
494                  break;
495         case 35: if (optarg)
496                      argument.exclude_list_glob = stralloc(optarg);
497                  break;
498         case 36: if (optarg  && strcasecmp(optarg, "YES") == 0)
499                      argument.verbose = 1;
500                  break;
501         case ':':
502         case '?':
503                 break;
504         }
505     }
506
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);
511
512     argument.argc = argc - optind;
513     argument.argv = argv + optind;
514
515     if (argument.config) {
516         config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
517                     argument.config);
518         dbrename(get_config_name(), DBG_SUBDIR_CLIENT);
519     }
520
521     if (config_errors(NULL) >= CFGERR_ERRORS) {
522         g_critical(_("errors processing config file"));
523     }
524
525     re_table = build_re_table(init_re_table, normal_message, ignore_message,
526                               strange_message);
527
528     for(i=0;i<256;i++)
529         exit_value[i] = 1; /* BAD  */
530     exit_value[0] = 0;     /* GOOD */
531     exit_value[1] = 0;     /* GOOD */
532     if (exit_handling) {
533         char *s = exit_handling;
534         while (s) {
535             char *r = strchr(s, '=');
536             if (r) {
537                 int j = atoi(s);
538                 if (j >= 0 && j < 256) {
539                     r++;
540                     if (strncasecmp(r, "GOOD", 4) == 0) {
541                         exit_value[j] = 0;
542                     }
543                 }
544             }
545             s = strchr(s+1, ' ');
546         }
547     }
548
549     gnutar_listdir = getconf_str(CNF_GNUTAR_LIST_DIR);
550     if (strlen(gnutar_listdir) == 0)
551         gnutar_listdir = NULL;
552
553     if (gnutar_path) {
554         dbprintf("GNUTAR-PATH %s\n", gnutar_path);
555     } else {
556         dbprintf("GNUTAR-PATH is not set\n");
557     }
558     if (gnutar_listdir) {
559             dbprintf("GNUTAR-LISTDIR %s\n", gnutar_listdir);
560     } else {
561         dbprintf("GNUTAR-LISTDIR is not set\n");
562     }
563     if (gnutar_directory) {
564         dbprintf("DIRECTORY %s\n", gnutar_directory);
565     }
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");
574     {
575         amregex_t *rp;
576         for (rp = re_table; rp->regex != NULL; rp++) {
577             switch (rp->typ) {
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;
583             }
584         }
585     }
586
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);
599     } else {
600         dbprintf("Unknown command `%s'.\n", command);
601         fprintf(stderr, "Unknown command `%s'.\n", command);
602         exit (1);
603     }
604     return 0;
605 }
606
607 static void
608 amgtar_support(
609     application_argument_t *argument)
610 {
611     (void)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");
633 }
634
635 static void
636 amgtar_selfcheck(
637     application_argument_t *argument)
638 {
639     amgtar_build_exinclude(&argument->dle, 1, NULL, NULL, NULL, NULL);
640
641     printf("OK amgtar\n");
642     if (gnutar_path) {
643         check_file(gnutar_path, X_OK);
644     } else {
645         printf(_("ERROR [GNUTAR program not available]\n"));
646     }
647
648     set_root_privs(1);
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);
653     } else {
654         printf(_("ERROR [No GNUTAR-LISTDIR]\n"));
655     }
656
657     if (argument->dle.disk) {
658         char *qdisk = quote_string(argument->dle.disk);
659         fprintf(stdout, "OK %s\n", qdisk);
660         amfree(qdisk);
661     }
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);
666     }
667     if (argument->calcsize) {
668         char *calcsize = vstralloc(amlibexecdir, "/", "calcsize", NULL);
669         check_file(calcsize, X_OK);
670         check_suid(calcsize);
671         amfree(calcsize);
672     }
673     set_root_privs(0);
674 }
675
676 static void
677 amgtar_estimate(
678     application_argument_t *argument)
679 {
680     char      *incrname = NULL;
681     GPtrArray *argv_ptr;
682     char      *cmd = NULL;
683     int        nullfd = -1;
684     int        pipefd = -1;
685     FILE      *dumpout = NULL;
686     off_t      size = -1;
687     char       line[32768];
688     char      *errmsg = NULL;
689     char      *qerrmsg = NULL;
690     char      *qdisk;
691     amwait_t   wait_status;
692     int        tarpid;
693     amregex_t *rp;
694     times_t    start_time;
695     int        level;
696     GSList    *levels;
697     char      *file_exclude;
698     char      *file_include;
699
700     if (!argument->level) {
701         fprintf(stderr, "ERROR No level argument\n");
702         error(_("No level argument"));
703     }
704     if (!argument->dle.disk) {
705         fprintf(stderr, "ERROR No disk argument\n");
706         error(_("No disk argument"));
707     }
708     if (!argument->dle.device) {
709         fprintf(stderr, "ERROR No device argument\n");
710         error(_("No device argument"));
711     }
712
713     qdisk = quote_string(argument->dle.disk);
714
715     if (argument->calcsize) {
716         char *dirname;
717         int   nb_exclude;
718         int   nb_include;
719
720         if (gnutar_directory) {
721             dirname = gnutar_directory;
722         } else {
723             dirname = amname_to_dirname(argument->dle.device);
724         }
725         amgtar_build_exinclude(&argument->dle, 1,
726                                &nb_exclude, &file_exclude,
727                                &nb_include, &file_include);
728
729         run_calcsize(argument->config, "GNUTAR", argument->dle.disk, dirname,
730                      argument->level, file_exclude, file_include);
731
732         if (argument->verbose == 0) {
733             if (file_exclude)
734                 unlink(file_exclude);
735             if (file_include)
736                 unlink(file_include);
737         }
738         return;
739     }
740
741     if (!gnutar_path) {
742         errmsg = vstrallocf(_("GNUTAR-PATH not defined"));
743         goto common_error;
744     }
745
746     if (!gnutar_listdir) {
747         errmsg = vstrallocf(_("GNUTAR-LISTDIR not defined"));
748         goto common_error;
749     }
750
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);
757
758         start_time = curclock();
759
760         if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
761             errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
762                                 strerror(errno));
763             goto common_exit;
764         }
765
766         tarpid = pipespawnv(cmd, STDERR_PIPE, 1,
767                             &nullfd, &nullfd, &pipefd,
768                             (char **)argv_ptr->pdata);
769
770         dumpout = fdopen(pipefd,"r");
771         if (!dumpout) {
772             error(_("Can't fdopen: %s"), strerror(errno));
773             /*NOTREACHED*/
774         }
775
776         size = (off_t)-1;
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';
780             if (line[0] == '\0')
781                 continue;
782             dbprintf("%s\n", line);
783             /* check for size match */
784             /*@ignore@*/
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);
789                         if(size < 0.0)
790                             size = 1.0;             /* found on NeXT -- sigh */
791                     }
792                     break;
793                 }
794             }
795             /*@end@*/
796         }
797
798         while (fgets(line, sizeof(line), dumpout) != NULL) {
799             dbprintf("%s", line);
800         }
801
802         dbprintf(".....\n");
803         dbprintf(_("estimate time for %s level %d: %s\n"),
804                  qdisk,
805                  level,
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);
810             dbprintf(".....\n");
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);
814             dbprintf(".....\n");
815         }
816         dbprintf(_("estimate size for %s level %d: %lld KB\n"),
817                  qdisk,
818                  level,
819                  (long long)size);
820
821         kill(-tarpid, SIGTERM);
822
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());
832             } else {
833                 /* Normal exit */
834             }
835         } else {
836             errmsg = vstrallocf(_("%s got bad exit: see %s"),
837                                 cmd, dbfn());
838         }
839         dbprintf(_("after %s %s wait\n"), cmd, qdisk);
840
841 common_exit:
842         if (errmsg) {
843             dbprintf("%s", errmsg);
844             fprintf(stdout, "ERROR %s\n", errmsg);
845         }
846
847         if (incrname) {
848             unlink(incrname);
849         }
850
851         if (argument->verbose == 0) {
852             if (file_exclude)
853                 unlink(file_exclude);
854             if (file_include)
855                 unlink(file_include);
856         }
857
858         g_ptr_array_free_full(argv_ptr);
859         amfree(cmd);
860
861         aclose(nullfd);
862         afclose(dumpout);
863
864         fprintf(stdout, "%d %lld 1\n", level, (long long)size);
865     }
866     amfree(qdisk);
867     return;
868
869 common_error:
870     qerrmsg = quote_string(errmsg);
871     amfree(qdisk);
872     dbprintf("%s", errmsg);
873     fprintf(stdout, "ERROR %s\n", qerrmsg);
874     amfree(errmsg);
875     amfree(qerrmsg);
876     return;
877 }
878
879 static void
880 amgtar_backup(
881     application_argument_t *argument)
882 {
883     int         dumpin;
884     char      *cmd = NULL;
885     char      *qdisk;
886     char      *incrname;
887     char       line[32768];
888     amregex_t *rp;
889     off_t      dump_size = -1;
890     char      *type;
891     char       startchr;
892     int        dataf = 1;
893     int        mesgf = 3;
894     int        indexf = 4;
895     int        outf;
896     FILE      *mesgstream;
897     FILE      *indexstream = NULL;
898     FILE      *outstream;
899     char      *errmsg = NULL;
900     amwait_t   wait_status;
901     GPtrArray *argv_ptr;
902     int        tarpid;
903     char      *file_exclude;
904     char      *file_include;
905
906     mesgstream = fdopen(mesgf, "w");
907     if (!mesgstream) {
908         error(_("error mesgstream(%d): %s\n"), mesgf, strerror(errno));
909     }
910
911     if (!gnutar_path) {
912         error(_("GNUTAR-PATH not defined"));
913     }
914     if (!gnutar_listdir) {
915         error(_("GNUTAR-LISTDIR not defined"));
916     }
917
918     if (!argument->level) {
919         fprintf(mesgstream, "? No level argument\n");
920         error(_("No level argument"));
921     }
922     if (!argument->dle.disk) {
923         fprintf(mesgstream, "? No disk argument\n");
924         error(_("No disk argument"));
925     }
926     if (!argument->dle.device) {
927         fprintf(mesgstream, "? No device argument\n");
928         error(_("No device argument"));
929     }
930
931     qdisk = quote_string(argument->dle.disk);
932
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);
939
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 */
943
944     aclose(dumpin);
945     aclose(dataf);
946     if (argument->dle.create_index) {
947         indexstream = fdopen(indexf, "w");
948         if (!indexstream) {
949             error(_("error indexstream(%d): %s\n"), indexf, strerror(errno));
950         }
951     }
952     outstream = fdopen(outf, "r");
953     if (!outstream) {
954         error(_("error outstream(%d): %s\n"), outf, strerror(errno));
955     }
956
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 . */
963             }
964         } else { /* message */
965             for(rp = re_table; rp->regex != NULL; rp++) {
966                 if(match(rp->regex, line)) {
967                     break;
968                 }
969             }
970             if(rp->typ == DMP_SIZE) {
971                 dump_size = (long)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0);
972             }
973             switch(rp->typ) {
974             case DMP_NORMAL:
975                 type = "normal";
976                 startchr = '|';
977                 break;
978             case DMP_IGNORE:
979                 continue;
980             case DMP_STRANGE:
981                 type = "strange";
982                 startchr = '?';
983                 break;
984             case DMP_SIZE:
985                 type = "size";
986                 startchr = '|';
987                 break;
988             case DMP_ERROR:
989                 type = "error";
990                 startchr = '?';
991                 break;
992             default:
993                 type = "unknown";
994                 startchr = '!';
995                 break;
996             }
997             dbprintf("%3d: %7s(%c): %s\n", rp->srcline, type, startchr, line);
998             fprintf(mesgstream,"%c %s\n", startchr, line);
999         }
1000     }
1001
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());
1010         } else {
1011             /* Normal exit */
1012         }
1013     } else {
1014         errmsg = vstrallocf(_("%s got bad exit: see %s"),
1015                             cmd, dbfn());
1016     }
1017     dbprintf(_("after %s %s wait\n"), cmd, qdisk);
1018     dbprintf(_("amgtar: %s: pid %ld\n"), cmd, (long)tarpid);
1019     if (errmsg) {
1020         dbprintf("%s", errmsg);
1021         g_fprintf(mesgstream, "sendbackup: error [%s]\n", errmsg);
1022     }
1023
1024     if (!errmsg && incrname && strlen(incrname) > 4) {
1025         char *nodotnew;
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));
1033         }
1034         amfree(nodotnew);
1035     }
1036
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");
1041
1042     if (argument->dle.create_index)
1043         fclose(indexstream);
1044
1045     fclose(mesgstream);
1046
1047     if (argument->verbose == 0) {
1048         if (file_exclude)
1049             unlink(file_exclude);
1050         if (file_include)
1051             unlink(file_include);
1052     }
1053
1054     amfree(incrname);
1055     amfree(qdisk);
1056     amfree(cmd);
1057     g_ptr_array_free_full(argv_ptr);
1058 }
1059
1060 static void
1061 amgtar_restore(
1062     application_argument_t *argument)
1063 {
1064     char       *cmd;
1065     GPtrArray  *argv_ptr = g_ptr_array_new();
1066     char      **env;
1067     int         j;
1068     char       *e;
1069     char       *include_filename = NULL;
1070     char       *exclude_filename = NULL;
1071     int         tarpid;
1072
1073     if (!gnutar_path) {
1074         error(_("GNUTAR-PATH not defined"));
1075     }
1076
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"));
1082     if (gnutar_acls)
1083         g_ptr_array_add(argv_ptr, stralloc("--acls"));
1084     if (gnutar_selinux)
1085         g_ptr_array_add(argv_ptr, stralloc("--selinux"));
1086     if (gnutar_xattrs)
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));
1096             exit(1);
1097         }
1098         if (!S_ISDIR(stat_buf.st_mode)) {
1099             fprintf(stderr,"%s is not a directory\n", gnutar_directory);
1100             exit(1);
1101         }
1102         if (access(gnutar_directory, W_OK) != 0) {
1103             fprintf(stderr, "Can't write to %s: %s\n", gnutar_directory, strerror(errno));
1104             exit(1);
1105         }
1106         g_ptr_array_add(argv_ptr, stralloc("--directory"));
1107         g_ptr_array_add(argv_ptr, stralloc(gnutar_directory));
1108     }
1109
1110     g_ptr_array_add(argv_ptr, stralloc("--wildcards"));
1111     if (argument->dle.exclude_list &&
1112         argument->dle.exclude_list->nb_element == 1) {
1113         FILE      *exclude;
1114         char      *sdisk;
1115         int        in_argv;
1116         int        entry_in_exclude = 0;
1117         char       line[2*PATH_MAX];
1118         FILE      *exclude_list;
1119
1120         if (argument->dle.disk) {
1121             sdisk = sanitise_filename(argument->dle.disk);
1122         } else {
1123             sdisk = g_strdup_printf("no_dle-%d", getpid());
1124         }
1125         exclude_filename= vstralloc(AMANDA_TMPDIR, "/", "exclude-", sdisk,  NULL);
1126         exclude_list = fopen(argument->dle.exclude_list->first->name, "r");
1127
1128         exclude = fopen(exclude_filename, "w");
1129         while (fgets(line, 2*PATH_MAX, exclude_list)) {
1130             char *escaped;
1131             line[strlen(line)-1] = '\0'; /* remove '\n' */
1132             escaped = escape_tar_glob(line, &in_argv);
1133             if (in_argv) {
1134                 g_ptr_array_add(argv_ptr, "--exclude");
1135                 g_ptr_array_add(argv_ptr, escaped);
1136             } else {
1137                 fprintf(exclude,"%s\n", escaped);
1138                 entry_in_exclude++;
1139                 amfree(escaped);
1140             }
1141         }
1142         fclose(exclude);
1143         g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1144         g_ptr_array_add(argv_ptr, exclude_filename);
1145     }
1146
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));
1150     }
1151
1152     {
1153         GPtrArray *argv_include = g_ptr_array_new();
1154         FILE      *include;
1155         char      *sdisk;
1156         int        in_argv;
1157         guint      i;
1158         int        entry_in_include = 0;
1159
1160         if (argument->dle.disk) {
1161             sdisk = sanitise_filename(argument->dle.disk);
1162         } else {
1163             sdisk = g_strdup_printf("no_dle-%d", getpid());
1164         }
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)) {
1172                 char *escaped;
1173                 line[strlen(line)-1] = '\0'; /* remove '\n' */
1174                 escaped = escape_tar_glob(line, &in_argv);
1175                 if (in_argv) {
1176                     g_ptr_array_add(argv_include, escaped);
1177                 } else {
1178                     fprintf(include,"%s\n", escaped);
1179                     entry_in_include++;
1180                     amfree(escaped);
1181                 }
1182             }
1183         }
1184
1185         for (j=1; j< argument->argc; j++) {
1186             char *escaped = escape_tar_glob(argument->argv[j], &in_argv);
1187             if (in_argv) {
1188                 g_ptr_array_add(argv_include, escaped);
1189             } else {
1190                 fprintf(include,"%s\n", escaped);
1191                 entry_in_include++;
1192                 amfree(escaped);
1193             }
1194         }
1195         fclose(include);
1196
1197         if (entry_in_include) {
1198             g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1199             g_ptr_array_add(argv_ptr, include_filename);
1200         }
1201
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));
1205         }
1206
1207         for (i = 0; i < argv_include->len; i++) {
1208             g_ptr_array_add(argv_ptr, (char *)g_ptr_array_index(argv_include,i));
1209         }
1210     }
1211     g_ptr_array_add(argv_ptr, NULL);
1212
1213     debug_executing(argv_ptr);
1214
1215     tarpid = fork();
1216     switch (tarpid) {
1217     case -1: error(_("%s: fork returned: %s"), get_pname(), strerror(errno));
1218     case 0:
1219         env = safe_env();
1220         become_root();
1221         execve(cmd, (char **)argv_ptr->pdata, env);
1222         e = strerror(errno);
1223         error(_("error [exec %s: %s]"), cmd, e);
1224         break;
1225     default: break;
1226     }
1227
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);
1234     }
1235 }
1236
1237 static void
1238 amgtar_validate(
1239     application_argument_t *argument G_GNUC_UNUSED)
1240 {
1241     char       *cmd;
1242     GPtrArray  *argv_ptr = g_ptr_array_new();
1243     char      **env;
1244     char       *e;
1245     char        buf[32768];
1246
1247     if (!gnutar_path) {
1248         dbprintf("GNUTAR-PATH not set; Piping to /dev/null\n");
1249         fprintf(stderr,"GNUTAR-PATH not set; Piping to /dev/null\n");
1250         goto pipe_to_null;
1251     }
1252
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);
1260
1261     debug_executing(argv_ptr);
1262     env = safe_env();
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);
1267 pipe_to_null:
1268     while (read(0, buf, 32768) > 0) {
1269     }
1270 }
1271
1272 static void
1273 amgtar_build_exinclude(
1274     dle_t  *dle,
1275     int     verbose,
1276     int    *nb_exclude,
1277     char  **file_exclude,
1278     int    *nb_include,
1279     char  **file_include)
1280 {
1281     int n_exclude = 0;
1282     int n_include = 0;
1283     char *exclude = NULL;
1284     char *include = NULL;
1285
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;
1290
1291     if (n_exclude > 0) exclude = build_exclude(dle, verbose);
1292     if (n_include > 0) include = build_include(dle, verbose);
1293
1294     if (nb_exclude)
1295         *nb_exclude = n_exclude;
1296     if (file_exclude)
1297         *file_exclude = exclude;
1298     else
1299         amfree(exclude);
1300
1301     if (nb_include)
1302         *nb_include = n_include;
1303     if (file_include)
1304         *file_include = include;
1305     else
1306         amfree(include);
1307 }
1308
1309 static char *
1310 amgtar_get_incrname(
1311     application_argument_t *argument,
1312     int                     level,
1313     FILE                   *mesgstream,
1314     int                     command)
1315 {
1316     char *basename = NULL;
1317     char *incrname = NULL;
1318     int   infd, outfd;
1319     ssize_t   nb;
1320     char *inputname = NULL;
1321     char *errmsg = NULL;
1322     char *buf;
1323
1324     if (gnutar_listdir) {
1325         char number[NUM_STR_SIZE];
1326         int baselevel;
1327         char *sdisk = sanitise_filename(argument->dle.disk);
1328
1329         basename = vstralloc(gnutar_listdir,
1330                              "/",
1331                              argument->host,
1332                              sdisk,
1333                              NULL);
1334         amfree(sdisk);
1335
1336         snprintf(number, SIZEOF(number), "%d", level);
1337         incrname = vstralloc(basename, "_", number, ".new", NULL);
1338         unlink(incrname);
1339
1340         /*
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.
1344          */
1345         baselevel = level;
1346         infd = -1;
1347         while (infd == -1) {
1348             if (--baselevel >= 0) {
1349                 snprintf(number, SIZEOF(number), "%d", baselevel);
1350                 inputname = newvstralloc(inputname,
1351                                          basename, "_", number, NULL);
1352             } else {
1353                 inputname = newstralloc(inputname, "/dev/null");
1354             }
1355             if ((infd = open(inputname, O_RDONLY)) == -1) {
1356
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);
1363                     } else {
1364                         fprintf(mesgstream, "? %s\n", errmsg);
1365                     }
1366                     exit(1);
1367                 }
1368                 amfree(errmsg);
1369             }
1370         }
1371
1372         /*
1373          * Copy the previous listed incremental file to the new one.
1374          */
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);
1381             } else {
1382                 fprintf(mesgstream, "? %s\n", errmsg);
1383             }
1384             exit(1);
1385         }
1386
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);
1392                 return NULL;
1393             }
1394         }
1395
1396         if (nb < 0) {
1397             errmsg = vstrallocf(_("reading from %s: %s"),
1398                                  inputname, strerror(errno));
1399             dbprintf("%s\n", errmsg);
1400             return NULL;
1401         }
1402
1403         if (close(infd) != 0) {
1404             errmsg = vstrallocf(_("closing %s: %s"),
1405                                  inputname, strerror(errno));
1406             dbprintf("%s\n", errmsg);
1407             return NULL;
1408         }
1409         if (close(outfd) != 0) {
1410             errmsg = vstrallocf(_("closing %s: %s"),
1411                                  incrname, strerror(errno));
1412             dbprintf("%s\n", errmsg);
1413             return NULL;
1414         }
1415
1416         amfree(inputname);
1417         amfree(basename);
1418     }
1419     return incrname;
1420 }
1421
1422 GPtrArray *amgtar_build_argv(
1423     application_argument_t *argument,
1424     char  *incrname,
1425     char **file_exclude,
1426     char **file_include,
1427     int    command)
1428 {
1429     int    nb_exclude;
1430     int    nb_include;
1431     char  *dirname;
1432     char   tmppath[PATH_MAX];
1433     GPtrArray *argv_ptr = g_ptr_array_new();
1434     GSList    *copt;
1435
1436     amgtar_build_exinclude(&argument->dle, 1,
1437                            &nb_exclude, file_exclude,
1438                            &nb_include, file_include);
1439
1440     if (gnutar_directory) {
1441         dirname = gnutar_directory;
1442     } else {
1443         dirname = amname_to_dirname(argument->dle.device);
1444     }
1445
1446     g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1447
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"));
1454     } else {
1455         g_ptr_array_add(argv_ptr, stralloc("-"));
1456     }
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"));
1468     if (gnutar_acls)
1469         g_ptr_array_add(argv_ptr, stralloc("--acls"));
1470     if (gnutar_selinux)
1471         g_ptr_array_add(argv_ptr, stralloc("--selinux"));
1472     if (gnutar_xattrs)
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));
1476     if (gnutar_sparse)
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));
1481     }
1482     g_ptr_array_add(argv_ptr, stralloc("--ignore-failed-read"));
1483     g_ptr_array_add(argv_ptr, stralloc("--totals"));
1484
1485     for (copt = argument->command_options; copt != NULL; copt = copt->next) {
1486         g_ptr_array_add(argv_ptr, stralloc((char *)copt->data));
1487     }
1488
1489     if (*file_exclude) {
1490         g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1491         g_ptr_array_add(argv_ptr, stralloc(*file_exclude));
1492     }
1493
1494     if (*file_include) {
1495         g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1496         g_ptr_array_add(argv_ptr, stralloc(*file_include));
1497     }
1498     else {
1499         g_ptr_array_add(argv_ptr, stralloc("."));
1500     }
1501     g_ptr_array_add(argv_ptr, NULL);
1502
1503     return(argv_ptr);
1504 }
1505