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