947a986ed25e28eb2d4a69c103e5ccbac5edbeb9
[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  */
61
62 #include "amanda.h"
63 #include "match.h"
64 #include "pipespawn.h"
65 #include "amfeatures.h"
66 #include "clock.h"
67 #include "util.h"
68 #include "getfsent.h"
69 #include "client_util.h"
70 #include "conffile.h"
71 #include "getopt.h"
72
73 int debug_application = 1;
74 #define application_debug(i, ...) do {  \
75         if ((i) <= debug_application) { \
76             dbprintf(__VA_ARGS__);      \
77         }                               \
78 } while (0)
79
80 static amregex_t init_re_table[] = {
81   /* tar prints the size in bytes */
82   AM_SIZE_RE("^ *Total bytes written: [0-9][0-9]*", 1, 1),
83   AM_NORMAL_RE("^could not open conf file"),
84   AM_NORMAL_RE("^Elapsed time:"),
85   AM_NORMAL_RE("^Throughput"),
86   AM_IGNORE_RE(": Directory is new$"),
87   AM_IGNORE_RE(": Directory has been renamed"),
88
89   /* GNU tar 1.13.17 will print this warning when (not) backing up a
90      Unix named socket.  */
91   AM_NORMAL_RE(": socket ignored$"),
92
93   /* GNUTAR produces a few error messages when files are modified or
94      removed while it is running.  They may cause data to be lost, but
95      then they may not.  We shouldn't consider them NORMAL until
96      further investigation.  */
97   AM_NORMAL_RE(": File .* shrunk by [0-9][0-9]* bytes, padding with zeros"),
98   AM_NORMAL_RE(": Cannot add file .*: No such file or directory$"),
99   AM_NORMAL_RE(": Error exit delayed from previous errors"),
100   
101   /* catch-all: DMP_STRANGE is returned for all other lines */
102   AM_STRANGE_RE(NULL)
103 };
104 static amregex_t *re_table;
105
106 /* local functions */
107 int main(int argc, char **argv);
108
109 typedef struct application_argument_s {
110     char      *config;
111     char      *host;
112     int        message;
113     int        collection;
114     int        calcsize;
115     char      *tar_blocksize;
116     GSList    *level;
117     GSList    *command_options;
118     char      *include_list_glob;
119     char      *exclude_list_glob;
120     dle_t      dle;
121     int        argc;
122     char     **argv;
123 } application_argument_t;
124
125 enum { CMD_ESTIMATE, CMD_BACKUP };
126
127 static void amgtar_support(application_argument_t *argument);
128 static void amgtar_selfcheck(application_argument_t *argument);
129 static void amgtar_estimate(application_argument_t *argument);
130 static void amgtar_backup(application_argument_t *argument);
131 static void amgtar_restore(application_argument_t *argument);
132 static void amgtar_validate(application_argument_t *argument);
133 static void amgtar_build_exinclude(dle_t *dle, int verbose,
134                                    int *nb_exclude, char **file_exclude,
135                                    int *nb_include, char **file_include);
136 static char *amgtar_get_incrname(application_argument_t *argument, int level,
137                                  FILE *mesgstream, int command);
138 static GPtrArray *amgtar_build_argv(application_argument_t *argument,
139                                 char *incrname, int command);
140 static char *gnutar_path;
141 static char *gnutar_listdir;
142 static char *gnutar_directory;
143 static int gnutar_onefilesystem;
144 static int gnutar_atimepreserve;
145 static int gnutar_acls;
146 static int gnutar_selinux;
147 static int gnutar_xattrs;
148 static int gnutar_checkdevice;
149 static int gnutar_no_unquote;
150 static int gnutar_sparse;
151 static GSList *normal_message = NULL;
152 static GSList *ignore_message = NULL;
153 static GSList *strange_message = NULL;
154 static char   *exit_handling;
155 static int    exit_value[256];
156
157 static struct option long_options[] = {
158     {"config"          , 1, NULL,  1},
159     {"host"            , 1, NULL,  2},
160     {"disk"            , 1, NULL,  3},
161     {"device"          , 1, NULL,  4},
162     {"level"           , 1, NULL,  5},
163     {"index"           , 1, NULL,  6},
164     {"message"         , 1, NULL,  7},
165     {"collection"      , 0, NULL,  8},
166     {"record"          , 0, NULL,  9},
167     {"gnutar-path"     , 1, NULL, 10},
168     {"gnutar-listdir"  , 1, NULL, 11},
169     {"one-file-system" , 1, NULL, 12},
170     {"sparse"          , 1, NULL, 13},
171     {"atime-preserve"  , 1, NULL, 14},
172     {"check-device"    , 1, NULL, 15},
173     {"include-file"    , 1, NULL, 16},
174     {"include-list"    , 1, NULL, 17},
175     {"include-optional", 1, NULL, 18},
176     {"exclude-file"    , 1, NULL, 19},
177     {"exclude-list"    , 1, NULL, 20},
178     {"exclude-optional", 1, NULL, 21},
179     {"directory"       , 1, NULL, 22},
180     {"normal"          , 1, NULL, 23},
181     {"ignore"          , 1, NULL, 24},
182     {"strange"         , 1, NULL, 25},
183     {"exit-handling"   , 1, NULL, 26},
184     {"calcsize"        , 0, NULL, 27},
185     {"tar-blocksize"   , 1, NULL, 28},
186     {"no-unquote"      , 1, NULL, 29},
187     {"acls"            , 1, NULL, 30},
188     {"selinux"         , 1, NULL, 31},
189     {"xattrs"          , 1, NULL, 32},
190     {"command-options" , 1, NULL, 33},
191     {"include-list-glob", 1, NULL, 34},
192     {"exclude-list-glob", 1, NULL, 35},
193     {NULL, 0, NULL, 0}
194 };
195
196 static char *
197 escape_tar_glob(
198     char *str,
199     int  *in_argv)
200 {
201     char *result = malloc(4*strlen(str)+1);
202     char *r = result;
203     char *s;
204
205     *in_argv = 0;
206     for (s = str; *s != '\0'; s++) {
207         if (*s == '\\') {
208             char c = *(s+1);
209             if (c == '\\') {
210                 *r++ = '\\';
211                 *r++ = '\\';
212                 *r++ = '\\';
213                 s++;
214             } else if (c == '?') {
215                 *r++ = 127;
216                 s++;
217                 continue;
218             } else if (c == 'a') {
219                 *r++ = 7;
220                 s++;
221                 continue;
222             } else if (c == 'b') {
223                 *r++ = 8;
224                 s++;
225                 continue;
226             } else if (c == 'f') {
227                 *r++ = 12;
228                 s++;
229                 continue;
230             } else if (c == 'n') {
231                 *r++ = 10;
232                 s++;
233                 *in_argv = 1;
234                 continue;
235             } else if (c == 'r') {
236                 *r++ = 13;
237                 s++;
238                 *in_argv = 1;
239                 continue;
240             } else if (c == 't') {
241                 *r++ = 9;
242                 s++;
243                 continue;
244             } else if (c == 'v') {
245                 *r++ = 11;
246                 s++;
247                 continue;
248             } else if (c >= '0' && c <= '9') {
249                 char d = c-'0';
250                 s++;
251                 c = *(s+1);
252                 if (c >= '0' && c <= '9') {
253                     d = (d*8)+(c-'0');
254                     s++;
255                     c = *(s+1);
256                     if (c >= '0' && c <= '9') {
257                         d = (d*8)+(c-'0');
258                         s++;
259                     }
260                 }
261                 *r++ = d;
262                 continue;
263             } else {
264                 *r++ = '\\';
265             }
266         } else if (*s == '?') {
267             *r++ = '\\';
268             *r++ = '\\';
269         } else if (*s == '*' || *s == '[') {
270             *r++ = '\\';
271         }
272         *r++ = *s;
273     }
274     *r = '\0';
275
276     return result;
277 }
278
279
280 int
281 main(
282     int         argc,
283     char **     argv)
284 {
285     int c;
286     char *command;
287     application_argument_t argument;
288     int i;
289
290 #ifdef GNUTAR
291     gnutar_path = GNUTAR;
292 #else
293     gnutar_path = NULL;
294 #endif
295     gnutar_directory = NULL;
296     gnutar_onefilesystem = 1;
297     gnutar_atimepreserve = 1;
298     gnutar_acls = 0;
299     gnutar_selinux = 0;
300     gnutar_xattrs = 0;
301     gnutar_checkdevice = 1;
302     gnutar_sparse = 1;
303     gnutar_no_unquote = 0;
304     exit_handling = NULL;
305
306     /* initialize */
307
308     /*
309      * Configure program for internationalization:
310      *   1) Only set the message locale for now.
311      *   2) Set textdomain for all amanda related programs to "amanda"
312      *      We don't want to be forced to support dozens of message catalogs.
313      */
314     setlocale(LC_MESSAGES, "C");
315     textdomain("amanda");
316
317     if (argc < 2) {
318         printf("ERROR no command given to amgtar\n");
319         error(_("No command given to amgtar"));
320     }
321
322     /* drop root privileges */
323     if (!set_root_privs(0)) {
324         if (strcmp(argv[1], "selfcheck") == 0) {
325             printf("ERROR amgtar must be run setuid root\n");
326         }
327         error(_("amgtar must be run setuid root"));
328     }
329
330     safe_fd(3, 2);
331
332     set_pname("amgtar");
333
334     /* Don't die when child closes pipe */
335     signal(SIGPIPE, SIG_IGN);
336
337 #if defined(USE_DBMALLOC)
338     malloc_size_1 = malloc_inuse(&malloc_hist_1);
339 #endif
340
341     add_amanda_log_handler(amanda_log_stderr);
342     add_amanda_log_handler(amanda_log_syslog);
343     dbopen(DBG_SUBDIR_CLIENT);
344     startclock();
345     dbprintf(_("version %s\n"), VERSION);
346
347     config_init(CONFIG_INIT_CLIENT, NULL);
348
349     //check_running_as(RUNNING_AS_DUMPUSER_PREFERRED);
350     //root for amrecover
351     //RUNNING_AS_CLIENT_LOGIN from selfcheck, sendsize, sendbackup
352
353     /* parse argument */
354     command = argv[1];
355
356     argument.config     = NULL;
357     argument.host       = NULL;
358     argument.message    = 0;
359     argument.collection = 0;
360     argument.calcsize   = 0;
361     argument.tar_blocksize = NULL;
362     argument.level      = NULL;
363     argument.command_options = NULL;
364     argument.include_list_glob = NULL;
365     argument.exclude_list_glob = NULL;
366     init_dle(&argument.dle);
367
368     while (1) {
369         int option_index = 0;
370         c = getopt_long (argc, argv, "", long_options, &option_index);
371         if (c == -1) {
372             break;
373         }
374         switch (c) {
375         case 1: argument.config = stralloc(optarg);
376                 break;
377         case 2: argument.host = stralloc(optarg);
378                 break;
379         case 3: argument.dle.disk = stralloc(optarg);
380                 break;
381         case 4: argument.dle.device = stralloc(optarg);
382                 break;
383         case 5: argument.level = g_slist_append(argument.level,
384                                                 GINT_TO_POINTER(atoi(optarg)));
385                 break;
386         case 6: argument.dle.create_index = 1;
387                 break;
388         case 7: argument.message = 1;
389                 break;
390         case 8: argument.collection = 1;
391                 break;
392         case 9: argument.dle.record = 1;
393                 break;
394         case 10: gnutar_path = stralloc(optarg);
395                  break;
396         case 11: gnutar_listdir = stralloc(optarg);
397                  break;
398         case 12: if (optarg && strcasecmp(optarg, "NO") == 0)
399                      gnutar_onefilesystem = 0;
400                  else if (optarg && strcasecmp(optarg, "YES") == 0)
401                      gnutar_onefilesystem = 1;
402                  else if (strcasecmp(command, "selfcheck") == 0)
403                      printf(_("ERROR [%s: bad ONE-FILE-SYSTEM property value (%s)]\n"), get_pname(), optarg);
404                  break;
405         case 13: if (optarg && strcasecmp(optarg, "NO") == 0)
406                      gnutar_sparse = 0;
407                  else if (optarg && strcasecmp(optarg, "YES") == 0)
408                      gnutar_sparse = 1;
409                  else if (strcasecmp(command, "selfcheck") == 0)
410                      printf(_("ERROR [%s: bad SPARSE property value (%s)]\n"), get_pname(), optarg);
411                  break;
412         case 14: if (optarg && strcasecmp(optarg, "NO") == 0)
413                      gnutar_atimepreserve = 0;
414                  else if (optarg && strcasecmp(optarg, "YES") == 0)
415                      gnutar_atimepreserve = 1;
416                  else if (strcasecmp(command, "selfcheck") == 0)
417                      printf(_("ERROR [%s: bad ATIME-PRESERVE property value (%s)]\n"), get_pname(), optarg);
418                  break;
419         case 15: if (optarg && strcasecmp(optarg, "NO") == 0)
420                      gnutar_checkdevice = 0;
421                  else if (optarg && strcasecmp(optarg, "YES") == 0)
422                      gnutar_checkdevice = 1;
423                  else if (strcasecmp(command, "selfcheck") == 0)
424                      printf(_("ERROR [%s: bad CHECK-DEVICE property value (%s)]\n"), get_pname(), optarg);
425                  break;
426         case 16: if (optarg)
427                      argument.dle.include_file =
428                          append_sl(argument.dle.include_file, optarg);
429                  break;
430         case 17: if (optarg)
431                      argument.dle.include_list =
432                          append_sl(argument.dle.include_list, optarg);
433                  break;
434         case 18: argument.dle.include_optional = 1;
435                  break;
436         case 19: if (optarg)
437                      argument.dle.exclude_file =
438                          append_sl(argument.dle.exclude_file, optarg);
439                  break;
440         case 20: if (optarg)
441                      argument.dle.exclude_list =
442                          append_sl(argument.dle.exclude_list, optarg);
443                  break;
444         case 21: argument.dle.exclude_optional = 1;
445                  break;
446         case 22: gnutar_directory = stralloc(optarg);
447                  break;
448         case 23: if (optarg)
449                      normal_message = 
450                          g_slist_append(normal_message, optarg);
451                  break;
452         case 24: if (optarg)
453                      ignore_message = 
454                          g_slist_append(ignore_message, optarg);
455                  break;
456         case 25: if (optarg)
457                      strange_message = 
458                          g_slist_append(strange_message, optarg);
459                  break;
460         case 26: if (optarg)
461                      exit_handling = stralloc(optarg);
462                  break;
463         case 27: argument.calcsize = 1;
464                  break;
465         case 28: argument.tar_blocksize = stralloc(optarg);
466                  break;
467         case 29: if (optarg && strcasecmp(optarg, "NO") == 0)
468                      gnutar_no_unquote = 0;
469                  else if (optarg && strcasecmp(optarg, "YES") == 0)
470                      gnutar_no_unquote = 1;
471                  else if (strcasecmp(command, "selfcheck") == 0)
472                      printf(_("ERROR [%s: bad No_UNQUOTE property value (%s)]\n"), get_pname(), optarg);
473                  break;
474         case 30: if (optarg && strcasecmp(optarg, "YES") == 0)
475                    gnutar_acls = 1;
476                  break;
477         case 31: if (optarg && strcasecmp(optarg, "YES") == 0)
478                    gnutar_selinux = 1;
479                  break;
480         case 32: if (optarg && strcasecmp(optarg, "YES") == 0)
481                    gnutar_xattrs = 1;
482                  break;
483         case 33: argument.command_options =
484                         g_slist_append(argument.command_options,
485                                        stralloc(optarg));
486                  break;
487         case 34: if (optarg)
488                      argument.include_list_glob = stralloc(optarg);
489                  break;
490         case 35: if (optarg)
491                      argument.exclude_list_glob = stralloc(optarg);
492                  break;
493         case ':':
494         case '?':
495                 break;
496         }
497     }
498
499     if (!argument.dle.disk && argument.dle.device)
500         argument.dle.disk = stralloc(argument.dle.device);
501     if (!argument.dle.device && argument.dle.disk)
502         argument.dle.device = stralloc(argument.dle.disk);
503
504     argument.argc = argc - optind;
505     argument.argv = argv + optind;
506
507     if (argument.config) {
508         config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
509                     argument.config);
510         dbrename(get_config_name(), DBG_SUBDIR_CLIENT);
511     }
512
513     if (config_errors(NULL) >= CFGERR_ERRORS) {
514         g_critical(_("errors processing config file"));
515     }
516
517     re_table = build_re_table(init_re_table, normal_message, ignore_message,
518                               strange_message);
519
520     for(i=0;i<256;i++)
521         exit_value[i] = 1; /* BAD  */
522     exit_value[0] = 0;     /* GOOD */
523     exit_value[1] = 0;     /* GOOD */
524     if (exit_handling) {
525         char *s = exit_handling;
526         while (s) {
527             char *r = strchr(s, '=');
528             if (r) {
529                 int j = atoi(s);
530                 if (j >= 0 && j < 256) {
531                     r++;
532                     if (strncasecmp(r, "GOOD", 4) == 0) {
533                         exit_value[j] = 0;
534                     }
535                 }
536             }
537             s = strchr(s+1, ' ');
538         }
539     }
540
541     gnutar_listdir = getconf_str(CNF_GNUTAR_LIST_DIR);
542     if (strlen(gnutar_listdir) == 0)
543         gnutar_listdir = NULL;
544
545     if (gnutar_path) {
546         dbprintf("GNUTAR-PATH %s\n", gnutar_path);
547     } else {
548         dbprintf("GNUTAR-PATH is not set\n");
549     }
550     if (gnutar_listdir) {
551             dbprintf("GNUTAR-LISTDIR %s\n", gnutar_listdir);
552     } else {
553         dbprintf("GNUTAR-LISTDIR is not set\n");
554     }
555     if (gnutar_directory) {
556         dbprintf("DIRECTORY %s\n", gnutar_directory);
557     }
558     dbprintf("ONE-FILE-SYSTEM %s\n", gnutar_onefilesystem? "yes":"no");
559     dbprintf("SPARSE %s\n", gnutar_sparse? "yes":"no");
560     dbprintf("NO-UNQUOTE %s\n", gnutar_no_unquote? "yes":"no");
561     dbprintf("ATIME-PRESERVE %s\n", gnutar_atimepreserve? "yes":"no");
562     dbprintf("ACLS %s\n", gnutar_acls? "yes":"no");
563     dbprintf("SELINUX %s\n", gnutar_selinux? "yes":"no");
564     dbprintf("XATTRS %s\n", gnutar_xattrs? "yes":"no");
565     dbprintf("CHECK-DEVICE %s\n", gnutar_checkdevice? "yes":"no");
566     {
567         amregex_t *rp;
568         for (rp = re_table; rp->regex != NULL; rp++) {
569             switch (rp->typ) {
570                 case DMP_NORMAL : dbprintf("NORMAL %s\n", rp->regex); break;
571                 case DMP_IGNORE : dbprintf("IGNORE %s\n", rp->regex); break;
572                 case DMP_STRANGE: dbprintf("STRANGE %s\n", rp->regex); break;
573                 case DMP_SIZE   : dbprintf("SIZE %s\n", rp->regex); break;
574                 case DMP_ERROR  : dbprintf("ERROR %s\n", rp->regex); break;
575             }
576         }
577     }
578
579     if (strcmp(command, "support") == 0) {
580         amgtar_support(&argument);
581     } else if (strcmp(command, "selfcheck") == 0) {
582         amgtar_selfcheck(&argument);
583     } else if (strcmp(command, "estimate") == 0) {
584         amgtar_estimate(&argument);
585     } else if (strcmp(command, "backup") == 0) {
586         amgtar_backup(&argument);
587     } else if (strcmp(command, "restore") == 0) {
588         amgtar_restore(&argument);
589     } else if (strcmp(command, "validate") == 0) {
590         amgtar_validate(&argument);
591     } else {
592         dbprintf("Unknown command `%s'.\n", command);
593         fprintf(stderr, "Unknown command `%s'.\n", command);
594         exit (1);
595     }
596     return 0;
597 }
598
599 static void
600 amgtar_support(
601     application_argument_t *argument)
602 {
603     (void)argument;
604     fprintf(stdout, "CONFIG YES\n");
605     fprintf(stdout, "HOST YES\n");
606     fprintf(stdout, "DISK YES\n");
607     fprintf(stdout, "MAX-LEVEL 399\n");
608     fprintf(stdout, "INDEX-LINE YES\n");
609     fprintf(stdout, "INDEX-XML NO\n");
610     fprintf(stdout, "MESSAGE-LINE YES\n");
611     fprintf(stdout, "MESSAGE-XML NO\n");
612     fprintf(stdout, "RECORD YES\n");
613     fprintf(stdout, "INCLUDE-FILE YES\n");
614     fprintf(stdout, "INCLUDE-LIST YES\n");
615     fprintf(stdout, "INCLUDE-LIST-GLOB YES\n");
616     fprintf(stdout, "INCLUDE-OPTIONAL YES\n");
617     fprintf(stdout, "EXCLUDE-FILE YES\n");
618     fprintf(stdout, "EXCLUDE-LIST YES\n");
619     fprintf(stdout, "EXCLUDE-LIST-GLOB YES\n");
620     fprintf(stdout, "EXCLUDE-OPTIONAL YES\n");
621     fprintf(stdout, "COLLECTION NO\n");
622     fprintf(stdout, "MULTI-ESTIMATE YES\n");
623     fprintf(stdout, "CALCSIZE YES\n");
624     fprintf(stdout, "CLIENT-ESTIMATE YES\n");
625 }
626
627 static void
628 amgtar_selfcheck(
629     application_argument_t *argument)
630 {
631     amgtar_build_exinclude(&argument->dle, 1, NULL, NULL, NULL, NULL);
632
633     printf("OK amgtar\n");
634     if (gnutar_path) {
635         check_file(gnutar_path, X_OK);
636     } else {
637         printf(_("ERROR [GNUTAR program not available]\n"));
638     }
639
640     set_root_privs(1);
641     if (gnutar_listdir && strlen(gnutar_listdir) == 0)
642         gnutar_listdir = NULL;
643     if (gnutar_listdir) {
644         check_dir(gnutar_listdir, R_OK|W_OK);
645     } else {
646         printf(_("ERROR [No GNUTAR-LISTDIR]\n"));
647     }
648
649     if (argument->dle.disk) {
650         char *qdisk = quote_string(argument->dle.disk);
651         fprintf(stdout, "OK %s\n", qdisk);
652         amfree(qdisk);
653     }
654     if (gnutar_directory) {
655         check_dir(gnutar_directory, R_OK);
656     } else if (argument->dle.device) {
657         check_dir(argument->dle.device, R_OK);
658     }
659     if (argument->calcsize) {
660         char *calcsize = vstralloc(amlibexecdir, "/", "calcsize", NULL);
661         check_file(calcsize, X_OK);
662         check_suid(calcsize);
663         amfree(calcsize);
664     }
665     set_root_privs(0);
666 }
667
668 static void
669 amgtar_estimate(
670     application_argument_t *argument)
671 {
672     char      *incrname = NULL;
673     GPtrArray *argv_ptr;
674     char      *cmd = NULL;
675     int        nullfd = -1;
676     int        pipefd = -1;
677     FILE      *dumpout = NULL;
678     off_t      size = -1;
679     char       line[32768];
680     char      *errmsg = NULL;
681     char      *qerrmsg = NULL;
682     char      *qdisk;
683     amwait_t   wait_status;
684     int        tarpid;
685     amregex_t *rp;
686     times_t    start_time;
687     int        level;
688     GSList    *levels;
689
690     if (!argument->level) {
691         fprintf(stderr, "ERROR No level argument\n");
692         error(_("No level argument"));
693     }
694     if (!argument->dle.disk) {
695         fprintf(stderr, "ERROR No disk argument\n");
696         error(_("No disk argument"));
697     }
698     if (!argument->dle.device) {
699         fprintf(stderr, "ERROR No device argument\n");
700         error(_("No device argument"));
701     }
702
703     qdisk = quote_string(argument->dle.disk);
704
705     if (argument->calcsize) {
706         char *dirname;
707         char *file_exclude;
708         char *file_include;
709         int   nb_exclude;
710         int   nb_include;
711
712         if (gnutar_directory) {
713             dirname = gnutar_directory;
714         } else {
715             dirname = amname_to_dirname(argument->dle.device);
716         }
717         amgtar_build_exinclude(&argument->dle, 1,
718                                &nb_exclude, &file_exclude,
719                                &nb_include, &file_include);
720
721         run_calcsize(argument->config, "GNUTAR", argument->dle.disk, dirname,
722                      argument->level, file_exclude, file_include);
723         return;
724     }
725
726     if (!gnutar_path) {
727         errmsg = vstrallocf(_("GNUTAR-PATH not defined"));
728         goto common_error;
729     }
730
731     if (!gnutar_listdir) {
732         errmsg = vstrallocf(_("GNUTAR-LISTDIR not defined"));
733         goto common_error;
734     }
735
736     for (levels = argument->level; levels != NULL; levels = levels->next) {
737         level = GPOINTER_TO_INT(levels->data);
738         incrname = amgtar_get_incrname(argument, level, stdout, CMD_ESTIMATE);
739         cmd = stralloc(gnutar_path);
740         argv_ptr = amgtar_build_argv(argument, incrname, CMD_ESTIMATE);
741
742         start_time = curclock();
743
744         if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
745             errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
746                                 strerror(errno));
747             goto common_exit;
748         }
749
750         tarpid = pipespawnv(cmd, STDERR_PIPE, 1,
751                             &nullfd, &nullfd, &pipefd,
752                             (char **)argv_ptr->pdata);
753
754         dumpout = fdopen(pipefd,"r");
755         if (!dumpout) {
756             error(_("Can't fdopen: %s"), strerror(errno));
757             /*NOTREACHED*/
758         }
759
760         size = (off_t)-1;
761         while (size < 0 && (fgets(line, sizeof(line), dumpout) != NULL)) {
762             if (line[strlen(line)-1] == '\n') /* remove trailling \n */
763                 line[strlen(line)-1] = '\0';
764             if (line[0] == '\0')
765                 continue;
766             dbprintf("%s\n", line);
767             /* check for size match */
768             /*@ignore@*/
769             for(rp = re_table; rp->regex != NULL; rp++) {
770                 if(match(rp->regex, line)) {
771                     if (rp->typ == DMP_SIZE) {
772                         size = ((the_num(line, rp->field)*rp->scale+1023.0)/1024.0);
773                         if(size < 0.0)
774                             size = 1.0;             /* found on NeXT -- sigh */
775                     }
776                     break;
777                 }
778             }
779             /*@end@*/
780         }
781
782         while (fgets(line, sizeof(line), dumpout) != NULL) {
783             dbprintf("%s", line);
784         }
785
786         dbprintf(".....\n");
787         dbprintf(_("estimate time for %s level %d: %s\n"),
788                  qdisk,
789                  level,
790                  walltime_str(timessub(curclock(), start_time)));
791         if(size == (off_t)-1) {
792             errmsg = vstrallocf(_("no size line match in %s output"), cmd);
793             dbprintf(_("%s for %s\n"), errmsg, qdisk);
794             dbprintf(".....\n");
795         } else if(size == (off_t)0 && argument->level == 0) {
796             dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"),
797                      cmd, argument->dle.disk);
798             dbprintf(".....\n");
799         }
800         dbprintf(_("estimate size for %s level %d: %lld KB\n"),
801                  qdisk,
802                  level,
803                  (long long)size);
804
805         kill(-tarpid, SIGTERM);
806
807         dbprintf(_("waiting for %s \"%s\" child\n"), cmd, qdisk);
808         waitpid(tarpid, &wait_status, 0);
809         if (WIFSIGNALED(wait_status)) {
810             errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
811                                 cmd, WTERMSIG(wait_status), dbfn());
812         } else if (WIFEXITED(wait_status)) {
813             if (exit_value[WEXITSTATUS(wait_status)] == 1) {
814                 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
815                                     cmd, WEXITSTATUS(wait_status), dbfn());
816             } else {
817                 /* Normal exit */
818             }
819         } else {
820             errmsg = vstrallocf(_("%s got bad exit: see %s"),
821                                 cmd, dbfn());
822         }
823         dbprintf(_("after %s %s wait\n"), cmd, qdisk);
824
825 common_exit:
826         if (errmsg) {
827             dbprintf("%s", errmsg);
828             fprintf(stdout, "ERROR %s\n", errmsg);
829         }
830
831         if (incrname) {
832             unlink(incrname);
833         }
834         g_ptr_array_free_full(argv_ptr);
835         amfree(cmd);
836
837         aclose(nullfd);
838         afclose(dumpout);
839
840         fprintf(stdout, "%d %lld 1\n", level, (long long)size);
841     }
842     amfree(qdisk);
843     return;
844
845 common_error:
846     qerrmsg = quote_string(errmsg);
847     amfree(qdisk);
848     dbprintf("%s", errmsg);
849     fprintf(stdout, "ERROR %s\n", qerrmsg);
850     amfree(errmsg);
851     amfree(qerrmsg);
852     return;
853 }
854
855 static void
856 amgtar_backup(
857     application_argument_t *argument)
858 {
859     int         dumpin;
860     char      *cmd = NULL;
861     char      *qdisk;
862     char      *incrname;
863     char       line[32768];
864     amregex_t *rp;
865     off_t      dump_size = -1;
866     char      *type;
867     char       startchr;
868     int        dataf = 1;
869     int        mesgf = 3;
870     int        indexf = 4;
871     int        outf;
872     FILE      *mesgstream;
873     FILE      *indexstream = NULL;
874     FILE      *outstream;
875     char      *errmsg = NULL;
876     amwait_t   wait_status;
877     GPtrArray *argv_ptr;
878     int        tarpid;
879
880     mesgstream = fdopen(mesgf, "w");
881     if (!mesgstream) {
882         error(_("error mesgstream(%d): %s\n"), mesgf, strerror(errno));
883     }
884
885     if (!gnutar_path) {
886         error(_("GNUTAR-PATH not defined"));
887     }
888     if (!gnutar_listdir) {
889         error(_("GNUTAR-LISTDIR not defined"));
890     }
891
892     if (!argument->level) {
893         fprintf(mesgstream, "? No level argument\n");
894         error(_("No level argument"));
895     }
896     if (!argument->dle.disk) {
897         fprintf(mesgstream, "? No disk argument\n");
898         error(_("No disk argument"));
899     }
900     if (!argument->dle.device) {
901         fprintf(mesgstream, "? No device argument\n");
902         error(_("No device argument"));
903     }
904
905     qdisk = quote_string(argument->dle.disk);
906
907     incrname = amgtar_get_incrname(argument,
908                                    GPOINTER_TO_INT(argument->level->data),
909                                    mesgstream, CMD_BACKUP);
910     cmd = stralloc(gnutar_path);
911     argv_ptr = amgtar_build_argv(argument, incrname, CMD_BACKUP);
912
913     tarpid = pipespawnv(cmd, STDIN_PIPE|STDERR_PIPE, 1,
914                         &dumpin, &dataf, &outf, (char **)argv_ptr->pdata);
915     /* close the write ends of the pipes */
916
917     aclose(dumpin);
918     aclose(dataf);
919     if (argument->dle.create_index) {
920         indexstream = fdopen(indexf, "w");
921         if (!indexstream) {
922             error(_("error indexstream(%d): %s\n"), indexf, strerror(errno));
923         }
924     }
925     outstream = fdopen(outf, "r");
926     if (!outstream) {
927         error(_("error outstream(%d): %s\n"), outf, strerror(errno));
928     }
929
930     while (fgets(line, sizeof(line), outstream) != NULL) {
931         if (line[strlen(line)-1] == '\n') /* remove trailling \n */
932             line[strlen(line)-1] = '\0';
933         if (*line == '.' && *(line+1) == '/') { /* filename */
934             if (argument->dle.create_index) {
935                 fprintf(indexstream, "%s\n", &line[1]); /* remove . */
936             }
937         } else { /* message */
938             for(rp = re_table; rp->regex != NULL; rp++) {
939                 if(match(rp->regex, line)) {
940                     break;
941                 }
942             }
943             if(rp->typ == DMP_SIZE) {
944                 dump_size = (long)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0);
945             }
946             switch(rp->typ) {
947             case DMP_NORMAL:
948                 type = "normal";
949                 startchr = '|';
950                 break;
951             case DMP_IGNORE:
952                 continue;
953             case DMP_STRANGE:
954                 type = "strange";
955                 startchr = '?';
956                 break;
957             case DMP_SIZE:
958                 type = "size";
959                 startchr = '|';
960                 break;
961             case DMP_ERROR:
962                 type = "error";
963                 startchr = '?';
964                 break;
965             default:
966                 type = "unknown";
967                 startchr = '!';
968                 break;
969             }
970             dbprintf("%3d: %7s(%c): %s\n", rp->srcline, type, startchr, line);
971             fprintf(mesgstream,"%c %s\n", startchr, line);
972         }
973     }
974
975     waitpid(tarpid, &wait_status, 0);
976     if (WIFSIGNALED(wait_status)) {
977         errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
978                             cmd, WTERMSIG(wait_status), dbfn());
979     } else if (WIFEXITED(wait_status)) {
980         if (exit_value[WEXITSTATUS(wait_status)] == 1) {
981             errmsg = vstrallocf(_("%s exited with status %d: see %s"),
982                                 cmd, WEXITSTATUS(wait_status), dbfn());
983         } else {
984             /* Normal exit */
985         }
986     } else {
987         errmsg = vstrallocf(_("%s got bad exit: see %s"),
988                             cmd, dbfn());
989     }
990     dbprintf(_("after %s %s wait\n"), cmd, qdisk);
991     dbprintf(_("amgtar: %s: pid %ld\n"), cmd, (long)tarpid);
992     if (errmsg) {
993         dbprintf("%s", errmsg);
994         g_fprintf(mesgstream, "sendbackup: error [%s]\n", errmsg);
995     }
996
997     if (!errmsg && incrname && strlen(incrname) > 4) {
998         char *nodotnew;
999         nodotnew = stralloc(incrname);
1000         nodotnew[strlen(nodotnew)-4] = '\0';
1001         if (rename(incrname, nodotnew)) {
1002             dbprintf(_("%s: warning [renaming %s to %s: %s]\n"),
1003                      get_pname(), incrname, nodotnew, strerror(errno));
1004             g_fprintf(mesgstream, _("? warning [renaming %s to %s: %s]\n"),
1005                       incrname, nodotnew, strerror(errno));
1006         }
1007         amfree(nodotnew);
1008     }
1009
1010     dbprintf("sendbackup: size %lld\n", (long long)dump_size);
1011     fprintf(mesgstream, "sendbackup: size %lld\n", (long long)dump_size);
1012     dbprintf("sendbackup: end\n");
1013     fprintf(mesgstream, "sendbackup: end\n");
1014
1015     if (argument->dle.create_index)
1016         fclose(indexstream);
1017
1018     fclose(mesgstream);
1019
1020     amfree(incrname);
1021     amfree(qdisk);
1022     amfree(cmd);
1023     g_ptr_array_free_full(argv_ptr);
1024 }
1025
1026 static void
1027 amgtar_restore(
1028     application_argument_t *argument)
1029 {
1030     char       *cmd;
1031     GPtrArray  *argv_ptr = g_ptr_array_new();
1032     char      **env;
1033     int         j;
1034     char       *e;
1035
1036     if (!gnutar_path) {
1037         error(_("GNUTAR-PATH not defined"));
1038     }
1039
1040     cmd = stralloc(gnutar_path);
1041     g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1042     g_ptr_array_add(argv_ptr, stralloc("--numeric-owner"));
1043     if (gnutar_no_unquote)
1044         g_ptr_array_add(argv_ptr, stralloc("--no-unquote"));
1045     if (gnutar_acls)
1046         g_ptr_array_add(argv_ptr, stralloc("--acls"));
1047     if (gnutar_selinux)
1048         g_ptr_array_add(argv_ptr, stralloc("--selinux"));
1049     if (gnutar_xattrs)
1050         g_ptr_array_add(argv_ptr, stralloc("--xattrs"));
1051     g_ptr_array_add(argv_ptr, stralloc("-xpGvf"));
1052     g_ptr_array_add(argv_ptr, stralloc("-"));
1053     if (gnutar_directory) {
1054         struct stat stat_buf;
1055         if(stat(gnutar_directory, &stat_buf) != 0) {
1056             fprintf(stderr,"can not stat directory %s: %s\n", gnutar_directory, strerror(errno));
1057             exit(1);
1058         }
1059         if (!S_ISDIR(stat_buf.st_mode)) {
1060             fprintf(stderr,"%s is not a directory\n", gnutar_directory);
1061             exit(1);
1062         }
1063         if (access(gnutar_directory, W_OK) != 0) {
1064             fprintf(stderr, "Can't write to %s: %s\n", gnutar_directory, strerror(errno));
1065             exit(1);
1066         }
1067         g_ptr_array_add(argv_ptr, stralloc("--directory"));
1068         g_ptr_array_add(argv_ptr, stralloc(gnutar_directory));
1069     }
1070
1071     g_ptr_array_add(argv_ptr, stralloc("--wildcards"));
1072     if (argument->dle.exclude_list &&
1073         argument->dle.exclude_list->nb_element == 1) {
1074         FILE      *exclude;
1075         char      *sdisk;
1076         char      *filename;
1077         int        in_argv;
1078         int        entry_in_exclude = 0;
1079         char       line[2*PATH_MAX];
1080         FILE      *exclude_list;
1081
1082         if (argument->dle.disk) {
1083             sdisk = sanitise_filename(argument->dle.disk);
1084         } else {
1085             sdisk = g_strdup_printf("installcheck-exclude-%d", getpid());
1086         }
1087         filename = vstralloc(AMANDA_TMPDIR, "/", "exclude-", sdisk,  NULL);
1088         exclude_list = fopen(argument->dle.exclude_list->first->name, "r");
1089
1090         exclude = fopen(filename, "w");
1091         while (fgets(line, 2*PATH_MAX, exclude_list)) {
1092             char *escaped;
1093             line[strlen(line)-1] = '\0'; /* remove '\n' */
1094             escaped = escape_tar_glob(line, &in_argv);
1095             if (in_argv) {
1096                 g_ptr_array_add(argv_ptr, "--exclude");
1097                 g_ptr_array_add(argv_ptr, escaped);
1098             } else {
1099                 fprintf(exclude,"%s\n", escaped);
1100                 entry_in_exclude++;
1101                 amfree(escaped);
1102             }
1103         }
1104         fclose(exclude);
1105         g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1106         g_ptr_array_add(argv_ptr, filename);
1107     }
1108
1109     if (argument->exclude_list_glob) {
1110         g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1111         g_ptr_array_add(argv_ptr, stralloc(argument->exclude_list_glob));
1112     }
1113
1114     {
1115         GPtrArray *argv_include = g_ptr_array_new();
1116         FILE      *include;
1117         char      *sdisk;
1118         char      *filename;
1119         int        in_argv;
1120         guint      i;
1121         int        entry_in_include = 0;
1122
1123         if (argument->dle.disk) {
1124             sdisk = sanitise_filename(argument->dle.disk);
1125         } else {
1126             sdisk = g_strdup_printf("installcheck-include-%d", getpid());
1127         }
1128         filename = vstralloc(AMANDA_TMPDIR, "/", "include-", sdisk,  NULL);
1129         include = fopen(filename, "w");
1130         if (argument->dle.include_list &&
1131             argument->dle.include_list->nb_element == 1) {
1132             char line[2*PATH_MAX];
1133             FILE *include_list = fopen(argument->dle.include_list->first->name, "r");
1134             while (fgets(line, 2*PATH_MAX, include_list)) {
1135                 char *escaped;
1136                 line[strlen(line)-1] = '\0'; /* remove '\n' */
1137                 escaped = escape_tar_glob(line, &in_argv);
1138                 if (in_argv) {
1139                     g_ptr_array_add(argv_include, escaped);
1140                 } else {
1141                     fprintf(include,"%s\n", escaped);
1142                     entry_in_include++;
1143                     amfree(escaped);
1144                 }
1145             }
1146         }
1147
1148         for (j=1; j< argument->argc; j++) {
1149             char *escaped = escape_tar_glob(argument->argv[j], &in_argv);
1150             if (in_argv) {
1151                 g_ptr_array_add(argv_include, escaped);
1152             } else {
1153                 fprintf(include,"%s\n", escaped);
1154                 entry_in_include++;
1155                 amfree(escaped);
1156             }
1157         }
1158         fclose(include);
1159
1160         if (entry_in_include) {
1161             g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1162             g_ptr_array_add(argv_ptr, filename);
1163         }
1164
1165         if (argument->include_list_glob) {
1166             g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1167             g_ptr_array_add(argv_ptr, stralloc(argument->include_list_glob));
1168         }
1169
1170         for (i = 0; i < argv_include->len; i++) {
1171             g_ptr_array_add(argv_ptr, (char *)g_ptr_array_index(argv_include,i));
1172         }
1173     }
1174     g_ptr_array_add(argv_ptr, NULL);
1175
1176     debug_executing(argv_ptr);
1177     env = safe_env();
1178     become_root();
1179     execve(cmd, (char **)argv_ptr->pdata, env);
1180     e = strerror(errno);
1181     error(_("error [exec %s: %s]"), cmd, e);
1182 }
1183
1184 static void
1185 amgtar_validate(
1186     application_argument_t *argument G_GNUC_UNUSED)
1187 {
1188     char       *cmd;
1189     GPtrArray  *argv_ptr = g_ptr_array_new();
1190     char      **env;
1191     char       *e;
1192     char        buf[32768];
1193
1194     if (!gnutar_path) {
1195         dbprintf("GNUTAR-PATH not set; Piping to /dev/null\n");
1196         fprintf(stderr,"GNUTAR-PATH not set; Piping to /dev/null\n");
1197         goto pipe_to_null;
1198     }
1199
1200     cmd = stralloc(gnutar_path);
1201     g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1202     g_ptr_array_add(argv_ptr, stralloc("-tf"));
1203     g_ptr_array_add(argv_ptr, stralloc("-"));
1204     g_ptr_array_add(argv_ptr, NULL);
1205
1206     debug_executing(argv_ptr);
1207     env = safe_env();
1208     execve(cmd, (char **)argv_ptr->pdata, env);
1209     e = strerror(errno);
1210     dbprintf("failed to execute %s: %s; Piping to /dev/null\n", cmd, e);
1211     fprintf(stderr,"failed to execute %s: %s; Piping to /dev/null\n", cmd, e);
1212 pipe_to_null:
1213     while (read(0, buf, 32768) > 0) {
1214     }
1215 }
1216
1217 static void
1218 amgtar_build_exinclude(
1219     dle_t  *dle,
1220     int     verbose,
1221     int    *nb_exclude,
1222     char  **file_exclude,
1223     int    *nb_include,
1224     char  **file_include)
1225 {
1226     int n_exclude = 0;
1227     int n_include = 0;
1228     char *exclude = NULL;
1229     char *include = NULL;
1230
1231     if (dle->exclude_file) n_exclude += dle->exclude_file->nb_element;
1232     if (dle->exclude_list) n_exclude += dle->exclude_list->nb_element;
1233     if (dle->include_file) n_include += dle->include_file->nb_element;
1234     if (dle->include_list) n_include += dle->include_list->nb_element;
1235
1236     if (n_exclude > 0) exclude = build_exclude(dle, verbose);
1237     if (n_include > 0) include = build_include(dle, verbose);
1238
1239     if (nb_exclude)
1240         *nb_exclude = n_exclude;
1241     if (file_exclude)
1242         *file_exclude = exclude;
1243     else
1244         amfree(exclude);
1245
1246     if (nb_include)
1247         *nb_include = n_include;
1248     if (file_include)
1249         *file_include = include;
1250     else
1251         amfree(include);
1252 }
1253
1254 static char *
1255 amgtar_get_incrname(
1256     application_argument_t *argument,
1257     int                     level,
1258     FILE                   *mesgstream,
1259     int                     command)
1260 {
1261     char *basename = NULL;
1262     char *incrname = NULL;
1263     int   infd, outfd;
1264     ssize_t   nb;
1265     char *inputname = NULL;
1266     char *errmsg = NULL;
1267     char *buf;
1268
1269     if (gnutar_listdir) {
1270         char number[NUM_STR_SIZE];
1271         int baselevel;
1272         char *sdisk = sanitise_filename(argument->dle.disk);
1273
1274         basename = vstralloc(gnutar_listdir,
1275                              "/",
1276                              argument->host,
1277                              sdisk,
1278                              NULL);
1279         amfree(sdisk);
1280
1281         snprintf(number, SIZEOF(number), "%d", level);
1282         incrname = vstralloc(basename, "_", number, ".new", NULL);
1283         unlink(incrname);
1284
1285         /*
1286          * Open the listed incremental file from the previous level.  Search
1287          * backward until one is found.  If none are found (which will also
1288          * be true for a level 0), arrange to read from /dev/null.
1289          */
1290         baselevel = level;
1291         infd = -1;
1292         while (infd == -1) {
1293             if (--baselevel >= 0) {
1294                 snprintf(number, SIZEOF(number), "%d", baselevel);
1295                 inputname = newvstralloc(inputname,
1296                                          basename, "_", number, NULL);
1297             } else {
1298                 inputname = newstralloc(inputname, "/dev/null");
1299             }
1300             if ((infd = open(inputname, O_RDONLY)) == -1) {
1301
1302                 errmsg = vstrallocf(_("amgtar: error opening %s: %s"),
1303                                      inputname, strerror(errno));
1304                 dbprintf("%s\n", errmsg);
1305                 if (baselevel < 0) {
1306                     if (command == CMD_ESTIMATE) {
1307                         fprintf(mesgstream, "ERROR %s\n", errmsg);
1308                     } else {
1309                         fprintf(mesgstream, "? %s\n", errmsg);
1310                     }
1311                     exit(1);
1312                 }
1313                 amfree(errmsg);
1314             }
1315         }
1316
1317         /*
1318          * Copy the previous listed incremental file to the new one.
1319          */
1320         if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) {
1321             errmsg = vstrallocf(_("error opening %s: %s"),
1322                                  incrname, strerror(errno));
1323             dbprintf("%s\n", errmsg);
1324             if (command == CMD_ESTIMATE) {
1325                 fprintf(mesgstream, "ERROR %s\n", errmsg);
1326             } else {
1327                 fprintf(mesgstream, "? %s\n", errmsg);
1328             }
1329             exit(1);
1330         }
1331
1332         while ((nb = read(infd, &buf, SIZEOF(buf))) > 0) {
1333             if (full_write(outfd, &buf, (size_t)nb) < (size_t)nb) {
1334                 errmsg = vstrallocf(_("writing to %s: %s"),
1335                                      incrname, strerror(errno));
1336                 dbprintf("%s\n", errmsg);
1337                 return NULL;
1338             }
1339         }
1340
1341         if (nb < 0) {
1342             errmsg = vstrallocf(_("reading from %s: %s"),
1343                                  inputname, strerror(errno));
1344             dbprintf("%s\n", errmsg);
1345             return NULL;
1346         }
1347
1348         if (close(infd) != 0) {
1349             errmsg = vstrallocf(_("closing %s: %s"),
1350                                  inputname, strerror(errno));
1351             dbprintf("%s\n", errmsg);
1352             return NULL;
1353         }
1354         if (close(outfd) != 0) {
1355             errmsg = vstrallocf(_("closing %s: %s"),
1356                                  incrname, strerror(errno));
1357             dbprintf("%s\n", errmsg);
1358             return NULL;
1359         }
1360
1361         amfree(inputname);
1362         amfree(basename);
1363     }
1364     return incrname;
1365 }
1366
1367 GPtrArray *amgtar_build_argv(
1368     application_argument_t *argument,
1369     char *incrname,
1370     int   command)
1371 {
1372     int    nb_exclude;
1373     int    nb_include;
1374     char  *file_exclude;
1375     char  *file_include;
1376     char  *dirname;
1377     char   tmppath[PATH_MAX];
1378     GPtrArray *argv_ptr = g_ptr_array_new();
1379     GSList    *copt;
1380
1381     amgtar_build_exinclude(&argument->dle, 1,
1382                            &nb_exclude, &file_exclude,
1383                            &nb_include, &file_include);
1384
1385     if (gnutar_directory) {
1386         dirname = gnutar_directory;
1387     } else {
1388         dirname = amname_to_dirname(argument->dle.device);
1389     }
1390
1391     g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
1392
1393     g_ptr_array_add(argv_ptr, stralloc("--create"));
1394     if (command == CMD_BACKUP && argument->dle.create_index)
1395         g_ptr_array_add(argv_ptr, stralloc("--verbose"));
1396     g_ptr_array_add(argv_ptr, stralloc("--file"));
1397     if (command == CMD_ESTIMATE) {
1398         g_ptr_array_add(argv_ptr, stralloc("/dev/null"));
1399     } else {
1400         g_ptr_array_add(argv_ptr, stralloc("-"));
1401     }
1402     if (gnutar_no_unquote)
1403         g_ptr_array_add(argv_ptr, stralloc("--no-unquote"));
1404     g_ptr_array_add(argv_ptr, stralloc("--directory"));
1405     canonicalize_pathname(dirname, tmppath);
1406     g_ptr_array_add(argv_ptr, stralloc(tmppath));
1407     if (gnutar_onefilesystem)
1408         g_ptr_array_add(argv_ptr, stralloc("--one-file-system"));
1409     if (gnutar_atimepreserve)
1410         g_ptr_array_add(argv_ptr, stralloc("--atime-preserve=system"));
1411     if (!gnutar_checkdevice)
1412         g_ptr_array_add(argv_ptr, stralloc("--no-check-device"));
1413     if (gnutar_acls)
1414         g_ptr_array_add(argv_ptr, stralloc("--acls"));
1415     if (gnutar_selinux)
1416         g_ptr_array_add(argv_ptr, stralloc("--selinux"));
1417     if (gnutar_xattrs)
1418         g_ptr_array_add(argv_ptr, stralloc("--xattrs"));
1419     g_ptr_array_add(argv_ptr, stralloc("--listed-incremental"));
1420     g_ptr_array_add(argv_ptr, stralloc(incrname));
1421     if (gnutar_sparse)
1422         g_ptr_array_add(argv_ptr, stralloc("--sparse"));
1423     if (argument->tar_blocksize) {
1424         g_ptr_array_add(argv_ptr, stralloc("--blocking-factor"));
1425         g_ptr_array_add(argv_ptr, stralloc(argument->tar_blocksize));
1426     }
1427     g_ptr_array_add(argv_ptr, stralloc("--ignore-failed-read"));
1428     g_ptr_array_add(argv_ptr, stralloc("--totals"));
1429
1430     for (copt = argument->command_options; copt != NULL; copt = copt->next) {
1431         g_ptr_array_add(argv_ptr, stralloc((char *)copt->data));
1432     }
1433
1434     if(file_exclude) {
1435         g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
1436         g_ptr_array_add(argv_ptr, stralloc(file_exclude));
1437     }
1438
1439     if(file_include) {
1440         g_ptr_array_add(argv_ptr, stralloc("--files-from"));
1441         g_ptr_array_add(argv_ptr, stralloc(file_include));
1442     }
1443     else {
1444         g_ptr_array_add(argv_ptr, stralloc("."));
1445     }
1446     g_ptr_array_add(argv_ptr, NULL);
1447
1448     return(argv_ptr);
1449 }
1450