Imported Upstream version 2.4.4p3
[debian/amanda] / server-src / conffile.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-2000 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Author: James da Silva, Systems Design and Analysis Group
24  *                         Computer Science Department
25  *                         University of Maryland at College Park
26  */
27 /*
28  * $Id: conffile.c,v 1.54.2.16.2.5.2.20 2003/11/26 16:12:19 martinea Exp $
29  *
30  * read configuration file
31  */
32 /*
33  *
34  * XXX - I'm not happy *at all* with this implementation, but I don't
35  * think YACC would be any easier.  A more table based implementation
36  * would be better.  Also clean up memory leaks.
37  */
38 #include "amanda.h"
39 #include "arglist.h"
40
41 #include "conffile.h"
42 #include "diskfile.h"
43 #include "driverio.h"
44 #include "clock.h"
45
46 #ifdef HAVE_LIMITS_H
47 #include <limits.h>
48 #endif
49
50 #ifndef INT_MAX
51 #define INT_MAX 2147483647
52 #endif
53
54 #define BIGINT  1000000000              /* 2 million yrs @ 1 per day */
55
56 /* internal types and variables */
57
58 /*
59  * XXX - this is used by the krb4 stuff.
60  * Hopefully nobody will need this here.  (not very likely).  -kovert
61  */
62 #if defined(INTERFACE)
63 #  undef INTERFACE
64 #endif
65
66 typedef enum {
67     UNKNOWN, ANY, COMMA, LBRACE, RBRACE, NL, END,
68     IDENT, INT, BOOL, REAL, STRING, TIME,
69
70     /* config parameters */
71     INCLUDEFILE,
72     ORG, MAILTO, DUMPUSER,
73     TAPECYCLE, TAPEDEV, CHNGRDEV, CHNGRFILE, LABELSTR,
74     BUMPSIZE, BUMPDAYS, BUMPMULT, ETIMEOUT, DTIMEOUT, CTIMEOUT,
75     TAPEBUFS, TAPELIST, DISKFILE, INFOFILE, LOGDIR, LOGFILE,
76     DISKDIR, DISKSIZE, INDEXDIR, NETUSAGE, INPARALLEL, DUMPORDER, TIMEOUT,
77     TPCHANGER, RUNTAPES,
78     DEFINE, DUMPTYPE, TAPETYPE, INTERFACE,
79     PRINTER, AUTOFLUSH, RESERVE, MAXDUMPSIZE,
80     COLUMNSPEC, 
81     AMRECOVER_DO_FSF, AMRECOVER_CHECK_LABEL, AMRECOVER_CHANGER,
82
83     TAPERALGO, FIRST, FIRSTFIT, LARGEST, LARGESTFIT, SMALLEST, LAST,
84
85     /* holding disk */
86     COMMENT, DIRECTORY, USE, CHUNKSIZE,
87
88     /* dump type */
89     /*COMMENT,*/ PROGRAM, DUMPCYCLE, RUNSPERCYCLE, MAXCYCLE, MAXDUMPS,
90     OPTIONS, PRIORITY, FREQUENCY, INDEX, MAXPROMOTEDAY,
91     STARTTIME, COMPRESS, AUTH, STRATEGY,
92     SKIP_INCR, SKIP_FULL, RECORD, HOLDING,
93     EXCLUDE, INCLUDE, KENCRYPT, IGNORE, COMPRATE,
94
95     /* tape type */
96     /*COMMENT,*/ BLOCKSIZE, FILE_PAD, LBL_TEMPL, FILEMARK, LENGTH, SPEED,
97
98     /* network interface */
99     /*COMMENT, USE,*/
100
101     /* dump options (obsolete) */
102     EXCLUDE_FILE, EXCLUDE_LIST,
103
104     /* compress */
105     NONE, FAST, BEST, SERVER, CLIENT,
106
107     /* priority */
108     LOW, MEDIUM, HIGH,
109
110     /* authentication */
111     KRB4_AUTH, BSD_AUTH,
112
113     /* dump strategy */
114     SKIP, STANDARD, NOFULL, NOINC, HANOI, INCRONLY,
115
116     /* exclude list */
117     LIST, EFILE, APPEND, OPTIONAL,
118
119     /* numbers */
120     INFINITY, MULT1, MULT7, MULT1K, MULT1M, MULT1G,
121
122     /* boolean */
123     ATRUE, AFALSE,
124
125     RAWTAPEDEV
126 } tok_t;
127
128 typedef struct {        /* token table entry */
129     char *keyword;
130     tok_t token;
131 } keytab_t;
132
133 keytab_t *keytable;
134
135 typedef union {
136     int i;
137     double r;
138     char *s;
139 } val_t;
140
141 /* this corresponds to the normal output of amanda, but may
142  * be adapted to any spacing as you like.
143  */
144 ColumnInfo ColumnData[] = {
145     { "HostName",   0, 12, 12, 0, "%-*.*s", "HOSTNAME" },
146     { "Disk",       1, 11, 11, 0, "%-*.*s", "DISK" },
147     { "Level",      1, 1,  1,  0, "%*.*d",  "L" },
148     { "OrigKB",     1, 7,  0,  0, "%*.*f",  "ORIG-KB" },
149     { "OutKB",      0, 7,  0,  0, "%*.*f",  "OUT-KB" },
150     { "Compress",   0, 6,  1,  0, "%*.*f",  "COMP%" },
151     { "DumpTime",   0, 7,  7,  0, "%*.*s",  "MMM:SS" },
152     { "DumpRate",   0, 6,  1,  0, "%*.*f",  "KB/s" },
153     { "TapeTime",   1, 6,  6,  0, "%*.*s",  "MMM:SS" },
154     { "TapeRate",   0, 6,  1,  0, "%*.*f",  "KB/s" },
155     { NULL,         0, 0,  0,  0, NULL,     NULL }
156 };
157
158 char *config_name = NULL;
159 char *config_dir = NULL;
160
161 /* visible holding disk variables */
162
163 holdingdisk_t *holdingdisks;
164 int num_holdingdisks;
165
166 /* configuration parameters */
167
168 /* strings */
169 static val_t conf_org;
170 static val_t conf_mailto;
171 static val_t conf_dumpuser;
172 static val_t conf_printer;
173 static val_t conf_tapedev;
174 static val_t conf_rawtapedev;
175 static val_t conf_tpchanger;
176 static val_t conf_chngrdev;
177 static val_t conf_chngrfile;
178 static val_t conf_labelstr;
179 static val_t conf_tapelist;
180 static val_t conf_infofile;
181 static val_t conf_logdir;
182 static val_t conf_diskfile;
183 static val_t conf_diskdir;
184 static val_t conf_tapetype;
185 static val_t conf_indexdir;
186 static val_t conf_columnspec;
187 static val_t conf_dumporder;
188 static val_t conf_amrecover_changer;
189
190 /* ints */
191 static val_t conf_dumpcycle;
192 static val_t conf_runspercycle;
193 static val_t conf_maxcycle;
194 static val_t conf_tapecycle;
195 static val_t conf_runtapes;
196 static val_t conf_disksize;
197 static val_t conf_netusage;
198 static val_t conf_inparallel;
199 static val_t conf_timeout;
200 static val_t conf_maxdumps;
201 static val_t conf_bumpsize;
202 static val_t conf_bumpdays;
203 static val_t conf_etimeout;
204 static val_t conf_dtimeout;
205 static val_t conf_ctimeout;
206 static val_t conf_tapebufs;
207 static val_t conf_autoflush;
208 static val_t conf_reserve;
209 static val_t conf_maxdumpsize;
210 static val_t conf_amrecover_do_fsf;
211 static val_t conf_amrecover_check_label;
212 static val_t conf_taperalgo;
213
214 /* reals */
215 static val_t conf_bumpmult;
216
217 /* other internal variables */
218 static holdingdisk_t hdcur;
219
220 static tapetype_t tpcur;
221
222 static dumptype_t dpcur;
223
224 static interface_t ifcur;
225
226 static int seen_org;
227 static int seen_mailto;
228 static int seen_dumpuser;
229 static int seen_rawtapedev;
230 static int seen_printer;
231 static int seen_tapedev;
232 static int seen_tpchanger;
233 static int seen_chngrdev;
234 static int seen_chngrfile;
235 static int seen_labelstr;
236 static int seen_runtapes;
237 static int seen_maxdumps;
238 static int seen_tapelist;
239 static int seen_infofile;
240 static int seen_diskfile;
241 static int seen_diskdir;
242 static int seen_logdir;
243 static int seen_bumpsize;
244 static int seen_bumpmult;
245 static int seen_bumpdays;
246 static int seen_tapetype;
247 static int seen_dumpcycle;
248 static int seen_runspercycle;
249 static int seen_maxcycle;
250 static int seen_tapecycle;
251 static int seen_disksize;
252 static int seen_netusage;
253 static int seen_inparallel;
254 static int seen_dumporder;
255 static int seen_timeout;
256 static int seen_indexdir;
257 static int seen_etimeout;
258 static int seen_dtimeout;
259 static int seen_ctimeout;
260 static int seen_tapebufs;
261 static int seen_autoflush;
262 static int seen_reserve;
263 static int seen_maxdumpsize;
264 static int seen_columnspec;
265 static int seen_amrecover_do_fsf;
266 static int seen_amrecover_check_label;
267 static int seen_amrecover_changer;
268 static int seen_taperalgo;
269
270 static int allow_overwrites;
271 static int token_pushed;
272
273 static tok_t tok, pushed_tok;
274 static val_t tokenval;
275
276 static int line_num, got_parserror;
277 static dumptype_t *dumplist = NULL;
278 static tapetype_t *tapelist = NULL;
279 static interface_t *interface_list = NULL;
280 static FILE *conf = (FILE *)NULL;
281 static char *confname = NULL;
282
283 /* predeclare local functions */
284
285 static void init_defaults P((void));
286 static void read_conffile_recursively P((char *filename));
287
288 static int read_confline P((void));
289 static void get_holdingdisk P((void));
290 static void init_holdingdisk_defaults P((void));
291 static void save_holdingdisk P((void));
292 static void get_dumptype P((void));
293 static void init_dumptype_defaults P((void));
294 static void save_dumptype P((void));
295 static void copy_dumptype P((void));
296 static void get_tapetype P((void));
297 static void init_tapetype_defaults P((void));
298 static void save_tapetype P((void));
299 static void copy_tapetype P((void));
300 static void get_interface P((void));
301 static void init_interface_defaults P((void));
302 static void save_interface P((void));
303 static void copy_interface P((void));
304 static void get_dumpopts P((void));
305 static void get_comprate P((void));
306 static void get_compress P((void));
307 static void get_priority P((void));
308 static void get_auth P((void));
309 static void get_strategy P((void));
310 static void get_exclude P((void));
311 static void get_include P((void));
312 static void get_taperalgo P((val_t *c_taperalgo, int *s_taperalgo));
313
314 static void get_simple P((val_t *var, int *seen, tok_t type));
315 static int get_time P((void));
316 static int get_number P((void));
317 static int get_bool P((void));
318 static void ckseen P((int *seen));
319 static void parserror P((char *format, ...))
320     __attribute__ ((format (printf, 1, 2)));
321 static tok_t lookup_keyword P((char *str));
322 static void unget_conftoken P((void));
323 static void get_conftoken P((tok_t exp));
324
325 /*
326 ** ------------------------
327 **  External entry points
328 ** ------------------------
329 */
330
331 int read_conffile(filename)
332 char *filename;
333 {
334     interface_t *ip;
335
336     init_defaults();
337
338     /* We assume that confname & conf are initialized to NULL above */
339     read_conffile_recursively(filename);
340
341     if(got_parserror != -1 ) {
342         if(lookup_tapetype(conf_tapetype.s) == NULL) {
343             char *save_confname = confname;
344
345             confname = filename;
346             if(!seen_tapetype)
347                 parserror("default tapetype %s not defined", conf_tapetype.s);
348             else {
349                 line_num = seen_tapetype;
350                 parserror("tapetype %s not defined", conf_tapetype.s);
351             }
352             confname = save_confname;
353         }
354     }
355
356     ip = alloc(sizeof(interface_t));
357     malloc_mark(ip);
358     ip->name = "";
359     ip->seen = seen_netusage;
360     ip->comment = "implicit from NETUSAGE";
361     ip->maxusage = conf_netusage.i;
362     ip->curusage = 0;
363     ip->next = interface_list;
364     interface_list = ip;
365
366     return got_parserror;
367 }
368
369 struct byname {
370     char *name;
371     confparm_t parm;
372     tok_t typ;
373 } byname_table [] = {
374     { "ORG", CNF_ORG, STRING },
375     { "MAILTO", CNF_MAILTO, STRING },
376     { "DUMPUSER", CNF_DUMPUSER, STRING },
377     { "PRINTER", CNF_PRINTER, STRING },
378     { "TAPEDEV", CNF_TAPEDEV, STRING },
379     { "TPCHANGER", CNF_TPCHANGER, STRING },
380     { "CHANGERDEV", CNF_CHNGRDEV, STRING },
381     { "CHANGERFILE", CNF_CHNGRFILE, STRING },
382     { "LABELSTR", CNF_LABELSTR, STRING },
383     { "TAPELIST", CNF_TAPELIST, STRING },
384     { "DISKFILE", CNF_DISKFILE, STRING },
385     { "INFOFILE", CNF_INFOFILE, STRING },
386     { "LOGDIR", CNF_LOGDIR, STRING },
387     /*{ "LOGFILE", CNF_LOGFILE, STRING },*/
388     /*{ "DISKDIR", CNF_DISKDIR, STRING },*/
389     { "INDEXDIR", CNF_INDEXDIR, STRING },
390     { "TAPETYPE", CNF_TAPETYPE, STRING },
391     { "DUMPCYCLE", CNF_DUMPCYCLE, INT },
392     { "RUNSPERCYCLE", CNF_RUNSPERCYCLE, INT },
393     { "MINCYCLE",  CNF_DUMPCYCLE, INT },
394     { "RUNTAPES",   CNF_RUNTAPES, INT },
395     { "TAPECYCLE", CNF_TAPECYCLE, INT },
396     /*{ "DISKSIZE", CNF_DISKSIZE, INT },*/
397     { "BUMPDAYS", CNF_BUMPDAYS, INT },
398     { "BUMPSIZE", CNF_BUMPSIZE, INT },
399     { "BUMPMULT", CNF_BUMPMULT, REAL },
400     { "NETUSAGE", CNF_NETUSAGE, INT },
401     { "INPARALLEL", CNF_INPARALLEL, INT },
402     { "DUMPORDER", CNF_DUMPORDER, STRING },
403     /*{ "TIMEOUT", CNF_TIMEOUT, INT },*/
404     { "MAXDUMPS", CNF_MAXDUMPS, INT },
405     { "ETIMEOUT", CNF_ETIMEOUT, INT },
406     { "DTIMEOUT", CNF_DTIMEOUT, INT },
407     { "CTIMEOUT", CNF_CTIMEOUT, INT },
408     { "TAPEBUFS", CNF_TAPEBUFS, INT },
409     { "RAWTAPEDEV", CNF_RAWTAPEDEV, STRING },
410     { "COLUMNSPEC", CNF_COLUMNSPEC, STRING },
411     { "AMRECOVER_DO_FSF", CNF_AMRECOVER_DO_FSF, BOOL },
412     { "AMRECOVER_CHECK_LABEL", CNF_AMRECOVER_CHECK_LABEL, BOOL },
413     { "AMRECOVER_CHANGER", CNF_AMRECOVER_CHANGER, STRING },
414     { "TAPERALGO", CNF_TAPERALGO, INT },
415     { "AUTOFLUSH", CNF_AUTOFLUSH, BOOL },
416     { "RESERVE", CNF_RESERVE, INT },
417     { "MAXDUMPSIZE", CNF_MAXDUMPSIZE, INT },
418     { NULL }
419 };
420
421 char *getconf_byname(str)
422 char *str;
423 {
424     static char *tmpstr;
425     char number[NUM_STR_SIZE];
426     struct byname *np;
427     char *s;
428     char ch;
429
430     tmpstr = stralloc(str);
431     s = tmpstr;
432     while((ch = *s++) != '\0') {
433         if(islower((int) ch)) s[-1] = toupper(ch);
434     }
435
436     for(np = byname_table; np->name != NULL; np++)
437         if(strcmp(np->name, tmpstr) == 0) break;
438
439     if(np->name == NULL) return NULL;
440
441     if(np->typ == INT) {
442         ap_snprintf(number, sizeof(number), "%d", getconf_int(np->parm));
443         tmpstr = newstralloc(tmpstr, number);
444     } else if(np->typ == REAL) {
445         ap_snprintf(number, sizeof(number), "%f", getconf_real(np->parm));
446         tmpstr = newstralloc(tmpstr, number);
447     } else {
448         tmpstr = newstralloc(tmpstr, getconf_str(np->parm));
449     }
450
451     return tmpstr;
452 }
453
454 int getconf_seen(parm)
455 confparm_t parm;
456 {
457     switch(parm) {
458     case CNF_ORG: return seen_org;
459     case CNF_MAILTO: return seen_mailto;
460     case CNF_DUMPUSER: return seen_dumpuser;
461     case CNF_PRINTER: return seen_printer;
462     case CNF_TAPEDEV: return seen_tapedev;
463     case CNF_TPCHANGER: return seen_tpchanger;
464     case CNF_CHNGRDEV: return seen_chngrdev;
465     case CNF_CHNGRFILE: return seen_chngrfile;
466     case CNF_LABELSTR: return seen_labelstr;
467     case CNF_RUNTAPES: return seen_runtapes;
468     case CNF_MAXDUMPS: return seen_maxdumps;
469     case CNF_TAPELIST: return seen_tapelist;
470     case CNF_INFOFILE: return seen_infofile;
471     case CNF_DISKFILE: return seen_diskfile;
472     /*case CNF_DISKDIR: return seen_diskdir;*/
473     case CNF_LOGDIR: return seen_logdir;
474     /*case CNF_LOGFILE: return seen_logfile;*/
475     case CNF_BUMPSIZE: return seen_bumpsize;
476     case CNF_BUMPMULT: return seen_bumpmult;
477     case CNF_BUMPDAYS: return seen_bumpdays;
478     case CNF_TAPETYPE: return seen_tapetype;
479     case CNF_DUMPCYCLE: return seen_dumpcycle;
480     case CNF_RUNSPERCYCLE: return seen_runspercycle;
481     /*case CNF_MAXCYCLE: return seen_maxcycle;*/
482     case CNF_TAPECYCLE: return seen_tapecycle;
483     /*case CNF_DISKSIZE: return seen_disksize;*/
484     case CNF_NETUSAGE: return seen_netusage;
485     case CNF_INPARALLEL: return seen_inparallel;
486     case CNF_DUMPORDER: return seen_dumporder;
487     /*case CNF_TIMEOUT: return seen_timeout;*/
488     case CNF_INDEXDIR: return seen_indexdir;
489     case CNF_ETIMEOUT: return seen_etimeout;
490     case CNF_DTIMEOUT: return seen_dtimeout;
491     case CNF_CTIMEOUT: return seen_ctimeout;
492     case CNF_TAPEBUFS: return seen_tapebufs;
493     case CNF_RAWTAPEDEV: return seen_rawtapedev;
494     case CNF_AUTOFLUSH: return seen_autoflush;
495     case CNF_RESERVE: return seen_reserve;
496     case CNF_MAXDUMPSIZE: return seen_maxdumpsize;
497     case CNF_AMRECOVER_DO_FSF: return seen_amrecover_do_fsf;
498     case CNF_AMRECOVER_CHECK_LABEL: return seen_amrecover_check_label;
499     case CNF_AMRECOVER_CHANGER: return seen_amrecover_changer;
500     case CNF_TAPERALGO: return seen_taperalgo;
501     default: return 0;
502     }
503 }
504
505 int getconf_int(parm)
506 confparm_t parm;
507 {
508     int r = 0;
509
510     switch(parm) {
511
512     case CNF_DUMPCYCLE: r = conf_dumpcycle.i; break;
513     case CNF_RUNSPERCYCLE: r = conf_runspercycle.i; break;
514     case CNF_TAPECYCLE: r = conf_tapecycle.i; break;
515     case CNF_RUNTAPES: r = conf_runtapes.i; break;
516     /*case CNF_DISKSIZE: r = conf_disksize.i; break;*/
517     case CNF_BUMPSIZE: r = conf_bumpsize.i; break;
518     case CNF_BUMPDAYS: r = conf_bumpdays.i; break;
519     case CNF_NETUSAGE: r = conf_netusage.i; break;
520     case CNF_INPARALLEL: r = conf_inparallel.i; break;
521     /*case CNF_TIMEOUT: r = conf_timeout.i; break;*/
522     case CNF_MAXDUMPS: r = conf_maxdumps.i; break;
523     case CNF_ETIMEOUT: r = conf_etimeout.i; break;
524     case CNF_DTIMEOUT: r = conf_dtimeout.i; break;
525     case CNF_CTIMEOUT: r = conf_ctimeout.i; break;
526     case CNF_TAPEBUFS: r = conf_tapebufs.i; break;
527     case CNF_AUTOFLUSH: r = conf_autoflush.i; break;
528     case CNF_RESERVE: r = conf_reserve.i; break;
529     case CNF_MAXDUMPSIZE: r = conf_maxdumpsize.i; break;
530     case CNF_AMRECOVER_DO_FSF: r = conf_amrecover_do_fsf.i; break;
531     case CNF_AMRECOVER_CHECK_LABEL: r = conf_amrecover_check_label.i; break;
532     case CNF_TAPERALGO: r = conf_taperalgo.i; break;
533
534     default:
535         error("error [unknown getconf_int parm: %d]", parm);
536         /* NOTREACHED */
537     }
538     return r;
539 }
540
541 double getconf_real(parm)
542 confparm_t parm;
543 {
544     double r = 0;
545
546     switch(parm) {
547
548     case CNF_BUMPMULT: r = conf_bumpmult.r; break;
549
550     default:
551         error("error [unknown getconf_real parm: %d]", parm);
552         /* NOTREACHED */
553     }
554     return r;
555 }
556
557 char *getconf_str(parm)
558 confparm_t parm;
559 {
560     char *r = 0;
561
562     switch(parm) {
563
564     case CNF_ORG: r = conf_org.s; break;
565     case CNF_MAILTO: r = conf_mailto.s; break;
566     case CNF_DUMPUSER: r = conf_dumpuser.s; break;
567     case CNF_PRINTER: r = conf_printer.s; break;
568     case CNF_TAPEDEV: r = conf_tapedev.s; break;
569     case CNF_TPCHANGER: r = conf_tpchanger.s; break;
570     case CNF_CHNGRDEV: r = conf_chngrdev.s; break;
571     case CNF_CHNGRFILE: r = conf_chngrfile.s; break;
572     case CNF_LABELSTR: r = conf_labelstr.s; break;
573     case CNF_TAPELIST: r = conf_tapelist.s; break;
574     case CNF_INFOFILE: r = conf_infofile.s; break;
575     case CNF_DUMPORDER: r = conf_dumporder.s; break;
576     case CNF_LOGDIR: r = conf_logdir.s; break;
577     /*case CNF_LOGFILE: r = conf_logfile.s; break;*/
578     case CNF_DISKFILE: r = conf_diskfile.s; break;
579     /*case CNF_DISKDIR: r = conf_diskdir.s; break;*/
580     case CNF_TAPETYPE: r = conf_tapetype.s; break;
581     case CNF_INDEXDIR: r = conf_indexdir.s; break;
582     case CNF_RAWTAPEDEV: r = conf_rawtapedev.s; break;
583     case CNF_COLUMNSPEC: r = conf_columnspec.s; break;
584     case CNF_AMRECOVER_CHANGER: r = conf_amrecover_changer.s; break;
585
586     default:
587         error("error [unknown getconf_str parm: %d]", parm);
588         /* NOTREACHED */
589     }
590     return r;
591 }
592
593 holdingdisk_t *getconf_holdingdisks()
594 {
595     return holdingdisks;
596 }
597
598 dumptype_t *lookup_dumptype(str)
599 char *str;
600 {
601     dumptype_t *p;
602
603     for(p = dumplist; p != NULL; p = p->next) {
604         if(strcmp(p->name, str) == 0) return p;
605     }
606     return NULL;
607 }
608
609 tapetype_t *lookup_tapetype(str)
610 char *str;
611 {
612     tapetype_t *p;
613
614     for(p = tapelist; p != NULL; p = p->next) {
615         if(strcmp(p->name, str) == 0) return p;
616     }
617     return NULL;
618 }
619
620 interface_t *lookup_interface(str)
621 char *str;
622 {
623     interface_t *p;
624
625     if(str == NULL) return interface_list;
626     for(p = interface_list; p != NULL; p = p->next) {
627         if(strcmp(p->name, str) == 0) return p;
628     }
629     return NULL;
630 }
631
632
633 /*
634 ** ------------------------
635 **  Internal routines
636 ** ------------------------
637 */
638
639
640 static void init_defaults()
641 {
642     char *s;
643
644     /* defaults for exported variables */
645
646 #ifdef DEFAULT_CONFIG
647     s = DEFAULT_CONFIG;
648 #else
649     s = "YOUR ORG";
650 #endif
651     conf_org.s = stralloc(s);
652     malloc_mark(conf_org.s);
653     conf_mailto.s = stralloc("operators");
654     malloc_mark(conf_mailto.s);
655     conf_dumpuser.s = stralloc(CLIENT_LOGIN);
656     malloc_mark(conf_dumpuser.s);
657 #ifdef DEFAULT_TAPE_DEVICE
658     s = DEFAULT_TAPE_DEVICE;
659 #else
660     s = "/dev/rmt8";
661 #endif
662     conf_tapedev.s = stralloc(s);
663     malloc_mark(conf_tapedev.s);
664 #ifdef DEFAULT_RAW_TAPE_DEVICE
665     s = DEFAULT_RAW_TAPE_DEVICE;
666 #else
667     s = "/dev/rawft0";
668 #endif
669     conf_rawtapedev.s = stralloc(s);
670     malloc_mark(conf_rawtapedev.s);
671     conf_tpchanger.s = stralloc("");
672     malloc_mark(conf_tpchanger.s);
673 #ifdef DEFAULT_CHANGER_DEVICE
674     s = DEFAULT_CHANGER_DEVICE;
675 #else
676     s = "/dev/null";
677 #endif
678     conf_chngrdev.s = stralloc(s);
679     malloc_mark(conf_chngrdev.s);
680     conf_chngrfile.s = stralloc("/usr/adm/amanda/changer-status");
681     malloc_mark(conf_chngrfile.s);
682     conf_labelstr.s = stralloc(".*");
683     malloc_mark(conf_labelstr.s);
684     conf_tapelist.s = stralloc("tapelist");
685     malloc_mark(conf_tapelist.s);
686     conf_infofile.s = stralloc("/usr/adm/amanda/curinfo");
687     malloc_mark(conf_infofile.s);
688     conf_logdir.s = stralloc("/usr/adm/amanda");
689     malloc_mark(conf_logdir.s);
690     conf_diskfile.s = stralloc("disklist");
691     malloc_mark(conf_diskfile.s);
692     conf_diskdir.s  = stralloc("/dumps/amanda");
693     malloc_mark(conf_diskdir.s);
694     conf_tapetype.s = stralloc("EXABYTE");
695     malloc_mark(conf_tapetype.s);
696     conf_indexdir.s = stralloc("/usr/adm/amanda/index");
697     malloc_mark(conf_indexdir.s);
698     conf_columnspec.s = stralloc("");
699     malloc_mark(conf_columnspec.s);
700     conf_dumporder.s = stralloc("ttt");
701     malloc_mark(conf_dumporder.s);
702     conf_amrecover_changer.s = stralloc("");
703     conf_printer.s = stralloc("");
704
705     conf_dumpcycle.i    = 10;
706     conf_runspercycle.i = 0;
707     conf_tapecycle.i    = 15;
708     conf_runtapes.i     = 1;
709     conf_disksize.i     = 0;
710     conf_netusage.i     = 300;
711     conf_inparallel.i   = 10;
712     conf_maxdumps.i     = 1;
713     conf_timeout.i      = 2;
714     conf_bumpsize.i     = 10*1024;
715     conf_bumpdays.i     = 2;
716     conf_bumpmult.r     = 1.5;
717     conf_etimeout.i     = 300;
718     conf_dtimeout.i     = 1800;
719     conf_ctimeout.i     = 30;
720     conf_tapebufs.i     = 20;
721     conf_autoflush.i    = 0;
722     conf_reserve.i      = 100;
723     conf_maxdumpsize.i  = -1;
724     conf_amrecover_do_fsf.i = 0;
725     conf_amrecover_check_label.i = 0;
726     conf_taperalgo.i = 0;
727
728     /* defaults for internal variables */
729
730     seen_org = 0;
731     seen_mailto = 0;
732     seen_dumpuser = 0;
733     seen_tapedev = 0;
734     seen_rawtapedev = 0;
735     seen_printer = 0;
736     seen_tpchanger = 0;
737     seen_chngrdev = 0;
738     seen_chngrfile = 0;
739     seen_labelstr = 0;
740     seen_runtapes = 0;
741     seen_maxdumps = 0;
742     seen_tapelist = 0;
743     seen_infofile = 0;
744     seen_diskfile = 0;
745     seen_diskdir = 0;
746     seen_logdir = 0;
747     seen_bumpsize = 0;
748     seen_bumpmult = 0;
749     seen_bumpdays = 0;
750     seen_tapetype = 0;
751     seen_dumpcycle = 0;
752     seen_runspercycle = 0;
753     seen_maxcycle = 0;
754     seen_tapecycle = 0;
755     seen_disksize = 0;
756     seen_netusage = 0;
757     seen_inparallel = 0;
758     seen_dumporder = 0;
759     seen_timeout = 0;
760     seen_indexdir = 0;
761     seen_etimeout = 0;
762     seen_dtimeout = 0;
763     seen_ctimeout = 0;
764     seen_tapebufs = 0;
765     seen_autoflush = 0;
766     seen_reserve = 0;
767     seen_maxdumpsize = 0;
768     seen_columnspec = 0;
769     seen_amrecover_do_fsf = 0;
770     seen_amrecover_check_label = 0;
771     seen_amrecover_changer = 0;
772     seen_taperalgo = 0;
773     line_num = got_parserror = 0;
774     allow_overwrites = 0;
775     token_pushed = 0;
776
777     while(holdingdisks != NULL) {
778         holdingdisk_t *hp;
779
780         hp = holdingdisks;
781         holdingdisks = holdingdisks->next;
782         amfree(hp);
783     }
784     num_holdingdisks = 0;
785
786     /* free any previously declared dump, tape and interface types */
787
788     while(dumplist != NULL) {
789         dumptype_t *dp;
790
791         dp = dumplist;
792         dumplist = dumplist->next;
793         amfree(dp);
794     }
795     while(tapelist != NULL) {
796         tapetype_t *tp;
797
798         tp = tapelist;
799         tapelist = tapelist->next;
800         amfree(tp);
801     }
802     while(interface_list != NULL) {
803         interface_t *ip;
804
805         ip = interface_list;
806         interface_list = interface_list->next;
807         amfree(ip);
808     }
809
810     /* create some predefined dumptypes for backwards compatability */
811     init_dumptype_defaults();
812     dpcur.name = "NO-COMPRESS"; dpcur.seen = -1;
813     dpcur.compress = COMP_NONE; dpcur.s_compress = -1;
814     save_dumptype();
815
816     init_dumptype_defaults();
817     dpcur.name = "COMPRESS-FAST"; dpcur.seen = -1;
818     dpcur.compress = COMP_FAST; dpcur.s_compress = -1;
819     save_dumptype();
820
821     init_dumptype_defaults();
822     dpcur.name = "COMPRESS-BEST"; dpcur.seen = -1;
823     dpcur.compress = COMP_BEST; dpcur.s_compress = -1;
824     save_dumptype();
825
826     init_dumptype_defaults();
827     dpcur.name = "SRVCOMPRESS"; dpcur.seen = -1;
828     dpcur.compress = COMP_SERV_FAST; dpcur.s_compress = -1;
829     save_dumptype();
830
831     init_dumptype_defaults();
832     dpcur.name = "BSD-AUTH"; dpcur.seen = -1;
833     dpcur.auth = AUTH_BSD; dpcur.s_auth = -1;
834     save_dumptype();
835
836     init_dumptype_defaults();
837     dpcur.name = "KRB4-AUTH"; dpcur.seen = -1;
838     dpcur.auth = AUTH_KRB4; dpcur.s_auth = -1;
839     save_dumptype();
840
841     init_dumptype_defaults();
842     dpcur.name = "NO-RECORD"; dpcur.seen = -1;
843     dpcur.record = 0; dpcur.s_record = -1;
844     save_dumptype();
845
846     init_dumptype_defaults();
847     dpcur.name = "NO-HOLD"; dpcur.seen = -1;
848     dpcur.no_hold = 1; dpcur.s_no_hold = -1;
849     save_dumptype();
850
851     init_dumptype_defaults();
852     dpcur.name = "NO-FULL"; dpcur.seen = -1;
853     dpcur.strategy = DS_NOFULL; dpcur.s_strategy = -1;
854     save_dumptype();
855 }
856
857 static void read_conffile_recursively(filename)
858 char *filename;
859 {
860     extern int errno;
861
862     /* Save globals used in read_confline(), elsewhere. */
863     int  save_line_num  = line_num;
864     FILE *save_conf     = conf;
865     char *save_confname = confname;
866
867     if (*filename == '/' || config_dir == NULL) {
868         confname = stralloc(filename);
869     } else {
870         confname = stralloc2(config_dir, filename);
871     }
872
873     if((conf = fopen(confname, "r")) == NULL) {
874         fprintf(stderr, "could not open conf file \"%s\": %s\n", confname,
875                 strerror(errno));
876         amfree(confname);
877         got_parserror = -1;
878         return;
879     }
880
881     line_num = 0;
882
883     /* read_confline() can invoke us recursively via "includefile" */
884     while(read_confline());
885     afclose(conf);
886
887     amfree(confname);
888
889     /* Restore globals */
890     line_num = save_line_num;
891     conf     = save_conf;
892     confname = save_confname;
893 }
894
895
896 /* ------------------------ */
897
898
899 keytab_t main_keytable[] = {
900     { "BUMPDAYS", BUMPDAYS },
901     { "BUMPMULT", BUMPMULT },
902     { "BUMPSIZE", BUMPSIZE },
903     { "DEFINE", DEFINE },
904     { "DISKDIR", DISKDIR },     /* XXX - historical */
905     { "DISKFILE", DISKFILE },
906     { "DISKSIZE", DISKSIZE },   /* XXX - historical */
907     { "DUMPCYCLE", DUMPCYCLE },
908     { "RUNSPERCYCLE", RUNSPERCYCLE },
909     { "DUMPTYPE", DUMPTYPE },
910     { "DUMPUSER", DUMPUSER },
911     { "PRINTER", PRINTER },
912     { "HOLDINGDISK", HOLDING },
913     { "INCLUDEFILE", INCLUDEFILE },
914     { "INDEXDIR", INDEXDIR },
915     { "INFOFILE", INFOFILE },
916     { "INPARALLEL", INPARALLEL },
917     { "DUMPORDER", DUMPORDER },
918     { "INTERFACE", INTERFACE },
919     { "LABELSTR", LABELSTR },
920     { "LOGDIR", LOGDIR },
921     { "LOGFILE", LOGFILE },     /* XXX - historical */
922     { "MAILTO", MAILTO },
923     { "MAXCYCLE", MAXCYCLE },   /* XXX - historical */
924     { "MAXDUMPS", MAXDUMPS },
925     { "MINCYCLE", DUMPCYCLE },  /* XXX - historical */
926     { "NETUSAGE", NETUSAGE },   /* XXX - historical */
927     { "ORG", ORG },
928     { "RUNTAPES", RUNTAPES },
929     { "TAPECYCLE", TAPECYCLE },
930     { "TAPEDEV", TAPEDEV },
931     { "TAPELIST", TAPELIST },
932     { "TAPETYPE", TAPETYPE },
933     { "TIMEOUT", TIMEOUT },     /* XXX - historical */
934     { "TPCHANGER", TPCHANGER },
935     { "CHANGERDEV", CHNGRDEV },
936     { "CHANGERFILE", CHNGRFILE },
937     { "ETIMEOUT", ETIMEOUT },
938     { "DTIMEOUT", DTIMEOUT },
939     { "CTIMEOUT", CTIMEOUT },
940     { "TAPEBUFS", TAPEBUFS },
941     { "RAWTAPEDEV", RAWTAPEDEV },
942     { "AUTOFLUSH", AUTOFLUSH },
943     { "RESERVE", RESERVE },
944     { "MAXDUMPSIZE", MAXDUMPSIZE },
945     { "COLUMNSPEC", COLUMNSPEC },
946     { "AMRECOVER_DO_FSF", AMRECOVER_DO_FSF },
947     { "AMRECOVER_CHECK_LABEL", AMRECOVER_CHECK_LABEL },
948     { "AMRECOVER_CHANGER", AMRECOVER_CHANGER },
949     { "TAPERALGO", TAPERALGO },
950     { NULL, IDENT }
951 };
952
953 static int read_confline()
954 {
955     keytable = main_keytable;
956
957     line_num += 1;
958     get_conftoken(ANY);
959     switch(tok) {
960     case INCLUDEFILE:
961         {
962             char *fn;
963
964             get_conftoken(STRING);
965             fn = tokenval.s;
966             read_conffile_recursively(fn);
967         }
968         break;
969
970     case ORG:       get_simple(&conf_org,       &seen_org,       STRING); break;
971     case MAILTO:    get_simple(&conf_mailto,    &seen_mailto,    STRING); break;
972     case DUMPUSER:  get_simple(&conf_dumpuser,  &seen_dumpuser,  STRING); break;
973     case PRINTER:   get_simple(&conf_printer,   &seen_printer,   STRING); break;
974     case DUMPCYCLE: get_simple(&conf_dumpcycle, &seen_dumpcycle, INT);
975                     if(conf_dumpcycle.i < 0) {
976                         parserror("dumpcycle must be positive");
977                     }
978                     break;
979     case RUNSPERCYCLE: get_simple(&conf_runspercycle, &seen_runspercycle, INT);
980                     if(conf_runspercycle.i < -1) {
981                         parserror("runspercycle must be >= -1");
982                     }
983                     break;
984     case MAXCYCLE:  get_simple(&conf_maxcycle,  &seen_maxcycle,  INT);    break;
985     case TAPECYCLE: get_simple(&conf_tapecycle, &seen_tapecycle, INT);
986                     if(conf_tapecycle.i < 1) {
987                         parserror("tapecycle must be positive");
988                     }
989                     break;
990     case RUNTAPES:  get_simple(&conf_runtapes,  &seen_runtapes,  INT);
991                     if(conf_runtapes.i < 1) {
992                         parserror("runtapes must be positive");
993                     }
994                     break;
995     case TAPEDEV:   get_simple(&conf_tapedev,   &seen_tapedev,   STRING); break;
996     case RAWTAPEDEV:get_simple(&conf_rawtapedev,&seen_rawtapedev,STRING); break;
997     case TPCHANGER: get_simple(&conf_tpchanger, &seen_tpchanger, STRING); break;
998     case CHNGRDEV:  get_simple(&conf_chngrdev,  &seen_chngrdev,  STRING); break;
999     case CHNGRFILE: get_simple(&conf_chngrfile, &seen_chngrfile, STRING); break;
1000     case LABELSTR:  get_simple(&conf_labelstr,  &seen_labelstr,  STRING); break;
1001     case TAPELIST:  get_simple(&conf_tapelist,  &seen_tapelist,  STRING); break;
1002     case INFOFILE:  get_simple(&conf_infofile,  &seen_infofile,  STRING); break;
1003     case LOGDIR:    get_simple(&conf_logdir,    &seen_logdir,    STRING); break;
1004     case DISKFILE:  get_simple(&conf_diskfile,  &seen_diskfile,  STRING); break;
1005     case BUMPMULT:  get_simple(&conf_bumpmult,  &seen_bumpmult,  REAL);
1006                     if(conf_bumpmult.r < 0.999) {
1007                         parserror("bumpmult must be positive");
1008                     }
1009                     break;
1010     case BUMPSIZE:  get_simple(&conf_bumpsize,  &seen_bumpsize,  INT);
1011                     if(conf_bumpsize.i < 1) {
1012                         parserror("bumpsize must be positive");
1013                     }
1014                     break;
1015     case BUMPDAYS:  get_simple(&conf_bumpdays,  &seen_bumpdays,  INT);
1016                     if(conf_bumpdays.i < 1) {
1017                         parserror("bumpdays must be positive");
1018                     }
1019                     break;
1020     case NETUSAGE:  get_simple(&conf_netusage,  &seen_netusage,  INT);
1021                     if(conf_netusage.i < 1) {
1022                         parserror("netusage must be positive");
1023                     }
1024                     break;
1025     case INPARALLEL:get_simple(&conf_inparallel,&seen_inparallel,INT);
1026                     if(conf_inparallel.i < 1 || conf_inparallel.i >MAX_DUMPERS){
1027                         parserror(
1028                             "inparallel must be between 1 and MAX_DUMPERS (%d)",
1029                             MAX_DUMPERS);
1030                     }
1031                     break;
1032     case DUMPORDER: get_simple(&conf_dumporder, &seen_dumporder, STRING); break;
1033     case TIMEOUT:   get_simple(&conf_timeout,   &seen_timeout,   INT);    break;
1034     case MAXDUMPS:  get_simple(&conf_maxdumps,  &seen_maxdumps,  INT);
1035                     if(conf_maxdumps.i < 1) {
1036                         parserror("maxdumps must be positive");
1037                     }
1038                     break;
1039     case TAPETYPE:  get_simple(&conf_tapetype,  &seen_tapetype,  IDENT);  break;
1040     case INDEXDIR:  get_simple(&conf_indexdir,  &seen_indexdir,  STRING); break;
1041     case ETIMEOUT:  get_simple(&conf_etimeout,  &seen_etimeout,  INT);    break;
1042     case DTIMEOUT:  get_simple(&conf_dtimeout,  &seen_dtimeout,  INT);
1043                     if(conf_dtimeout.i < 1) {
1044                         parserror("dtimeout must be positive");
1045                     }
1046                     break;
1047     case CTIMEOUT:  get_simple(&conf_ctimeout,  &seen_ctimeout,  INT);
1048                     if(conf_ctimeout.i < 1) {
1049                         parserror("ctimeout must be positive");
1050                     }
1051                     break;
1052     case TAPEBUFS:  get_simple(&conf_tapebufs,  &seen_tapebufs,  INT);
1053                     if(conf_tapebufs.i < 1) {
1054                         parserror("tapebufs must be positive");
1055                     }
1056                     break;
1057     case AUTOFLUSH: get_simple(&conf_autoflush, &seen_autoflush, BOOL);   break;
1058     case RESERVE:   get_simple(&conf_reserve,   &seen_reserve,   INT);
1059                     if(conf_reserve.i < 0 || conf_reserve.i > 100) {
1060                         parserror("reserve must be between 0 and 100");
1061                     }
1062                     break;
1063     case MAXDUMPSIZE:get_simple(&conf_maxdumpsize,&seen_maxdumpsize,INT); break;
1064     case COLUMNSPEC:get_simple(&conf_columnspec,&seen_columnspec,STRING); break;
1065
1066     case AMRECOVER_DO_FSF: get_simple(&conf_amrecover_do_fsf,&seen_amrecover_do_fsf, BOOL); break;
1067     case AMRECOVER_CHECK_LABEL: get_simple(&conf_amrecover_check_label,&seen_amrecover_check_label, BOOL); break;
1068     case AMRECOVER_CHANGER: get_simple(&conf_amrecover_changer,&seen_amrecover_changer, STRING); break;
1069
1070     case TAPERALGO: get_taperalgo(&conf_taperalgo,&seen_taperalgo); break;
1071
1072     case LOGFILE: /* XXX - historical */
1073         /* truncate the filename part and pretend he said "logdir" */
1074         {
1075             char *p;
1076
1077             get_simple(&conf_logdir, &seen_logdir, STRING);
1078
1079             p = strrchr(conf_logdir.s, '/');
1080             if (p != (char *)0) *p = '\0';
1081         }
1082         break;
1083
1084     case DISKDIR:
1085         {
1086             char *s;
1087
1088             get_conftoken(STRING);
1089             s = tokenval.s;
1090
1091             if(!seen_diskdir) {
1092                 conf_diskdir.s = newstralloc(conf_diskdir.s, s);
1093                 seen_diskdir = line_num;
1094             }
1095
1096             init_holdingdisk_defaults();
1097             hdcur.name = "default from DISKDIR";
1098             hdcur.seen = line_num;
1099             hdcur.diskdir = stralloc(s);
1100             hdcur.s_disk = line_num;
1101             hdcur.disksize = conf_disksize.i;
1102             hdcur.s_size = seen_disksize;
1103             save_holdingdisk();
1104         }
1105         break;
1106
1107     case DISKSIZE:
1108         {
1109             int i;
1110
1111             i = get_number();
1112             i = (i / DISK_BLOCK_KB) * DISK_BLOCK_KB;
1113
1114             if(!seen_disksize) {
1115                 conf_disksize.i = i;
1116                 seen_disksize = line_num;
1117             }
1118
1119             if(holdingdisks != NULL)
1120                 holdingdisks->disksize = i;
1121         }
1122
1123         break;
1124
1125     case HOLDING:
1126         get_holdingdisk();
1127         break;
1128
1129     case DEFINE:
1130         get_conftoken(ANY);
1131         if(tok == DUMPTYPE) get_dumptype();
1132         else if(tok == TAPETYPE) get_tapetype();
1133         else if(tok == INTERFACE) get_interface();
1134         else parserror("DUMPTYPE, INTERFACE or TAPETYPE expected");
1135         break;
1136
1137     case NL:    /* empty line */
1138         break;
1139     case END:   /* end of file */
1140         return 0;
1141     default:
1142         parserror("configuration keyword expected");
1143     }
1144     if(tok != NL) get_conftoken(NL);
1145     return 1;
1146 }
1147
1148 keytab_t holding_keytable[] = {
1149     { "DIRECTORY", DIRECTORY },
1150     { "COMMENT", COMMENT },
1151     { "USE", USE },
1152     { "CHUNKSIZE", CHUNKSIZE },
1153     { NULL, IDENT }
1154 };
1155
1156 static void get_holdingdisk()
1157 {
1158     int done;
1159     int save_overwrites;
1160     keytab_t *save_kt;
1161
1162     save_overwrites = allow_overwrites;
1163     allow_overwrites = 1;
1164
1165     save_kt = keytable;
1166     keytable = holding_keytable;
1167
1168     init_holdingdisk_defaults();
1169
1170     get_conftoken(IDENT);
1171     hdcur.name = stralloc(tokenval.s);
1172     malloc_mark(hdcur.name);
1173     hdcur.seen = line_num;
1174
1175     get_conftoken(LBRACE);
1176     get_conftoken(NL);
1177
1178     done = 0;
1179     do {
1180         line_num += 1;
1181         get_conftoken(ANY);
1182         switch(tok) {
1183
1184         case COMMENT:
1185             get_simple((val_t *)&hdcur.comment, &hdcur.s_comment, STRING);
1186             break;
1187         case DIRECTORY:
1188             get_simple((val_t *)&hdcur.diskdir, &hdcur.s_disk, STRING);
1189             break;
1190         case USE:
1191             get_simple((val_t *)&hdcur.disksize, &hdcur.s_size, INT);
1192             hdcur.disksize = am_floor(hdcur.disksize, DISK_BLOCK_KB);
1193             break;
1194         case CHUNKSIZE:
1195             get_simple((val_t *)&hdcur.chunksize, &hdcur.s_csize, INT);
1196             if(hdcur.chunksize == 0) {
1197                 hdcur.chunksize =  ((INT_MAX / 1024) - (2 * DISK_BLOCK_KB));
1198             } else if(hdcur.chunksize < 0) {
1199                 parserror("Negative chunksize (%ld) is no longer supported",
1200                           hdcur.chunksize);
1201             }
1202             hdcur.chunksize = am_floor(hdcur.chunksize, DISK_BLOCK_KB);
1203             break;
1204         case RBRACE:
1205             done = 1;
1206             break;
1207         case NL:        /* empty line */
1208             break;
1209         case END:       /* end of file */
1210             done = 1;
1211         default:
1212             parserror("holding disk parameter expected");
1213         }
1214         if(tok != NL && tok != END) get_conftoken(NL);
1215     } while(!done);
1216
1217     save_holdingdisk();
1218
1219     allow_overwrites = save_overwrites;
1220     keytable = save_kt;
1221 }
1222
1223 static void init_holdingdisk_defaults()
1224 {
1225     hdcur.comment = stralloc("");
1226     hdcur.diskdir = stralloc(conf_diskdir.s);
1227     malloc_mark(hdcur.diskdir);
1228     hdcur.disksize = 0;
1229     hdcur.chunksize = 1024*1024*1024; /* 1 Gb */
1230
1231     hdcur.s_comment = 0;
1232     hdcur.s_disk = 0;
1233     hdcur.s_size = 0;
1234     hdcur.s_csize = 0;
1235
1236     hdcur.up = (void *)0;
1237 }
1238
1239 static void save_holdingdisk()
1240 {
1241     holdingdisk_t *hp;
1242
1243     hp = alloc(sizeof(holdingdisk_t));
1244     malloc_mark(hp);
1245     *hp = hdcur;
1246     hp->next = holdingdisks;
1247     holdingdisks = hp;
1248
1249     num_holdingdisks++;
1250 }
1251
1252
1253 keytab_t dumptype_keytable[] = {
1254     { "AUTH", AUTH },
1255     { "COMMENT", COMMENT },
1256     { "COMPRATE", COMPRATE },
1257     { "COMPRESS", COMPRESS },
1258     { "DUMPCYCLE", DUMPCYCLE },
1259     { "EXCLUDE", EXCLUDE },
1260     { "FREQUENCY", FREQUENCY }, /* XXX - historical */
1261     { "HOLDINGDISK", HOLDING },
1262     { "IGNORE", IGNORE },
1263     { "INCLUDE", INCLUDE },
1264     { "INDEX", INDEX },
1265     { "KENCRYPT", KENCRYPT },
1266     { "MAXCYCLE", MAXCYCLE },   /* XXX - historical */
1267     { "MAXDUMPS", MAXDUMPS },
1268     { "MAXPROMOTEDAY", MAXPROMOTEDAY },
1269     { "OPTIONS", OPTIONS },     /* XXX - historical */
1270     { "PRIORITY", PRIORITY },
1271     { "PROGRAM", PROGRAM },
1272     { "RECORD", RECORD },
1273     { "SKIP-FULL", SKIP_FULL },
1274     { "SKIP-INCR", SKIP_INCR },
1275     { "STARTTIME", STARTTIME },
1276     { "STRATEGY", STRATEGY },
1277     { NULL, IDENT }
1278 };
1279
1280 dumptype_t *read_dumptype(name, from, fname, linenum)
1281      char *name;
1282      FILE *from;
1283      char *fname;
1284      int *linenum;
1285 {
1286     int done;
1287     int save_overwrites;
1288     keytab_t *save_kt;
1289     val_t tmpval;
1290     FILE *saved_conf = NULL;
1291     char *saved_fname = NULL;
1292
1293     if (from) {
1294         saved_conf = conf;
1295         conf = from;
1296     }
1297
1298     if (fname) {
1299         saved_fname = confname;
1300         confname = fname;
1301     }
1302
1303     if (linenum)
1304         line_num = *linenum;
1305
1306     save_overwrites = allow_overwrites;
1307     allow_overwrites = 1;
1308
1309     save_kt = keytable;
1310     keytable = dumptype_keytable;
1311
1312     init_dumptype_defaults();
1313
1314     if (name) {
1315         dpcur.name = name;
1316     } else {
1317         get_conftoken(IDENT);
1318         dpcur.name = stralloc(tokenval.s);
1319         malloc_mark(dpcur.name);
1320     }
1321
1322     dpcur.seen = line_num;
1323
1324     if (! name) {
1325         get_conftoken(LBRACE);
1326         get_conftoken(NL);
1327     }
1328
1329     done = 0;
1330     do {
1331         line_num += 1;
1332         get_conftoken(ANY);
1333         switch(tok) {
1334
1335         case AUTH:
1336             get_auth();
1337             break;
1338         case COMMENT:
1339             get_simple((val_t *)&dpcur.comment, &dpcur.s_comment, STRING);
1340             break;
1341         case COMPRATE:
1342             get_comprate();
1343             break;
1344         case COMPRESS:
1345             get_compress();
1346             break;
1347         case DUMPCYCLE:
1348             get_simple((val_t *)&dpcur.dumpcycle, &dpcur.s_dumpcycle, INT);
1349             if(dpcur.dumpcycle < 0) {
1350                 parserror("dumpcycle must be positive");
1351             }
1352             break;
1353         case EXCLUDE:
1354             get_exclude();
1355             break;
1356         case FREQUENCY:
1357             get_simple((val_t *)&dpcur.frequency, &dpcur.s_frequency, INT);
1358             break;
1359         case HOLDING:
1360             get_simple(&tmpval, &dpcur.s_no_hold, BOOL);
1361             dpcur.no_hold = (tmpval.i == 0);
1362             break;
1363         case IGNORE:
1364             get_simple(&tmpval, &dpcur.s_ignore, BOOL);
1365             dpcur.ignore = (tmpval.i != 0);
1366             break;
1367         case INCLUDE:
1368             get_include();
1369             break;
1370         case INDEX:
1371             get_simple(&tmpval, &dpcur.s_index, BOOL);
1372             dpcur.index = (tmpval.i != 0);
1373             break;
1374         case KENCRYPT:
1375             get_simple(&tmpval, &dpcur.s_kencrypt, BOOL);
1376             dpcur.kencrypt = (tmpval.i != 0);
1377             break;
1378         case MAXCYCLE:
1379             get_simple((val_t *)&conf_maxcycle, &dpcur.s_maxcycle, INT);
1380             break;
1381         case MAXDUMPS:
1382             get_simple((val_t *)&dpcur.maxdumps, &dpcur.s_maxdumps, INT);
1383             if(dpcur.maxdumps < 1) {
1384                 parserror("maxdumps must be positive");
1385             }
1386             break;
1387         case MAXPROMOTEDAY:
1388             get_simple((val_t *)&dpcur.maxpromoteday, &dpcur.s_maxpromoteday, INT);
1389             if(dpcur.maxpromoteday < 0) {
1390                 parserror("dpcur.maxpromoteday must be >= 0");
1391             }
1392             break;
1393         case OPTIONS:
1394             get_dumpopts();
1395             break;
1396         case PRIORITY:
1397             get_priority();
1398             break;
1399         case PROGRAM:
1400             get_simple((val_t *)&dpcur.program, &dpcur.s_program, STRING);
1401             if(strcmp(dpcur.program, "DUMP")
1402                && strcmp(dpcur.program, "GNUTAR"))
1403                 parserror("backup program \"%s\" unknown", dpcur.program);
1404             break;
1405         case RECORD:
1406             get_simple(&tmpval, &dpcur.s_record, BOOL);
1407             dpcur.record = (tmpval.i != 0);
1408             break;
1409         case SKIP_FULL:
1410             get_simple(&tmpval, &dpcur.s_skip_full, BOOL);
1411             dpcur.skip_full = (tmpval.i != 0);
1412             break;
1413         case SKIP_INCR:
1414             get_simple(&tmpval, &dpcur.s_skip_incr, BOOL);
1415             dpcur.skip_incr = (tmpval.i != 0);
1416             break;
1417         case STARTTIME:
1418             get_simple((val_t *)&dpcur.start_t, &dpcur.s_start_t, TIME);
1419             break;
1420         case STRATEGY:
1421             get_strategy();
1422             break;
1423
1424         case IDENT:
1425             copy_dumptype();
1426             break;
1427
1428         case RBRACE:
1429             done = 1;
1430             break;
1431         case NL:        /* empty line */
1432             break;
1433         case END:       /* end of file */
1434             done = 1;
1435         default:
1436             parserror("dump type parameter expected");
1437         }
1438         if(tok != NL && tok != END &&
1439            /* When a name is specified, we shouldn't consume the NL
1440               after the RBRACE.  */
1441            (tok != RBRACE || name == 0))
1442             get_conftoken(NL);
1443     } while(!done);
1444
1445     /* XXX - there was a stupidity check in here for skip-incr and
1446     ** skip-full.  This check should probably be somewhere else. */
1447
1448     save_dumptype();
1449
1450     allow_overwrites = save_overwrites;
1451     keytable = save_kt;
1452
1453     if (linenum)
1454         *linenum = line_num;
1455
1456     if (fname)
1457         confname = saved_fname;
1458
1459     if (from)
1460         conf = saved_conf;
1461
1462     return lookup_dumptype(dpcur.name);
1463 }
1464
1465 static void get_dumptype()
1466 {
1467     read_dumptype(NULL, NULL, NULL, NULL);
1468 }
1469
1470 static void init_dumptype_defaults()
1471 {
1472     dpcur.comment = stralloc("");
1473     dpcur.program = stralloc("DUMP");
1474     dpcur.exclude_file = NULL;
1475     dpcur.exclude_list = NULL;
1476     dpcur.include_file = NULL;
1477     dpcur.include_list = NULL;
1478     dpcur.priority = 1;
1479     dpcur.dumpcycle = conf_dumpcycle.i;
1480     dpcur.maxcycle = conf_maxcycle.i;
1481     dpcur.frequency = 1;
1482     dpcur.maxdumps = conf_maxdumps.i;
1483     dpcur.maxpromoteday = 10000;
1484     dpcur.start_t = 0;
1485
1486     dpcur.auth = AUTH_BSD;
1487
1488     /* options */
1489     dpcur.record = 1;
1490     dpcur.strategy = DS_STANDARD;
1491     dpcur.compress = COMP_FAST;
1492     dpcur.comprate[0] = dpcur.comprate[1] = 0.50;
1493     dpcur.skip_incr = dpcur.skip_full = 0;
1494     dpcur.no_hold = 0;
1495     dpcur.kencrypt = 0;
1496     dpcur.ignore = 0;
1497     dpcur.index = 0;
1498
1499     dpcur.s_comment = 0;
1500     dpcur.s_program = 0;
1501     dpcur.s_exclude_file = 0;
1502     dpcur.s_exclude_list = 0;
1503     dpcur.s_include_file = 0;
1504     dpcur.s_include_list = 0;
1505     dpcur.s_priority = 0;
1506     dpcur.s_dumpcycle = 0;
1507     dpcur.s_maxcycle = 0;
1508     dpcur.s_frequency = 0;
1509     dpcur.s_maxdumps = 0;
1510     dpcur.s_maxpromoteday = 0;
1511     dpcur.s_start_t = 0;
1512     dpcur.s_auth = 0;
1513     dpcur.s_record = 0;
1514     dpcur.s_strategy = 0;
1515     dpcur.s_compress = 0;
1516     dpcur.s_comprate = 0;
1517     dpcur.s_skip_incr = 0;
1518     dpcur.s_skip_full = 0;
1519     dpcur.s_no_hold = 0;
1520     dpcur.s_kencrypt = 0;
1521     dpcur.s_ignore = 0;
1522     dpcur.s_index = 0;
1523 }
1524
1525 static void save_dumptype()
1526 {
1527     dumptype_t *dp;
1528
1529     dp = lookup_dumptype(dpcur.name);
1530
1531     if(dp != (dumptype_t *)0) {
1532         parserror("dumptype %s already defined on line %d", dp->name, dp->seen);
1533         return;
1534     }
1535
1536     dp = alloc(sizeof(dumptype_t));
1537     malloc_mark(dp);
1538     *dp = dpcur;
1539     dp->next = dumplist;
1540     dumplist = dp;
1541 }
1542
1543 static void copy_dumptype()
1544 {
1545     dumptype_t *dt;
1546
1547     dt = lookup_dumptype(tokenval.s);
1548
1549     if(dt == NULL) {
1550         parserror("dump type parameter expected");
1551         return;
1552     }
1553
1554 #define dtcopy(v,s) if(dt->s) { dpcur.v = dt->v; dpcur.s = dt->s; }
1555
1556     if(dt->s_comment) {
1557         dpcur.comment = newstralloc(dpcur.comment, dt->comment);
1558         dpcur.s_comment = dt->s_comment;
1559     }
1560     if(dt->s_program) {
1561         dpcur.program = newstralloc(dpcur.program, dt->program);
1562         dpcur.s_program = dt->s_program;
1563     }
1564     if(dt->s_exclude_file) {
1565         dpcur.exclude_file = duplicate_sl(dt->exclude_file);
1566         dpcur.s_exclude_file = dt->s_exclude_file;
1567     }
1568     if(dt->s_exclude_list) {
1569         dpcur.exclude_list = duplicate_sl(dt->exclude_list);
1570         dpcur.s_exclude_list = dt->s_exclude_list;
1571     }
1572     if(dt->s_include_file) {
1573         dpcur.include_file = duplicate_sl(dt->include_file);
1574         dpcur.s_include_file = dt->s_include_file;
1575     }
1576     if(dt->s_include_list) {
1577         dpcur.include_list = duplicate_sl(dt->include_list);
1578         dpcur.s_include_list = dt->s_include_list;
1579     }
1580     dtcopy(priority, s_priority);
1581     dtcopy(dumpcycle, s_dumpcycle);
1582     dtcopy(maxcycle, s_maxcycle);
1583     dtcopy(frequency, s_frequency);
1584     dtcopy(maxdumps, s_maxdumps);
1585     dtcopy(maxpromoteday, s_maxpromoteday);
1586     dtcopy(start_t, s_start_t);
1587     dtcopy(auth, s_auth);
1588     dtcopy(record, s_record);
1589     dtcopy(strategy, s_strategy);
1590     dtcopy(compress, s_compress);
1591     dtcopy(comprate[0], s_comprate);
1592     dtcopy(comprate[1], s_comprate);
1593     dtcopy(skip_incr, s_skip_incr);
1594     dtcopy(skip_full, s_skip_full);
1595     dtcopy(no_hold, s_no_hold);
1596     dtcopy(kencrypt, s_kencrypt);
1597     dtcopy(ignore, s_ignore);
1598     dtcopy(index, s_index);
1599 }
1600
1601 keytab_t tapetype_keytable[] = {
1602     { "COMMENT", COMMENT },
1603     { "LBL-TEMPL", LBL_TEMPL },
1604     { "BLOCKSIZE", BLOCKSIZE },
1605     { "FILE-PAD", FILE_PAD },
1606     { "FILEMARK", FILEMARK },
1607     { "LENGTH", LENGTH },
1608     { "SPEED", SPEED },
1609     { NULL, IDENT }
1610 };
1611
1612 static void get_tapetype()
1613 {
1614     int done;
1615     int save_overwrites;
1616     val_t value;
1617
1618     keytab_t *save_kt;
1619
1620     save_overwrites = allow_overwrites;
1621     allow_overwrites = 1;
1622
1623     save_kt = keytable;
1624     keytable = tapetype_keytable;
1625
1626     init_tapetype_defaults();
1627
1628     get_conftoken(IDENT);
1629     tpcur.name = stralloc(tokenval.s);
1630     malloc_mark(tpcur.name);
1631     tpcur.seen = line_num;
1632
1633     get_conftoken(LBRACE);
1634     get_conftoken(NL);
1635
1636     done = 0;
1637     do {
1638         line_num += 1;
1639         get_conftoken(ANY);
1640         switch(tok) {
1641
1642         case RBRACE:
1643             done = 1;
1644             break;
1645         case COMMENT:
1646             get_simple((val_t *)&tpcur.comment, &tpcur.s_comment, STRING);
1647             break;
1648         case LBL_TEMPL:
1649             get_simple((val_t *)&tpcur.lbl_templ, &tpcur.s_lbl_templ, STRING);
1650             break;
1651         case BLOCKSIZE:
1652             get_simple((val_t *)&tpcur.blocksize, &tpcur.s_blocksize, INT);
1653             if(tpcur.blocksize < DISK_BLOCK_KB) {
1654                 parserror("Tape blocksize must be at least %d KBytes",
1655                           DISK_BLOCK_KB);
1656             } else if(tpcur.blocksize > MAX_TAPE_BLOCK_KB) {
1657                 parserror("Tape blocksize must not be larger than %d KBytes",
1658                           MAX_TAPE_BLOCK_KB);
1659             }
1660             break;
1661         case FILE_PAD:
1662             get_simple(&value, &tpcur.s_file_pad, BOOL);
1663             tpcur.file_pad = (value.i != 0);
1664             break;
1665         case LENGTH:
1666             get_simple(&value, &tpcur.s_length, INT);
1667             if(value.i < 0) {
1668                 parserror("Tape length must be positive");
1669             }
1670             else {
1671                 tpcur.length = value.i;
1672             }
1673             break;
1674         case FILEMARK:
1675             get_simple(&value, &tpcur.s_filemark, INT);
1676             if(value.i < 0) {
1677                 parserror("Tape file mark size must be positive");
1678             }
1679             else {
1680                 tpcur.filemark = value.i;
1681             }
1682             break;
1683         case SPEED:
1684             get_simple((val_t *)&tpcur.speed, &tpcur.s_speed, INT);
1685             if(tpcur.speed < 0) {
1686                 parserror("Speed must be positive");
1687             }
1688             break;
1689         case IDENT:
1690             copy_tapetype();
1691             break;
1692         case NL:        /* empty line */
1693             break;
1694         case END:       /* end of file */
1695             done = 1;
1696         default:
1697             parserror("tape type parameter expected");
1698         }
1699         if(tok != NL && tok != END) get_conftoken(NL);
1700     } while(!done);
1701
1702     save_tapetype();
1703
1704     allow_overwrites = save_overwrites;
1705     keytable = save_kt;
1706 }
1707
1708 static void init_tapetype_defaults()
1709 {
1710     tpcur.comment = stralloc("");
1711     tpcur.lbl_templ = stralloc("");
1712     tpcur.blocksize = (DISK_BLOCK_KB);
1713     tpcur.file_pad = 1;
1714     tpcur.length = 2000 * 1024;
1715     tpcur.filemark = 1000;
1716     tpcur.speed = 200;
1717
1718     tpcur.s_comment = 0;
1719     tpcur.s_lbl_templ = 0;
1720     tpcur.s_blocksize = 0;
1721     tpcur.s_file_pad = 0;
1722     tpcur.s_length = 0;
1723     tpcur.s_filemark = 0;
1724     tpcur.s_speed = 0;
1725 }
1726
1727 static void save_tapetype()
1728 {
1729     tapetype_t *tp;
1730
1731     tp = lookup_tapetype(tpcur.name);
1732
1733     if(tp != (tapetype_t *)0) {
1734         amfree(tpcur.name);
1735         parserror("tapetype %s already defined on line %d", tp->name, tp->seen);
1736         return;
1737     }
1738
1739     tp = alloc(sizeof(tapetype_t));
1740     malloc_mark(tp);
1741     *tp = tpcur;
1742     tp->next = tapelist;
1743     tapelist = tp;
1744 }
1745
1746 static void copy_tapetype()
1747 {
1748     tapetype_t *tp;
1749
1750     tp = lookup_tapetype(tokenval.s);
1751
1752     if(tp == NULL) {
1753         parserror("tape type parameter expected");
1754         return;
1755     }
1756
1757 #define ttcopy(v,s) if(tp->s) { tpcur.v = tp->v; tpcur.s = tp->s; }
1758
1759     if(tp->s_comment) {
1760         tpcur.comment = newstralloc(tpcur.comment, tp->comment);
1761         tpcur.s_comment = tp->s_comment;
1762     }
1763     if(tp->s_lbl_templ) {
1764         tpcur.lbl_templ = newstralloc(tpcur.lbl_templ, tp->lbl_templ);
1765         tpcur.s_lbl_templ = tp->s_lbl_templ;
1766     }
1767     ttcopy(blocksize, s_blocksize);
1768     ttcopy(file_pad, s_file_pad);
1769     ttcopy(length, s_length);
1770     ttcopy(filemark, s_filemark);
1771     ttcopy(speed, s_speed);
1772 }
1773
1774 keytab_t interface_keytable[] = {
1775     { "COMMENT", COMMENT },
1776     { "USE", USE },
1777     { NULL, IDENT }
1778 };
1779
1780 static void get_interface()
1781 {
1782     int done;
1783     int save_overwrites;
1784     keytab_t *save_kt;
1785
1786     save_overwrites = allow_overwrites;
1787     allow_overwrites = 1;
1788
1789     save_kt = keytable;
1790     keytable = interface_keytable;
1791
1792     init_interface_defaults();
1793
1794     get_conftoken(IDENT);
1795     ifcur.name = stralloc(tokenval.s);
1796     malloc_mark(ifcur.name);
1797     ifcur.seen = line_num;
1798
1799     get_conftoken(LBRACE);
1800     get_conftoken(NL);
1801
1802     done = 0;
1803     do {
1804         line_num += 1;
1805         get_conftoken(ANY);
1806         switch(tok) {
1807
1808         case RBRACE:
1809             done = 1;
1810             break;
1811         case COMMENT:
1812             get_simple((val_t *)&ifcur.comment, &ifcur.s_comment, STRING);
1813             break;
1814         case USE:
1815             get_simple((val_t *)&ifcur.maxusage, &ifcur.s_maxusage, INT);
1816             if(ifcur.maxusage <1) {
1817                 parserror("use must bbe positive");
1818             }
1819             break;
1820         case IDENT:
1821             copy_interface();
1822             break;
1823         case NL:        /* empty line */
1824             break;
1825         case END:       /* end of file */
1826             done = 1;
1827         default:
1828             parserror("interface parameter expected");
1829         }
1830         if(tok != NL && tok != END) get_conftoken(NL);
1831     } while(!done);
1832
1833     save_interface();
1834
1835     allow_overwrites = save_overwrites;
1836     keytable = save_kt;
1837
1838     return;
1839 }
1840
1841 static void init_interface_defaults()
1842 {
1843     ifcur.comment = stralloc("");
1844     ifcur.maxusage = 300;
1845
1846     ifcur.s_comment = 0;
1847     ifcur.s_maxusage = 0;
1848
1849     ifcur.curusage = 0;
1850 }
1851
1852 static void save_interface()
1853 {
1854     interface_t *ip;
1855
1856     ip = lookup_interface(ifcur.name);
1857
1858     if(ip != (interface_t *)0) {
1859         parserror("interface %s already defined on line %d", ip->name, ip->seen);
1860         return;
1861     }
1862
1863     ip = alloc(sizeof(interface_t));
1864     malloc_mark(ip);
1865     *ip = ifcur;
1866     ip->next = interface_list;
1867     interface_list = ip;
1868 }
1869
1870 static void copy_interface()
1871 {
1872     interface_t *ip;
1873
1874     ip = lookup_interface(tokenval.s);
1875
1876     if(ip == NULL) {
1877         parserror("interface parameter expected");
1878         return;
1879     }
1880
1881 #define ifcopy(v,s) if(ip->s) { ifcur.v = ip->v; ifcur.s = ip->s; }
1882
1883     if(ip->s_comment) {
1884         ifcur.comment = newstralloc(ifcur.comment, ip->comment);
1885         ifcur.s_comment = ip->s_comment;
1886     }
1887     ifcopy(maxusage, s_maxusage);
1888 }
1889
1890 keytab_t dumpopts_keytable[] = {
1891     { "COMPRESS", COMPRESS },
1892     { "INDEX", INDEX },
1893     { "EXCLUDE-FILE", EXCLUDE_FILE },
1894     { "EXCLUDE-LIST", EXCLUDE_LIST },
1895     { "KENCRYPT", KENCRYPT },
1896     { "SKIP-FULL", SKIP_FULL },
1897     { "SKIP-INCR", SKIP_INCR },
1898     { NULL, IDENT }
1899 };
1900
1901 static void get_dumpopts() /* XXX - for historical compatability */
1902 {
1903     int done;
1904     keytab_t *save_kt;
1905
1906     save_kt = keytable;
1907     keytable = dumpopts_keytable;
1908
1909     done = 0;
1910     do {
1911         get_conftoken(ANY);
1912         switch(tok) {
1913         case COMPRESS:   ckseen(&dpcur.s_compress);  dpcur.compress = COMP_FAST; break;
1914         case EXCLUDE_FILE:
1915             ckseen(&dpcur.s_exclude_file);
1916             get_conftoken(STRING);
1917             dpcur.exclude_file = append_sl(dpcur.exclude_file, stralloc(tokenval.s));
1918             break;
1919         case EXCLUDE_LIST:
1920             ckseen(&dpcur.s_exclude_list);
1921             get_conftoken(STRING);
1922             dpcur.exclude_list = append_sl(dpcur.exclude_list, stralloc(tokenval.s));
1923             break;
1924         case KENCRYPT:   ckseen(&dpcur.s_kencrypt);  dpcur.kencrypt = 1; break;
1925         case SKIP_INCR:  ckseen(&dpcur.s_skip_incr); dpcur.skip_incr= 1; break;
1926         case SKIP_FULL:  ckseen(&dpcur.s_skip_full); dpcur.skip_full= 1; break;
1927         case INDEX:      ckseen(&dpcur.s_index);     dpcur.index    = 1; break;
1928         case IDENT:
1929             copy_dumptype();
1930             break;
1931         case NL: done = 1; break;
1932         case COMMA: break;
1933         case END:
1934             done = 1;
1935         default:
1936             parserror("dump option expected");
1937         }
1938     } while(!done);
1939
1940     keytable = save_kt;
1941 }
1942
1943 static void get_comprate()
1944 {
1945     val_t var;
1946
1947     get_simple(&var, &dpcur.s_comprate, REAL);
1948     dpcur.comprate[0] = dpcur.comprate[1] = var.r;
1949     if(dpcur.comprate[0] < 0) {
1950         parserror("full compression rate must be >= 0");
1951     }
1952
1953     get_conftoken(ANY);
1954     switch(tok) {
1955     case NL:
1956         return;
1957     case COMMA:
1958         break;
1959     default:
1960         unget_conftoken();
1961     }
1962
1963     get_conftoken(REAL);
1964     dpcur.comprate[1] = tokenval.r;
1965     if(dpcur.comprate[1] < 0) {
1966         parserror("incremental compression rate must be >= 0");
1967     }
1968 }
1969
1970 keytab_t compress_keytable[] = {
1971     { "BEST", BEST },
1972     { "CLIENT", CLIENT },
1973     { "FAST", FAST },
1974     { "NONE", NONE },
1975     { "SERVER", SERVER },
1976     { NULL, IDENT }
1977 };
1978
1979 static void get_compress()
1980 {
1981     keytab_t *save_kt;
1982     int serv, clie, none, fast, best;
1983     int done;
1984     int comp;
1985
1986     save_kt = keytable;
1987     keytable = compress_keytable;
1988
1989     ckseen(&dpcur.s_compress);
1990
1991     serv = clie = none = fast = best = 0;
1992
1993     done = 0;
1994     do {
1995         get_conftoken(ANY);
1996         switch(tok) {
1997         case NONE:   none = 1; break;
1998         case FAST:   fast = 1; break;
1999         case BEST:   best = 1; break;
2000         case CLIENT: clie = 1; break;
2001         case SERVER: serv = 1; break;
2002         case NL:     done = 1; break;
2003         default:
2004             done = 1;
2005             serv = clie = 1; /* force an error */
2006         }
2007     } while(!done);
2008
2009     if(serv + clie == 0) clie = 1;      /* default to client */
2010     if(none + fast + best == 0) fast = 1; /* default to fast */
2011
2012     comp = -1;
2013
2014     if(!serv && clie) {
2015         if(none && !fast && !best) comp = COMP_NONE;
2016         if(!none && fast && !best) comp = COMP_FAST;
2017         if(!none && !fast && best) comp = COMP_BEST;
2018     }
2019
2020     if(serv && !clie) {
2021         if(none && !fast && !best) comp = COMP_NONE;
2022         if(!none && fast && !best) comp = COMP_SERV_FAST;
2023         if(!none && !fast && best) comp = COMP_SERV_BEST;
2024     }
2025
2026     if(comp == -1) {
2027         parserror("NONE, CLIENT FAST, CLIENT BEST, SERVER FAST or SERVER BEST expected");
2028         comp = COMP_NONE;
2029     }
2030
2031     dpcur.compress = comp;
2032
2033     keytable = save_kt;
2034 }
2035
2036 keytab_t taperalgo_keytable[] = {
2037     { "FIRST", FIRST },
2038     { "FIRSTFIT", FIRSTFIT },
2039     { "LARGEST", LARGEST },
2040     { "LARGESTFIT", LARGESTFIT },
2041     { "SMALLEST", SMALLEST },
2042     { "LAST", LAST },
2043     { NULL, IDENT }
2044 };
2045
2046 static void get_taperalgo(c_taperalgo, s_taperalgo)
2047 val_t *c_taperalgo;
2048 int *s_taperalgo;
2049 {
2050     keytab_t *save_kt;
2051
2052     save_kt = keytable;
2053     keytable = taperalgo_keytable;
2054
2055     ckseen(s_taperalgo);
2056
2057     get_conftoken(ANY);
2058     switch(tok) {
2059     case FIRST:      c_taperalgo->i = ALGO_FIRST;      break;
2060     case FIRSTFIT:   c_taperalgo->i = ALGO_FIRSTFIT;   break;
2061     case LARGEST:    c_taperalgo->i = ALGO_LARGEST;    break;
2062     case LARGESTFIT: c_taperalgo->i = ALGO_LARGESTFIT; break;
2063     case SMALLEST:   c_taperalgo->i = ALGO_SMALLEST;   break;
2064     case LAST:       c_taperalgo->i = ALGO_LAST;       break;
2065     default:
2066         parserror("FIRST, FIRSTFIT, LARGEST, LARGESTFIT, SMALLEST or LAST expected");
2067     }
2068
2069     keytable = save_kt;
2070 }
2071
2072 keytab_t priority_keytable[] = {
2073     { "HIGH", HIGH },
2074     { "LOW", LOW },
2075     { "MEDIUM", MEDIUM },
2076     { NULL, IDENT }
2077 };
2078
2079 static void get_priority()
2080 {
2081     int pri;
2082     keytab_t *save_kt;
2083
2084     save_kt = keytable;
2085     keytable = priority_keytable;
2086
2087     ckseen(&dpcur.s_priority);
2088
2089     get_conftoken(ANY);
2090     switch(tok) {
2091     case LOW: pri = 0; break;
2092     case MEDIUM: pri = 1; break;
2093     case HIGH: pri = 2; break;
2094     case INT: pri = tokenval.i; break;
2095     default:
2096         parserror("LOW, MEDIUM, HIGH or integer expected");
2097         pri = 0;
2098     }
2099     dpcur.priority = pri;
2100
2101     keytable = save_kt;
2102 }
2103
2104 keytab_t auth_keytable[] = {
2105     { "BSD", BSD_AUTH },
2106     { "KRB4", KRB4_AUTH },
2107     { NULL, IDENT }
2108 };
2109
2110 static void get_auth()
2111 {
2112     auth_t auth;
2113     keytab_t *save_kt;
2114
2115     save_kt = keytable;
2116     keytable = auth_keytable;
2117
2118     ckseen(&dpcur.s_auth);
2119
2120     get_conftoken(ANY);
2121     switch(tok) {
2122     case BSD_AUTH:
2123         auth = AUTH_BSD;
2124         break;
2125     case KRB4_AUTH:
2126         auth = AUTH_KRB4;
2127         break;
2128     default:
2129         parserror("BSD or KRB4 expected");
2130         auth = AUTH_BSD;
2131     }
2132     dpcur.auth = auth;
2133
2134     keytable = save_kt;
2135 }
2136
2137 keytab_t strategy_keytable[] = {
2138     { "HANOI", HANOI },
2139     { "NOFULL", NOFULL },
2140     { "NOINC", NOINC },
2141     { "SKIP", SKIP },
2142     { "STANDARD", STANDARD },
2143     { "INCRONLY", INCRONLY },
2144     { NULL, IDENT }
2145 };
2146
2147 static void get_strategy()
2148 {
2149     int strat;
2150     keytab_t *save_kt;
2151
2152     save_kt = keytable;
2153     keytable = strategy_keytable;
2154
2155     ckseen(&dpcur.s_strategy);
2156
2157     get_conftoken(ANY);
2158     switch(tok) {
2159     case SKIP:
2160         strat = DS_SKIP;
2161         break;
2162     case STANDARD:
2163         strat = DS_STANDARD;
2164         break;
2165     case NOFULL:
2166         strat = DS_NOFULL;
2167         break;
2168     case NOINC:
2169         strat = DS_NOINC;
2170         break;
2171     case HANOI:
2172         strat = DS_HANOI;
2173         break;
2174     case INCRONLY:
2175         strat = DS_INCRONLY;
2176         break;
2177     default:
2178         parserror("STANDARD or NOFULL expected");
2179         strat = DS_STANDARD;
2180     }
2181     dpcur.strategy = strat;
2182
2183     keytable = save_kt;
2184 }
2185
2186 keytab_t exclude_keytable[] = {
2187     { "LIST", LIST },
2188     { "FILE", EFILE },
2189     { "APPEND", APPEND },
2190     { "OPTIONAL", OPTIONAL },
2191     { NULL, IDENT }
2192 };
2193
2194 static void get_exclude()
2195 {
2196     int list, got_one = 0;
2197     keytab_t *save_kt;
2198     sl_t *exclude;
2199     int optional = 0;
2200     int append = 0;
2201
2202     save_kt = keytable;
2203     keytable = exclude_keytable;
2204
2205     get_conftoken(ANY);
2206     if(tok == LIST) {
2207         list = 1;
2208         exclude = dpcur.exclude_list;
2209         ckseen(&dpcur.s_exclude_list);
2210         get_conftoken(ANY);
2211     }
2212     else {
2213         list = 0;
2214         exclude = dpcur.exclude_file;
2215         ckseen(&dpcur.s_exclude_file);
2216         if(tok == EFILE) get_conftoken(ANY);
2217     }
2218
2219     if(tok == OPTIONAL) {
2220         get_conftoken(ANY);
2221         optional = 1;
2222     }
2223
2224     if(tok == APPEND) {
2225         get_conftoken(ANY);
2226         append = 1;
2227     }
2228     else {
2229         free_sl(exclude);
2230         exclude = NULL;
2231         append = 0;
2232     }
2233
2234     while(tok == STRING) {
2235         exclude = append_sl(exclude, tokenval.s);
2236         got_one = 1;
2237         get_conftoken(ANY);
2238     }
2239     unget_conftoken();
2240
2241     if(got_one == 0) { free_sl(exclude); exclude = NULL; }
2242
2243     if(list == 0)
2244         dpcur.exclude_file = exclude;
2245     else {
2246         dpcur.exclude_list = exclude;
2247         if(!append || optional)
2248             dpcur.exclude_optional = optional;
2249     }
2250
2251     keytable = save_kt;
2252 }
2253
2254
2255 static void get_include()
2256 {
2257     int list, got_one = 0;
2258     keytab_t *save_kt;
2259     sl_t *include;
2260     int optional = 0;
2261     int append = 0;
2262
2263     save_kt = keytable;
2264     keytable = exclude_keytable;
2265
2266     get_conftoken(ANY);
2267     if(tok == LIST) {
2268         list = 1;
2269         include = dpcur.include_list;
2270         ckseen(&dpcur.s_include_list);
2271         get_conftoken(ANY);
2272     }
2273     else {
2274         list = 0;
2275         include = dpcur.include_file;
2276         ckseen(&dpcur.s_include_file);
2277         if(tok == EFILE) get_conftoken(ANY);
2278     }
2279
2280     if(tok == OPTIONAL) {
2281         get_conftoken(ANY);
2282         optional = 1;
2283     }
2284
2285     if(tok == APPEND) {
2286         get_conftoken(ANY);
2287         append = 1;
2288     }
2289     else {
2290         free_sl(include);
2291         include = NULL;
2292         append = 0;
2293     }
2294
2295     while(tok == STRING) {
2296         include = append_sl(include, tokenval.s);
2297         got_one = 1;
2298         get_conftoken(ANY);
2299     }
2300     unget_conftoken();
2301
2302     if(got_one == 0) { free_sl(include); include = NULL; }
2303
2304     if(list == 0)
2305         dpcur.include_file = include;
2306     else {
2307         dpcur.include_list = include;
2308         if(!append || optional)
2309             dpcur.include_optional = optional;
2310     }
2311
2312     keytable = save_kt;
2313 }
2314
2315
2316 /* ------------------------ */
2317
2318
2319 static void get_simple(var, seen, type)
2320 val_t *var;
2321 int *seen;
2322 tok_t type;
2323 {
2324     ckseen(seen);
2325
2326     switch(type) {
2327     case STRING:
2328     case IDENT:
2329         get_conftoken(type);
2330         var->s = newstralloc(var->s, tokenval.s);
2331         malloc_mark(var->s);
2332         break;
2333     case INT:
2334         var->i = get_number();
2335         break;
2336     case BOOL:
2337         var->i = get_bool();
2338         break;
2339     case REAL:
2340         get_conftoken(REAL);
2341         var->r = tokenval.r;
2342         break;
2343     case TIME:
2344         var->i = get_time();
2345         break;
2346     default:
2347         error("error [unknown get_simple type: %d]", type);
2348         /* NOTREACHED */
2349     }
2350     return;
2351 }
2352
2353 static int get_time()
2354 {
2355     time_t st = start_time.r.tv_sec;
2356     struct tm *stm;
2357     int hhmm;
2358
2359     get_conftoken(INT);
2360     hhmm = tokenval.i;
2361
2362     stm = localtime(&st);
2363     st -= stm->tm_sec + 60 * (stm->tm_min + 60 * stm->tm_hour);
2364     st += ((hhmm/100*60) + hhmm%100)*60;
2365
2366     if (st-start_time.r.tv_sec<-43200)
2367         st += 86400;
2368
2369     return st;
2370 }
2371
2372 keytab_t numb_keytable[] = {
2373     { "B", MULT1 },
2374     { "BPS", MULT1 },
2375     { "BYTE", MULT1 },
2376     { "BYTES", MULT1 },
2377     { "DAY", MULT1 },
2378     { "DAYS", MULT1 },
2379     { "INF", INFINITY },
2380     { "K", MULT1K },
2381     { "KB", MULT1K },
2382     { "KBPS", MULT1K },
2383     { "KBYTE", MULT1K },
2384     { "KBYTES", MULT1K },
2385     { "KILOBYTE", MULT1K },
2386     { "KILOBYTES", MULT1K },
2387     { "KPS", MULT1K },
2388     { "M", MULT1M },
2389     { "MB", MULT1M },
2390     { "MBPS", MULT1M },
2391     { "MBYTE", MULT1M },
2392     { "MBYTES", MULT1M },
2393     { "MEG", MULT1M },
2394     { "MEGABYTE", MULT1M },
2395     { "MEGABYTES", MULT1M },
2396     { "G", MULT1G },
2397     { "GB", MULT1G },
2398     { "GBPS", MULT1G },
2399     { "GBYTE", MULT1G },
2400     { "GBYTES", MULT1G },
2401     { "GIG", MULT1G },
2402     { "GIGABYTE", MULT1G },
2403     { "GIGABYTES", MULT1G },
2404     { "MPS", MULT1M },
2405     { "TAPE", MULT1 },
2406     { "TAPES", MULT1 },
2407     { "WEEK", MULT7 },
2408     { "WEEKS", MULT7 },
2409     { NULL, IDENT }
2410 };
2411
2412 static int get_number()
2413 {
2414     int val;
2415     keytab_t *save_kt;
2416
2417     save_kt = keytable;
2418     keytable = numb_keytable;
2419
2420     get_conftoken(ANY);
2421
2422     switch(tok) {
2423     case INT:
2424         val = tokenval.i;
2425         break;
2426     case INFINITY:
2427         val = BIGINT;
2428         break;
2429     default:
2430         parserror("an integer expected");
2431         val = 0;
2432     }
2433
2434     /* get multiplier, if any */
2435     get_conftoken(ANY);
2436
2437     switch(tok) {
2438     case NL:                    /* multiply by one */
2439     case MULT1:
2440     case MULT1K:
2441         break;
2442     case MULT7:
2443         val *= 7;
2444         break;
2445     case MULT1M:
2446         val *= 1024;
2447         break;
2448     case MULT1G:
2449         val *= 1024*1024;
2450         break;
2451     default:    /* it was not a multiplier */
2452         unget_conftoken();
2453     }
2454
2455     keytable = save_kt;
2456
2457     return val;
2458 }
2459
2460 keytab_t bool_keytable[] = {
2461     { "Y", ATRUE },
2462     { "YES", ATRUE },
2463     { "T", ATRUE },
2464     { "TRUE", ATRUE },
2465     { "ON", ATRUE },
2466     { "N", AFALSE },
2467     { "NO", AFALSE },
2468     { "F", AFALSE },
2469     { "FALSE", AFALSE },
2470     { "OFF", AFALSE },
2471     { NULL, IDENT }
2472 };
2473
2474 static int get_bool()
2475 {
2476     int val;
2477     keytab_t *save_kt;
2478
2479     save_kt = keytable;
2480     keytable = bool_keytable;
2481
2482     get_conftoken(ANY);
2483
2484     switch(tok) {
2485     case INT:
2486         val = tokenval.i ? 1 : 0;
2487         break;
2488     case ATRUE:
2489         val = 1;
2490         break;
2491     case AFALSE:
2492         val = 0;
2493         break;
2494     case NL:
2495     default:
2496         unget_conftoken();
2497         val = 2; /* no argument - most likely TRUE */
2498     }
2499
2500     keytable = save_kt;
2501
2502     return val;
2503 }
2504
2505 static void ckseen(seen)
2506 int *seen;
2507 {
2508     if(*seen && !allow_overwrites) {
2509         parserror("duplicate parameter, prev def on line %d", *seen);
2510     }
2511     *seen = line_num;
2512 }
2513
2514 printf_arglist_function(static void parserror, char *, format)
2515 {
2516     va_list argp;
2517
2518     /* print error message */
2519
2520     fprintf(stderr, "\"%s\", line %d: ", confname, line_num);
2521     arglist_start(argp, format);
2522     vfprintf(stderr, format, argp);
2523     arglist_end(argp);
2524     fputc('\n', stderr);
2525
2526     got_parserror = 1;
2527 }
2528
2529 static tok_t lookup_keyword(str)
2530 char *str;
2531 {
2532     keytab_t *kwp;
2533
2534     /* switch to binary search if performance warrants */
2535
2536     for(kwp = keytable; kwp->keyword != NULL; kwp++) {
2537         if(strcmp(kwp->keyword, str) == 0) break;
2538     }
2539     return kwp->token;
2540 }
2541
2542 static char tkbuf[4096];
2543
2544 /* push the last token back (can only unget ANY tokens) */
2545 static void unget_conftoken()
2546 {
2547     token_pushed = 1;
2548     pushed_tok = tok;
2549     tok = UNKNOWN;
2550     return;
2551 }
2552
2553 static void get_conftoken(exp)
2554 tok_t exp;
2555 {
2556     int ch, i, d;
2557     char *buf;
2558     int token_overflow;
2559
2560     if(token_pushed) {
2561         token_pushed = 0;
2562         tok = pushed_tok;
2563
2564         /* If it looked like a key word before then look it
2565         ** up again in the current keyword table. */
2566         switch(tok) {
2567         case INT:     case REAL:    case STRING:
2568         case LBRACE:  case RBRACE:  case COMMA:
2569         case NL:      case END:     case UNKNOWN:
2570             break;
2571         default:
2572             if(exp == IDENT) tok = IDENT;
2573             else tok = lookup_keyword(tokenval.s);
2574         }
2575     }
2576     else {
2577         ch = getc(conf);
2578
2579         while(ch != EOF && ch != '\n' && isspace(ch)) ch = getc(conf);
2580         if(ch == '#') {         /* comment - eat everything but eol/eof */
2581             while((ch = getc(conf)) != EOF && ch != '\n') {}
2582         }
2583
2584         if(isalpha(ch)) {               /* identifier */
2585             buf = tkbuf;
2586             token_overflow = 0;
2587             do {
2588                 if(islower(ch)) ch = toupper(ch);
2589                 if(buf < tkbuf+sizeof(tkbuf)-1) {
2590                     *buf++ = ch;
2591                 } else {
2592                     *buf = '\0';
2593                     if(!token_overflow) {
2594                         parserror("token too long: %.20s...", tkbuf);
2595                     }
2596                     token_overflow = 1;
2597                 }
2598                 ch = getc(conf);
2599             } while(isalnum(ch) || ch == '_' || ch == '-');
2600
2601             ungetc(ch, conf);
2602             *buf = '\0';
2603
2604             tokenval.s = tkbuf;
2605
2606             if(token_overflow) tok = UNKNOWN;
2607             else if(exp == IDENT) tok = IDENT;
2608             else tok = lookup_keyword(tokenval.s);
2609         }
2610         else if(isdigit(ch)) {  /* integer */
2611             int sign;
2612             if (1) {
2613                 sign = 1;
2614             } else {
2615             negative_number: /* look for goto negative_number below */
2616                 sign = -1;
2617             }
2618             tokenval.i = 0;
2619             do {
2620                 tokenval.i = tokenval.i * 10 + (ch - '0');
2621                 ch = getc(conf);
2622             } while(isdigit(ch));
2623             if(ch != '.') {
2624                 if(exp != REAL) {
2625                     tok = INT;
2626                     tokenval.i *= sign;
2627                 } else {
2628                     /* automatically convert to real when expected */
2629                     i = tokenval.i;
2630                     tokenval.r = sign * (double) i;
2631                     tok = REAL;
2632                 }
2633             }
2634             else {
2635                 /* got a real number, not an int */
2636                 i = tokenval.i;
2637                 tokenval.r = sign * (double) i;
2638                 i=0; d=1;
2639                 ch = getc(conf);
2640                 while(isdigit(ch)) {
2641                     i = i * 10 + (ch - '0');
2642                     d = d * 10;
2643                     ch = getc(conf);
2644                 }
2645                 tokenval.r += sign * ((double)i)/d;
2646                 tok = REAL;
2647             }
2648             ungetc(ch,conf);
2649         }
2650         else switch(ch) {
2651
2652         case '"':                       /* string */
2653             buf = tkbuf;
2654             token_overflow = 0;
2655             ch = getc(conf);
2656             while(ch != '"' && ch != '\n' && ch != EOF) {
2657                 if(buf < tkbuf+sizeof(tkbuf)-1) {
2658                     *buf++ = ch;
2659                 } else {
2660                     *buf = '\0';
2661                     if(!token_overflow) {
2662                         parserror("string too long: %.20s...", tkbuf);
2663                     }
2664                     token_overflow = 1;
2665                 }
2666                 ch = getc(conf);
2667             }
2668             if(ch != '"') {
2669                 parserror("missing end quote");
2670                 ungetc(ch, conf);
2671             }
2672             *buf = '\0';
2673             tokenval.s = tkbuf;
2674             if(token_overflow) tok = UNKNOWN;
2675             else tok = STRING;
2676             break;
2677
2678         case '-':
2679             ch = getc(conf);
2680             if (isdigit(ch))
2681                 goto negative_number;
2682             else {
2683                 ungetc(ch, conf);
2684                 tok = UNKNOWN;
2685             }
2686             break;
2687         case ',':  tok = COMMA; break;
2688         case '{':  tok = LBRACE; break;
2689         case '}':  tok = RBRACE; break;
2690         case '\n': tok = NL; break;
2691         case EOF:  tok = END; break;
2692         default:   tok = UNKNOWN;
2693         }
2694     }
2695
2696     if(exp != ANY && tok != exp) {
2697         char *str;
2698         keytab_t *kwp;
2699
2700         switch(exp) {
2701         case LBRACE: str = "\"{\""; break;
2702         case RBRACE: str = "\"}\""; break;
2703         case COMMA:  str = "\",\""; break;
2704
2705         case NL: str = "end of line"; break;
2706         case END: str = "end of file"; break;
2707         case INT: str = "an integer"; break;
2708         case REAL: str = "a real number"; break;
2709         case STRING: str = "a quoted string"; break;
2710         case IDENT: str = "an identifier"; break;
2711         default:
2712             for(kwp = keytable; kwp->keyword != NULL; kwp++)
2713                 if(exp == kwp->token) break;
2714             if(kwp->keyword == NULL) str = "token not";
2715             else str = kwp->keyword;
2716         }
2717         parserror("%s expected", str);
2718         tok = exp;
2719         if(tok == INT) tokenval.i = 0;
2720         else tokenval.s = "";
2721     }
2722
2723     return;
2724 }
2725
2726 int ColumnDataCount()
2727 {
2728     return sizeof(ColumnData) / sizeof(ColumnData[0]);
2729 }
2730
2731 /* conversion from string to table index
2732  */
2733 int StringToColumn(char *s) {
2734     int cn;
2735     for (cn=0; ColumnData[cn].Name != NULL; cn++) {
2736         if (strcasecmp(s, ColumnData[cn].Name) == 0) {
2737             break;
2738         }
2739     }
2740     return cn;
2741 }
2742
2743 char LastChar(char *s) {
2744     return s[strlen(s)-1];
2745 }
2746
2747 int SetColumDataFromString(ColumnInfo* ci, char *s, char **errstr) {
2748     /* Convert from a Columspec string to our internal format
2749      * of columspec. The purpose is to provide this string
2750      * as configuration paramter in the amanda.conf file or
2751      * (maybe) as environment variable.
2752      * 
2753      * This text should go as comment into the sample amanda.conf
2754      *
2755      * The format for such a ColumnSpec string s is a ',' seperated
2756      * list of triples. Each triple consists of
2757      *   -the name of the column (as in ColumnData.Name)
2758      *   -prefix before the column
2759      *   -the width of the column
2760      *       if set to -1 it will be recalculated
2761      *   to the maximum length of a line to print.
2762      * Example:
2763      *  "Disk=1:17,HostName=1:10,OutKB=1:7"
2764      * or
2765      *  "Disk=1:-1,HostName=1:10,OutKB=1:7"
2766      *  
2767      * You need only specify those colums that should be changed from
2768      * the default. If nothing is specified in the configfile, the
2769      * above compiled in values will be in effect, resulting in an
2770      * output as it was all the time.
2771      *                                                  ElB, 1999-02-24.
2772      */
2773 #ifdef TEST
2774     char *myname= "SetColumDataFromString";
2775 #endif
2776
2777     while (s && *s) {
2778         int Space, Width;
2779         int cn;
2780         char *eon= strchr(s, '=');
2781
2782         if (eon == NULL) {
2783             *errstr = stralloc2("invalid columnspec: ", s);
2784 #ifdef TEST
2785             fprintf(stderr, "%s: %s\n", myname, *errstr);
2786 #endif
2787             return -1;
2788         }
2789         *eon= '\0';
2790         cn=StringToColumn(s);
2791         if (ColumnData[cn].Name == NULL) {
2792             *errstr = stralloc2("invalid column name: ", s);
2793 #ifdef TEST
2794             fprintf(stderr, "%s: %s\n", myname, *errstr);
2795 #endif
2796             return -1;
2797         }
2798         if (sscanf(eon+1, "%d:%d", &Space, &Width) != 2) {
2799             *errstr = stralloc2("invalid format: ", eon + 1);
2800 #ifdef TEST
2801             fprintf(stderr, "%s: %s\n", myname, *errstr);
2802 #endif
2803             return -1;
2804         }
2805         ColumnData[cn].Width= Width;
2806         ColumnData[cn].PrefixSpace= Space;
2807         if (LastChar(ColumnData[cn].Format) == 's') {
2808             if (Width < 0)
2809                 ColumnData[cn].MaxWidth= 1;
2810             else
2811                 if (Width > ColumnData[cn].Precision)
2812                     ColumnData[cn].Precision= Width;
2813         }
2814         else if (Width < ColumnData[cn].Precision)
2815             ColumnData[cn].Precision= Width;
2816         s= strchr(eon+1, ',');
2817         if (s != NULL)
2818             s++;
2819     }
2820     return 0;
2821 }
2822
2823
2824 char *taperalgo2str(taperalgo)
2825 int taperalgo;
2826 {
2827     if(taperalgo == ALGO_FIRST) return "FIRST";
2828     if(taperalgo == ALGO_FIRSTFIT) return "FIRSTFIT";
2829     if(taperalgo == ALGO_LARGEST) return "LARGEST";
2830     if(taperalgo == ALGO_LARGESTFIT) return "LARGESTFIT";
2831     if(taperalgo == ALGO_SMALLEST) return "SMALLEST";
2832     if(taperalgo == ALGO_LAST) return "LAST";
2833     return "UNKNOWN";
2834 }
2835
2836
2837 /* ------------------------ */
2838
2839
2840 #ifdef TEST
2841
2842 void
2843 dump_configuration(filename)
2844     char *filename;
2845 {
2846     tapetype_t *tp;
2847     dumptype_t *dp;
2848     interface_t *ip;
2849     holdingdisk_t *hp;
2850     time_t st;
2851     struct tm *stm;
2852
2853     printf("AMANDA CONFIGURATION FROM FILE \"%s\":\n\n", filename);
2854
2855     printf("conf_org = \"%s\"\n", getconf_str(CNF_ORG));
2856     printf("conf_mailto = \"%s\"\n", getconf_str(CNF_MAILTO));
2857     printf("conf_dumpuser = \"%s\"\n", getconf_str(CNF_DUMPUSER));
2858     printf("conf_printer = \"%s\"\n", getconf_str(CNF_PRINTER));
2859     printf("conf_tapedev = \"%s\"\n", getconf_str(CNF_TAPEDEV));
2860     printf("conf_rawtapedev = \"%s\"\n", getconf_str(CNF_RAWTAPEDEV));
2861     printf("conf_tpchanger = \"%s\"\n", getconf_str(CNF_TPCHANGER));
2862     printf("conf_chngrdev = \"%s\"\n", getconf_str(CNF_CHNGRDEV));
2863     printf("conf_chngrfile = \"%s\"\n", getconf_str(CNF_CHNGRFILE));
2864     printf("conf_labelstr = \"%s\"\n", getconf_str(CNF_LABELSTR));
2865     printf("conf_tapelist = \"%s\"\n", getconf_str(CNF_TAPELIST));
2866     printf("conf_infofile = \"%s\"\n", getconf_str(CNF_INFOFILE));
2867     printf("conf_logdir = \"%s\"\n", getconf_str(CNF_LOGDIR));
2868     printf("conf_diskfile = \"%s\"\n", getconf_str(CNF_DISKFILE));
2869     printf("conf_tapetype = \"%s\"\n", getconf_str(CNF_TAPETYPE));
2870
2871     printf("conf_dumpcycle = %d\n", getconf_int(CNF_DUMPCYCLE));
2872     printf("conf_runspercycle = %d\n", getconf_int(CNF_RUNSPERCYCLE));
2873     printf("conf_runtapes = %d\n", getconf_int(CNF_RUNTAPES));
2874     printf("conf_tapecycle = %d\n", getconf_int(CNF_TAPECYCLE));
2875     printf("conf_bumpsize = %d\n", getconf_int(CNF_BUMPSIZE));
2876     printf("conf_bumpdays = %d\n", getconf_int(CNF_BUMPDAYS));
2877     printf("conf_bumpmult = %f\n", getconf_real(CNF_BUMPMULT));
2878     printf("conf_netusage = %d\n", getconf_int(CNF_NETUSAGE));
2879     printf("conf_inparallel = %d\n", getconf_int(CNF_INPARALLEL));
2880     printf("conf_dumporder = \"%s\"\n", getconf_str(CNF_DUMPORDER));
2881     /*printf("conf_timeout = %d\n", getconf_int(CNF_TIMEOUT));*/
2882     printf("conf_maxdumps = %d\n", getconf_int(CNF_MAXDUMPS));
2883     printf("conf_etimeout = %d\n", getconf_int(CNF_ETIMEOUT));
2884     printf("conf_dtimeout = %d\n", getconf_int(CNF_DTIMEOUT));
2885     printf("conf_ctimeout = %d\n", getconf_int(CNF_CTIMEOUT));
2886     printf("conf_tapebufs = %d\n", getconf_int(CNF_TAPEBUFS));
2887     printf("conf_autoflush  = %d\n", getconf_int(CNF_AUTOFLUSH));
2888     printf("conf_reserve  = %d\n", getconf_int(CNF_RESERVE));
2889     printf("conf_maxdumpsize  = %d\n", getconf_int(CNF_MAXDUMPSIZE));
2890     printf("conf_amrecover_do_fsf  = %d\n", getconf_int(CNF_AMRECOVER_DO_FSF));
2891     printf("conf_amrecover_check_label  = %d\n", getconf_int(CNF_AMRECOVER_CHECK_LABEL));
2892     printf("conf_amrecover_changer = \"%s\"\n", getconf_str(CNF_AMRECOVER_CHANGER));
2893     printf("conf_taperalgo  = %s\n", taperalgo2str(getconf_int(CNF_TAPERALGO)));
2894
2895     /*printf("conf_diskdir = \"%s\"\n", getconf_str(CNF_DISKDIR));*/
2896     /*printf("conf_disksize = %d\n", getconf_int(CNF_DISKSIZE));*/
2897     printf("conf_columnspec = \"%s\"\n", getconf_str(CNF_COLUMNSPEC));
2898     printf("conf_indexdir = \"%s\"\n", getconf_str(CNF_INDEXDIR));
2899     printf("num_holdingdisks = %d\n", num_holdingdisks);
2900     for(hp = holdingdisks; hp != NULL; hp = hp->next) {
2901         printf("\nHOLDINGDISK %s:\n", hp->name);
2902         printf("        COMMENT \"%s\"\n", hp->comment);
2903         printf("        DISKDIR \"%s\"\n", hp->diskdir);
2904         printf("        SIZE %ld\n", (long)hp->disksize);
2905         printf("        CHUNKSIZE %ld\n", (long)hp->chunksize);
2906     }
2907
2908     for(tp = tapelist; tp != NULL; tp = tp->next) {
2909         printf("\nTAPETYPE %s:\n", tp->name);
2910         printf("        COMMENT \"%s\"\n", tp->comment);
2911         printf("        LBL_TEMPL %s\n", tp->lbl_templ);
2912         printf("        BLOCKSIZE %ld\n", (long)tp->blocksize);
2913         printf("        FILE_PAD %s\n", (tp->file_pad) ? "YES" : "NO");
2914         printf("        LENGTH %lu\n", (unsigned long)tp->length);
2915         printf("        FILEMARK %lu\n", (unsigned long)tp->filemark);
2916         printf("        SPEED %ld\n", (long)tp->speed);
2917     }
2918
2919     for(dp = dumplist; dp != NULL; dp = dp->next) {
2920         printf("\nDUMPTYPE %s:\n", dp->name);
2921         printf("        COMMENT \"%s\"\n", dp->comment);
2922         printf("        PROGRAM \"%s\"\n", dp->program);
2923         printf("        PRIORITY %ld\n", (long)dp->priority);
2924         printf("        DUMPCYCLE %ld\n", (long)dp->dumpcycle);
2925         st = dp->start_t;
2926         if(st) {
2927             stm = localtime(&st);
2928             printf("    STARTTIME %d:%02d:%02d\n",
2929               stm->tm_hour, stm->tm_min, stm->tm_sec);
2930         }
2931         if(dp->exclude_file) {
2932             sle_t *excl;
2933             printf("    EXCLUDE FILE");
2934             for(excl = dp->exclude_file->first; excl != NULL; excl =excl->next){
2935                 printf(" \"%s\"", excl->name);
2936             }
2937             printf("\n");
2938         }
2939         if(dp->exclude_list) {
2940             sle_t *excl;
2941             printf("    EXCLUDE LIST");
2942             for(excl = dp->exclude_list->first; excl != NULL; excl =excl->next){
2943                 printf(" \"%s\"", excl->name);
2944             }
2945             printf("\n");
2946         }
2947         if(dp->include_file) {
2948             sle_t *incl;
2949             printf("    INCLUDE FILE");
2950             for(incl = dp->include_file->first; incl != NULL; incl =incl->next){
2951                 printf(" \"%s\"", incl->name);
2952             }
2953             printf("\n");
2954         }
2955         if(dp->include_list) {
2956             sle_t *incl;
2957             printf("    INCLUDE LIST");
2958             for(incl = dp->include_list->first; incl != NULL; incl =incl->next){
2959                 printf(" \"%s\"", incl->name);
2960             }
2961             printf("\n");
2962         }
2963         printf("        FREQUENCY %ld\n", (long)dp->frequency);
2964         printf("        MAXDUMPS %d\n", dp->maxdumps);
2965         printf("        MAXPROMOTEDAY %d\n", dp->maxpromoteday);
2966         printf("        STRATEGY ");
2967         switch(dp->strategy) {
2968         case DS_SKIP:
2969             printf("SKIP");
2970             break;
2971         case DS_STANDARD:
2972             printf("STANDARD");
2973             break;
2974         case DS_NOFULL:
2975             printf("NOFULL");
2976             break;
2977         case DS_NOINC:
2978             printf("NOINC");
2979             break;
2980         case DS_HANOI:
2981             printf("HANOI");
2982             break;
2983         case DS_INCRONLY:
2984             printf("INCRONLY");
2985             break;
2986         }
2987         putchar('\n');
2988         printf("        COMPRATE %f, %f\n", dp->comprate[0], dp->comprate[1]);
2989
2990         printf("        OPTIONS: ");
2991
2992         switch(dp->compress) {
2993         case COMP_NONE:
2994             printf("NO-COMPRESS ");
2995             break;
2996         case COMP_FAST:
2997             printf("COMPRESS-FAST ");
2998             break;
2999         case COMP_BEST:
3000             printf("COMPRESS-BEST ");
3001             break;
3002         case COMP_SERV_FAST:
3003             printf("SRVCOMP-FAST ");
3004             break;
3005         case COMP_SERV_BEST:
3006             printf("SRVCOMP-BEST ");
3007             break;
3008         }
3009
3010         if(!dp->record) printf("NO-");
3011         printf("RECORD");
3012         if(dp->auth == AUTH_BSD) printf(" BSD-AUTH");
3013         else if(dp->auth == AUTH_KRB4) printf(" KRB4-AUTH");
3014         else printf(" UNKNOWN-AUTH");
3015         if(dp->skip_incr) printf(" SKIP-INCR");
3016         if(dp->skip_full) printf(" SKIP-FULL");
3017         if(dp->no_hold) printf(" NO-HOLD");
3018         if(dp->kencrypt) printf(" KENCRYPT");
3019         /* an ignored disk will never reach this point */
3020         assert(!dp->ignore);
3021         if(dp->index) printf(" INDEX");
3022         putchar('\n');
3023     }
3024
3025     for(ip = interface_list; ip != NULL; ip = ip->next) {
3026         printf("\nINTERFACE %s:\n", ip->name);
3027         printf("        COMMENT \"%s\"\n", ip->comment);
3028         printf("        USE %d\n", ip->maxusage);
3029     }
3030 }
3031
3032 int
3033 main(argc, argv)
3034     int argc;
3035     char *argv[];
3036 {
3037   char *conffile;
3038   char *diskfile;
3039   int result;
3040   int fd;
3041   unsigned long malloc_hist_1, malloc_size_1;
3042   unsigned long malloc_hist_2, malloc_size_2;
3043
3044   for(fd = 3; fd < FD_SETSIZE; fd++) {
3045     /*
3046      * Make sure nobody spoofs us with a lot of extra open files
3047      * that would cause an open we do to get a very high file
3048      * descriptor, which in turn might be used as an index into
3049      * an array (e.g. an fd_set).
3050      */
3051     close(fd);
3052   }
3053
3054   set_pname("conffile");
3055
3056   malloc_size_1 = malloc_inuse(&malloc_hist_1);
3057
3058   startclock();
3059
3060   if (argc > 1) {
3061     if (argv[1][0] == '/') {
3062       config_dir = stralloc(argv[1]);
3063       config_name = strrchr(config_dir, '/') + 1;
3064       config_name[-1] = '\0';
3065       config_dir = newstralloc2(config_dir, config_dir, "/");
3066     } else {
3067       config_name = stralloc(argv[1]);
3068       config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
3069     }
3070   } else {
3071     char my_cwd[STR_SIZE];
3072
3073     if (getcwd(my_cwd, sizeof(my_cwd)) == NULL) {
3074       error("cannot determine current working directory");
3075     }
3076     config_dir = stralloc2(my_cwd, "/");
3077     if ((config_name = strrchr(my_cwd, '/')) != NULL) {
3078       config_name = stralloc(config_name + 1);
3079     }
3080   }
3081
3082   conffile = stralloc2(config_dir, CONFFILE_NAME);
3083   result = read_conffile(conffile);
3084   if (result == 0) {
3085     diskfile = getconf_str(CNF_DISKFILE);
3086     if (diskfile != NULL && access(diskfile, R_OK) == 0) {
3087       result = (read_diskfile(diskfile) == NULL);
3088     }
3089   }
3090   dump_configuration(CONFFILE_NAME);
3091   amfree(conffile);
3092
3093   malloc_size_2 = malloc_inuse(&malloc_hist_2);
3094
3095   if(malloc_size_1 != malloc_size_2) {
3096     malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
3097   }
3098
3099   return result;
3100 }
3101
3102 #endif /* TEST */