7765532e1e0dd525729736246d271d767a574df9
[debian/amanda] / client-src / client_util.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: client_util.c,v 1.34 2006/05/25 01:47:11 johnfranks Exp $
28  *
29  */
30
31 #include "amanda.h"
32 #include "conffile.h"
33 #include "client_util.h"
34 #include "getfsent.h"
35 #include "util.h"
36 #include "timestamp.h"
37 #include "pipespawn.h"
38
39 #define MAXMAXDUMPS 16
40
41 static int add_exclude(FILE *file_exclude, char *aexc, int verbose);
42 static int add_include(char *disk, char *device, FILE *file_include, char *ainc, int verbose);
43 static char *build_name(char *disk, char *exin, int verbose);
44 static char *get_name(char *diskname, char *exin, time_t t, int n);
45
46
47 char *
48 fixup_relative(
49     char *      name,
50     char *      device)
51 {
52     char *newname;
53     if(*name != '/') {
54         char *dirname = amname_to_dirname(device);
55         newname = vstralloc(dirname, "/", name , NULL);
56         amfree(dirname);
57     }
58     else {
59         newname = stralloc(name);
60     }
61     return newname;
62 }
63
64
65 static char *
66 get_name(
67     char *      diskname,
68     char *      exin,
69     time_t      t,
70     int         n)
71 {
72     char number[NUM_STR_SIZE];
73     char *filename;
74     char *ts;
75
76     ts = get_timestamp_from_time(t);
77     if(n == 0)
78         number[0] = '\0';
79     else
80         g_snprintf(number, SIZEOF(number), "%03d", n - 1);
81         
82     filename = vstralloc(get_pname(), ".", diskname, ".", ts, number, ".",
83                          exin, NULL);
84     amfree(ts);
85     return filename;
86 }
87
88
89 static char *
90 build_name(
91     char *      disk,
92     char *      exin,
93     int         verbose)
94 {
95     int n;
96     int fd;
97     char *filename = NULL;
98     char *afilename = NULL;
99     char *diskname;
100     time_t curtime;
101     char *dbgdir;
102     char *e = NULL;
103     DIR *d;
104     struct dirent *entry;
105     char *test_name;
106     size_t match_len, d_name_len;
107     char *quoted;
108
109     time(&curtime);
110     diskname = sanitise_filename(disk);
111
112     dbgdir = stralloc2(AMANDA_TMPDIR, "/");
113     if((d = opendir(AMANDA_TMPDIR)) == NULL) {
114         error(_("open debug directory \"%s\": %s"),
115                 AMANDA_TMPDIR, strerror(errno));
116         /*NOTREACHED*/
117     }
118     test_name = get_name(diskname, exin,
119                          curtime - (AMANDA_DEBUG_DAYS * 24 * 60 * 60), 0);
120     match_len = strlen(get_pname()) + strlen(diskname) + 2;
121     while((entry = readdir(d)) != NULL) {
122         if(is_dot_or_dotdot(entry->d_name)) {
123             continue;
124         }
125         d_name_len = strlen(entry->d_name);
126         if(strncmp(test_name, entry->d_name, match_len) != 0
127            || d_name_len < match_len + 14 + 8
128            || strcmp(entry->d_name+ d_name_len - 7, exin) != 0) {
129             continue;                           /* not one of our files */
130         }
131         if(strcmp(entry->d_name, test_name) < 0) {
132             e = newvstralloc(e, dbgdir, entry->d_name, NULL);
133             (void) unlink(e);                   /* get rid of old file */
134         }
135     }
136     amfree(test_name);
137     amfree(e);
138     closedir(d);
139
140     n=0;
141     do {
142         filename = get_name(diskname, exin, curtime, n);
143         afilename = newvstralloc(afilename, dbgdir, filename, NULL);
144         if((fd=open(afilename, O_WRONLY|O_CREAT|O_APPEND, 0600)) < 0){
145             amfree(afilename);
146             n++;
147         }
148         else {
149             close(fd);
150         }
151         amfree(filename);
152     } while(!afilename && n < 1000);
153
154     if(afilename == NULL) {
155         filename = get_name(diskname, exin, curtime, 0);
156         afilename = newvstralloc(afilename, dbgdir, filename, NULL);
157         quoted = quote_string(afilename);
158         dbprintf(_("Cannot create %s (%s)\n"), quoted, strerror(errno));
159         if(verbose) {
160             g_printf(_("ERROR [cannot create %s (%s)]\n"),
161                         quoted, strerror(errno));
162         }
163         amfree(quoted);
164         amfree(afilename);
165         amfree(filename);
166     }
167
168     amfree(dbgdir);
169     amfree(diskname);
170
171     return afilename;
172 }
173
174
175 static int
176 add_exclude(
177     FILE *      file_exclude,
178     char *      aexc,
179     int         verbose)
180 {
181     size_t l;
182     char *quoted, *file;
183
184     (void)verbose;      /* Quiet unused parameter warning */
185
186     l = strlen(aexc);
187     if(aexc[l-1] == '\n') {
188         aexc[l-1] = '\0';
189         l--;
190     }
191     file = quoted = quote_string(aexc);
192     if (*file == '"') {
193         file[strlen(file) - 1] = '\0';
194         file++;
195     }
196     g_fprintf(file_exclude, "%s\n", file);
197     amfree(quoted);
198     return 1;
199 }
200
201 static int
202 add_include(
203     char *      disk,
204     char *      device,
205     FILE *      file_include,
206     char *      ainc,
207     int         verbose)
208 {
209     size_t l;
210     int nb_exp=0;
211     char *quoted, *file;
212
213     (void)disk; /* Quiet unused parameter warning */
214
215     l = strlen(ainc);
216     if(ainc[l-1] == '\n') {
217         ainc[l-1] = '\0';
218         l--;
219     }
220     if (strncmp(ainc, "./", 2) != 0) {
221         quoted = quote_string(ainc);
222         dbprintf(_("include must start with './' (%s)\n"), quoted);
223         if(verbose) {
224             g_printf(_("ERROR [include must start with './' (%s)]\n"), quoted);
225         }
226         amfree(quoted);
227     }
228     else {
229         char *incname = ainc+2;
230
231         if(strchr(incname, '/')) {
232             file = quoted = quote_string(ainc);
233             if (*file == '"') {
234                 file[strlen(file) - 1] = '\0';
235                 file++;
236             }
237             g_fprintf(file_include, "%s\n", file);
238             amfree(quoted);
239             nb_exp++;
240         }
241         else {
242             char *regex;
243             DIR *d;
244             struct dirent *entry;
245
246             regex = glob_to_regex(incname);
247             if((d = opendir(device)) == NULL) {
248                 quoted = quote_string(device);
249                 dbprintf(_("Can't open disk %s\n"), quoted);
250                 if(verbose) {
251                     g_printf(_("ERROR [Can't open disk %s]\n"), quoted);
252                 }
253                 amfree(quoted);
254             }
255             else {
256                 while((entry = readdir(d)) != NULL) {
257                     if(is_dot_or_dotdot(entry->d_name)) {
258                         continue;
259                     }
260                     if(match(regex, entry->d_name)) {
261                         incname = vstralloc("./", entry->d_name, NULL);
262                         file = quoted = quote_string(incname);
263                         if (*file == '"') {
264                             file[strlen(file) - 1] = '\0';
265                             file++;
266                         }
267                         g_fprintf(file_include, "%s\n", file);
268                         amfree(quoted);
269                         amfree(incname);
270                         nb_exp++;
271                     }
272                 }
273                 closedir(d);
274             }
275             amfree(regex);
276         }
277     }
278     return nb_exp;
279 }
280
281 char *
282 build_exclude(
283     char *      disk,
284     char *      device,
285     option_t *  options,
286     int         verbose)
287 {
288     char *filename;
289     FILE *file_exclude;
290     FILE *exclude;
291     char *aexc;
292     sle_t *excl;
293     int nb_exclude = 0;
294     char *quoted;
295
296     if(options->exclude_file) nb_exclude += options->exclude_file->nb_element;
297     if(options->exclude_list) nb_exclude += options->exclude_list->nb_element;
298
299     if(nb_exclude == 0) return NULL;
300
301     if((filename = build_name(disk, "exclude", verbose)) != NULL) {
302         if((file_exclude = fopen(filename,"w")) != NULL) {
303
304             if(options->exclude_file) {
305                 for(excl = options->exclude_file->first; excl != NULL;
306                     excl = excl->next) {
307                     add_exclude(file_exclude, excl->name,
308                                 verbose && options->exclude_optional == 0);
309                 }
310             }
311
312             if(options->exclude_list) {
313                 for(excl = options->exclude_list->first; excl != NULL;
314                     excl = excl->next) {
315                     char *exclname = fixup_relative(excl->name, device);
316                     if((exclude = fopen(exclname, "r")) != NULL) {
317                         while ((aexc = agets(exclude)) != NULL) {
318                             if (aexc[0] == '\0') {
319                                 amfree(aexc);
320                                 continue;
321                             }
322                             add_exclude(file_exclude, aexc,
323                                         verbose && options->exclude_optional == 0);
324                             amfree(aexc);
325                         }
326                         fclose(exclude);
327                     }
328                     else {
329                         quoted = quote_string(exclname);
330                         dbprintf(_("Can't open exclude file %s (%s)\n"),
331                                   quoted, strerror(errno));
332                         if(verbose && (options->exclude_optional == 0 ||
333                                        errno != ENOENT)) {
334                             g_printf(_("ERROR [Can't open exclude file %s (%s)]\n"),
335                                    quoted, strerror(errno));
336                         }
337                         amfree(quoted);
338                     }
339                     amfree(exclname);
340                 }
341             }
342             fclose(file_exclude);
343         }
344         else {
345             quoted = quote_string(filename);
346             dbprintf(_("Can't create exclude file %s (%s)\n"),
347                       quoted, strerror(errno));
348             if(verbose) {
349                 g_printf(_("ERROR [Can't create exclude file %s (%s)]\n"),
350                         quoted, strerror(errno));
351             }
352             amfree(quoted);
353         }
354     }
355
356     return filename;
357 }
358
359 char *
360 build_include(
361     char *      disk,
362     char *      device,
363     option_t *  options,
364     int         verbose)
365 {
366     char *filename;
367     FILE *file_include;
368     FILE *include;
369     char *ainc = NULL;
370     sle_t *incl;
371     int nb_include = 0;
372     int nb_exp = 0;
373     char *quoted;
374
375     if(options->include_file) nb_include += options->include_file->nb_element;
376     if(options->include_list) nb_include += options->include_list->nb_element;
377
378     if(nb_include == 0) return NULL;
379
380     if((filename = build_name(disk, "include", verbose)) != NULL) {
381         if((file_include = fopen(filename,"w")) != NULL) {
382
383             if(options->include_file) {
384                 for(incl = options->include_file->first; incl != NULL;
385                     incl = incl->next) {
386                     nb_exp += add_include(disk, device, file_include,
387                                   incl->name,
388                                   verbose && options->include_optional == 0);
389                 }
390             }
391
392             if(options->include_list) {
393                 for(incl = options->include_list->first; incl != NULL;
394                     incl = incl->next) {
395                     char *inclname = fixup_relative(incl->name, device);
396                     if((include = fopen(inclname, "r")) != NULL) {
397                         while ((ainc = agets(include)) != NULL) {
398                             if (ainc[0] == '\0') {
399                                 amfree(ainc);
400                                 continue;
401                             }
402                             nb_exp += add_include(disk, device,
403                                                   file_include, ainc,
404                                                   verbose && options->include_optional == 0);
405                             amfree(ainc);
406                         }
407                         fclose(include);
408                     }
409                     else {
410                         quoted = quote_string(inclname);
411                         dbprintf(_("Can't open include file %s (%s)\n"),
412                                   quoted, strerror(errno));
413                         if(verbose && (options->include_optional == 0 ||
414                                        errno != ENOENT)) {
415                             g_printf(_("ERROR [Can't open include file %s (%s)]\n"),
416                                    quoted, strerror(errno));
417                         }
418                         amfree(quoted);
419                    }
420                    amfree(inclname);
421                 }
422             }
423             fclose(file_include);
424         }
425         else {
426             quoted = quote_string(filename);
427             dbprintf(_("Can't create include file %s (%s)\n"),
428                       quoted, strerror(errno));
429             if(verbose) {
430                 g_printf(_("ERROR [Can't create include file %s (%s)]\n"),
431                         quoted, strerror(errno));
432             }
433             amfree(quoted);
434         }
435     }
436         
437     if(nb_exp == 0) {
438         quoted = quote_string(disk);
439         dbprintf(_("No include for %s\n"), quoted);
440         if(verbose && options->include_optional == 0) {
441             g_printf(_("ERROR [No include for %s]\n"), quoted);
442         }
443         amfree(quoted);
444     }
445
446     return filename;
447 }
448
449
450 void
451 init_options(
452     option_t *options)
453 {
454     options->str = NULL;
455     options->compress = COMP_NONE;
456     options->srvcompprog = NULL;
457     options->clntcompprog = NULL;
458     options->encrypt = ENCRYPT_NONE;
459     options->kencrypt = 0;
460     options->srv_encrypt = NULL;
461     options->clnt_encrypt = NULL;
462     options->srv_decrypt_opt = NULL;
463     options->clnt_decrypt_opt = NULL;
464     options->no_record = 0;
465     options->createindex = 0;
466     options->auth = NULL;
467     options->exclude_file = NULL;
468     options->exclude_list = NULL;
469     options->include_file = NULL;
470     options->include_list = NULL;
471     options->exclude_optional = 0;
472     options->include_optional = 0;
473 }
474
475
476 option_t *
477 parse_options(
478     char *str,
479     char *disk,
480     char *device,
481     am_feature_t *fs,
482     int verbose)
483 {
484     char *exc;
485     char *inc;
486     option_t *options;
487     char *p, *tok;
488     char *quoted;
489
490     (void)disk;         /* Quiet unused parameter warning */
491     (void)device;       /* Quiet unused parameter warning */
492
493     options = alloc(SIZEOF(option_t));
494     init_options(options);
495     options->str = stralloc(str);
496
497     p = stralloc(str);
498     tok = strtok(p,";");
499
500     while (tok != NULL) {
501         if(am_has_feature(fs, fe_options_auth)
502            && BSTRNCMP(tok,"auth=") == 0) {
503             if(options->auth != NULL) {
504                 quoted = quote_string(tok + 5);
505                 dbprintf(_("multiple auth option %s\n"), quoted);
506                 if(verbose) {
507                     g_printf(_("ERROR [multiple auth option %s]\n"), quoted);
508                 }
509                 amfree(quoted);
510             }
511             options->auth = stralloc(&tok[5]);
512         }
513         else if(am_has_feature(fs, fe_options_bsd_auth)
514            && BSTRNCMP(tok, "bsd-auth") == 0) {
515             if(options->auth != NULL) {
516                 dbprintf(_("multiple auth option\n"));
517                 if(verbose) {
518                     g_printf(_("ERROR [multiple auth option]\n"));
519                 }
520             }
521             options->auth = stralloc("bsd");
522         }
523         else if(am_has_feature(fs, fe_options_krb4_auth)
524            && BSTRNCMP(tok, "krb4-auth") == 0) {
525             if(options->auth != NULL) {
526                 dbprintf(_("multiple auth option\n"));
527                 if(verbose) {
528                     g_printf(_("ERROR [multiple auth option]\n"));
529                 }
530             }
531             options->auth = stralloc("krb4");
532         }
533         else if(BSTRNCMP(tok, "compress-fast") == 0) {
534             if(options->compress != COMP_NONE) {
535                 dbprintf(_("multiple compress option\n"));
536                 if(verbose) {
537                     g_printf(_("ERROR [multiple compress option]\n"));
538                 }
539             }
540             options->compress = COMP_FAST;
541         }
542         else if(BSTRNCMP(tok, "compress-best") == 0) {
543             if(options->compress != COMP_NONE) {
544                 dbprintf(_("multiple compress option\n"));
545                 if(verbose) {
546                     g_printf(_("ERROR [multiple compress option]\n"));
547                 }
548             }
549             options->compress = COMP_BEST;
550         }
551         else if(BSTRNCMP(tok, "srvcomp-fast") == 0) {
552             if(options->compress != COMP_NONE) {
553                 dbprintf(_("multiple compress option\n"));
554                 if(verbose) {
555                     g_printf(_("ERROR [multiple compress option]\n"));
556                 }
557             }
558             options->compress = COMP_SERVER_FAST;
559         }
560         else if(BSTRNCMP(tok, "srvcomp-best") == 0) {
561             if(options->compress != COMP_NONE) {
562                 dbprintf(_("multiple compress option\n"));
563                 if(verbose) {
564                     g_printf(_("ERROR [multiple compress option]\n"));
565                 }
566             }
567             options->compress = COMP_SERVER_BEST;
568         }
569         else if(BSTRNCMP(tok, "srvcomp-cust=") == 0) {
570             if(options->compress != COMP_NONE) {
571                 dbprintf(_("multiple compress option\n"));
572                 if(verbose) {
573                     g_printf(_("ERROR [multiple compress option]\n"));
574                 }
575             }
576             options->srvcompprog = stralloc(tok + SIZEOF("srvcomp-cust=") -1);
577             options->compress = COMP_SERVER_CUST;
578         }
579         else if(BSTRNCMP(tok, "comp-cust=") == 0) {
580             if(options->compress != COMP_NONE) {
581                 dbprintf(_("multiple compress option\n"));
582                 if(verbose) {
583                     g_printf(_("ERROR [multiple compress option]\n"));
584                 }
585             }
586             options->clntcompprog = stralloc(tok + SIZEOF("comp-cust=") -1);
587             options->compress = COMP_CUST;
588             /* parse encryption options */
589         } 
590         else if(BSTRNCMP(tok, "encrypt-serv-cust=") == 0) {
591             if(options->encrypt != ENCRYPT_NONE) {
592                 dbprintf(_("multiple encrypt option\n"));
593                 if(verbose) {
594                     g_printf(_("ERROR [multiple encrypt option]\n"));
595                 }
596             }
597             options->srv_encrypt = stralloc(tok + SIZEOF("encrypt-serv-cust=") -1);
598             options->encrypt = ENCRYPT_SERV_CUST;
599         } 
600         else if(BSTRNCMP(tok, "encrypt-cust=") == 0) {
601             if(options->encrypt != ENCRYPT_NONE) {
602                 dbprintf(_("multiple encrypt option\n"));
603                 if(verbose) {
604                     g_printf(_("ERROR [multiple encrypt option]\n"));
605                 }
606             }
607             options->clnt_encrypt= stralloc(tok + SIZEOF("encrypt-cust=") -1);
608             options->encrypt = ENCRYPT_CUST;
609         } 
610         else if(BSTRNCMP(tok, "server-decrypt-option=") == 0) {
611           options->srv_decrypt_opt = stralloc(tok + SIZEOF("server-decrypt-option=") -1);
612         }
613         else if(BSTRNCMP(tok, "client-decrypt-option=") == 0) {
614           options->clnt_decrypt_opt = stralloc(tok + SIZEOF("client-decrypt-option=") -1);
615         }
616         else if(BSTRNCMP(tok, "no-record") == 0) {
617             if(options->no_record != 0) {
618                 dbprintf(_("multiple no-record option\n"));
619                 if(verbose) {
620                     g_printf(_("ERROR [multiple no-record option]\n"));
621                 }
622             }
623             options->no_record = 1;
624         }
625         else if(BSTRNCMP(tok, "index") == 0) {
626             if(options->createindex != 0) {
627                 dbprintf(_("multiple index option\n"));
628                 if(verbose) {
629                     g_printf(_("ERROR [multiple index option]\n"));
630                 }
631             }
632             options->createindex = 1;
633         }
634         else if(BSTRNCMP(tok, "exclude-optional") == 0) {
635             if(options->exclude_optional != 0) {
636                 dbprintf(_("multiple exclude-optional option\n"));
637                 if(verbose) {
638                     g_printf(_("ERROR [multiple exclude-optional option]\n"));
639                 }
640             }
641             options->exclude_optional = 1;
642         }
643         else if(strcmp(tok, "include-optional") == 0) {
644             if(options->include_optional != 0) {
645                 dbprintf(_("multiple include-optional option\n"));
646                 if(verbose) {
647                     g_printf(_("ERROR [multiple include-optional option]\n"));
648                 }
649             }
650             options->include_optional = 1;
651         }
652         else if(BSTRNCMP(tok,"exclude-file=") == 0) {
653             exc = unquote_string(&tok[13]);
654             options->exclude_file = append_sl(options->exclude_file, exc);
655             amfree(exc);
656         }
657         else if(BSTRNCMP(tok,"exclude-list=") == 0) {
658             exc = unquote_string(&tok[13]);
659             options->exclude_list = append_sl(options->exclude_list, exc);
660             amfree(exc);
661         }
662         else if(BSTRNCMP(tok,"include-file=") == 0) {
663             inc = unquote_string(&tok[13]);
664             options->include_file = append_sl(options->include_file, inc);
665             amfree(inc);
666         }
667         else if(BSTRNCMP(tok,"include-list=") == 0) {
668             inc = unquote_string(&tok[13]);
669             options->include_list = append_sl(options->include_list, inc);
670             amfree(inc);
671         }
672         else if(BSTRNCMP(tok,"kencrypt") == 0) {
673             options->kencrypt = 1;
674         }
675         else if(strcmp(tok,"|") != 0) {
676             quoted = quote_string(tok);
677             dbprintf(_("unknown option %s\n"), quoted);
678             if(verbose) {
679                 g_printf(_("ERROR [unknown option: %s]\n"), quoted);
680             }
681             amfree(quoted);
682         }
683         tok = strtok(NULL, ";");
684     }
685     amfree(p);
686     return options;
687 }
688
689 void
690 output_tool_property(
691     FILE     *tool,
692     option_t *options)
693 {
694     sle_t *sle;
695     char *q;
696
697     if (!is_empty_sl(options->exclude_file)) {
698         for(sle = options->exclude_file->first ; sle != NULL; sle=sle->next) {
699             q = quote_string(sle->name);
700             g_fprintf(tool, "EXCLUDE-FILE %s\n", q);
701             amfree(q);
702         }
703     }
704
705     if (!is_empty_sl(options->exclude_list)) {
706         for(sle = options->exclude_list->first ; sle != NULL; sle=sle->next) {
707             q = quote_string(sle->name);
708             g_fprintf(tool, "EXCLUDE-LIST %s\n", q);
709             amfree(q);
710         }
711     }
712
713     if (!is_empty_sl(options->include_file)) {
714         for(sle = options->include_file->first ; sle != NULL; sle=sle->next) {
715             q = quote_string(sle->name);
716             g_fprintf(tool, "INCLUDE-FILE %s\n", q);
717             amfree(q);
718         }
719     }
720
721     if (!is_empty_sl(options->include_list)) {
722         for(sle = options->include_list->first ; sle != NULL; sle=sle->next) {
723             q = quote_string(sle->name);
724             g_fprintf(tool, "INCLUDE-LIST %s\n", q);
725             amfree(q);
726         }
727     }
728
729     if (!is_empty_sl(options->exclude_file) ||
730         !is_empty_sl(options->exclude_list)) {
731         if (options->exclude_optional)
732             g_fprintf(tool, "EXCLUDE-OPTIONAL YES\n");
733         else
734             g_fprintf(tool, "EXCLUDE-OPTIONAL NO\n");
735     }
736
737     if (!is_empty_sl(options->include_file) ||
738         !is_empty_sl(options->include_list)) {
739         if (options->include_optional)
740             g_fprintf(tool, "INCLUDE-OPTIONAL YES\n");
741         else
742             g_fprintf(tool, "INCLUDE-OPTIONAL NO\n");
743     }
744 }
745
746 backup_support_option_t *
747 backup_support_option(
748     char       *program,
749     g_option_t *g_options,
750     char       *disk,
751     char       *amdevice)
752 {
753     pid_t   supportpid;
754     int     supportin, supportout, supporterr;
755     char   *cmd;
756     char  **argvchild;
757     int     i;
758     FILE   *streamout;
759     char   *line;
760     backup_support_option_t *bsu;
761
762     cmd = vstralloc(DUMPER_DIR, "/", program, NULL);
763     argvchild = malloc(5 * SIZEOF(char *));
764     i = 0;
765     argvchild[i++] = program;
766     argvchild[i++] = "support";
767     if (g_options->config) {
768         argvchild[i++] = "--config";
769         argvchild[i++] = g_options->config;
770     }
771     if (g_options->hostname) {
772         argvchild[i++] = "--host";
773         argvchild[i++] = g_options->hostname;
774     }
775     if (disk) {
776         argvchild[i++] = "--disk";
777         argvchild[i++] = disk;
778     }
779     if (amdevice) {
780         argvchild[i++] = "--device";
781         argvchild[i++] = amdevice;
782     }
783     argvchild[i++] = NULL;
784
785     supporterr = fileno(stderr);
786     supportpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE, &supportin,
787                             &supportout, &supporterr, argvchild);
788
789     aclose(supportin);
790
791     bsu = malloc(SIZEOF(*bsu));
792     memset(bsu, '\0', SIZEOF(*bsu));
793     streamout = fdopen(supportout, "r");
794     while((line = agets(streamout)) != NULL) {
795         dbprintf(_("support line: %s\n"), line);
796         if (strncmp(line,"CONFIG ", 7) == 0) {
797             if (strcmp(line+7, "YES") == 0)
798                 bsu->config = 1;
799         } else if (strncmp(line,"HOST ", 5) == 0) {
800             if (strcmp(line+5, "YES") == 0)
801             bsu->host = 1;
802         } else if (strncmp(line,"DISK ", 5) == 0) {
803             if (strcmp(line+5, "YES") == 0)
804                 bsu->host = 1;
805         } else if (strncmp(line,"INDEX-LINE ", 11) == 0) {
806             if (strcmp(line+11, "YES") == 0)
807                 bsu->index_line = 1;
808         } else if (strncmp(line,"INDEX-XML ", 10) == 0) {
809             if (strcmp(line+10, "YES") == 0)
810                 bsu->index_xml = 1;
811         } else if (strncmp(line,"MESSAGE-LINE ", 13) == 0) {
812             if (strcmp(line+13, "YES") == 0)
813                 bsu->message_line = 1;
814         } else if (strncmp(line,"MESSAGE-XML ", 12) == 0) {
815             if (strcmp(line+12, "YES") == 0)
816                 bsu->message_xml = 1;
817         } else if (strncmp(line,"RECORD ", 7) == 0) {
818             if (strcmp(line+7, "YES") == 0)
819                 bsu->record = 1;
820         } else if (strncmp(line,"INCLUDE-FILE ", 13) == 0) {
821             if (strcmp(line+13, "YES") == 0)
822                 bsu->include_file = 1;
823         } else if (strncmp(line,"INCLUDE-LIST ", 13) == 0) {
824             if (strcmp(line+13, "YES") == 0)
825                 bsu->include_list = 1;
826         } else if (strncmp(line,"EXCLUDE-FILE ", 13) == 0) {
827             if (strcmp(line+13, "YES") == 0)
828                 bsu->exclude_file = 1;
829         } else if (strncmp(line,"EXCLUDE-LIST ", 13) == 0) {
830             if (strcmp(line+13, "YES") == 0)
831                 bsu->exclude_list = 1;
832         } else if (strncmp(line,"COLLECTION ", 11) == 0) {
833             if (strcmp(line+11, "YES") == 0)
834                 bsu->collection = 1;
835         } else if (strncmp(line,"MAX-LEVEL ", 10) == 0) {
836             bsu->max_level  = atoi(line+10);
837         } else {
838             dbprintf(_("Invalid support line: %s\n"), line);
839         }
840         amfree(line);
841     }
842     aclose(supportout);
843
844     return NULL;
845 }
846