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