Imported Upstream version 2.6.0
[debian/amanda] / client-src / client_util.c
index 557fee618a94017b2d8ad3438cc6bbeb62437a41..7765532e1e0dd525729736246d271d767a574df9 100644 (file)
  * file named AUTHORS, in the root directory of this distribution.
  */
 /* 
- * $Id: client_util.c,v 1.1.2.27 2003/07/02 17:03:32 martinea Exp $
+ * $Id: client_util.c,v 1.34 2006/05/25 01:47:11 johnfranks Exp $
  *
  */
 
+#include "amanda.h"
+#include "conffile.h"
 #include "client_util.h"
 #include "getfsent.h"
 #include "util.h"
+#include "timestamp.h"
+#include "pipespawn.h"
 
 #define MAXMAXDUMPS 16
 
-static char *fixup_relative(name, device)
-char *name;
-char *device;
+static int add_exclude(FILE *file_exclude, char *aexc, int verbose);
+static int add_include(char *disk, char *device, FILE *file_include, char *ainc, int verbose);
+static char *build_name(char *disk, char *exin, int verbose);
+static char *get_name(char *diskname, char *exin, time_t t, int n);
+
+
+char *
+fixup_relative(
+    char *     name,
+    char *     device)
 {
     char *newname;
     if(*name != '/') {
@@ -51,20 +62,22 @@ char *device;
 }
 
 
-static char *get_name(diskname, exin, t, n)
-char *diskname, *exin;
-time_t t;
-int n;
+static char *
+get_name(
+    char *     diskname,
+    char *     exin,
+    time_t     t,
+    int                n)
 {
     char number[NUM_STR_SIZE];
     char *filename;
     char *ts;
 
-    ts = construct_timestamp(&t);
+    ts = get_timestamp_from_time(t);
     if(n == 0)
        number[0] = '\0';
     else
-       ap_snprintf(number, sizeof(number), "%03d", n - 1);
+       g_snprintf(number, SIZEOF(number), "%03d", n - 1);
        
     filename = vstralloc(get_pname(), ".", diskname, ".", ts, number, ".",
                         exin, NULL);
@@ -73,29 +86,34 @@ int n;
 }
 
 
-static char *build_name(disk, exin, verbose)
-char *disk, *exin;
+static char *
+build_name(
+    char *     disk,
+    char *     exin,
+    int                verbose)
 {
-    int n=0, fd=-1;
+    int n;
+    int fd;
     char *filename = NULL;
     char *afilename = NULL;
     char *diskname;
     time_t curtime;
-    char *dbgdir = NULL;
+    char *dbgdir;
     char *e = NULL;
     DIR *d;
     struct dirent *entry;
-    char *test_name = NULL;
-    int match_len, d_name_len;
-
+    char *test_name;
+    size_t match_len, d_name_len;
+    char *quoted;
 
     time(&curtime);
     diskname = sanitise_filename(disk);
 
     dbgdir = stralloc2(AMANDA_TMPDIR, "/");
     if((d = opendir(AMANDA_TMPDIR)) == NULL) {
-       error("open debug directory \"%s\": %s",
-       AMANDA_TMPDIR, strerror(errno));
+       error(_("open debug directory \"%s\": %s"),
+               AMANDA_TMPDIR, strerror(errno));
+       /*NOTREACHED*/
     }
     test_name = get_name(diskname, exin,
                         curtime - (AMANDA_DEBUG_DAYS * 24 * 60 * 60), 0);
@@ -123,7 +141,7 @@ char *disk, *exin;
     do {
        filename = get_name(diskname, exin, curtime, n);
        afilename = newvstralloc(afilename, dbgdir, filename, NULL);
-       if((fd=open(afilename, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0600)) < 0){
+       if((fd=open(afilename, O_WRONLY|O_CREAT|O_APPEND, 0600)) < 0){
            amfree(afilename);
            n++;
        }
@@ -136,11 +154,15 @@ char *disk, *exin;
     if(afilename == NULL) {
        filename = get_name(diskname, exin, curtime, 0);
        afilename = newvstralloc(afilename, dbgdir, filename, NULL);
-       dbprintf(("%s: Cannot create '%s'\n", debug_prefix(NULL), afilename));
-       if(verbose)
-           printf("ERROR [cannot create: %s]\n", afilename);
-       amfree(filename);
+       quoted = quote_string(afilename);
+       dbprintf(_("Cannot create %s (%s)\n"), quoted, strerror(errno));
+       if(verbose) {
+           g_printf(_("ERROR [cannot create %s (%s)]\n"),
+                       quoted, strerror(errno));
+       }
+       amfree(quoted);
        amfree(afilename);
+       amfree(filename);
     }
 
     amfree(dbgdir);
@@ -150,52 +172,70 @@ char *disk, *exin;
 }
 
 
-static int add_exclude(file_exclude, aexc, verbose)
-FILE *file_exclude;
-char *aexc;
+static int
+add_exclude(
+    FILE *     file_exclude,
+    char *     aexc,
+    int                verbose)
 {
-    int l;
+    size_t l;
+    char *quoted, *file;
+
+    (void)verbose;     /* Quiet unused parameter warning */
 
     l = strlen(aexc);
     if(aexc[l-1] == '\n') {
        aexc[l-1] = '\0';
        l--;
     }
-    fprintf(file_exclude, "%s\n", aexc);
+    file = quoted = quote_string(aexc);
+    if (*file == '"') {
+       file[strlen(file) - 1] = '\0';
+       file++;
+    }
+    g_fprintf(file_exclude, "%s\n", file);
+    amfree(quoted);
     return 1;
 }
 
-static int add_include(disk, device, file_include, ainc, verbose)
-char *disk, *device;
-FILE *file_include;
-char *ainc;
+static int
+add_include(
+    char *     disk,
+    char *     device,
+    FILE *     file_include,
+    char *     ainc,
+    int                verbose)
 {
-    int l;
+    size_t l;
     int nb_exp=0;
+    char *quoted, *file;
+
+    (void)disk;        /* Quiet unused parameter warning */
 
     l = strlen(ainc);
     if(ainc[l-1] == '\n') {
        ainc[l-1] = '\0';
        l--;
     }
-    if(l < 3) {
-       dbprintf(("%s: include must be at least 3 character long: %s\n",
-                 debug_prefix(NULL), ainc));
-       if(verbose)
-           printf("ERROR [include must be at least 3 character long: %s]\n", ainc);
-       return 0;
-    }
-    else if(ainc[0] != '.' && ainc[0] != '\0' && ainc[1] != '/') {
-        dbprintf(("%s: include must start with './': %s\n",
-                 debug_prefix(NULL), ainc));
-       if(verbose)
-           printf("ERROR [include must start with './': %s]\n", ainc);
-       return 0;
+    if (strncmp(ainc, "./", 2) != 0) {
+        quoted = quote_string(ainc);
+        dbprintf(_("include must start with './' (%s)\n"), quoted);
+       if(verbose) {
+           g_printf(_("ERROR [include must start with './' (%s)]\n"), quoted);
+       }
+       amfree(quoted);
     }
     else {
        char *incname = ainc+2;
+
        if(strchr(incname, '/')) {
-           fprintf(file_include, "./%s\n", incname);
+            file = quoted = quote_string(ainc);
+           if (*file == '"') {
+               file[strlen(file) - 1] = '\0';
+               file++;
+           }
+           g_fprintf(file_include, "%s\n", file);
+           amfree(quoted);
            nb_exp++;
        }
        else {
@@ -205,11 +245,12 @@ char *ainc;
 
            regex = glob_to_regex(incname);
            if((d = opendir(device)) == NULL) {
-               dbprintf(("%s: Can't open disk '%s']\n",
-                     debug_prefix(NULL), device));
-               if(verbose)
-                   printf("ERROR [Can't open disk '%s']\n", device);
-               return 0;
+               quoted = quote_string(device);
+               dbprintf(_("Can't open disk %s\n"), quoted);
+               if(verbose) {
+                   g_printf(_("ERROR [Can't open disk %s]\n"), quoted);
+               }
+               amfree(quoted);
            }
            else {
                while((entry = readdir(d)) != NULL) {
@@ -217,28 +258,40 @@ char *ainc;
                        continue;
                    }
                    if(match(regex, entry->d_name)) {
-                       fprintf(file_include, "./%s\n", entry->d_name);
+                       incname = vstralloc("./", entry->d_name, NULL);
+                       file = quoted = quote_string(incname);
+                       if (*file == '"') {
+                           file[strlen(file) - 1] = '\0';
+                           file++;
+                       }
+                       g_fprintf(file_include, "%s\n", file);
+                       amfree(quoted);
+                       amfree(incname);
                        nb_exp++;
                    }
                }
                closedir(d);
            }
+           amfree(regex);
        }
     }
     return nb_exp;
 }
 
-char *build_exclude(disk, device, options, verbose)
-char *disk, *device;
-option_t *options;
-int verbose;
+char *
+build_exclude(
+    char *     disk,
+    char *     device,
+    option_t * options,
+    int                verbose)
 {
     char *filename;
     FILE *file_exclude;
     FILE *exclude;
-    char *aexc = NULL;
+    char *aexc;
     sle_t *excl;
     int nb_exclude = 0;
+    char *quoted;
 
     if(options->exclude_file) nb_exclude += options->exclude_file->nb_element;
     if(options->exclude_list) nb_exclude += options->exclude_list->nb_element;
@@ -262,6 +315,10 @@ int verbose;
                    char *exclname = fixup_relative(excl->name, device);
                    if((exclude = fopen(exclname, "r")) != NULL) {
                        while ((aexc = agets(exclude)) != NULL) {
+                           if (aexc[0] == '\0') {
+                               amfree(aexc);
+                               continue;
+                           }
                            add_exclude(file_exclude, aexc,
                                        verbose && options->exclude_optional == 0);
                            amfree(aexc);
@@ -269,14 +326,15 @@ int verbose;
                        fclose(exclude);
                    }
                    else {
-                       dbprintf(("%s: Can't open exclude file '%s': %s\n",
-                                 debug_prefix(NULL),
-                                 exclname,
-                                 strerror(errno)));
+                       quoted = quote_string(exclname);
+                       dbprintf(_("Can't open exclude file %s (%s)\n"),
+                                 quoted, strerror(errno));
                        if(verbose && (options->exclude_optional == 0 ||
-                                      errno != ENOENT))
-                           printf("ERROR [Can't open exclude file '%s': %s]\n",
-                                  exclname, strerror(errno));
+                                      errno != ENOENT)) {
+                           g_printf(_("ERROR [Can't open exclude file %s (%s)]\n"),
+                                  quoted, strerror(errno));
+                       }
+                       amfree(quoted);
                    }
                    amfree(exclname);
                }
@@ -284,24 +342,26 @@ int verbose;
             fclose(file_exclude);
        }
        else {
-           dbprintf(("%s: Can't create exclude file '%s': %s\n",
-                     debug_prefix(NULL),
-                     filename,
-                     strerror(errno)));
-           if(verbose)
-               printf("ERROR [Can't create exclude file '%s': %s]\n", filename,
-                       strerror(errno));
+           quoted = quote_string(filename);
+           dbprintf(_("Can't create exclude file %s (%s)\n"),
+                     quoted, strerror(errno));
+           if(verbose) {
+               g_printf(_("ERROR [Can't create exclude file %s (%s)]\n"),
+                       quoted, strerror(errno));
+           }
+           amfree(quoted);
        }
     }
 
     return filename;
 }
 
