544346a66e7d307d461cf005fe1fe908a834fd46
[debian/amanda] / server-src / diskfile.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  * Author: James da Silva, Systems Design and Analysis Group
24  *                         Computer Science Department
25  *                         University of Maryland at College Park
26  */
27 /*
28  * $Id: diskfile.c,v 1.95 2006/07/26 15:17:37 martinea Exp $
29  *
30  * read disklist file
31  */
32 #include "amanda.h"
33 #include "match.h"
34 #include "arglist.h"
35 #include "conffile.h"
36 #include "diskfile.h"
37 #include "util.h"
38 #include "amxml.h"
39
40 static am_host_t *hostlist;
41 static netif_t *all_netifs;
42
43 /* local functions */
44 static char *upcase(char *st);
45 static int parse_diskline(disklist_t *, const char *, FILE *, int *, char **);
46 static void disk_parserror(const char *, int, const char *, ...)
47                             G_GNUC_PRINTF(3, 4);
48
49
50 cfgerr_level_t
51 read_diskfile(
52     const char *filename,
53     disklist_t *lst)
54 {
55     FILE *diskf;
56     int line_num;
57     char *line = NULL;
58
59     /* initialize */
60     hostlist = NULL;
61     lst->head = lst->tail = NULL;
62     line_num = 0;
63
64     /* if we already have config errors, then don't bother */
65     if (config_errors(NULL) >= CFGERR_ERRORS) {
66         return config_errors(NULL);
67     }
68
69     if ((diskf = fopen(filename, "r")) == NULL) {
70         config_add_error(CFGERR_ERRORS,
71             vstrallocf(_("Could not open '%s': %s"), filename, strerror(errno)));
72         goto end;
73         /*NOTREACHED*/
74     }
75
76     while ((line = agets(diskf)) != NULL) {
77         line_num++;
78         if (line[0] != '\0') {
79             if (parse_diskline(lst, filename, diskf, &line_num, &line) < 0) {
80                 goto end;
81             }
82         }
83         amfree(line);
84     }
85
86 end:
87     amfree(line);
88     afclose(diskf);
89     return config_errors(NULL);
90 }
91
92 am_host_t *
93 get_hostlist(void)
94 {
95     return hostlist;
96 }
97
98 am_host_t *
99 lookup_host(
100     const char *hostname)
101 {
102     am_host_t *p;
103
104     for (p = hostlist; p != NULL; p = p->next) {
105         if(strcasecmp(p->hostname, hostname) == 0) return p;
106     }
107     return (NULL);
108 }
109
110 disk_t *
111 lookup_disk(
112     const char *hostname,
113     const char *diskname)
114 {
115     am_host_t *host;
116     disk_t *disk;
117
118     host = lookup_host(hostname);
119     if (host == NULL)
120         return (NULL);
121
122     for (disk = host->disks; disk != NULL; disk = disk->hostnext) {
123         if (strcmp(disk->name, diskname) == 0)
124             return (disk);
125     }
126     return (NULL);
127 }
128
129
130 /*
131  * put disk on end of queue
132  */
133
134 void
135 enqueue_disk(
136     disklist_t *list,
137     disk_t *    disk)
138 {
139     if(list->tail == NULL) list->head = disk;
140     else list->tail->next = disk;
141     disk->prev = list->tail;
142
143     list->tail = disk;
144     disk->next = NULL;
145 }
146
147
148 /*
149  * put disk on head of queue
150  */
151
152 void
153 headqueue_disk(
154     disklist_t *list,
155     disk_t *    disk)
156 {
157     if(list->head == NULL) list->tail = disk;
158     else list->head->prev = disk;
159     disk->next = list->head;
160
161     list->head = disk;
162     disk->prev = NULL;
163 }
164
165
166 /*
167  * insert in sorted order
168  */
169
170 void
171 insert_disk(
172     disklist_t *list,
173     disk_t *    disk,
174     int         (*cmp)(disk_t *a, disk_t *b))
175 {
176     disk_t *prev, *ptr;
177
178     prev = NULL;
179     ptr = list->head;
180
181     while(ptr != NULL) {
182         if(cmp(disk, ptr) < 0) break;
183         prev = ptr;
184         ptr = ptr->next;
185     }
186     disk->next = ptr;
187     disk->prev = prev;
188
189     if(prev == NULL) list->head = disk;
190     else prev->next = disk;
191     if(ptr == NULL) list->tail = disk;
192     else ptr->prev = disk;
193 }
194
195 disk_t *
196 add_disk(
197     disklist_t *list,
198     char *      hostname,
199     char *      diskname)
200 {
201     disk_t *disk;
202     am_host_t *host;
203
204     disk = alloc(SIZEOF(disk_t));
205     bzero(disk, SIZEOF(disk_t));
206     disk->line = 0;
207     disk->allow_split = 0;
208     disk->max_warnings = 20;
209     disk->splitsize = (off_t)0;
210     disk->tape_splitsize = (off_t)0;
211     disk->split_diskbuffer = NULL;
212     disk->fallback_splitsize = (off_t)0;
213     disk->hostname = stralloc(hostname);
214     disk->name = stralloc(diskname);
215     disk->device = stralloc(diskname);
216     disk->spindle = -1;
217     disk->up = NULL;
218     disk->compress = COMP_NONE;
219     disk->encrypt  = ENCRYPT_NONE;
220     disk->start_t = 0;
221     disk->todo = 1;
222     disk->index = 1;
223     disk->exclude_list = NULL;
224     disk->exclude_file = NULL;
225     disk->include_list = NULL;
226     disk->include_file = NULL;
227     disk->application = NULL;
228     disk->pp_scriptlist = NULL;
229
230     host = lookup_host(hostname);
231     if(host == NULL) {
232         host = alloc(SIZEOF(am_host_t));
233         host->next = hostlist;
234         hostlist = host;
235
236         host->hostname = stralloc(hostname);
237         host->disks = NULL;
238         host->inprogress = 0;
239         host->maxdumps = 1;
240         host->netif = NULL;
241         host->start_t = 0;
242         host->up = NULL;
243         host->features = NULL;
244         host->pre_script = 0;
245         host->post_script = 0;
246     }
247     enqueue_disk(list, disk);
248
249     disk->host = host;
250     disk->hostnext = host->disks;
251     host->disks = disk;
252
253     return disk;
254 }
255
256
257 /*
258  * check if disk is present in list. Return true if so, false otherwise.
259  */
260
261 int
262 find_disk(
263     disklist_t *list,
264     disk_t *    disk)
265 {
266     disk_t *t;
267
268     t = list->head;
269     while ((t != NULL) && (t != disk)) {
270         t = t->next;
271     }
272     return (t == disk);
273 }
274
275
276 /*
277  * sort a whole queue
278  */
279
280 void
281 sort_disk(
282     disklist_t *in,
283     disklist_t *out,
284     int         (*cmp)(disk_t *a, disk_t *b))
285 {
286     disklist_t *tmp;
287     disk_t *disk;
288
289     tmp = in;           /* just in case in == out */
290
291     out->head = (disk_t *)0;
292     out->tail = (disk_t *)0;
293
294     while((disk = dequeue_disk(tmp)))
295         insert_disk(out, disk, cmp);
296 }
297
298
299 /*
300  * remove disk from front of queue
301  */
302
303 disk_t *
304 dequeue_disk(
305     disklist_t *list)
306 {
307     disk_t *disk;
308
309     if(list->head == NULL) return NULL;
310
311     disk = list->head;
312     list->head = disk->next;
313
314     if(list->head == NULL) list->tail = NULL;
315     else list->head->prev = NULL;
316
317     disk->prev = disk->next = NULL;     /* for debugging */
318     return disk;
319 }
320
321 void
322 remove_disk(
323     disklist_t *list,
324     disk_t *    disk)
325 {
326     if(disk->prev == NULL) list->head = disk->next;
327     else disk->prev->next = disk->next;
328
329     if(disk->next == NULL) list->tail = disk->prev;
330     else disk->next->prev = disk->prev;
331
332     disk->prev = disk->next = NULL;
333 }
334
335 void
336 free_disklist(
337     disklist_t* dl)
338 {
339     disk_t    *dp;
340     am_host_t *host, *hostnext;
341     netif_t *netif, *next_if;
342
343     while (dl->head != NULL) {
344         dp = dequeue_disk(dl);
345         amfree(dp->filename);
346         amfree(dp->name);
347         amfree(dp->hostname);
348         amfree(dp->device);
349         free_sl(dp->exclude_file);
350         free_sl(dp->exclude_list);
351         free_sl(dp->include_file);
352         free_sl(dp->include_list);
353         free(dp);
354     }
355
356     for(host=hostlist; host != NULL; host = hostnext) {
357         amfree(host->hostname);
358         am_release_feature_set(host->features);
359         host->features = NULL;
360         hostnext = host->next;
361         amfree(host);
362     }
363     hostlist=NULL;
364
365     for (netif = all_netifs; netif != NULL; netif = next_if) {
366         next_if = netif->next;
367         amfree(netif);
368     }
369     all_netifs = NULL;
370 }
371
372 static char *
373 upcase(
374     char *st)
375 {
376     char *s = st;
377
378     while(*s) {
379         if(islower((int)*s)) *s = (char)toupper((int)*s);
380         s++;
381     }
382     return st;
383 }
384
385
386 /* return  0 on success */
387 /* return -1 on error   */
388 static int
389 parse_diskline(
390     disklist_t *lst,
391     const char *filename,
392     FILE *      diskf,
393     int *       line_num_p,
394     /*@keep@*/ char **  line_p)
395 {
396     am_host_t *host;
397     disk_t *disk;
398     dumptype_t *dtype;
399     netif_t *netif = NULL;
400     interface_t *cfg_if = NULL;
401     char *hostname = NULL;
402     char *diskname, *diskdevice;
403     char *dumptype;
404     char *s, *fp;
405     int ch, dup = 0;
406     char *line = *line_p;
407     int line_num = *line_num_p;
408     struct tm *stm;
409     time_t st;
410     char *shost, *sdisk;
411     am_host_t *p;
412     disk_t *dp;
413     identlist_t pp_iter;
414
415     assert(filename != NULL);
416     assert(line_num > 0);
417     assert(line != NULL);
418
419     s = line;
420     ch = *s++;
421     skip_whitespace(s, ch);
422     if(ch == '\0' || ch == '#')
423         return (0);
424
425     fp = s - 1;
426     skip_non_whitespace(s, ch);
427     s[-1] = '\0';
428     if (g_str_equal(fp, "includefile")) {
429         char *include_name;
430         char *include_filename;
431         skip_whitespace(s, ch);
432         if (ch == '\0' || ch == '#') {
433             disk_parserror(filename, line_num, _("include filename name expected"));
434             return (-1);
435         }
436         fp = s - 1;
437         skip_quoted_string(s, ch);
438         s[-1] = '\0';
439         include_name = unquote_string(fp);
440         include_filename = config_dir_relative(include_name);
441         read_diskfile(include_filename, lst);
442         g_free(include_filename);
443         g_free(include_name);
444         if (config_errors(NULL) >= CFGERR_WARNINGS) {
445             return -1;
446         } else {
447             return 0;
448         }
449     }
450     host = lookup_host(fp);
451     if (host == NULL) {
452         hostname = stralloc(fp);
453     } else {
454         hostname = stralloc(host->hostname);
455         if (strcmp(host->hostname, fp) != 0) {
456             disk_parserror(filename, line_num, _("Same host with different case: \"%s\" and \"%s\"."), host->hostname, fp);
457             return -1;
458         }
459     }
460
461     shost = sanitise_filename(hostname);
462     for (p = hostlist; p != NULL; p = p->next) {
463         char *shostp = sanitise_filename(p->hostname);
464         if (strcmp(hostname, p->hostname) &&
465             !strcmp(shost, shostp)) {
466             disk_parserror(filename, line_num, _("Two hosts are mapping to the same name: \"%s\" and \"%s\""), p->hostname, hostname);
467             return(-1);
468         }
469         else if (strcasecmp(hostname, p->hostname) &&
470                  match_host(hostname, p->hostname) &&
471                  match_host(p->hostname, hostname)) {
472             disk_parserror(filename, line_num, _("Duplicate host name: \"%s\" and \"%s\""), p->hostname, hostname);
473             return(-1);
474         }
475         amfree(shostp);
476     }
477     amfree(shost);
478
479     skip_whitespace(s, ch);
480     if(ch == '\0' || ch == '#') {
481         disk_parserror(filename, line_num, _("disk device name expected"));
482         amfree(hostname);
483         return (-1);
484     }
485
486     fp = s - 1;
487     skip_quoted_string(s, ch);
488     s[-1] = '\0';
489     diskname = unquote_string(fp);
490     if (strlen(diskname) == 0) {
491         disk_parserror(filename, line_num, _("invalid empty diskname"));
492         amfree(hostname);
493         return (-1);
494     }
495     skip_whitespace(s, ch);
496     if(ch == '\0' || ch == '#') {
497         disk_parserror(filename, line_num, _("disk dumptype expected"));
498         amfree(hostname);
499         amfree(diskname);
500         return (-1);
501     }
502     fp = s - 1;
503     skip_quoted_string(s, ch);
504     s[-1] = '\0';
505
506     /* diskdevice */
507     dumptype = NULL;
508     diskdevice = NULL;
509     if(fp[0] != '{') {
510         dumptype = unquote_string(fp);
511         if (strlen(dumptype) == 0) {
512             disk_parserror(filename, line_num, _("invalid empty diskdevice"));
513             amfree(hostname);
514             return (-1);
515         }
516         if ((dtype = lookup_dumptype(dumptype)) == NULL) {
517             diskdevice = dumptype;
518             skip_whitespace(s, ch);
519             if(ch == '\0' || ch == '#') {
520                 disk_parserror(filename, line_num,
521                         _("disk dumptype '%s' not found"), dumptype);
522                 amfree(hostname);
523                 amfree(diskdevice);
524                 amfree(diskname);
525                 return (-1);
526             }
527
528             fp = s - 1;
529             skip_quoted_string(s, ch);
530             s[-1] = '\0';
531             if (fp[0] != '{') {
532                 dumptype = unquote_string(fp);
533             }
534         }
535     }
536
537     /* check for duplicate disk */
538     disk = NULL;
539     if (host) {
540         if ((disk = lookup_disk(hostname, diskname)) != NULL) {
541             dup = 1;
542         } else {
543             disk = host->disks;
544             do {
545                 char *a1, *a2;
546                 a1 = clean_regex(diskname, 1);
547                 a2 = clean_regex(disk->name, 1);
548
549                 if (match_disk(a1, disk->name) && match_disk(a2, diskname)) {
550                     dup = 1;
551                 } else {
552                     disk = disk->hostnext;
553                 }
554                 amfree(a1);
555                 amfree(a2);
556             }
557             while (dup == 0 && disk != NULL);
558         }
559         if (dup == 1) {
560             disk_parserror(filename, line_num,
561                            _("duplicate disk record, previous on line %d"),
562                            disk->line);
563         }
564     }
565     if (!disk) {
566         disk = alloc(SIZEOF(disk_t));
567         disk->filename = g_strdup(filename);
568         disk->line = line_num;
569         disk->hostname = hostname;
570         disk->name = diskname;
571         disk->device = diskdevice;
572         disk->spindle = -1;
573         disk->up = NULL;
574         disk->inprogress = 0;
575         disk->application = NULL;
576         disk->pp_scriptlist = NULL;
577         disk->dataport_list = NULL;
578     }
579
580     if (host) {
581         sdisk = sanitise_filename(diskname);
582         for (dp = host->disks; dp != NULL; dp = dp->hostnext) {
583             char *sdiskp = sanitise_filename(dp->name);
584             if (strcmp(diskname, dp->name) != 0 &&
585                  strcmp(sdisk, sdiskp) == 0) {
586                 disk_parserror(filename, line_num,
587                  _("Two disks are mapping to the same name: \"%s\" and \"%s\"; you must use different diskname"),
588                  dp->name, diskname);
589             return(-1);
590             }
591             amfree(sdiskp);
592         }
593         amfree(sdisk);
594     }
595
596     if (fp[0] == '{') {
597         s[-1] = (char)ch;
598         s = fp+2;
599         skip_whitespace(s, ch);
600         if (ch != '\0' && ch != '#') {
601             disk_parserror(filename, line_num,
602                       _("expected line break after `{\', ignoring rest of line"));
603         }
604
605         if (strchr(s-1, '}') &&
606             (strchr(s-1, '#') == NULL ||
607              strchr(s-1, '}') < strchr(s-1, '#'))) {
608             disk_parserror(filename, line_num,_("'}' on same line than '{'"));
609             amfree(hostname);
610             if(!dup) {
611                 amfree(disk->device);
612                 amfree(disk->name);
613                 amfree(disk);
614             } else {
615                 amfree(diskdevice);
616                 amfree(diskname);
617             }
618             return (-1);
619         }
620         dtype = read_dumptype(vstralloc("custom(", hostname,
621                                         ":", disk->name, ")",
622                                         ".", anonymous_value(), NULL),
623                               diskf, (char*)filename, line_num_p);
624         if (dtype == NULL || dup) {
625             disk_parserror(filename, line_num,
626                            _("read of custom dumptype failed"));
627             amfree(hostname);
628             if(!dup) {
629                 amfree(disk->device);
630                 amfree(disk->name);
631                 amfree(disk);
632             } else {
633                 amfree(diskdevice);
634                 amfree(diskname);
635             }
636             return (-1);
637         }
638         amfree(line);
639
640         *line_p = line = agets(diskf);
641         line_num = *line_num_p; /* no incr, read_dumptype did it already */
642
643         if (line == NULL)
644             *line_p = line = stralloc("");
645         s = line;
646         ch = *s++;
647     } else {
648         if((dtype = lookup_dumptype(dumptype)) == NULL) {
649             char *qdt = quote_string(dumptype);
650
651             disk_parserror(filename, line_num, _("undefined dumptype `%s'"), qdt);
652             amfree(qdt);
653             amfree(hostname);
654             if (!dup) {
655                 amfree(disk->device);
656                 amfree(disk->name);
657                 amfree(disk);
658             } else {
659                 amfree(diskdevice);
660                 amfree(diskname);
661             }
662             return (-1);
663         }
664         amfree(dumptype);
665     }
666
667     if (dup) {
668         /* disk_parserror already called, above */
669         g_assert(config_errors(NULL) != CFGERR_OK);
670         amfree(hostname);
671         amfree(diskdevice);
672         amfree(diskname);
673         return (-1);
674     }
675
676     disk->dtype_name         = dumptype_name(dtype);
677     disk->config             = dtype;
678     disk->program            = dumptype_get_program(dtype);
679     disk->exclude_list     = duplicate_sl(dumptype_get_exclude(dtype).sl_list);
680     disk->exclude_file     = duplicate_sl(dumptype_get_exclude(dtype).sl_file);
681     disk->exclude_optional   = dumptype_get_exclude(dtype).optional;
682     disk->include_list     = duplicate_sl(dumptype_get_include(dtype).sl_list);
683     disk->include_file     = duplicate_sl(dumptype_get_include(dtype).sl_file);
684     disk->include_optional   = dumptype_get_include(dtype).optional;
685     disk->priority           = dumptype_get_priority(dtype);
686     disk->dumpcycle          = dumptype_get_dumpcycle(dtype);
687 /*    disk->frequency        = dumptype_get_frequency(dtype);*/
688     disk->auth               = dumptype_get_auth(dtype);
689     disk->maxdumps           = dumptype_get_maxdumps(dtype);
690     disk->allow_split        = dumptype_get_allow_split(dtype);
691     disk->max_warnings       = dumptype_get_max_warnings(dtype);
692     disk->tape_splitsize     = dumptype_get_tape_splitsize(dtype);
693     disk->split_diskbuffer   = dumptype_get_split_diskbuffer(dtype);
694     disk->fallback_splitsize = dumptype_get_fallback_splitsize(dtype);
695     if (disk->allow_split) {
696         tapetype_t *tapetype = lookup_tapetype(getconf_str(CNF_TAPETYPE));
697         disk->splitsize = tapetype_get_part_size(tapetype);
698     } else {
699         disk->splitsize = disk->tape_splitsize;
700     }
701     disk->maxpromoteday      = dumptype_get_maxpromoteday(dtype);
702     disk->bumppercent        = dumptype_get_bumppercent(dtype);
703     disk->bumpsize           = dumptype_get_bumpsize(dtype);
704     disk->bumpdays           = dumptype_get_bumpdays(dtype);
705     disk->bumpmult           = dumptype_get_bumpmult(dtype);
706     disk->starttime          = dumptype_get_starttime(dtype);
707     disk->application        = dumptype_get_application(dtype);
708     disk->pp_scriptlist      = dumptype_get_scriptlist(dtype);
709     disk->start_t = 0;
710     if (disk->starttime > 0) {
711         st = time(NULL);
712         disk->start_t = st;
713         stm = localtime(&st);
714         disk->start_t -= stm->tm_sec + 60 * stm->tm_min + 3600 * stm->tm_hour;
715         disk->start_t += disk->starttime / 100 * 3600 +
716                          disk->starttime % 100 * 60;
717         if ((disk->start_t - st) < -43200)
718             disk->start_t += 86400;
719     }
720     disk->strategy           = dumptype_get_strategy(dtype);
721     disk->ignore             = dumptype_get_ignore(dtype);
722     disk->estimatelist       = dumptype_get_estimatelist(dtype);
723     disk->compress           = dumptype_get_compress(dtype);
724     disk->srvcompprog        = dumptype_get_srvcompprog(dtype);
725     disk->clntcompprog       = dumptype_get_clntcompprog(dtype);
726     disk->encrypt            = dumptype_get_encrypt(dtype);
727     disk->srv_decrypt_opt    = dumptype_get_srv_decrypt_opt(dtype);
728     disk->clnt_decrypt_opt   = dumptype_get_clnt_decrypt_opt(dtype);
729     disk->srv_encrypt        = dumptype_get_srv_encrypt(dtype);
730     disk->clnt_encrypt       = dumptype_get_clnt_encrypt(dtype);
731     disk->amandad_path       = dumptype_get_amandad_path(dtype);
732     disk->client_username    = dumptype_get_client_username(dtype);
733     disk->client_port        = dumptype_get_client_port(dtype);
734     disk->ssh_keys           = dumptype_get_ssh_keys(dtype);
735     disk->comprate[0]        = dumptype_get_comprate(dtype)[0];
736     disk->comprate[1]        = dumptype_get_comprate(dtype)[1];
737     disk->data_path          = dumptype_get_data_path(dtype);
738     disk->dump_limit         = dumptype_get_dump_limit(dtype);
739
740     /*
741      * Boolean parameters with no value (Appears here as value 2) defaults
742      * to TRUE for backward compatibility and for logical consistency.
743      */
744     disk->record             = dumptype_get_record(dtype) != 0;
745     disk->skip_incr          = dumptype_get_skip_incr(dtype) != 0;
746     disk->skip_full          = dumptype_get_skip_full(dtype) != 0;
747     disk->to_holdingdisk     = dumptype_get_to_holdingdisk(dtype);
748     disk->kencrypt           = dumptype_get_kencrypt(dtype) != 0;
749     disk->index              = dumptype_get_index(dtype) != 0; 
750
751     disk->todo               = 1;
752
753     skip_whitespace(s, ch);
754     fp = s - 1;
755     if(ch && ch != '#') {               /* get optional spindle number */
756         char *fp1;
757         int is_digit=1;
758
759         skip_non_whitespace(s, ch);
760         s[-1] = '\0';
761         fp1=fp;
762         if (*fp1 == '-') fp1++;
763         for(;*fp1!='\0';fp1++) {
764             if(!isdigit((int)*fp1)) {
765                 is_digit = 0;
766             }
767         }
768         if(is_digit == 0) {
769             disk_parserror(filename, line_num, _("non-integer spindle `%s'"), fp);
770             amfree(hostname);
771             amfree(disk->name);
772             amfree(disk);
773             return (-1);
774         }
775         disk->spindle = atoi(fp);
776         skip_integer(s, ch);
777     }
778
779     skip_whitespace(s, ch);
780     fp = s - 1;
781     if(ch && ch != '#') {               /* get optional network interface */
782         skip_non_whitespace(s, ch);
783         s[-1] = '\0';
784         if((cfg_if = lookup_interface(upcase(fp))) == NULL) {
785             disk_parserror(filename, line_num,
786                 _("undefined network interface `%s'"), fp);
787             amfree(hostname);
788             amfree(disk->name);
789             amfree(disk);
790             return (-1);
791         }
792     } else {
793         cfg_if = lookup_interface("default");
794     }
795
796     /* see if we already have a netif_t for this interface */
797     for (netif = all_netifs; netif != NULL; netif = netif->next) {
798         if (netif->config == cfg_if)
799             break;
800     }
801
802     /* nope; make up a new one */
803     if (!netif) {
804         netif = alloc(sizeof(*netif));
805         netif->next = all_netifs;
806         all_netifs = netif;
807         netif->config = cfg_if;
808         netif->curusage = 0;
809     }
810
811     skip_whitespace(s, ch);
812     if(ch && ch != '#') {               /* now we have garbage, ignore it */
813         disk_parserror(filename, line_num, _("end of line expected"));
814     }
815
816     if (disk->program && disk->application &&
817         strcmp(disk->program,"APPLICATION")) {
818         disk_parserror(filename, line_num,
819                        _("Both program and application set"));
820     }
821
822     if (disk->program && strcmp(disk->program,"APPLICATION")==0 &&
823         !disk->application) {
824         disk_parserror(filename, line_num,
825                        _("program set to APPLICATION but no application set"));
826     }
827
828     if (disk->application) {
829         application_t *application;
830         char          *plugin;
831
832         application = lookup_application(disk->application);
833         g_assert(application != NULL);
834         plugin = application_get_plugin(application);
835         if (!plugin || strlen(plugin) == 0) {
836             disk_parserror(filename, line_num,
837                            _("plugin not set for application"));
838         }
839     }
840
841     for (pp_iter = disk->pp_scriptlist; pp_iter != NULL;
842          pp_iter = pp_iter->next) {
843         pp_script_t *pp_script;
844         char        *plugin;
845         char        *pp_script_name;
846
847         pp_script_name = (char*)pp_iter->data;
848         pp_script = lookup_pp_script(pp_script_name);
849         g_assert(pp_script != NULL);
850         plugin = pp_script_get_plugin(pp_script);
851         if (!plugin || strlen(plugin) == 0) {
852             disk_parserror(filename, line_num, _("plugin not set for script"));
853         }
854     }
855
856     /* success, add disk to lists */
857
858     if(host == NULL) {                  /* new host */
859         host = alloc(SIZEOF(am_host_t));
860         host->next = hostlist;
861         hostlist = host;
862
863         host->hostname = stralloc(hostname);
864         hostname = NULL;
865         host->disks = NULL;
866         host->inprogress = 0;
867         host->maxdumps = 1;             /* will be overwritten */
868         host->netif = NULL;
869         host->start_t = 0;
870         host->up = NULL;
871         host->features = NULL;
872         host->pre_script = 0;
873         host->post_script = 0;
874     }
875
876     host->netif = netif;
877
878     enqueue_disk(lst, disk);
879
880     disk->host = host;
881     disk->hostnext = host->disks;
882     host->disks = disk;
883     host->maxdumps = disk->maxdumps;
884
885     return (0);
886 }
887
888
889 printf_arglist_function2(void disk_parserror, const char *, filename,
890     int, line_num, const char *, format)
891 {
892     va_list argp;
893     char * msg;
894     char * errstr;
895
896     /* format the error message and hand it off to conffile */
897
898     arglist_start(argp, format);
899     msg = g_strdup_vprintf(format, argp);
900     errstr = g_strdup_printf("\"%s\", line %d: %s", filename, line_num, msg);
901     amfree(msg);
902     arglist_end(argp);
903
904     config_add_error(CFGERR_ERRORS, errstr);
905 }
906
907
908 void
909 dump_queue(
910     char *      st,
911     disklist_t  q,
912     int         npr,    /* we print first npr disks on queue, plus last two */
913     FILE *      f)
914 {
915     disk_t *d,*p;
916     int pos;
917     char *qname;
918
919     if(empty(q)) {
920         g_fprintf(f, _("%s QUEUE: empty\n"), st);
921         return;
922     }
923     g_fprintf(f, _("%s QUEUE:\n"), st);
924     for(pos = 0, d = q.head, p = NULL; d != NULL; p = d, d = d->next, pos++) {
925         qname = quote_string(d->name);
926         if(pos < npr) g_fprintf(f, "%3d: %-10s %-4s\n",
927                               pos, d->host->hostname, qname);
928         amfree(qname);
929     }
930     if(pos > npr) {
931         if(pos > npr+2) g_fprintf(f, "  ...\n");
932         if(pos > npr+1) {
933             d = p->prev;
934             g_fprintf(f, "%3d: %-10s %-4s\n", pos-2, d->host->hostname, d->name);
935         }
936         d = p;
937         g_fprintf(f, "%3d: %-10s %-4s\n", pos-1, d->host->hostname, d->name);
938     }
939 }
940
941 GPtrArray *
942 validate_optionstr(
943     disk_t       *dp)
944 {
945     GPtrArray *errarray;
946     int        nb_exclude;
947     int        nb_include;
948     am_feature_t *their_features = dp->host->features;
949
950     assert(dp != NULL);
951     assert(dp->host != NULL);
952
953     errarray = g_ptr_array_new();
954
955     if (!am_has_feature(their_features, fe_options_auth)) {
956         if (strcasecmp(dp->auth, "bsd") == 0)
957             if (!am_has_feature(their_features, fe_options_bsd_auth))
958                 g_ptr_array_add(errarray, _("does not support auth"));
959     }
960
961     switch(dp->compress) {
962     case COMP_FAST:
963         if (!am_has_feature(their_features, fe_options_compress_fast)) {
964             g_ptr_array_add(errarray, _("does not support fast compression"));
965         }
966         break;
967     case COMP_BEST:
968         if (!am_has_feature(their_features, fe_options_compress_best)) {
969             g_ptr_array_add(errarray, _("does not support best compression"));
970         }
971         break;
972     case COMP_CUST:
973         if (am_has_feature(their_features, fe_options_compress_cust)) {
974             if (dp->clntcompprog == NULL || strlen(dp->clntcompprog) == 0) {
975                 g_ptr_array_add(errarray, _("client custom compression with no compression program specified"));
976             }
977         } else {
978             g_ptr_array_add(errarray, _("does not support client custom compression"));
979         }
980         break;
981     case COMP_SERVER_FAST:
982         break;
983     case COMP_SERVER_BEST:
984         break;
985     case COMP_SERVER_CUST:
986         if (dp->srvcompprog == NULL || strlen(dp->srvcompprog) == 0) {
987             g_ptr_array_add(errarray, _("server custom compression with no compression program specified"));
988         }
989         break;
990     }
991
992     switch(dp->encrypt) {
993     case ENCRYPT_CUST:
994         if (am_has_feature(their_features, fe_options_encrypt_cust)) {
995             if (dp->clnt_decrypt_opt) {
996                 if (!am_has_feature(their_features, fe_options_client_decrypt_option)) {
997                     g_ptr_array_add(errarray, _("does not support client decrypt option"));
998                 }
999             }
1000             if (dp->clnt_encrypt == NULL || strlen(dp->clnt_encrypt) == 0) {
1001                 g_ptr_array_add(errarray, _("encrypt client with no encryption program specified"));
1002             }
1003             if (dp->compress == COMP_SERVER_FAST ||
1004                 dp->compress == COMP_SERVER_BEST ||
1005                 dp->compress == COMP_SERVER_CUST ) {
1006                 g_ptr_array_add(errarray, _("Client encryption with server compression is not supported. See amanda.conf(5) for detail"));
1007             }
1008         } else {
1009             g_ptr_array_add(errarray, _("does not support client data encryption"));
1010         }
1011         break;
1012     case ENCRYPT_SERV_CUST:
1013         if (dp->srv_encrypt == NULL || strlen(dp->srv_encrypt) == 0) {
1014             g_ptr_array_add(errarray, _("No encryption program specified in dumptypes, Change the dumptype in the disklist or mention the encryption program to use in the dumptypes file"));
1015         }
1016         break;
1017     }
1018
1019     if (!dp->record) {
1020         if (!am_has_feature(their_features, fe_options_no_record)) {
1021             g_ptr_array_add(errarray, _("does not support no record"));
1022         }
1023     }
1024
1025     if (dp->index) {
1026         if (!am_has_feature(their_features, fe_options_index)) {
1027             g_ptr_array_add(errarray, _("does not support index"));
1028         }
1029     }
1030
1031     if (dp->kencrypt) {
1032         if (!am_has_feature(their_features, fe_options_kencrypt)) {
1033             g_ptr_array_add(errarray, _("does not support kencrypt"));
1034         }
1035     }
1036
1037     nb_exclude = 0;
1038     if (dp->exclude_file != NULL && dp->exclude_file->nb_element > 0) {
1039         nb_exclude = dp->exclude_file->nb_element;
1040         if (!am_has_feature(their_features, fe_options_exclude_file)) {
1041             g_ptr_array_add(errarray, _("does not support exclude file"));
1042         }
1043     }
1044
1045     if (dp->exclude_list != NULL && dp->exclude_list->nb_element > 0) {
1046         nb_exclude += dp->exclude_list->nb_element;
1047         if (!am_has_feature(their_features, fe_options_exclude_list)) {
1048             g_ptr_array_add(errarray, _("does not support exclude list"));
1049         }
1050     }
1051
1052     if (nb_exclude > 1 &&
1053         !am_has_feature(their_features, fe_options_multiple_exclude)) {
1054         g_ptr_array_add(errarray, _("does not support multiple exclude"));
1055     }
1056
1057     nb_include = 0;
1058     if (dp->include_file != NULL && dp->include_file->nb_element > 0) {
1059         nb_include = dp->include_file->nb_element;
1060         if (!am_has_feature(their_features, fe_options_include_file)) {
1061             g_ptr_array_add(errarray, ("does not support include file"));
1062         }
1063     }
1064
1065     if (dp->include_list != NULL && dp->include_list->nb_element > 0) {
1066         nb_include += dp->include_list->nb_element;
1067         if (!am_has_feature(their_features, fe_options_include_list)) {
1068             g_ptr_array_add(errarray, _("does not support include list"));
1069         }
1070     }
1071
1072     if (nb_include > 1 &&
1073         !am_has_feature(their_features, fe_options_multiple_exclude)) {
1074         g_ptr_array_add(errarray, _("does not support multiple include"));
1075     }
1076
1077     if (dp->exclude_optional) {
1078         if (!am_has_feature(their_features, fe_options_optional_exclude)) {
1079             g_ptr_array_add(errarray, _("does not support optional exclude"));
1080         }
1081     }
1082     if (dp->include_optional) {
1083         if (!am_has_feature(their_features, fe_options_optional_include)) {
1084             g_ptr_array_add(errarray, _("does not support optional include"));
1085         }
1086     }
1087
1088     return errarray;
1089 }
1090
1091 char *
1092 optionstr(
1093     disk_t *    dp)
1094 {
1095     char *auth_opt = NULL;
1096     char *kencrypt_opt = "";
1097     char *compress_opt = "";
1098     char *encrypt_opt = stralloc("");
1099     char *decrypt_opt = stralloc("");
1100     char *record_opt = "";
1101     char *index_opt = "";
1102     char *exclude_file = NULL;
1103     char *exclude_list = NULL;
1104     char *include_file = NULL;
1105     char *include_list = NULL;
1106     char *excl_opt = "";
1107     char *incl_opt = "";
1108     char *exc = NULL;
1109     char *result = NULL;
1110     sle_t *excl;
1111     char *qdpname;
1112     char *qname;
1113     am_feature_t *their_features = dp->host->features;
1114
1115     assert(dp != NULL);
1116     assert(dp->host != NULL);
1117
1118     qdpname = quote_string(dp->name);
1119     if (am_has_feature(their_features, fe_options_auth)) {
1120         auth_opt = vstralloc("auth=", dp->auth, ";", NULL);
1121     } else if(strcasecmp(dp->auth, "bsd") == 0) {
1122         if(am_has_feature(their_features, fe_options_bsd_auth))
1123             auth_opt = stralloc("bsd-auth;");
1124     }
1125
1126     switch(dp->compress) {
1127     case COMP_FAST:
1128         compress_opt = "compress-fast;";
1129         break;
1130     case COMP_BEST:
1131         compress_opt = "compress-best;";
1132         break;
1133     case COMP_CUST:
1134         compress_opt = vstralloc("comp-cust=", dp->clntcompprog, ";", NULL);
1135         break;
1136     case COMP_SERVER_FAST:
1137         compress_opt = "srvcomp-fast;";
1138         break;
1139     case COMP_SERVER_BEST:
1140         compress_opt = "srvcomp-best;";
1141         break;
1142     case COMP_SERVER_CUST:
1143         compress_opt = vstralloc("srvcomp-cust=", dp->srvcompprog, ";", NULL);
1144         break;
1145     }
1146
1147     switch(dp->encrypt) {
1148     case ENCRYPT_CUST:
1149         encrypt_opt = newvstralloc(encrypt_opt, "encrypt-cust=",
1150                                    dp->clnt_encrypt, ";", NULL);
1151         if (dp->clnt_decrypt_opt) {
1152              decrypt_opt = newvstralloc(decrypt_opt, "client-decrypt-option=",
1153                                         dp->clnt_decrypt_opt, ";", NULL);
1154         }
1155         break;
1156     case ENCRYPT_SERV_CUST:
1157         encrypt_opt = newvstralloc(encrypt_opt, "encrypt-serv-cust=",
1158                                    dp->srv_encrypt, ";", NULL);
1159         if (dp->srv_decrypt_opt) {
1160             decrypt_opt = newvstralloc(decrypt_opt, "server-decrypt-option=",
1161                                        dp->srv_decrypt_opt, ";", NULL);
1162          }
1163          break;
1164     }
1165
1166     if (!dp->record) {
1167         record_opt = "no-record;";
1168     }
1169
1170     if (dp->index) {
1171         index_opt = "index;";
1172     }
1173
1174     if (dp->kencrypt) {
1175         kencrypt_opt = "kencrypt;";
1176     }
1177
1178     exclude_file = stralloc("");
1179     if (dp->exclude_file != NULL && dp->exclude_file->nb_element > 0) {
1180         for(excl = dp->exclude_file->first; excl != NULL;
1181                                             excl = excl->next) {
1182             qname = quote_string(excl->name);
1183             exc = newvstralloc( exc, "exclude-file=", qname, ";", NULL);
1184             strappend(exclude_file, exc);
1185             amfree(qname);
1186         }
1187     }
1188     exclude_list = stralloc("");
1189     if (dp->exclude_list != NULL && dp->exclude_list->nb_element > 0) {
1190         for(excl = dp->exclude_list->first; excl != NULL;
1191                                             excl = excl->next) {
1192             qname = quote_string(excl->name);
1193             exc = newvstralloc( exc, "exclude-list=", qname, ";", NULL);
1194             strappend(exclude_list, exc);
1195             amfree(qname);
1196         }
1197     }
1198
1199     include_file = stralloc("");
1200     if (dp->include_file != NULL && dp->include_file->nb_element > 0) {
1201         for(excl = dp->include_file->first; excl != NULL;
1202                                             excl = excl->next) {
1203             qname = quote_string(excl->name);
1204             exc = newvstralloc(exc, "include-file=", qname, ";", NULL);
1205             strappend(include_file, exc);
1206             amfree(qname);
1207         }
1208     }
1209     include_list = stralloc("");
1210     if (dp->include_list != NULL && dp->include_list->nb_element > 0) {
1211         for(excl = dp->include_list->first; excl != NULL;
1212                                             excl = excl->next) {
1213             qname = quote_string(excl->name);
1214             exc = newvstralloc(exc, "include-list=", qname, ";", NULL);
1215             strappend(include_list, exc);
1216             amfree(qname);
1217         }
1218     }
1219
1220     if (dp->exclude_optional) {
1221         excl_opt = "exclude-optional;";
1222     }
1223     if (dp->include_optional) {
1224         incl_opt = "include-optional;";
1225     }
1226
1227     result = vstralloc(";",
1228                        auth_opt,
1229                        kencrypt_opt,
1230                        compress_opt,
1231                        encrypt_opt,
1232                        decrypt_opt,
1233                        record_opt,
1234                        index_opt,
1235                        exclude_file,
1236                        exclude_list,
1237                        include_file,
1238                        include_list,
1239                        excl_opt,
1240                        incl_opt,
1241                        NULL);
1242     amfree(qdpname);
1243     amfree(auth_opt);
1244     amfree(exclude_list);
1245     amfree(exclude_file);
1246     amfree(include_file);
1247     amfree(include_list);
1248     amfree(exc);
1249     amfree(decrypt_opt);
1250     amfree(encrypt_opt);
1251
1252     /* result contains at least 'auth=...' */
1253     return result;
1254 }
1255
1256 typedef struct {
1257     am_feature_t  *features;
1258     char          *result;
1259 } xml_app_t;
1260
1261 /* A GHFunc (callback for g_hash_table_foreach) */
1262 static void xml_property(
1263     gpointer key_p,
1264     gpointer value_p,
1265     gpointer user_data_p)
1266 {
1267     char       *tmp;
1268     property_t *property = value_p;
1269     xml_app_t  *xml_app = user_data_p;
1270     GSList     *value;
1271     GString    *strbuf;
1272
1273     strbuf = g_string_new(xml_app->result);
1274
1275     tmp = amxml_format_tag("name", (char *)key_p);
1276     g_string_append_printf(strbuf, "    <property>\n      %s\n", tmp);
1277     g_free(tmp);
1278
1279     // TODO if client have fe_xml_property_priority
1280     if (property->priority
1281         && am_has_feature(xml_app->features, fe_xml_property_priority))
1282         g_string_append(strbuf, "      <priority>yes</priority>\n");
1283
1284     for (value = property->values; value != NULL; value = value->next) {
1285         tmp = amxml_format_tag("value", value->data);
1286         g_string_append_printf(strbuf, "      %s", tmp);
1287         g_free(tmp);
1288     }
1289     g_string_append_printf(strbuf, "\n    </property>\n");
1290
1291     g_free(xml_app->result);
1292     xml_app->result = g_string_free(strbuf, FALSE);
1293 }
1294
1295 char *
1296 xml_optionstr(
1297     disk_t *            dp,
1298     int                 to_server)
1299 {
1300     char *auth_opt;
1301     char *kencrypt_opt;
1302     char *compress_opt;
1303     char *encrypt_opt = stralloc("");
1304     char *decrypt_opt = stralloc("");
1305     char *record_opt;
1306     char *index_opt;
1307     char *data_path_opt = stralloc("");
1308     char *exclude = stralloc("");
1309     char *exclude_file = NULL;
1310     char *exclude_list = NULL;
1311     char *include = stralloc("");
1312     char *include_file = NULL;
1313     char *include_list = NULL;
1314     char *excl_opt = "";
1315     char *incl_opt = "";
1316     char *exc = NULL;
1317     char *script_opt;
1318     char *result = NULL;
1319     sle_t *excl;
1320     char *qdpname;
1321     char *q64name;
1322     am_feature_t *their_features = dp->host->features;
1323
1324     assert(dp != NULL);
1325     assert(dp->host != NULL);
1326
1327     qdpname = quote_string(dp->name);
1328     if (am_has_feature(their_features, fe_options_auth)) {
1329         auth_opt = vstralloc("  <auth>", dp->auth, "</auth>\n", NULL);
1330     } else {
1331         auth_opt = stralloc("");
1332     }
1333
1334     switch(dp->compress) {
1335     case COMP_FAST:
1336         compress_opt = stralloc("  <compress>FAST</compress>\n");
1337         break;
1338     case COMP_BEST:
1339         compress_opt = stralloc("  <compress>BEST</compress>\n");
1340         break;
1341     case COMP_CUST:
1342         compress_opt = vstralloc("  <compress>CUSTOM"
1343                                  "<custom-compress-program>",
1344                                  dp->clntcompprog,
1345                                  "</custom-compress-program>\n"
1346                                  "  </compress>\n", NULL);
1347         break;
1348     case COMP_SERVER_FAST:
1349         compress_opt = stralloc("  <compress>SERVER-FAST</compress>\n");
1350         break;
1351     case COMP_SERVER_BEST:
1352         compress_opt = stralloc("  <compress>SERVER-BEST</compress>\n");
1353         break;
1354     case COMP_SERVER_CUST:
1355         compress_opt = vstralloc("  <compress>SERVER-CUSTOM"
1356                                  "<custom-compress-program>",
1357                                  dp->srvcompprog,
1358                                  "</custom-compress-program>\n"
1359                                  "  </compress>\n", NULL);
1360         break;
1361     default:
1362         compress_opt = stralloc("");
1363     }
1364
1365     switch(dp->encrypt) {
1366     case ENCRYPT_CUST:
1367         if (dp->clnt_decrypt_opt) {
1368             decrypt_opt = newvstralloc(decrypt_opt,
1369                                        "    <decrypt-option>",
1370                                        dp->clnt_decrypt_opt,
1371                                        "</decrypt-option>\n", NULL);
1372             }
1373         if (decrypt_opt) {
1374              encrypt_opt = newvstralloc(encrypt_opt,
1375                                         "  <encrypt>CUSTOM"
1376                                         "<custom-encrypt-program>",
1377                                         dp->clnt_encrypt,
1378                                         "</custom-encrypt-program>\n",
1379                                         decrypt_opt,
1380                                         "  </encrypt>\n", NULL);
1381         }
1382         break;
1383     case ENCRYPT_SERV_CUST:
1384         if (to_server) {
1385             decrypt_opt =  newvstralloc(decrypt_opt,
1386                                         "    <decrypt-option>",
1387                                         dp->srv_decrypt_opt, 
1388                                         "</decrypt-option>\n", NULL);
1389             encrypt_opt = newvstralloc(encrypt_opt,
1390                                        "  <encrypt>SERVER-CUSTOM"
1391                                        "<custom-encrypt-program>",
1392                                        dp->srv_encrypt,
1393                                        "</custom-encrypt-program>\n",
1394                                        decrypt_opt,
1395                                        "  </encrypt>\n", NULL);
1396         }
1397         break;
1398     }
1399     
1400     if (!dp->record) {
1401         record_opt = "  <record>NO</record>\n";
1402     } else {
1403         record_opt = "  <record>YES</record>\n";
1404     }
1405
1406     if(dp->index) {
1407         index_opt = "  <index>YES</index>\n";
1408     } else {
1409         index_opt = "";
1410     }
1411
1412     if (dp->kencrypt) {
1413         kencrypt_opt = "  <kencrypt>YES</kencrypt>\n";
1414     } else {
1415         kencrypt_opt = "";
1416     }
1417
1418     if (am_has_feature(their_features, fe_xml_data_path)) {
1419         switch(dp->data_path) {
1420         case DATA_PATH_AMANDA:
1421             amfree(data_path_opt);
1422             data_path_opt = stralloc("  <datapath>AMANDA</datapath>\n");
1423             break;
1424         case DATA_PATH_DIRECTTCP:
1425           { /* dp->dataport_list is not set for selfcheck/sendsize */
1426             if (am_has_feature(their_features, fe_xml_directtcp_list)) {
1427                 char *s, *sc;
1428                 char *value, *b64value;
1429
1430                 amfree(data_path_opt);
1431                 data_path_opt = stralloc("  <datapath>DIRECTTCP");
1432                 if (dp->dataport_list) {
1433                     s = sc = stralloc(dp->dataport_list);
1434                     do {
1435                         value = s;
1436                         s = strchr(s, ';');
1437                         if (s) {
1438                             *s++ = '\0';
1439                         }
1440
1441                         b64value = amxml_format_tag("directtcp", value);
1442                         vstrextend(&data_path_opt, "\n    ", b64value, NULL);
1443                         amfree(b64value);
1444                     } while (s);
1445                     amfree(sc);
1446                     strappend(data_path_opt, "\n  ");
1447                 }
1448                 strappend(data_path_opt, "</datapath>\n");
1449             }
1450           }
1451           break;
1452         }
1453     }
1454
1455     exclude_file = stralloc("");
1456     if (dp->exclude_file != NULL && dp->exclude_file->nb_element > 0) {
1457         for(excl = dp->exclude_file->first; excl != NULL;
1458                                             excl = excl->next) {
1459             q64name = amxml_format_tag("file", excl->name);
1460             exc = newvstralloc( exc, "    ", q64name, "\n", NULL);
1461             strappend(exclude_file, exc);
1462             amfree(q64name);
1463         }
1464     }
1465     exclude_list = stralloc("");
1466     if (dp->exclude_list != NULL && dp->exclude_list->nb_element > 0) {
1467         for(excl = dp->exclude_list->first; excl != NULL;
1468                                             excl = excl->next) {
1469             q64name = amxml_format_tag("list", excl->name);
1470             exc = newvstralloc(exc, "    ", q64name, "\n", NULL);
1471             strappend(exclude_list, exc);
1472             amfree(q64name);
1473         }
1474     }
1475
1476     include_file = stralloc("");
1477     if (dp->include_file != NULL && dp->include_file->nb_element > 0) {
1478         for(excl = dp->include_file->first; excl != NULL;
1479                                             excl = excl->next) {
1480             q64name = amxml_format_tag("file", excl->name);
1481             exc = newvstralloc( exc, "    ", q64name, "\n", NULL);
1482             strappend(include_file, exc);
1483             amfree(q64name);
1484         }
1485     }
1486     include_list = stralloc("");
1487     if (dp->include_list != NULL && dp->include_list->nb_element > 0) {
1488         for(excl = dp->include_list->first; excl != NULL;
1489                                             excl = excl->next) {
1490             q64name = amxml_format_tag("list", excl->name);
1491             exc = newvstralloc( exc, "    ", q64name, "\n", NULL);
1492             strappend(include_list, exc);
1493             amfree(q64name);
1494         }
1495     }
1496
1497     if (dp->exclude_optional) {
1498         excl_opt = "    <optional>YES</optional>\n";
1499     }
1500     if (dp->include_optional) {
1501         incl_opt = "    <optional>YES</optional>\n";
1502     }
1503
1504     if (dp->exclude_file || dp->exclude_list)
1505         exclude = newvstralloc(exclude,
1506                                "  <exclude>\n",
1507                                exclude_file,
1508                                exclude_list,
1509                                excl_opt,
1510                                "  </exclude>\n", NULL);
1511     if (dp->include_file || dp->include_list)
1512         include = newvstralloc(include,
1513                                "  <include>\n",
1514                                include_file,
1515                                include_list,
1516                                incl_opt,
1517                                "  </include>\n", NULL);
1518     script_opt = xml_scripts(dp->pp_scriptlist, their_features);
1519     result = vstralloc(auth_opt,
1520                        kencrypt_opt,
1521                        compress_opt,
1522                        encrypt_opt,
1523                        record_opt,
1524                        index_opt,
1525                        data_path_opt,
1526                        exclude,
1527                        include,
1528                        script_opt,
1529                        NULL);
1530
1531     amfree(qdpname);
1532     amfree(auth_opt);
1533     amfree(data_path_opt);
1534     amfree(compress_opt);
1535     amfree(exclude);
1536     amfree(exclude_list);
1537     amfree(exclude_file);
1538     amfree(include);
1539     amfree(include_file);
1540     amfree(include_list);
1541     amfree(exc);
1542     amfree(decrypt_opt);
1543     amfree(encrypt_opt);
1544     amfree(script_opt);
1545
1546     /* result contains at least 'auth=...' */
1547     return result;
1548 }
1549
1550 char *
1551 xml_dumptype_properties(
1552     disk_t *dp)
1553 {
1554     xml_app_t xml_dumptype;
1555
1556     xml_dumptype.result = g_strdup("");
1557     xml_dumptype.features = NULL;
1558     if (dp && dp->config) {
1559         g_hash_table_foreach(dumptype_get_property(dp->config), xml_property,
1560                              &xml_dumptype);
1561     }
1562     return xml_dumptype.result;
1563 }
1564
1565 char *
1566 xml_estimate(
1567     estimatelist_t estimatelist,
1568     am_feature_t *their_features)
1569 {
1570     estimatelist_t el;
1571     char *l = NULL;
1572
1573     if (am_has_feature(their_features, fe_xml_estimatelist)) {
1574         vstrextend(&l, "  <estimate>", NULL);
1575         for (el=estimatelist; el != NULL; el = el->next) {
1576             switch (GPOINTER_TO_INT(el->data)) {
1577             case ES_CLIENT  : vstrextend(&l, "CLIENT ", NULL); break;
1578             case ES_SERVER  : vstrextend(&l, "SERVER ", NULL); break;
1579             case ES_CALCSIZE: vstrextend(&l, "CALCSIZE ", NULL); break;
1580             }
1581         }
1582         vstrextend(&l, "</estimate>", NULL);
1583     } else { /* add the first estimate only */
1584         if (am_has_feature(their_features, fe_xml_estimate)) {
1585             vstrextend(&l, "  <estimate>", NULL);
1586             switch (GPOINTER_TO_INT(estimatelist->data)) {
1587             case ES_CLIENT  : vstrextend(&l, "CLIENT", NULL); break;
1588             case ES_SERVER  : vstrextend(&l, "SERVER", NULL); break;
1589             case ES_CALCSIZE: vstrextend(&l, "CALCSIZE", NULL); break;
1590             }
1591         }
1592         vstrextend(&l, "</estimate>", NULL);
1593         if (GPOINTER_TO_INT(estimatelist->data) == ES_CALCSIZE) {
1594             vstrextend(&l, "  <calcsize>YES</calcsize>", NULL);
1595         }
1596     }
1597
1598     return l;
1599 }
1600
1601 char *
1602 clean_dle_str_for_client(
1603     char *dle_str,
1604     am_feature_t *their_features)
1605 {
1606     char *rval_dle_str;
1607     char *hack1, *hack2;
1608     char *pend, *pscript, *pproperty, *eproperty;
1609     int len;
1610
1611     if (!dle_str)
1612         return NULL;
1613
1614     rval_dle_str = stralloc(dle_str);
1615
1616     /* Remove everything between "  <encrypt>SERVER-CUSTOM" and "</encrypt>\n"
1617      */
1618 #define SC "</encrypt>\n"
1619 #define SC_LEN strlen(SC)
1620     hack1 = strstr(rval_dle_str, "  <encrypt>SERVER-CUSTOM");
1621     if (hack1) {
1622         hack2 = strstr(hack1, SC);
1623         /* +1 is to also move the trailing '\0' */
1624         memmove(hack1, hack2 + SC_LEN, strlen(hack2 + SC_LEN) + 1);
1625     }
1626 #undef SC
1627 #undef SC_LEN
1628
1629     if (!am_has_feature(their_features, fe_dumptype_property)) {
1630 #define SC "</property>\n"
1631 #define SC_LEN strlen(SC)
1632         /* remove all dle properties, they are before backup-program or script
1633           properties */
1634         hack1 = rval_dle_str;
1635         pend = strstr(rval_dle_str, "<backup-program>");
1636         pscript = strstr(rval_dle_str, "<script>");
1637         if (pscript && pscript < pend)
1638             pend = pscript;
1639         if (!pend) /* the complete string */
1640             pend = rval_dle_str + strlen(rval_dle_str);
1641         while (hack1) {
1642             pproperty = strstr(hack1, "    <property>");
1643             if (pproperty && pproperty < pend) { /* remove it */
1644                 eproperty = strstr(pproperty, SC);
1645                 len = eproperty + SC_LEN - pproperty;
1646                 memmove(pproperty, eproperty + SC_LEN, strlen(eproperty + SC_LEN) + 1);
1647                 pend  -= len;
1648                 hack1 = pproperty;
1649             } else {
1650                 hack1 = NULL;
1651             }
1652         }
1653     } else {
1654     }
1655 #undef SC
1656 #undef SC_LEN
1657
1658     return rval_dle_str;
1659 }
1660
1661
1662 char *
1663 xml_application(
1664     disk_t        *dp G_GNUC_UNUSED,
1665     application_t *application,
1666     am_feature_t  *their_features)
1667 {
1668     char       *plugin;
1669     char       *b64plugin;
1670     char       *client_name;
1671     xml_app_t   xml_app;
1672     proplist_t  proplist;
1673
1674     xml_app.features = their_features;
1675     xml_app.result   = NULL;
1676     plugin = application_get_plugin(application);
1677     b64plugin = amxml_format_tag("plugin", plugin);
1678     xml_app.result = vstralloc("  <backup-program>\n",
1679                         "    ", b64plugin, "\n",
1680                         NULL);
1681     proplist = application_get_property(application);
1682     g_hash_table_foreach(proplist, xml_property, &xml_app);
1683
1684     client_name = application_get_client_name(application);
1685     if (client_name && strlen(client_name) > 0 &&
1686         am_has_feature(their_features, fe_application_client_name)) {
1687         char *b64client_name = amxml_format_tag("client_name", client_name);
1688         vstrextend(&xml_app.result, "    ", b64client_name, "\n", NULL);
1689     }
1690
1691     vstrextend(&xml_app.result, "  </backup-program>\n", NULL);
1692
1693     amfree(b64plugin);
1694
1695     return xml_app.result;
1696 }
1697
1698
1699 char *
1700 xml_scripts(
1701     identlist_t pp_scriptlist,
1702     am_feature_t  *their_features)
1703 {
1704     char       *plugin;
1705     char       *b64plugin;
1706     char       *client_name;
1707     char       *xml_scr;
1708     char       *xml_scr1;
1709     char       *str = "";
1710     char       *sep;
1711     char       *eo_str;
1712     execute_on_t execute_on;
1713     int          execute_where;
1714     proplist_t  proplist;
1715     identlist_t pp_iter;
1716     pp_script_t *pp_script;
1717     xml_app_t   xml_app;
1718
1719     xml_app.features = their_features;
1720
1721     xml_scr = stralloc("");
1722     for (pp_iter = pp_scriptlist; pp_iter != NULL;
1723          pp_iter = pp_iter->next) {
1724         char *pp_script_name = pp_iter->data;
1725         pp_script = lookup_pp_script(pp_script_name);
1726         g_assert(pp_script != NULL);
1727         plugin = pp_script_get_plugin(pp_script);
1728         b64plugin = amxml_format_tag("plugin", plugin);
1729         xml_scr1 = vstralloc("  <script>\n",
1730                              "    ", b64plugin, "\n",
1731                              NULL);
1732
1733         execute_where = pp_script_get_execute_where(pp_script);
1734         switch (execute_where) {
1735             case ES_CLIENT: str = "CLIENT"; break;
1736             case ES_SERVER: str = "SERVER"; break;
1737         }
1738         xml_scr1 = vstrextend(&xml_scr1, "    <execute_where>",
1739                               str, "</execute_where>\n", NULL);
1740
1741         execute_on = pp_script_get_execute_on(pp_script);
1742         sep = "";
1743         eo_str = stralloc("");
1744         if (execute_on & EXECUTE_ON_PRE_DLE_AMCHECK) {
1745             eo_str = vstrextend(&eo_str, sep, "PRE-DLE-AMCHECK", NULL);
1746             sep = ",";
1747         }
1748         if (execute_on & EXECUTE_ON_PRE_HOST_AMCHECK) {
1749             eo_str = vstrextend(&eo_str, sep, "PRE-HOST-AMCHECK", NULL);
1750             sep = ",";
1751         }
1752         if (execute_on & EXECUTE_ON_POST_DLE_AMCHECK) {
1753             eo_str = vstrextend(&eo_str, sep, "POST-DLE-AMCHECK", NULL);
1754             sep = ",";
1755         }
1756         if (execute_on & EXECUTE_ON_POST_HOST_AMCHECK) {
1757             eo_str = vstrextend(&eo_str, sep, "POST-HOST-AMCHECK", NULL);
1758             sep = ",";
1759         }
1760         if (execute_on & EXECUTE_ON_PRE_DLE_ESTIMATE) {
1761             eo_str = vstrextend(&eo_str, sep, "PRE-DLE-ESTIMATE", NULL);
1762             sep = ",";
1763         }
1764         if (execute_on & EXECUTE_ON_PRE_HOST_ESTIMATE) {
1765             eo_str = vstrextend(&eo_str, sep, "PRE-HOST-ESTIMATE", NULL);
1766             sep = ",";
1767         }
1768         if (execute_on & EXECUTE_ON_POST_DLE_ESTIMATE) {
1769             eo_str = vstrextend(&eo_str, sep, "POST-DLE-ESTIMATE", NULL);
1770             sep = ",";
1771         }
1772         if (execute_on & EXECUTE_ON_POST_HOST_ESTIMATE) {
1773             eo_str = vstrextend(&eo_str, sep, "POST-HOST-ESTIMATE", NULL);
1774             sep = ",";
1775         }
1776         if (execute_on & EXECUTE_ON_PRE_DLE_BACKUP) {
1777             eo_str = vstrextend(&eo_str, sep, "PRE-DLE-BACKUP", NULL);
1778             sep = ",";
1779         }
1780         if (execute_on & EXECUTE_ON_PRE_HOST_BACKUP) {
1781             eo_str = vstrextend(&eo_str, sep, "PRE-HOST-BACKUP", NULL);
1782             sep = ",";
1783         }
1784         if (execute_on & EXECUTE_ON_POST_DLE_BACKUP) {
1785             eo_str = vstrextend(&eo_str, sep, "POST-DLE-BACKUP", NULL);
1786             sep = ",";
1787         }
1788         if (execute_on & EXECUTE_ON_POST_HOST_BACKUP) {
1789             eo_str = vstrextend(&eo_str, sep, "POST-HOST-BACKUP", NULL);
1790             sep = ",";
1791         }
1792         if (execute_on & EXECUTE_ON_PRE_RECOVER) {
1793             eo_str = vstrextend(&eo_str, sep, "PRE-RECOVER", NULL);
1794             sep = ",";
1795         }
1796         if (execute_on & EXECUTE_ON_POST_RECOVER) {
1797             eo_str = vstrextend(&eo_str, sep, "POST-RECOVER", NULL);
1798             sep = ",";
1799         }
1800         if (execute_on & EXECUTE_ON_PRE_LEVEL_RECOVER) {
1801             eo_str = vstrextend(&eo_str, sep, "PRE-LEVEL-RECOVER", NULL);
1802             sep = ",";
1803         }
1804         if (execute_on & EXECUTE_ON_POST_LEVEL_RECOVER) {
1805             eo_str = vstrextend(&eo_str, sep, "POST-LEVEL-RECOVER", NULL);
1806             sep = ",";
1807         }
1808         if (execute_on & EXECUTE_ON_INTER_LEVEL_RECOVER) {
1809             eo_str = vstrextend(&eo_str, sep, "INTER-LEVEL-RECOVER", NULL);
1810             sep = ",";
1811         }
1812         if (execute_on != 0)
1813             xml_scr1 = vstrextend(&xml_scr1,
1814                                   "    <execute_on>", eo_str,
1815                                   "</execute_on>\n", NULL);
1816         amfree(eo_str);
1817         proplist = pp_script_get_property(pp_script);
1818         xml_app.result   = stralloc("");
1819         g_hash_table_foreach(proplist, xml_property, &xml_app);
1820
1821         client_name = pp_script_get_client_name(pp_script);
1822         if (client_name && strlen(client_name) > 0 &&
1823             am_has_feature(their_features, fe_script_client_name)) {
1824             char *b64client_name = amxml_format_tag("client_name",
1825                                                     client_name);
1826             vstrextend(&xml_app.result, "    ", b64client_name, "\n", NULL);
1827         }
1828
1829         xml_scr = vstrextend(&xml_scr, xml_scr1, xml_app.result, "  </script>\n", NULL);
1830         amfree(b64plugin);
1831         amfree(xml_app.result);
1832         amfree(xml_scr1);
1833     }
1834     return xml_scr;
1835 }
1836
1837
1838 void
1839 disable_skip_disk(
1840     disklist_t *origqp)
1841 {
1842     disk_t *dp;
1843
1844     for (dp = origqp->head; dp != NULL; dp = dp->next) {
1845         if (dp->ignore || dp->strategy == DS_SKIP)
1846             dp->todo = 0;
1847     }
1848 }
1849
1850
1851 char *
1852 match_disklist(
1853     disklist_t *origqp,
1854     int         sargc,
1855     char **     sargv)
1856 {
1857     char *prevhost = NULL;
1858     char *errstr = NULL;
1859     int i;
1860     int match_a_host;
1861     int match_a_disk;
1862     int prev_match;
1863     disk_t *dp_skip;
1864     disk_t *dp;
1865
1866     if(sargc <= 0)
1867         return NULL;
1868
1869     for(dp = origqp->head; dp != NULL; dp = dp->next) {
1870         if(dp->todo == 1)
1871             dp->todo = -1;
1872     }
1873
1874     prev_match = 0;
1875     for(i=0;i<sargc;i++) {
1876         match_a_host = 0;
1877         for(dp = origqp->head; dp != NULL; dp = dp->next) {
1878             if(match_host(sargv[i], dp->host->hostname))
1879                 match_a_host = 1;
1880         }
1881         match_a_disk = 0;
1882         dp_skip = NULL;
1883         for(dp = origqp->head; dp != NULL; dp = dp->next) {
1884             if(prevhost != NULL &&
1885                match_host(prevhost, dp->host->hostname) &&
1886                (match_disk(sargv[i], dp->name) ||
1887                 (dp->device && match_disk(sargv[i], dp->device)))) {
1888                 if(match_a_host) {
1889                     error(_("Argument %s cannot be both a host and a disk"),sargv[i]);
1890                     /*NOTREACHED*/
1891                 }
1892                 else {
1893                     if(dp->todo == -1) {
1894                         dp->todo = 1;
1895                         match_a_disk = 1;
1896                         prev_match = 0;
1897                     } else if (dp->todo == 0) {
1898                         match_a_disk = 1;
1899                         prev_match = 0;
1900                         dp_skip = dp;
1901                     } else { /* dp->todo == 1 */
1902                         match_a_disk = 1;
1903                         prev_match = 0;
1904                     }
1905                 }
1906             }
1907         }
1908         if(!match_a_disk) {
1909             if(match_a_host == 1) {
1910                 if(prev_match == 1) { /* all disk of the previous host */
1911                     for(dp = origqp->head; dp != NULL; dp = dp->next) {
1912                         if(match_host(prevhost,dp->host->hostname))
1913                             if(dp->todo == -1) {
1914                                 dp->todo = 1;
1915                                 match_a_disk = 1;
1916                             }
1917                     }
1918                     if (!match_a_disk) {
1919                         char *errstr1;
1920                         errstr1 = vstrallocf(_("All disks on host '%s' are ignored or have strategy \"skip\".\n"), prevhost);
1921                         vstrextend(&errstr, errstr1, NULL);
1922                         amfree(errstr1);
1923                     }
1924                 }
1925                 prevhost = sargv[i];
1926                 prev_match = 1;
1927             }
1928             else {
1929                 char *errstr1;
1930                 if (strchr(sargv[i], (int)'\\')) {
1931                     errstr1 = vstrallocf(_("Argument '%s' matches neither a host nor a disk; quoting may not be correct.\n"), sargv[i]);
1932                 } else {
1933                     errstr1 = vstrallocf(_("Argument '%s' matches neither a host nor a disk.\n"), sargv[i]);
1934                 }
1935                 vstrextend(&errstr, errstr1, NULL);
1936                 amfree(errstr1);
1937                 prev_match = 0;
1938             }
1939         } else if (dp_skip) {
1940                 char *errstr1;
1941                 if (dp_skip->strategy == DS_SKIP) {
1942                     errstr1 = vstrallocf(_("Argument '%s' matches a disk with strategy \"skip\".\n"), sargv[i]);
1943                 } else {
1944                     errstr1 = vstrallocf(_("Argument '%s' matches a disk marked \"ignore\".\n"), sargv[i]);
1945                 }
1946                 vstrextend(&errstr, errstr1, NULL);
1947                 amfree(errstr1);
1948                 prev_match = 0;
1949         }
1950     }
1951
1952     if(prev_match == 1) { /* all disk of the previous host */
1953         match_a_disk = 0;
1954         for(dp = origqp->head; dp != NULL; dp = dp->next) {
1955             if(match_host(prevhost,dp->host->hostname))
1956                 if(dp->todo == -1) {
1957                     dp->todo = 1;
1958                     match_a_disk = 1;
1959                 }
1960         }
1961         if (!match_a_disk) {
1962             char *errstr1;
1963             errstr1 = vstrallocf(_("All disks on host '%s' are ignored or have strategy \"skip\".\n"), prevhost);
1964             vstrextend(&errstr, errstr1, NULL);
1965             amfree(errstr1);
1966         }
1967     }
1968
1969     for(dp = origqp->head; dp != NULL; dp = dp->next) {
1970         if(dp->todo == -1)
1971             dp->todo = 0;
1972     }
1973
1974     return errstr;
1975 }
1976
1977 gboolean
1978 match_dumpfile(
1979     dumpfile_t  *file,
1980     int         sargc,
1981     char **     sargv)
1982 {
1983     disk_t d;
1984     am_host_t h;
1985     disklist_t dl;
1986
1987     /* rather than try to reproduce the adaptive matching logic in
1988      * match_disklist, this simply creates a new, fake disklist with one
1989      * element in it, and calls match_disklist directly */
1990
1991     bzero(&h, sizeof(h));
1992     h.hostname = file->name;
1993     h.disks = &d;
1994
1995     bzero(&d, sizeof(d));
1996     d.host = &h;
1997     d.hostname = file->name;
1998     d.name = file->disk;
1999     d.device = file->disk;
2000     d.todo = 1;
2001
2002     dl.head = dl.tail = &d;
2003
2004     (void)match_disklist(&dl, sargc, sargv);
2005     return d.todo;
2006 }
2007
2008 netif_t *
2009 disklist_netifs(void)
2010 {
2011     return all_netifs;
2012 }
2013
2014 #ifdef TEST
2015
2016 static void dump_disk(const disk_t *);
2017 static void dump_disklist(const disklist_t *);
2018 int main(int, char *[]);
2019
2020 static void
2021 dump_disk(
2022     const disk_t *      dp)
2023 {
2024     g_printf(_("  DISK %s (HOST %s, LINE %d) TYPE %s NAME %s SPINDLE %d\n"),
2025            dp->name, dp->host->hostname, dp->line, dp->dtype_name,
2026            dp->name == NULL? "(null)": dp->name,
2027            dp->spindle);
2028 }
2029
2030 static void
2031 dump_disklist(
2032     const disklist_t *  lst)
2033 {
2034     const disk_t *dp, *prev;
2035     const am_host_t *hp;
2036
2037     if(hostlist == NULL) {
2038         g_printf(_("DISKLIST not read in\n"));
2039         return;
2040     }
2041
2042     g_printf(_("DISKLIST BY HOSTNAME:\n"));
2043
2044     for(hp = hostlist; hp != NULL; hp = hp->next) {
2045         char *if_name = NULL;
2046         if (hp->netif && hp->netif->config)
2047             if_name = interface_name(hp->netif->config);
2048
2049         g_printf(_("HOST %s INTERFACE %s\n"),
2050                hp->hostname,
2051                if_name ? _("(null)") : if_name);
2052         for(dp = hp->disks; dp != NULL; dp = dp->hostnext)
2053             dump_disk(dp);
2054         putchar('\n');
2055     }
2056
2057
2058     g_printf(_("DISKLIST IN FILE ORDER:\n"));
2059
2060     prev = NULL;
2061     for(dp = lst->head; dp != NULL; prev = dp, dp = dp->next) {
2062         dump_disk(dp);
2063         /* check pointers */
2064         if(dp->prev != prev) g_printf(_("*** prev pointer mismatch!\n"));
2065         if(dp->next == NULL && lst->tail != dp) g_printf(_("tail mismatch!\n"));
2066     }
2067 }
2068
2069 int
2070 main(
2071     int         argc,
2072     char **     argv)
2073 {
2074   char *conffile;
2075   char *conf_diskfile;
2076   disklist_t lst;
2077   int result;
2078
2079   /*
2080    * Configure program for internationalization:
2081    *   1) Only set the message locale for now.
2082    *   2) Set textdomain for all amanda related programs to "amanda"
2083    *      We don't want to be forced to support dozens of message catalogs.
2084    */  
2085   setlocale(LC_MESSAGES, "C");
2086   textdomain("amanda"); 
2087
2088   safe_fd(-1, 0);
2089
2090   set_pname("diskfile");
2091
2092   dbopen(DBG_SUBDIR_SERVER);
2093
2094   /* Don't die when child closes pipe */
2095   signal(SIGPIPE, SIG_IGN);
2096
2097   if (argc>1) {
2098     config_init(CONFIG_INIT_EXPLICIT_NAME, argv[1]);
2099   } else {
2100     config_init(CONFIG_INIT_USE_CWD, NULL)
2101   }
2102
2103   if (config_errors(NULL) >= CFGERR_WARNINGS) {
2104     config_print_errors();
2105     if (config_errors(NULL) >= CFGERR_ERRORS) {
2106       g_critical(_("errors processing config file"));
2107     }
2108   }
2109
2110   conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE));
2111   result = read_diskfile(conf_diskfile, &lst);
2112   if(result == CFGERR_OK) {
2113     dump_disklist(&lst);
2114   } else {
2115     config_print_errors();
2116   }
2117   amfree(conf_diskfile);
2118   amfree(conffile);
2119   amfree(config_dir);
2120
2121   return result;
2122 }
2123 #endif /* TEST */