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-2013 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 = NULL;
42 static netif_t *all_netifs = NULL;
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
read_diskfile(const char * filename,disklist_t * lst)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     if (hostlist == NULL) {
62 	lst->head = lst->tail = NULL;
63     }
64     line_num = 0;
65 
66     /* if we already have config errors, then don't bother */
67     if (config_errors(NULL) >= CFGERR_ERRORS) {
68 	return config_errors(NULL);
69     }
70 
71     if ((diskf = fopen(filename, "r")) == NULL) {
72 	config_add_error(CFGERR_ERRORS,
73 	    vstrallocf(_("Could not open '%s': %s"), filename, strerror(errno)));
74 	goto end;
75         /*NOTREACHED*/
76     }
77 
78     while ((line = agets(diskf)) != NULL) {
79 	line_num++;
80 	if (line[0] != '\0') {
81 	    if (parse_diskline(lst, filename, diskf, &line_num, &line) < 0) {
82 		goto end;
83 	    }
84 	}
85 	amfree(line);
86     }
87 
88 end:
89     amfree(line);
90     afclose(diskf);
91     return config_errors(NULL);
92 }
93 
94 am_host_t *
get_hostlist(void)95 get_hostlist(void)
96 {
97     return hostlist;
98 }
99 
100 am_host_t *
lookup_host(const char * hostname)101 lookup_host(
102     const char *hostname)
103 {
104     am_host_t *p;
105 
106     for (p = hostlist; p != NULL; p = p->next) {
107 	if(strcasecmp(p->hostname, hostname) == 0) return p;
108     }
109     return (NULL);
110 }
111 
112 disk_t *
lookup_disk(const char * hostname,const char * diskname)113 lookup_disk(
114     const char *hostname,
115     const char *diskname)
116 {
117     am_host_t *host;
118     disk_t *disk;
119 
120     host = lookup_host(hostname);
121     if (host == NULL)
122 	return (NULL);
123 
124     for (disk = host->disks; disk != NULL; disk = disk->hostnext) {
125 	if (strcmp(disk->name, diskname) == 0)
126 	    return (disk);
127     }
128     return (NULL);
129 }
130 
131 
132 /*
133  * put disk on end of queue
134  */
135 
136 void
enqueue_disk(disklist_t * list,disk_t * disk)137 enqueue_disk(
138     disklist_t *list,
139     disk_t *	disk)
140 {
141     if(list->tail == NULL) list->head = disk;
142     else list->tail->next = disk;
143     disk->prev = list->tail;
144 
145     list->tail = disk;
146     disk->next = NULL;
147 }
148 
149 
150 /*
151  * put disk on head of queue
152  */
153 
154 void
headqueue_disk(disklist_t * list,disk_t * disk)155 headqueue_disk(
156     disklist_t *list,
157     disk_t *	disk)
158 {
159     if(list->head == NULL) list->tail = disk;
160     else list->head->prev = disk;
161     disk->next = list->head;
162 
163     list->head = disk;
164     disk->prev = NULL;
165 }
166 
167 
168 /*
169  * insert in sorted order
170  */
171 
172 void
insert_disk(disklist_t * list,disk_t * disk,int (* cmp)(disk_t * a,disk_t * b))173 insert_disk(
174     disklist_t *list,
175     disk_t *	disk,
176     int		(*cmp)(disk_t *a, disk_t *b))
177 {
178     disk_t *prev, *ptr;
179 
180     prev = NULL;
181     ptr = list->head;
182 
183     while(ptr != NULL) {
184 	if(cmp(disk, ptr) < 0) break;
185 	prev = ptr;
186 	ptr = ptr->next;
187     }
188     disk->next = ptr;
189     disk->prev = prev;
190 
191     if(prev == NULL) list->head = disk;
192     else prev->next = disk;
193     if(ptr == NULL) list->tail = disk;
194     else ptr->prev = disk;
195 }
196 
197 disk_t *
add_disk(disklist_t * list,char * hostname,char * diskname)198 add_disk(
199     disklist_t *list,
200     char *	hostname,
201     char *	diskname)
202 {
203     disk_t *disk;
204     am_host_t *host;
205 
206     disk = alloc(SIZEOF(disk_t));
207     bzero(disk, SIZEOF(disk_t));
208     disk->line = 0;
209     disk->allow_split = 0;
210     disk->max_warnings = 20;
211     disk->splitsize = (off_t)0;
212     disk->tape_splitsize = (off_t)0;
213     disk->split_diskbuffer = NULL;
214     disk->fallback_splitsize = (off_t)0;
215     disk->hostname = stralloc(hostname);
216     disk->name = stralloc(diskname);
217     disk->device = stralloc(diskname);
218     disk->spindle = -1;
219     disk->up = NULL;
220     disk->compress = COMP_NONE;
221     disk->encrypt  = ENCRYPT_NONE;
222     disk->start_t = 0;
223     disk->todo = 1;
224     disk->index = 1;
225     disk->exclude_list = NULL;
226     disk->exclude_file = NULL;
227     disk->include_list = NULL;
228     disk->include_file = NULL;
229     disk->application = NULL;
230     disk->pp_scriptlist = NULL;
231 
232     host = lookup_host(hostname);
233     if(host == NULL) {
234 	host = alloc(SIZEOF(am_host_t));
235 	host->next = hostlist;
236 	hostlist = host;
237 
238 	host->hostname = stralloc(hostname);
239 	host->disks = NULL;
240 	host->inprogress = 0;
241 	host->maxdumps = 1;
242 	host->netif = NULL;
243 	host->start_t = 0;
244 	host->up = NULL;
245 	host->features = NULL;
246 	host->pre_script = 0;
247 	host->post_script = 0;
248     }
249     enqueue_disk(list, disk);
250 
251     disk->host = host;
252     disk->hostnext = host->disks;
253     host->disks = disk;
254 
255     return disk;
256 }
257 
258 
259 /*
260  * check if disk is present in list. Return true if so, false otherwise.
261  */
262 
263 int
find_disk(disklist_t * list,disk_t * disk)264 find_disk(
265     disklist_t *list,
266     disk_t *	disk)
267 {
268     disk_t *t;
269 
270     t = list->head;
271     while ((t != NULL) && (t != disk)) {
272         t = t->next;
273     }
274     return (t == disk);
275 }
276 
277 
278 /*
279  * sort a whole queue
280  */
281 
282 void
sort_disk(disklist_t * in,disklist_t * out,int (* cmp)(disk_t * a,disk_t * b))283 sort_disk(
284     disklist_t *in,
285     disklist_t *out,
286     int		(*cmp)(disk_t *a, disk_t *b))
287 {
288     disklist_t *tmp;
289     disk_t *disk;
290 
291     tmp = in;		/* just in case in == out */
292 
293     out->head = (disk_t *)0;
294     out->tail = (disk_t *)0;
295 
296     while((disk = dequeue_disk(tmp)))
297 	insert_disk(out, disk, cmp);
298 }
299 
300 
301 /*
302  * remove disk from front of queue
303  */
304 
305 disk_t *
dequeue_disk(disklist_t * list)306 dequeue_disk(
307     disklist_t *list)
308 {
309     disk_t *disk;
310 
311     if(list->head == NULL) return NULL;
312 
313     disk = list->head;
314     list->head = disk->next;
315 
316     if(list->head == NULL) list->tail = NULL;
317     else list->head->prev = NULL;
318 
319     disk->prev = disk->next = NULL;	/* for debugging */
320     return disk;
321 }
322 
323 void
remove_disk(disklist_t * list,disk_t * disk)324 remove_disk(
325     disklist_t *list,
326     disk_t *	disk)
327 {
328     if(disk->prev == NULL) list->head = disk->next;
329     else disk->prev->next = disk->next;
330 
331     if(disk->next == NULL) list->tail = disk->prev;
332     else disk->next->prev = disk->prev;
333 
334     disk->prev = disk->next = NULL;
335 }
336 
337 void
unload_disklist(void)338 unload_disklist(void)
339 {
340     disk_t    *dp, *dpnext;
341     am_host_t *host, *hostnext;
342     netif_t *netif, *next_if;
343 
344     for(host=hostlist; host != NULL; host = hostnext) {
345 	amfree(host->hostname);
346 	am_release_feature_set(host->features);
347 	host->features = NULL;
348 	hostnext = host->next;
349 	for (dp = host->disks; dp != NULL ; dp = dpnext) {
350 	    dpnext = dp->hostnext;
351 	    amfree(dp->filename);
352 	    amfree(dp->name);
353 	    amfree(dp->hostname);
354 	    amfree(dp->device);
355 	    free_sl(dp->exclude_file);
356 	    free_sl(dp->exclude_list);
357 	    free_sl(dp->include_file);
358 	    free_sl(dp->include_list);
359 	    free(dp);
360 	}
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 *
upcase(char * st)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
parse_diskline(disklist_t * lst,const char * filename,FILE * diskf,int * line_num_p,char ** line_p)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 (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->orig_holdingdisk   = dumptype_get_to_holdingdisk(dtype);
748     disk->to_holdingdisk     = disk->orig_holdingdisk;
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 
printf_arglist_function2(void disk_parserror,const char *,filename,int,line_num,const char *,format)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
dump_queue(char * st,disklist_t q,int npr,FILE * f)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 *
validate_optionstr(disk_t * dp)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 *
optionstr(disk_t * dp)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) */
xml_property(gpointer key_p,gpointer value_p,gpointer user_data_p)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 *
xml_optionstr(disk_t * dp,int to_server)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 *
xml_dumptype_properties(disk_t * dp)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 *
xml_estimate(estimatelist_t estimatelist,am_feature_t * their_features)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 *
clean_dle_str_for_client(char * dle_str,am_feature_t * their_features)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 *
xml_application(disk_t * dp G_GNUC_UNUSED,application_t * application,am_feature_t * their_features)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 *
xml_scripts(identlist_t pp_scriptlist,am_feature_t * their_features)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
disable_skip_disk(disklist_t * origqp)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 *
match_disklist(disklist_t * origqp,gboolean exact_match,int sargc,char ** sargv)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
match_dumpfile(dumpfile_t * file,gboolean exact_match,int sargc,char ** sargv)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 *
disklist_netifs(void)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
dump_disk(const disk_t * dp)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
dump_disklist(const disklist_t * lst)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
main(int argc,char ** argv)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 */
2146