-char *build_include(disk, device, options, verbose)
-char *disk;
-char *device;
-option_t *options;
-int verbose;
+char *
+build_include(
+    char *     disk,
+    char *     device,
+    option_t * options,
+    int                verbose)
 {
     char *filename;
     FILE *file_include;
@@ -310,6 +370,7 @@ int verbose;
     sle_t *incl;
     int nb_include = 0;
     int nb_exp = 0;
+    char *quoted;
 
     if(options->include_file) nb_include += options->include_file->nb_element;
     if(options->include_list) nb_include += options->include_list->nb_element;
@@ -324,7 +385,7 @@ int verbose;
                    incl = incl->next) {
                    nb_exp += add_include(disk, device, file_include,
                                  incl->name,
-                                  verbose && options->include_optional == 0);
+                                 verbose && options->include_optional == 0);
                }
            }
 
@@ -334,6 +395,10 @@ int verbose;
                    char *inclname = fixup_relative(incl->name, device);
                    if((include = fopen(inclname, "r")) != NULL) {
                        while ((ainc = agets(include)) != NULL) {
+                           if (ainc[0] == '\0') {
+                               amfree(ainc);
+                               continue;
+                           }
                            nb_exp += add_include(disk, device,
                                                  file_include, ainc,
                                                  verbose && options->include_optional == 0);
@@ -342,14 +407,15 @@ int verbose;
                        fclose(include);
                    }
                    else {
-                       dbprintf(("%s: Can't open include file '%s': %s\n",
-                                 debug_prefix(NULL),
-                                 inclname,
-                                 strerror(errno)));
+                       quoted = quote_string(inclname);
+                       dbprintf(_("Can't open include file %s (%s)\n"),
+                                 quoted, strerror(errno));
                        if(verbose && (options->include_optional == 0 ||
-                                       errno != ENOENT))
-                           printf("ERROR [Can't open include file '%s': %s]\n",
-                                  inclname, strerror(errno));
+                                      errno != ENOENT)) {
+                           g_printf(_("ERROR [Can't open include file %s (%s)]\n"),
+                                  quoted, strerror(errno));
+                       }
+                       amfree(quoted);
                   }
                   amfree(inclname);
                }
@@ -357,38 +423,47 @@ int verbose;
             fclose(file_include);
        }
        else {
-           dbprintf(("%s: Can't create include file '%s': %s\n",
-                     debug_prefix(NULL),
-                     filename,
-                     strerror(errno)));
-           if(verbose)
-               printf("ERROR [Can't create include file '%s': %s]\n", filename,
-                       strerror(errno));
+           quoted = quote_string(filename);
+           dbprintf(_("Can't create include file %s (%s)\n"),
+                     quoted, strerror(errno));
+           if(verbose) {
+               g_printf(_("ERROR [Can't create include file %s (%s)]\n"),
+                       quoted, strerror(errno));
+           }
+           amfree(quoted);
        }
     }
        
     if(nb_exp == 0) {
-       dbprintf(("%s: No include for '%s'\n", debug_prefix(NULL), disk));
-       if(verbose && options->include_optional == 0)
-           printf("ERROR [No include for '%s']\n", disk);
+       quoted = quote_string(disk);
+       dbprintf(_("No include for %s\n"), quoted);
+       if(verbose && options->include_optional == 0) {
+           g_printf(_("ERROR [No include for %s]\n"), quoted);
+       }
+       amfree(quoted);
     }
 
     return filename;
 }
 
 
-void init_options(options)
-option_t *options;
+void
+init_options(
+    option_t *options)
 {
     options->str = NULL;
-    options->compress = NO_COMPR;
+    options->compress = COMP_NONE;
+    options->srvcompprog = NULL;
+    options->clntcompprog = NULL;
+    options->encrypt = ENCRYPT_NONE;
+    options->kencrypt = 0;
+    options->srv_encrypt = NULL;
+    options->clnt_encrypt = NULL;
+    options->srv_decrypt_opt = NULL;
+    options->clnt_decrypt_opt = NULL;
     options->no_record = 0;
-    options->bsd_auth = 0;
     options->createindex = 0;
-#ifdef KRB4_SECURITY
-    options->krb4_auth = 0;
-    options->kencrypt = 0;
-#endif
+    options->auth = NULL;
     options->exclude_file = NULL;
     options->exclude_list = NULL;
     options->include_file = NULL;
@@ -398,17 +473,24 @@ option_t *options;
 }
 
 
-option_t *parse_options(str, disk, device, fs, verbose)
-char *str;
-char *disk, *device;
-am_feature_t *fs;
-int verbose;
+option_t *
+parse_options(
+    char *str,
+    char *disk,
+    char *device,
+    am_feature_t *fs,
+    int verbose)
 {
     char *exc;
+    char *inc;
     option_t *options;
     char *p, *tok;
+    char *quoted;
+
+    (void)disk;                /* Quiet unused parameter warning */
+    (void)device;      /* Quiet unused parameter warning */
 
-    options = alloc(sizeof(option_t));
+    options = alloc(SIZEOF(option_t));
     init_options(options);
     options->str = stralloc(str);
 
@@ -417,174 +499,186 @@ int verbose;
 
     while (tok != NULL) {
        if(am_has_feature(fs, fe_options_auth)
-          && strncmp(tok, "auth=", 5) == 0) {
-           if(options->bsd_auth
-#ifdef KRB4_SECURITY
-              + options->krb4_auth
-#endif
-              > 0) {
-               dbprintf(("%s: multiple auth option\n", 
-                         debug_prefix(NULL)));
+          && BSTRNCMP(tok,"auth=") == 0) {
+           if(options->auth != NULL) {
+               quoted = quote_string(tok + 5);
+               dbprintf(_("multiple auth option %s\n"), quoted);
                if(verbose) {
-                   printf("ERROR [multiple auth option]\n");
+                   g_printf(_("ERROR [multiple auth option %s]\n"), quoted);
                }
+               amfree(quoted);
            }
-           if(strcasecmp(tok + 5, "bsd") == 0) {
-               options->bsd_auth = 1;
-           }
-#ifdef KRB4_SECURITY
-           else if(strcasecmp(tok + 5, "krb4") == 0) {
-               options->krb4_auth = 1;
-           }
-#endif
-           else {
-               dbprintf(("%s: unknown auth= value \"%s\"\n",
-                         debug_prefix(NULL), tok + 5));
+           options->auth = stralloc(&tok[5]);
+       }
+       else if(am_has_feature(fs, fe_options_bsd_auth)
+          && BSTRNCMP(tok, "bsd-auth") == 0) {
+           if(options->auth != NULL) {
+               dbprintf(_("multiple auth option\n"));
                if(verbose) {
-                   printf("ERROR [unknown auth= value \"%s\"]\n", tok + 5);
+                   g_printf(_("ERROR [multiple auth option]\n"));
                }
            }
+           options->auth = stralloc("bsd");
        }
-       else if(strcmp(tok, "compress-fast") == 0) {
-           if(options->compress != NO_COMPR) {
-               dbprintf(("%s: multiple compress option\n", 
-                         debug_prefix(NULL)));
+       else if(am_has_feature(fs, fe_options_krb4_auth)
+          && BSTRNCMP(tok, "krb4-auth") == 0) {
+           if(options->auth != NULL) {
+               dbprintf(_("multiple auth option\n"));
                if(verbose) {
-                   printf("ERROR [multiple compress option]\n");
+                   g_printf(_("ERROR [multiple auth option]\n"));
                }
            }
-           options->compress = COMPR_FAST;
+           options->auth = stralloc("krb4");
        }
-       else if(strcmp(tok, "compress-best") == 0) {
-           if(options->compress != NO_COMPR) {
-               dbprintf(("%s: multiple compress option\n", 
-                         debug_prefix(NULL)));
+       else if(BSTRNCMP(tok, "compress-fast") == 0) {
+           if(options->compress != COMP_NONE) {
+               dbprintf(_("multiple compress option\n"));
                if(verbose) {
-                   printf("ERROR [multiple compress option]\n");
+                   g_printf(_("ERROR [multiple compress option]\n"));
                }
            }
-           options->compress = COMPR_BEST;
+           options->compress = COMP_FAST;
        }
-       else if(strcmp(tok, "srvcomp-fast") == 0) {
-           if(options->compress != NO_COMPR) {
-               dbprintf(("%s: multiple compress option\n", 
-                         debug_prefix(NULL)));
+       else if(BSTRNCMP(tok, "compress-best") == 0) {
+           if(options->compress != COMP_NONE) {
+               dbprintf(_("multiple compress option\n"));
                if(verbose) {
-                   printf("ERROR [multiple compress option]\n");
+                   g_printf(_("ERROR [multiple compress option]\n"));
                }
            }
-           options->compress = COMPR_SERVER_FAST;
+           options->compress = COMP_BEST;
        }
-       else if(strcmp(tok, "srvcomp-best") == 0) {
-           if(options->compress != NO_COMPR) {
-               dbprintf(("%s: multiple compress option\n", 
-                         debug_prefix(NULL)));
+       else if(BSTRNCMP(tok, "srvcomp-fast") == 0) {
+           if(options->compress != COMP_NONE) {
+               dbprintf(_("multiple compress option\n"));
                if(verbose) {
-                   printf("ERROR [multiple compress option]\n");
+                   g_printf(_("ERROR [multiple compress option]\n"));
                }
            }
-           options->compress = COMPR_SERVER_BEST;
+           options->compress = COMP_SERVER_FAST;
        }
-       else if(strcmp(tok, "no-record") == 0) {
-           if(options->no_record != 0) {
-               dbprintf(("%s: multiple no-record option\n", 
-                         debug_prefix(NULL)));
+       else if(BSTRNCMP(tok, "srvcomp-best") == 0) {
+           if(options->compress != COMP_NONE) {
+               dbprintf(_("multiple compress option\n"));
                if(verbose) {
-                   printf("ERROR [multiple no-record option]\n");
+                   g_printf(_("ERROR [multiple compress option]\n"));
                }
            }
-           options->no_record = 1;
+           options->compress = COMP_SERVER_BEST;
        }
-       else if(strcmp(tok, "bsd-auth") == 0) {
-           if(options->bsd_auth
-#ifdef KRB4_SECURITY
-              + options->krb4_auth
-#endif
-              > 0) {
-               dbprintf(("%s: multiple auth option\n", 
-                         debug_prefix(NULL)));
+       else if(BSTRNCMP(tok, "srvcomp-cust=") == 0) {
+           if(options->compress != COMP_NONE) {
+               dbprintf(_("multiple compress option\n"));
                if(verbose) {
-                   printf("ERROR [multiple auth option]\n");
+                   g_printf(_("ERROR [multiple compress option]\n"));
                }
            }
-           options->bsd_auth = 1;
+           options->srvcompprog = stralloc(tok + SIZEOF("srvcomp-cust=") -1);
+           options->compress = COMP_SERVER_CUST;
        }
-       else if(strcmp(tok, "index") == 0) {
-           if(options->createindex != 0) {
-               dbprintf(("%s: multiple index option\n", 
-                         debug_prefix(NULL)));
+       else if(BSTRNCMP(tok, "comp-cust=") == 0) {
+           if(options->compress != COMP_NONE) {
+               dbprintf(_("multiple compress option\n"));
                if(verbose) {
-                   printf("ERROR [multiple index option]\n");
+                   g_printf(_("ERROR [multiple compress option]\n"));
                }
            }
-           options->createindex = 1;
+           options->clntcompprog = stralloc(tok + SIZEOF("comp-cust=") -1);
+           options->compress = COMP_CUST;
+           /* parse encryption options */
+       } 
+       else if(BSTRNCMP(tok, "encrypt-serv-cust=") == 0) {
+           if(options->encrypt != ENCRYPT_NONE) {
+               dbprintf(_("multiple encrypt option\n"));
+               if(verbose) {
+                   g_printf(_("ERROR [multiple encrypt option]\n"));
+               }
+           }
+           options->srv_encrypt = stralloc(tok + SIZEOF("encrypt-serv-cust=") -1);
+           options->encrypt = ENCRYPT_SERV_CUST;
+       } 
+       else if(BSTRNCMP(tok, "encrypt-cust=") == 0) {
+           if(options->encrypt != ENCRYPT_NONE) {
+               dbprintf(_("multiple encrypt option\n"));
+               if(verbose) {
+                   g_printf(_("ERROR [multiple encrypt option]\n"));
+               }
+           }
+           options->clnt_encrypt= stralloc(tok + SIZEOF("encrypt-cust=") -1);
+           options->encrypt = ENCRYPT_CUST;
+       } 
+       else if(BSTRNCMP(tok, "server-decrypt-option=") == 0) {
+         options->srv_decrypt_opt = stralloc(tok + SIZEOF("server-decrypt-option=") -1);
+       }
+       else if(BSTRNCMP(tok, "client-decrypt-option=") == 0) {
+         options->clnt_decrypt_opt = stralloc(tok + SIZEOF("client-decrypt-option=") -1);
        }
-#ifdef KRB4_SECURITY
-       else if(strcmp(tok, "krb4-auth") == 0) {
-           if(options->bsd_auth + options->krb4_auth > 0) {
-               dbprintf(("%s: multiple auth option\n", 
-                         debug_prefix(NULL)));
+       else if(BSTRNCMP(tok, "no-record") == 0) {
+           if(options->no_record != 0) {
+               dbprintf(_("multiple no-record option\n"));
                if(verbose) {
-                   printf("ERROR [multiple auth option]\n");
+                   g_printf(_("ERROR [multiple no-record option]\n"));
                }
            }
-           options->krb4_auth = 1;
+           options->no_record = 1;
        }
-       else if(strcmp(tok, "kencrypt") == 0) {
-           if(options->kencrypt != 0) {
-               dbprintf(("%s: multiple kencrypt option\n", 
-                         debug_prefix(NULL)));
+       else if(BSTRNCMP(tok, "index") == 0) {
+           if(options->createindex != 0) {
+               dbprintf(_("multiple index option\n"));
                if(verbose) {
-                   printf("ERROR [multiple kencrypt option]\n");
+                   g_printf(_("ERROR [multiple index option]\n"));
                }
            }
-           options->kencrypt = 1;
+           options->createindex = 1;
        }
-#endif
-       else if(strcmp(tok, "exclude-optional") == 0) {
+       else if(BSTRNCMP(tok, "exclude-optional") == 0) {
            if(options->exclude_optional != 0) {
-               dbprintf(("%s: multiple exclude-optional option\n", 
-                         debug_prefix(NULL)));
+               dbprintf(_("multiple exclude-optional option\n"));
                if(verbose) {
-                   printf("ERROR [multiple exclude-optional option]\n");
+                   g_printf(_("ERROR [multiple exclude-optional option]\n"));
                }
            }
            options->exclude_optional = 1;
        }
        else if(strcmp(tok, "include-optional") == 0) {
            if(options->include_optional != 0) {
-               dbprintf(("%s: multiple include-optional option\n", 
-                         debug_prefix(NULL)));
+               dbprintf(_("multiple include-optional option\n"));
                if(verbose) {
-                   printf("ERROR [multiple include-optional option]\n");
+                   g_printf(_("ERROR [multiple include-optional option]\n"));
                }
            }
            options->include_optional = 1;
        }
-       else if(strncmp(tok,"exclude-file=", 13) == 0) {
-           exc = &tok[13];
-           options->exclude_file = append_sl(options->exclude_file,exc);
+       else if(BSTRNCMP(tok,"exclude-file=") == 0) {
+           exc = unquote_string(&tok[13]);
+           options->exclude_file = append_sl(options->exclude_file, exc);
+           amfree(exc);
        }
-       else if(strncmp(tok,"exclude-list=", 13) == 0) {
-           exc = &tok[13];
+       else if(BSTRNCMP(tok,"exclude-list=") == 0) {
+           exc = unquote_string(&tok[13]);
            options->exclude_list = append_sl(options->exclude_list, exc);
+           amfree(exc);
        }
-       else if(strncmp(tok,"include-file=", 13) == 0) {
-           exc = &tok[13];
-           options->include_file = append_sl(options->include_file,exc);
+       else if(BSTRNCMP(tok,"include-file=") == 0) {
+           inc = unquote_string(&tok[13]);
+           options->include_file = append_sl(options->include_file, inc);
+           amfree(inc);
        }
-       else if(strncmp(tok,"include-list=", 13) == 0) {
-           exc = &tok[13];
-           options->include_list = append_sl(options->include_list, exc);
+       else if(BSTRNCMP(tok,"include-list=") == 0) {
+           inc = unquote_string(&tok[13]);
+           options->include_list = append_sl(options->include_list, inc);
+           amfree(inc);
        }
-       else if(strcmp(tok,"|") == 0) {
+       else if(BSTRNCMP(tok,"kencrypt") == 0) {
+           options->kencrypt = 1;
        }
-       else {
-           dbprintf(("%s: unknown option \"%s\"\n",
-                                  debug_prefix(NULL), tok));
+       else if(strcmp(tok,"|") != 0) {
+           quoted = quote_string(tok);
+           dbprintf(_("unknown option %s\n"), quoted);
            if(verbose) {
-               printf("ERROR [unknown option \"%s\"]\n", tok);
+               g_printf(_("ERROR [unknown option: %s]\n"), quoted);
            }
+           amfree(quoted);
        }
        tok = strtok(NULL, ";");
     }
@@ -592,105 +686,161 @@ int verbose;
     return options;
 }
 
-
-void init_g_options(g_options)
-g_option_t *g_options;
-{
-    g_options->features = NULL;
-    g_options->hostname = NULL;
-    g_options->maxdumps = 0;
-}
-
-
-g_option_t *parse_g_options(str, verbose)
-char *str;
-int verbose;
+void
+output_tool_property(
+    FILE     *tool,
+    option_t *options)
 {
-    g_option_t *g_options;
-    char *p, *tok;
-    int new_maxdumps;
+    sle_t *sle;
+    char *q;
 
-    g_options = alloc(sizeof(g_option_t));
-    init_g_options(g_options);
-    g_options->str = stralloc(str);
-
-    p = stralloc(str);
-    tok = strtok(p,";");
-
-    while (tok != NULL) {
-       if(strncmp(tok,"features=", 9) == 0) {
-           if(g_options->features != NULL) {
-               dbprintf(("%s: multiple features option\n", 
-                         debug_prefix(NULL)));
-               if(verbose) {
-                   printf("ERROR [multiple features option]\n");
-               }
-           }
-           if((g_options->features = am_string_to_feature(tok+9)) == NULL) {
-               dbprintf(("%s: bad features value \"%s\n",
-                         debug_prefix(NULL), tok+10));
-               if(verbose) {
-                   printf("ERROR [bad features value \"%s\"]\n", tok+10);
-               }
-           }
+    if (!is_empty_sl(options->exclude_file)) {
+       for(sle = options->exclude_file->first ; sle != NULL; sle=sle->next) {
+           q = quote_string(sle->name);
+           g_fprintf(tool, "EXCLUDE-FILE %s\n", q);
+           amfree(q);
        }
-       else if(strncmp(tok,"hostname=", 9) == 0) {
-           if(g_options->hostname != NULL) {
-               dbprintf(("%s: multiple hostname option\n", 
-                         debug_prefix(NULL)));
-               if(verbose) {
-                   printf("ERROR [multiple hostname option]\n");
-               }
-           }
-           g_options->hostname = stralloc(tok+9);
+    }
+
+    if (!is_empty_sl(options->exclude_list)) {
+       for(sle = options->exclude_list->first ; sle != NULL; sle=sle->next) {
+           q = quote_string(sle->name);
+           g_fprintf(tool, "EXCLUDE-LIST %s\n", q);
+           amfree(q);
        }
-       else if(strncmp(tok,"maxdumps=", 9) == 0) {
-           if(g_options->maxdumps != 0) {
-               dbprintf(("%s: multiple maxdumps option\n", 
-                         debug_prefix(NULL)));
-               if(verbose) {
-                   printf("ERROR [multiple maxdumps option]\n");
-               }
-           }
-           if(sscanf(tok+9, "%d;", &new_maxdumps) == 1) {
-               if (new_maxdumps > MAXMAXDUMPS) {
-                   g_options->maxdumps = MAXMAXDUMPS;
-               }
-               else if (new_maxdumps > 0) {
-                   g_options->maxdumps = new_maxdumps;
-               }
-               else {
-                   dbprintf(("%s: bad maxdumps value \"%s\"\n",
-                             debug_prefix(NULL), tok+9));
-                   if(verbose) {
-                       printf("ERROR [bad maxdumps value \"%s\"]\n",
-                              tok+9);
-                   }
-               }
-           }
-           else {
-               dbprintf(("%s: bad maxdumps value \"%s\"\n",
-                         debug_prefix(NULL), tok+9));
-               if(verbose) {
-                   printf("ERROR [bad maxdumps value \"%s\"]\n",
-                          tok+9);
-               }
-           }
+    }
+
+    if (!is_empty_sl(options->include_file)) {
+       for(sle = options->include_file->first ; sle != NULL; sle=sle->next) {
+           q = quote_string(sle->name);
+           g_fprintf(tool, "INCLUDE-FILE %s\n", q);
+           amfree(q);
        }
-       else {
-           dbprintf(("%s: unknown option \"%s\"\n",
-                                  debug_prefix(NULL), tok));
-           if(verbose) {
-               printf("ERROR [unknown option \"%s\"]\n", tok);
-           }
+    }
+
+    if (!is_empty_sl(options->include_list)) {
+       for(sle = options->include_list->first ; sle != NULL; sle=sle->next) {
+           q = quote_string(sle->name);
+           g_fprintf(tool, "INCLUDE-LIST %s\n", q);
+           amfree(q);
        }
-       tok = strtok(NULL, ";");
     }
-    if(g_options->features == NULL) {
-       g_options->features = am_set_default_feature_set();
+
+    if (!is_empty_sl(options->exclude_file) ||
+       !is_empty_sl(options->exclude_list)) {
+       if (options->exclude_optional)
+           g_fprintf(tool, "EXCLUDE-OPTIONAL YES\n");
+       else
+           g_fprintf(tool, "EXCLUDE-OPTIONAL NO\n");
+    }
+
+    if (!is_empty_sl(options->include_file) ||
+       !is_empty_sl(options->include_list)) {
+       if (options->include_optional)
+           g_fprintf(tool, "INCLUDE-OPTIONAL YES\n");
+       else
+           g_fprintf(tool, "INCLUDE-OPTIONAL NO\n");
     }
-    if(g_options->maxdumps == 0) /* default */
-       g_options->maxdumps = 1;
-    amfree(p);
-    return g_options;
 }
+
+backup_support_option_t *
+backup_support_option(
+    char       *program,
+    g_option_t *g_options,
+    char       *disk,
+    char       *amdevice)
+{
+    pid_t   supportpid;
+    int     supportin, supportout, supporterr;
+    char   *cmd;
+    char  **argvchild;
+    int     i;
+    FILE   *streamout;
+    char   *line;
+    backup_support_option_t *bsu;
+
+    cmd = vstralloc(DUMPER_DIR, "/", program, NULL);
+    argvchild = malloc(5 * SIZEOF(char *));
+    i = 0;
+    argvchild[i++] = program;
+    argvchild[i++] = "support";
+    if (g_options->config) {
+       argvchild[i++] = "--config";
+       argvchild[i++] = g_options->config;
+    }
+    if (g_options->hostname) {
+       argvchild[i++] = "--host";
+       argvchild[i++] = g_options->hostname;
+    }
+    if (disk) {
+       argvchild[i++] = "--disk";
+       argvchild[i++] = disk;
+    }
+    if (amdevice) {
+       argvchild[i++] = "--device";
+       argvchild[i++] = amdevice;
+    }
+    argvchild[i++] = NULL;
+
+    supporterr = fileno(stderr);
+    supportpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE, &supportin,
+                           &supportout, &supporterr, argvchild);
+
+    aclose(supportin);
+
+    bsu = malloc(SIZEOF(*bsu));
+    memset(bsu, '\0', SIZEOF(*bsu));
+    streamout = fdopen(supportout, "r");
+    while((line = agets(streamout)) != NULL) {
+       dbprintf(_("support line: %s\n"), line);
+       if (strncmp(line,"CONFIG ", 7) == 0) {
+           if (strcmp(line+7, "YES") == 0)
+               bsu->config = 1;
+       } else if (strncmp(line,"HOST ", 5) == 0) {
+           if (strcmp(line+5, "YES") == 0)
+           bsu->host = 1;
+       } else if (strncmp(line,"DISK ", 5) == 0) {
+           if (strcmp(line+5, "YES") == 0)
+               bsu->host = 1;
+       } else if (strncmp(line,"INDEX-LINE ", 11) == 0) {
+           if (strcmp(line+11, "YES") == 0)
+               bsu->index_line = 1;
+       } else if (strncmp(line,"INDEX-XML ", 10) == 0) {
+           if (strcmp(line+10, "YES") == 0)
+               bsu->index_xml = 1;
+       } else if (strncmp(line,"MESSAGE-LINE ", 13) == 0) {
+           if (strcmp(line+13, "YES") == 0)
+               bsu->message_line = 1;
+       } else if (strncmp(line,"MESSAGE-XML ", 12) == 0) {
+           if (strcmp(line+12, "YES") == 0)
+               bsu->message_xml = 1;
+       } else if (strncmp(line,"RECORD ", 7) == 0) {
+           if (strcmp(line+7, "YES") == 0)
+               bsu->record = 1;
+       } else if (strncmp(line,"INCLUDE-FILE ", 13) == 0) {
+           if (strcmp(line+13, "YES") == 0)
+               bsu->include_file = 1;
+       } else if (strncmp(line,"INCLUDE-LIST ", 13) == 0) {
+           if (strcmp(line+13, "YES") == 0)
+               bsu->include_list = 1;
+       } else if (strncmp(line,"EXCLUDE-FILE ", 13) == 0) {
+           if (strcmp(line+13, "YES") == 0)
+               bsu->exclude_file = 1;
+       } else if (strncmp(line,"EXCLUDE-LIST ", 13) == 0) {
+           if (strcmp(line+13, "YES") == 0)
+               bsu->exclude_list = 1;
+       } else if (strncmp(line,"COLLECTION ", 11) == 0) {
+           if (strcmp(line+11, "YES") == 0)
+               bsu->collection = 1;
+       } else if (strncmp(line,"MAX-LEVEL ", 10) == 0) {
+           bsu->max_level  = atoi(line+10);
+       } else {
+           dbprintf(_("Invalid support line: %s\n"), line);
+       }
+       amfree(line);
+    }
+    aclose(supportout);
+
+    return NULL;
+}
+