18afa9e8d1843d86b275ac25a792ee12c6397175
[debian/amanda] / common-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.156 2006/07/26 15:17:37 martinea Exp $
29  *
30  * read configuration file
31  */
32
33 #include "amanda.h"
34 #include "arglist.h"
35 #include "util.h"
36 #include "conffile.h"
37 #include "clock.h"
38
39 /*
40  * Lexical analysis
41  */
42
43 /* This module implements its own quixotic lexer and parser, present for historical
44  * reasons.  If this were written from scratch, it would use flex/bison. */
45
46 /* An enumeration of the various tokens that might appear in a configuration file.
47  *
48  * - CONF_UNKNOWN has special meaning as an unrecognized token.
49  * - CONF_ANY can be used to request any token, rather than requiring a specific
50  *   token.
51  */
52 typedef enum {
53     CONF_UNKNOWN,               CONF_ANY,               CONF_COMMA,
54     CONF_LBRACE,                CONF_RBRACE,            CONF_NL,
55     CONF_END,                   CONF_IDENT,             CONF_INT,
56     CONF_AM64,                  CONF_BOOL,              CONF_REAL,
57     CONF_STRING,                CONF_TIME,              CONF_SIZE,
58
59     /* config parameters */
60     CONF_INCLUDEFILE,           CONF_ORG,               CONF_MAILTO,
61     CONF_DUMPUSER,              CONF_TAPECYCLE,         CONF_TAPEDEV,
62     CONF_CHANGERDEV,            CONF_CHANGERFILE,       CONF_LABELSTR,
63     CONF_BUMPPERCENT,           CONF_BUMPSIZE,          CONF_BUMPDAYS,
64     CONF_BUMPMULT,              CONF_ETIMEOUT,          CONF_DTIMEOUT,
65     CONF_CTIMEOUT,              CONF_TAPEBUFS,          CONF_TAPELIST,
66     CONF_DEVICE_OUTPUT_BUFFER_SIZE,
67     CONF_DISKFILE,              CONF_INFOFILE,          CONF_LOGDIR,
68     CONF_LOGFILE,               CONF_DISKDIR,           CONF_DISKSIZE,
69     CONF_INDEXDIR,              CONF_NETUSAGE,          CONF_INPARALLEL,
70     CONF_DUMPORDER,             CONF_TIMEOUT,           CONF_TPCHANGER,
71     CONF_RUNTAPES,              CONF_DEFINE,            CONF_DUMPTYPE,
72     CONF_TAPETYPE,              CONF_INTERFACE,         CONF_PRINTER,
73     CONF_AUTOFLUSH,             CONF_RESERVE,           CONF_MAXDUMPSIZE,
74     CONF_COLUMNSPEC,            CONF_AMRECOVER_DO_FSF,  CONF_AMRECOVER_CHECK_LABEL,
75     CONF_AMRECOVER_CHANGER,     CONF_LABEL_NEW_TAPES,   CONF_USETIMESTAMPS,
76
77     CONF_TAPERALGO,             CONF_FIRST,             CONF_FIRSTFIT,
78     CONF_LARGEST,               CONF_LARGESTFIT,        CONF_SMALLEST,
79     CONF_LAST,                  CONF_DISPLAYUNIT,       CONF_RESERVED_UDP_PORT,
80     CONF_RESERVED_TCP_PORT,     CONF_UNRESERVED_TCP_PORT,
81     CONF_TAPERFLUSH,
82     CONF_FLUSH_THRESHOLD_DUMPED,
83     CONF_FLUSH_THRESHOLD_SCHEDULED,
84     CONF_DEVICE_PROPERTY,
85
86     /* kerberos 5 */
87     CONF_KRB5KEYTAB,            CONF_KRB5PRINCIPAL,
88
89     /* holding disk */
90     CONF_COMMENT,               CONF_DIRECTORY,         CONF_USE,
91     CONF_CHUNKSIZE,
92
93     /* dump type */
94     /*COMMENT,*/                CONF_PROGRAM,           CONF_DUMPCYCLE,
95     CONF_RUNSPERCYCLE,          CONF_MAXCYCLE,          CONF_MAXDUMPS,
96     CONF_OPTIONS,               CONF_PRIORITY,          CONF_FREQUENCY,
97     CONF_INDEX,                 CONF_MAXPROMOTEDAY,     CONF_STARTTIME,
98     CONF_COMPRESS,              CONF_ENCRYPT,           CONF_AUTH,
99     CONF_STRATEGY,              CONF_ESTIMATE,          CONF_SKIP_INCR,
100     CONF_SKIP_FULL,             CONF_RECORD,            CONF_HOLDING,
101     CONF_EXCLUDE,               CONF_INCLUDE,           CONF_KENCRYPT,
102     CONF_IGNORE,                CONF_COMPRATE,          CONF_TAPE_SPLITSIZE,
103     CONF_SPLIT_DISKBUFFER,      CONF_FALLBACK_SPLITSIZE,CONF_SRVCOMPPROG,
104     CONF_CLNTCOMPPROG,          CONF_SRV_ENCRYPT,       CONF_CLNT_ENCRYPT,
105     CONF_SRV_DECRYPT_OPT,       CONF_CLNT_DECRYPT_OPT,  CONF_AMANDAD_PATH,
106     CONF_CLIENT_USERNAME,
107
108     /* tape type */
109     /*COMMENT,*/                CONF_BLOCKSIZE,         CONF_FILE_PAD,
110     CONF_LBL_TEMPL,             CONF_FILEMARK,          CONF_LENGTH,
111     CONF_SPEED,                 CONF_READBLOCKSIZE,
112
113     /* client conf */
114     CONF_CONF,                  CONF_INDEX_SERVER,      CONF_TAPE_SERVER,
115     CONF_SSH_KEYS,              CONF_GNUTAR_LIST_DIR,   CONF_AMANDATES,
116
117     /* protocol config */
118     CONF_REP_TRIES,             CONF_CONNECT_TRIES,     CONF_REQ_TRIES,
119
120     /* debug config */
121     CONF_DEBUG_AMANDAD,         CONF_DEBUG_AMIDXTAPED,  CONF_DEBUG_AMINDEXD,
122     CONF_DEBUG_AMRECOVER,       CONF_DEBUG_AUTH,        CONF_DEBUG_EVENT,
123     CONF_DEBUG_HOLDING,         CONF_DEBUG_PROTOCOL,    CONF_DEBUG_PLANNER,
124     CONF_DEBUG_DRIVER,          CONF_DEBUG_DUMPER,      CONF_DEBUG_CHUNKER,
125     CONF_DEBUG_TAPER,           CONF_DEBUG_SELFCHECK,   CONF_DEBUG_SENDSIZE,
126     CONF_DEBUG_SENDBACKUP,
127
128     /* network interface */
129     /* COMMENT, */              /* USE, */
130
131     /* dump options (obsolete) */
132     CONF_EXCLUDE_FILE,          CONF_EXCLUDE_LIST,
133
134     /* compress, estimate, encryption */
135     CONF_NONE,                  CONF_FAST,              CONF_BEST,
136     CONF_SERVER,                CONF_CLIENT,            CONF_CALCSIZE,
137     CONF_CUSTOM,
138
139     /* holdingdisk */
140     CONF_NEVER,                 CONF_AUTO,              CONF_REQUIRED,
141
142     /* priority */
143     CONF_LOW,                   CONF_MEDIUM,            CONF_HIGH,
144
145     /* dump strategy */
146     CONF_SKIP,                  CONF_STANDARD,          CONF_NOFULL,
147     CONF_NOINC,                 CONF_HANOI,             CONF_INCRONLY,
148
149     /* exclude list */
150     CONF_LIST,                  CONF_EFILE,             CONF_APPEND,
151     CONF_OPTIONAL,
152
153     /* numbers */
154     CONF_AMINFINITY,            CONF_MULT1,             CONF_MULT7,
155     CONF_MULT1K,                CONF_MULT1M,            CONF_MULT1G,
156
157     /* boolean */
158     CONF_ATRUE,                 CONF_AFALSE
159 } tok_t;
160
161 /* A keyword table entry, mapping the given keyword to the given token.
162  * Note that punctuation, integers, and quoted strings are handled 
163  * internally to the lexer, so they do not appear here. */
164 typedef struct {
165     char *keyword;
166     tok_t token;
167 } keytab_t;
168
169 /* The current keyword table, used by all token-related functions */
170 static keytab_t *keytable = NULL;
171
172 /* Has a token been "ungotten", and if so, what was it? */
173 static int token_pushed;
174 static tok_t pushed_tok;
175
176 /* The current token and its value.  Note that, unlike most other val_t*,
177  * tokenval's v.s points to statically allocated memory which cannot be
178  * free()'d. */
179 static tok_t tok;
180 static val_t tokenval;
181
182 /* The current input information: file, filename, line, and character 
183  * (which points somewhere within current_line) */
184 static FILE *current_file = NULL;
185 static char *current_filename = NULL;
186 static char *current_line = NULL;
187 static char *current_char = NULL;
188 static int current_line_num = 0; /* (technically, managed by the parser) */
189
190 /* A static buffer for storing tokens while they are being scanned. */
191 static char tkbuf[4096];
192
193 /* Look up the name of the given token in the current keytable */
194 static char *get_token_name(tok_t);
195
196 /* Look up a token in keytable, given a string, returning CONF_UNKNOWN 
197  * for unrecognized strings.  Search is case-insensitive. */
198 static tok_t lookup_keyword(char *str);
199
200 /* Get the next token.  If exp is anything but CONF_ANY, and the next token
201  * does not match, then a parse error is flagged.  This function reads from the
202  * current_* static variables, recognizes keywords against the keytable static
203  * variable, and places its result in tok and tokenval. */
204 static void get_conftoken(tok_t exp);
205
206 /* "Unget" the current token; this supports a 1-token lookahead. */
207 static void unget_conftoken(void);
208
209 /* Tokenizer character-by-character access. */
210 static int  conftoken_getc(void);
211 static int  conftoken_ungetc(int c);
212
213 /*
214  * Parser
215  */
216
217 /* A parser table entry.  Read as "<token> introduces parameter <parm>,
218  * the data for which will be read by <read_function> and validated by
219  * <validate_function> (if not NULL).  <type> is only used in formatting 
220  * config overwrites. */
221 typedef struct conf_var_s {
222     tok_t       token;
223     conftype_t  type;
224     void        (*read_function) (struct conf_var_s *, val_t*);
225     int         parm;
226     void        (*validate_function) (struct conf_var_s *, val_t *);
227 } conf_var_t;
228
229 /* If allow_overwrites is true, the a parameter which has already been
230  * seen will simply overwrite the old value, rather than triggering an 
231  * error.  Note that this does not apply to all parameters, e.g., 
232  * device_property */
233 static int allow_overwrites;
234
235 /* subsection structs
236  *
237  * The 'seen' fields in these structs are useless outside this module;
238  * they are only used to generate error messages for multiply defined
239  * subsections.
240  */
241 struct tapetype_s {
242     struct tapetype_s *next;
243     int seen;
244     char *name;
245
246     val_t value[TAPETYPE_TAPETYPE];
247 };
248
249 struct dumptype_s {
250     struct dumptype_s *next;
251     int seen;
252     char *name;
253
254     val_t value[DUMPTYPE_DUMPTYPE];
255 };
256
257 struct interface_s {
258     struct interface_s *next;
259     int seen;
260     char *name;
261
262     val_t value[INTER_INTER];
263 };
264
265 struct holdingdisk_s {
266     struct holdingdisk_s *next;
267     int seen;
268     char *name;
269
270     val_t value[HOLDING_HOLDING];
271 };
272
273 /* The current parser table */
274 static conf_var_t *parsetable = NULL;
275
276 /* Read and parse a configuration file, recursively reading any included
277  * files.  This function sets the keytable and parsetable appropriately
278  * according to is_client.
279  *
280  * @param filename: configuration file to read
281  * @param is_client: true if this is a client
282  * @returns: false if an error occurred
283  */
284 static gboolean read_conffile(char *filename,
285                               gboolean is_client);
286
287 /* Read and process a line of input from the current file, using the 
288  * current keytable and parsetable.  For blocks, this recursively
289  * reads the entire block.
290  *
291  * @param is_client: true if this is a client
292  * @returns: true on success, false on EOF or error
293  */
294 static gboolean read_confline(gboolean is_client);
295
296 /* Handle an invalid token, by issuing a warning or an error, depending
297  * on how long the token has been deprecated.
298  *
299  * @param token: the identifier
300  */
301 static void handle_invalid_keyword(const char * token);
302
303 /* Read a brace-delimited block using the given parse table.  This
304  * function is used to read brace-delimited subsections in the config
305  * files and also (via read_dumptype) to read dumptypes from
306  * the disklist.
307  *
308  * This function implements "inheritance" as follows: if a bare
309  * identifier occurs within the braces, it calls copy_function (if
310  * not NULL), which looks up an existing subsection using the
311  * identifier from tokenval and copies any values not already seen
312  * into valarray.
313  *
314  * @param read_var: the parse table to use
315  * @param valarray: the (pre-initialized) val_t array to fill in
316  * @param errormsg: error message to display for unrecognized keywords
317  * @param read_brace: if true, read the opening brace
318  * @param copy_function: function to copy configuration from
319  *     another subsection into this one.
320  */
321 static void read_block(conf_var_t *read_var, val_t *valarray, 
322                        char *errormsg, int read_brace,
323                        void (*copy_function)(void));
324
325 /* For each subsection type, we have a global and  four functions:
326  *  - foocur is a temporary struct used to assemble new subsections
327  *  - get_foo is called after reading "DEFINE FOO", and
328  *    is responsible for reading the entire block, using
329  *    read_block()
330  *  - init_foo_defaults initializes a new subsection struct
331  *    to its default values
332  *  - save_foo copies foocur to a newly allocated struct and
333  *    inserts that into the relevant list.
334  *  - copy_foo implements inheritance as described in read_block()
335  */
336 static holdingdisk_t hdcur;
337 static void get_holdingdisk(void);
338 static void init_holdingdisk_defaults(void);
339 static void save_holdingdisk(void);
340 /* (holdingdisks don't support inheritance) */
341
342 static dumptype_t dpcur;
343 static void get_dumptype(void);
344 static void init_dumptype_defaults(void);
345 static void save_dumptype(void);
346 static void copy_dumptype(void);
347
348 static tapetype_t tpcur;
349 static void get_tapetype(void);
350 static void init_tapetype_defaults(void);
351 static void save_tapetype(void);
352 static void copy_tapetype(void);
353
354 static interface_t ifcur;
355 static void get_interface(void);
356 static void init_interface_defaults(void);
357 static void save_interface(void);
358 static void copy_interface(void);
359
360 /* read_functions -- these fit into the read_function slot in a parser
361  * table entry, and are responsible for calling getconf_token as necessary
362  * to consume their arguments, and setting their second argument with the
363  * result.  The first argument is a copy of the parser table entry, if
364  * needed. */
365 static void read_int(conf_var_t *, val_t *);
366 static void read_am64(conf_var_t *, val_t *);
367 static void read_real(conf_var_t *, val_t *);
368 static void read_str(conf_var_t *, val_t *);
369 static void read_ident(conf_var_t *, val_t *);
370 static void read_time(conf_var_t *, val_t *);
371 static void read_size(conf_var_t *, val_t *);
372 static void read_bool(conf_var_t *, val_t *);
373 static void read_compress(conf_var_t *, val_t *);
374 static void read_encrypt(conf_var_t *, val_t *);
375 static void read_holding(conf_var_t *, val_t *);
376 static void read_estimate(conf_var_t *, val_t *);
377 static void read_strategy(conf_var_t *, val_t *);
378 static void read_taperalgo(conf_var_t *, val_t *);
379 static void read_priority(conf_var_t *, val_t *);
380 static void read_rate(conf_var_t *, val_t *);
381 static void read_exinclude(conf_var_t *, val_t *);
382 static void read_intrange(conf_var_t *, val_t *);
383 static void read_property(conf_var_t *, val_t *);
384
385 /* Functions to get various types of values.  These are called by
386  * read_functions to take care of any variations in the way that these
387  * values can be written: integers can have units, boolean values can be
388  * specified with a number of names, etc.  They form utility functions
389  * for the read_functions, below. */
390 static time_t  get_time(void);
391 static int     get_int(void);
392 static ssize_t get_size(void);
393 static off_t   get_am64_t(void);
394 static int     get_bool(void);
395
396 /* Check the given 'seen', flagging an error if this value has already
397  * been seen and allow_overwrites is false.  Also marks the value as
398  * seen on the current line.
399  *
400  * @param seen: (in/out) seen value to adjust
401  */
402 static void ckseen(int *seen);
403
404 /* validate_functions -- these fit into the validate_function solt in
405  * a parser table entry.  They call conf_parserror if the value in their
406  * second argument is invalid.  */
407 static void validate_nonnegative(conf_var_t *, val_t *);
408 static void validate_positive(conf_var_t *, val_t *);
409 static void validate_runspercycle(conf_var_t *, val_t *);
410 static void validate_bumppercent(conf_var_t *, val_t *);
411 static void validate_bumpmult(conf_var_t *, val_t *);
412 static void validate_inparallel(conf_var_t *, val_t *);
413 static void validate_displayunit(conf_var_t *, val_t *);
414 static void validate_reserve(conf_var_t *, val_t *);
415 static void validate_use(conf_var_t *, val_t *);
416 static void validate_chunksize(conf_var_t *, val_t *);
417 static void validate_blocksize(conf_var_t *, val_t *);
418 static void validate_debug(conf_var_t *, val_t *);
419 static void validate_port_range(val_t *, int, int);
420 static void validate_reserved_port_range(conf_var_t *, val_t *);
421 static void validate_unreserved_port_range(conf_var_t *, val_t *);
422
423 /*
424  * Initialization
425  */
426
427 /* Name of the current configuration (part of API) */
428 char *config_name = NULL;
429
430 /* Current configuration directory (part of API) */
431 char *config_dir = NULL;
432
433 /* Current toplevel configuration file (part of API) */
434 char *config_filename = NULL;
435
436 /* Has the config been initialized? */
437 static gboolean config_initialized = FALSE;
438
439 /* Are we running a client? (true if last init was
440  * with CONFIG_INIT_CLIENT) */
441 static gboolean config_client = FALSE;
442
443 /* What config overwrites are applied? */
444 static config_overwrites_t *applied_config_overwrites = NULL;
445
446 /* All global parameters */
447 static val_t conf_data[CNF_CNF];
448
449 /* Linked list of holding disks */
450 static holdingdisk_t *holdinglist = NULL;
451 static dumptype_t *dumplist = NULL;
452 static tapetype_t *tapelist = NULL;
453 static interface_t *interface_list = NULL;
454
455 /* storage for derived values */
456 static long int unit_divisor = 1;
457
458 int debug_amandad    = 0;
459 int debug_amidxtaped = 0;
460 int debug_amindexd   = 0;
461 int debug_amrecover  = 0;
462 int debug_auth       = 0;
463 int debug_event      = 0;
464 int debug_holding    = 0;
465 int debug_protocol   = 0;
466 int debug_planner    = 0;
467 int debug_driver     = 0;
468 int debug_dumper     = 0;
469 int debug_chunker    = 0;
470 int debug_taper      = 0;
471 int debug_selfcheck  = 0;
472 int debug_sendsize   = 0;
473 int debug_sendbackup = 0;
474
475 /* Reset all configuration values to their defaults (which, in many
476  * cases, come from --with-foo options at build time) */
477 static void init_defaults(void);
478
479 /* Update all dervied values based on the current configuration.  This
480  * function can be called multiple times, once after each adjustment
481  * to the current configuration.
482  *
483  * @param is_client: are we running a client?
484  */
485 static void update_derived_values(gboolean is_client);
486
487 /* per-type conf_init functions, used as utilities for init_defaults
488  * and for each subsection's init_foo_defaults.
489  *
490  * These set the value's type and seen flags, as well as copying
491  * the relevant value into the 'v' field.
492  */
493 static void conf_init_int(val_t *val, int i);
494 static void conf_init_am64(val_t *val, off_t l);
495 static void conf_init_real(val_t *val, float r);
496 static void conf_init_str(val_t *val, char *s);
497 static void conf_init_ident(val_t *val, char *s);
498 static void conf_init_time(val_t *val, time_t t);
499 static void conf_init_size(val_t *val, ssize_t sz);
500 static void conf_init_bool(val_t *val, int i);
501 static void conf_init_compress(val_t *val, comp_t i);
502 static void conf_init_encrypt(val_t *val, encrypt_t i);
503 static void conf_init_holding(val_t *val, dump_holdingdisk_t i);
504 static void conf_init_estimate(val_t *val, estimate_t i);
505 static void conf_init_strategy(val_t *val, strategy_t);
506 static void conf_init_taperalgo(val_t *val, taperalgo_t i);
507 static void conf_init_priority(val_t *val, int i);
508 static void conf_init_rate(val_t *val, float r1, float r2);
509 static void conf_init_exinclude(val_t *val); /* to empty list */
510 static void conf_init_intrange(val_t *val, int i1, int i2);
511 static void conf_init_proplist(val_t *val); /* to empty list */
512
513 /*
514  * Command-line Handling
515  */
516
517 typedef struct config_overwrite_s {
518     char *key;
519     char *value;
520 } config_overwrite_t;
521
522 struct config_overwrites_s {
523     int n_allocated;
524     int n_used;
525     config_overwrite_t *ovr;
526 };
527
528 /*
529  * val_t Management
530  */
531
532 static void copy_val_t(val_t *, val_t *);
533 static void free_val_t(val_t *);
534
535 /*
536  * Utilities
537  */
538
539
540 /* Utility functions/structs for val_t_display_strs */
541 static char *exinclude_display_str(val_t *val, int file);
542 static void proplist_display_str_foreach_fn(gpointer key_p, gpointer value_p, gpointer user_data_p);
543 static void val_t_print_token(FILE *output, char *prefix, char *format, keytab_t *kt, val_t *val);
544
545 /* Given a key name as used in config overwrites, return a pointer to the corresponding
546  * conf_var_t in the current parsetable, and the val_t representing that value.  This
547  * function will access subsections if key has the form  TYPE:SUBSEC:KEYWORD.  Returns
548  * false if the value does not exist.
549  *
550  * Assumes keytable and parsetable are set correctly, which is generally OK after 
551  * config_init has been called.
552  *
553  * @param key: the key to look up
554  * @param parm: (result) the parse table entry
555  * @param val: (result) the parameter value
556  * @returns: true on success
557  */
558 static int parm_key_info(char *key, conf_var_t **parm, val_t **val);
559
560 /*
561  * Error handling
562  */
563
564 /* Have we seen a parse error yet?  Parsing continues after an error, so this
565  * flag is checked after the parse is complete.
566  */
567 static gboolean got_parserror;
568
569 static void    conf_parserror(const char *format, ...)
570                 __attribute__ ((format (printf, 1, 2)));
571
572 static void    conf_parswarn(const char *format, ...)
573                 __attribute__ ((format (printf, 1, 2)));
574
575 /*
576  * Tables
577  */
578
579 /* First, the keyword tables for client and server */
580 keytab_t client_keytab[] = {
581     { "CONF", CONF_CONF },
582     { "INDEX_SERVER", CONF_INDEX_SERVER },
583     { "TAPE_SERVER", CONF_TAPE_SERVER },
584     { "TAPEDEV", CONF_TAPEDEV },
585     { "AUTH", CONF_AUTH },
586     { "SSH_KEYS", CONF_SSH_KEYS },
587     { "AMANDAD_PATH", CONF_AMANDAD_PATH },
588     { "CLIENT_USERNAME", CONF_CLIENT_USERNAME },
589     { "GNUTAR_LIST_DIR", CONF_GNUTAR_LIST_DIR },
590     { "AMANDATES", CONF_AMANDATES },
591     { "KRB5KEYTAB", CONF_KRB5KEYTAB },
592     { "KRB5PRINCIPAL", CONF_KRB5PRINCIPAL },
593     { "INCLUDEFILE", CONF_INCLUDEFILE },
594     { "CONNECT_TRIES", CONF_CONNECT_TRIES },
595     { "REP_TRIES", CONF_REP_TRIES },
596     { "REQ_TRIES", CONF_REQ_TRIES },
597     { "DEBUG_AMANDAD", CONF_DEBUG_AMANDAD },
598     { "DEBUG_AMIDXTAPED", CONF_DEBUG_AMIDXTAPED },
599     { "DEBUG_AMINDEXD", CONF_DEBUG_AMINDEXD },
600     { "DEBUG_AMRECOVER", CONF_DEBUG_AMRECOVER },
601     { "DEBUG_AUTH", CONF_DEBUG_AUTH },
602     { "DEBUG_EVENT", CONF_DEBUG_EVENT },
603     { "DEBUG_HOLDING", CONF_DEBUG_HOLDING },
604     { "DEBUG_PROTOCOL", CONF_DEBUG_PROTOCOL },
605     { "DEBUG_PLANNER", CONF_DEBUG_PLANNER },
606     { "DEBUG_DRIVER", CONF_DEBUG_DRIVER },
607     { "DEBUG_DUMPER", CONF_DEBUG_DUMPER },
608     { "DEBUG_CHUNKER", CONF_DEBUG_CHUNKER },
609     { "DEBUG_TAPER", CONF_DEBUG_TAPER },
610     { "DEBUG_SELFCHECK", CONF_DEBUG_SELFCHECK },
611     { "DEBUG_SENDSIZE", CONF_DEBUG_SENDSIZE },
612     { "DEBUG_SENDBACKUP", CONF_DEBUG_SENDBACKUP },
613     { "RESERVED-UDP-PORT", CONF_RESERVED_UDP_PORT },
614     { "RESERVED-TCP-PORT", CONF_RESERVED_TCP_PORT },
615     { "UNRESERVED-TCP-PORT", CONF_UNRESERVED_TCP_PORT },
616     { NULL, CONF_UNKNOWN },
617 };
618
619 keytab_t server_keytab[] = {
620     { "AMANDAD_PATH", CONF_AMANDAD_PATH },
621     { "AMRECOVER_CHANGER", CONF_AMRECOVER_CHANGER },
622     { "AMRECOVER_CHECK_LABEL", CONF_AMRECOVER_CHECK_LABEL },
623     { "AMRECOVER_DO_FSF", CONF_AMRECOVER_DO_FSF },
624     { "APPEND", CONF_APPEND },
625     { "AUTH", CONF_AUTH },
626     { "AUTO", CONF_AUTO },
627     { "AUTOFLUSH", CONF_AUTOFLUSH },
628     { "BEST", CONF_BEST },
629     { "BLOCKSIZE", CONF_BLOCKSIZE },
630     { "BUMPDAYS", CONF_BUMPDAYS },
631     { "BUMPMULT", CONF_BUMPMULT },
632     { "BUMPPERCENT", CONF_BUMPPERCENT },
633     { "BUMPSIZE", CONF_BUMPSIZE },
634     { "CALCSIZE", CONF_CALCSIZE },
635     { "CHANGERDEV", CONF_CHANGERDEV },
636     { "CHANGERFILE", CONF_CHANGERFILE },
637     { "CHUNKSIZE", CONF_CHUNKSIZE },
638     { "CLIENT", CONF_CLIENT },
639     { "CLIENT_CUSTOM_COMPRESS", CONF_CLNTCOMPPROG },
640     { "CLIENT_DECRYPT_OPTION", CONF_CLNT_DECRYPT_OPT },
641     { "CLIENT_ENCRYPT", CONF_CLNT_ENCRYPT },
642     { "CLIENT_USERNAME", CONF_CLIENT_USERNAME },
643     { "COLUMNSPEC", CONF_COLUMNSPEC },
644     { "COMMENT", CONF_COMMENT },
645     { "COMPRATE", CONF_COMPRATE },
646     { "COMPRESS", CONF_COMPRESS },
647     { "CONNECT_TRIES", CONF_CONNECT_TRIES },
648     { "CTIMEOUT", CONF_CTIMEOUT },
649     { "CUSTOM", CONF_CUSTOM },
650     { "DEBUG_AMANDAD"    , CONF_DEBUG_AMANDAD },
651     { "DEBUG_AMIDXTAPED" , CONF_DEBUG_AMIDXTAPED },
652     { "DEBUG_AMINDEXD"   , CONF_DEBUG_AMINDEXD },
653     { "DEBUG_AMRECOVER"  , CONF_DEBUG_AMRECOVER },
654     { "DEBUG_AUTH"       , CONF_DEBUG_AUTH },
655     { "DEBUG_EVENT"      , CONF_DEBUG_EVENT },
656     { "DEBUG_HOLDING"    , CONF_DEBUG_HOLDING },
657     { "DEBUG_PROTOCOL"   , CONF_DEBUG_PROTOCOL },
658     { "DEBUG_PLANNER"    , CONF_DEBUG_PLANNER },
659     { "DEBUG_DRIVER"     , CONF_DEBUG_DRIVER },
660     { "DEBUG_DUMPER"     , CONF_DEBUG_DUMPER },
661     { "DEBUG_CHUNKER"    , CONF_DEBUG_CHUNKER },
662     { "DEBUG_TAPER"      , CONF_DEBUG_TAPER },
663     { "DEBUG_SELFCHECK"  , CONF_DEBUG_SELFCHECK },
664     { "DEBUG_SENDSIZE"   , CONF_DEBUG_SENDSIZE },
665     { "DEBUG_SENDBACKUP" , CONF_DEBUG_SENDBACKUP },
666     { "DEFINE", CONF_DEFINE },
667     { "DEVICE_PROPERTY", CONF_DEVICE_PROPERTY },
668     { "DIRECTORY", CONF_DIRECTORY },
669     { "DISKFILE", CONF_DISKFILE },
670     { "DISPLAYUNIT", CONF_DISPLAYUNIT },
671     { "DTIMEOUT", CONF_DTIMEOUT },
672     { "DUMPCYCLE", CONF_DUMPCYCLE },
673     { "DUMPORDER", CONF_DUMPORDER },
674     { "DUMPTYPE", CONF_DUMPTYPE },
675     { "DUMPUSER", CONF_DUMPUSER },
676     { "ENCRYPT", CONF_ENCRYPT },
677     { "ESTIMATE", CONF_ESTIMATE },
678     { "ETIMEOUT", CONF_ETIMEOUT },
679     { "EXCLUDE", CONF_EXCLUDE },
680     { "EXCLUDE-FILE", CONF_EXCLUDE_FILE },
681     { "EXCLUDE-LIST", CONF_EXCLUDE_LIST },
682     { "FALLBACK_SPLITSIZE", CONF_FALLBACK_SPLITSIZE },
683     { "FAST", CONF_FAST },
684     { "FILE", CONF_EFILE },
685     { "FILE-PAD", CONF_FILE_PAD },
686     { "FILEMARK", CONF_FILEMARK },
687     { "FIRST", CONF_FIRST },
688     { "FIRSTFIT", CONF_FIRSTFIT },
689     { "HANOI", CONF_HANOI },
690     { "HIGH", CONF_HIGH },
691     { "HOLDINGDISK", CONF_HOLDING },
692     { "IGNORE", CONF_IGNORE },
693     { "INCLUDE", CONF_INCLUDE },
694     { "INCLUDEFILE", CONF_INCLUDEFILE },
695     { "INCRONLY", CONF_INCRONLY },
696     { "INDEX", CONF_INDEX },
697     { "INDEXDIR", CONF_INDEXDIR },
698     { "INFOFILE", CONF_INFOFILE },
699     { "INPARALLEL", CONF_INPARALLEL },
700     { "INTERFACE", CONF_INTERFACE },
701     { "KENCRYPT", CONF_KENCRYPT },
702     { "KRB5KEYTAB", CONF_KRB5KEYTAB },
703     { "KRB5PRINCIPAL", CONF_KRB5PRINCIPAL },
704     { "LABELSTR", CONF_LABELSTR },
705     { "LABEL_NEW_TAPES", CONF_LABEL_NEW_TAPES },
706     { "LARGEST", CONF_LARGEST },
707     { "LARGESTFIT", CONF_LARGESTFIT },
708     { "LAST", CONF_LAST },
709     { "LBL-TEMPL", CONF_LBL_TEMPL },
710     { "LENGTH", CONF_LENGTH },
711     { "LIST", CONF_LIST },
712     { "LOGDIR", CONF_LOGDIR },
713     { "LOW", CONF_LOW },
714     { "MAILTO", CONF_MAILTO },
715     { "READBLOCKSIZE", CONF_READBLOCKSIZE },
716     { "MAXDUMPS", CONF_MAXDUMPS },
717     { "MAXDUMPSIZE", CONF_MAXDUMPSIZE },
718     { "MAXPROMOTEDAY", CONF_MAXPROMOTEDAY },
719     { "MEDIUM", CONF_MEDIUM },
720     { "NETUSAGE", CONF_NETUSAGE },
721     { "NEVER", CONF_NEVER },
722     { "NOFULL", CONF_NOFULL },
723     { "NOINC", CONF_NOINC },
724     { "NONE", CONF_NONE },
725     { "OPTIONAL", CONF_OPTIONAL },
726     { "ORG", CONF_ORG },
727     { "PRINTER", CONF_PRINTER },
728     { "PRIORITY", CONF_PRIORITY },
729     { "PROGRAM", CONF_PROGRAM },
730     { "RECORD", CONF_RECORD },
731     { "REP_TRIES", CONF_REP_TRIES },
732     { "REQ_TRIES", CONF_REQ_TRIES },
733     { "REQUIRED", CONF_REQUIRED },
734     { "RESERVE", CONF_RESERVE },
735     { "RESERVED-UDP-PORT", CONF_RESERVED_UDP_PORT },
736     { "RESERVED-TCP-PORT", CONF_RESERVED_TCP_PORT },
737     { "RUNSPERCYCLE", CONF_RUNSPERCYCLE },
738     { "RUNTAPES", CONF_RUNTAPES },
739     { "SERVER", CONF_SERVER },
740     { "SERVER_CUSTOM_COMPRESS", CONF_SRVCOMPPROG },
741     { "SERVER_DECRYPT_OPTION", CONF_SRV_DECRYPT_OPT },
742     { "SERVER_ENCRYPT", CONF_SRV_ENCRYPT },
743     { "SKIP", CONF_SKIP },
744     { "SKIP-FULL", CONF_SKIP_FULL },
745     { "SKIP-INCR", CONF_SKIP_INCR },
746     { "SMALLEST", CONF_SMALLEST },
747     { "SPEED", CONF_SPEED },
748     { "SPLIT_DISKBUFFER", CONF_SPLIT_DISKBUFFER },
749     { "SSH_KEYS", CONF_SSH_KEYS },
750     { "STANDARD", CONF_STANDARD },
751     { "STARTTIME", CONF_STARTTIME },
752     { "STRATEGY", CONF_STRATEGY },
753     { "TAPEBUFS", CONF_TAPEBUFS },
754     { "DEVICE_OUTPUT_BUFFER_SIZE", CONF_DEVICE_OUTPUT_BUFFER_SIZE },
755     { "TAPECYCLE", CONF_TAPECYCLE },
756     { "TAPEDEV", CONF_TAPEDEV },
757     { "TAPELIST", CONF_TAPELIST },
758     { "TAPERALGO", CONF_TAPERALGO },
759     { "FLUSH-THRESHOLD-DUMPED", CONF_FLUSH_THRESHOLD_DUMPED },
760     { "FLUSH-THRESHOLD-SCHEDULED", CONF_FLUSH_THRESHOLD_SCHEDULED },
761     { "TAPERFLUSH", CONF_TAPERFLUSH },
762     { "TAPETYPE", CONF_TAPETYPE },
763     { "TAPE_SPLITSIZE", CONF_TAPE_SPLITSIZE },
764     { "TPCHANGER", CONF_TPCHANGER },
765     { "UNRESERVED-TCP-PORT", CONF_UNRESERVED_TCP_PORT },
766     { "USE", CONF_USE },
767     { "USETIMESTAMPS", CONF_USETIMESTAMPS },
768     { NULL, CONF_IDENT },
769     { NULL, CONF_UNKNOWN }
770 };
771
772 /* A keyword table for recognizing unit suffixes.  No distinction is made for kinds
773  * of suffixes: 1024 weeks = 7 k. */
774 keytab_t numb_keytable[] = {
775     { "B", CONF_MULT1 },
776     { "BPS", CONF_MULT1 },
777     { "BYTE", CONF_MULT1 },
778     { "BYTES", CONF_MULT1 },
779     { "DAY", CONF_MULT1 },
780     { "DAYS", CONF_MULT1 },
781     { "INF", CONF_AMINFINITY },
782     { "K", CONF_MULT1K },
783     { "KB", CONF_MULT1K },
784     { "KBPS", CONF_MULT1K },
785     { "KBYTE", CONF_MULT1K },
786     { "KBYTES", CONF_MULT1K },
787     { "KILOBYTE", CONF_MULT1K },
788     { "KILOBYTES", CONF_MULT1K },
789     { "KPS", CONF_MULT1K },
790     { "M", CONF_MULT1M },
791     { "MB", CONF_MULT1M },
792     { "MBPS", CONF_MULT1M },
793     { "MBYTE", CONF_MULT1M },
794     { "MBYTES", CONF_MULT1M },
795     { "MEG", CONF_MULT1M },
796     { "MEGABYTE", CONF_MULT1M },
797     { "MEGABYTES", CONF_MULT1M },
798     { "G", CONF_MULT1G },
799     { "GB", CONF_MULT1G },
800     { "GBPS", CONF_MULT1G },
801     { "GBYTE", CONF_MULT1G },
802     { "GBYTES", CONF_MULT1G },
803     { "GIG", CONF_MULT1G },
804     { "GIGABYTE", CONF_MULT1G },
805     { "GIGABYTES", CONF_MULT1G },
806     { "MPS", CONF_MULT1M },
807     { "TAPE", CONF_MULT1 },
808     { "TAPES", CONF_MULT1 },
809     { "WEEK", CONF_MULT7 },
810     { "WEEKS", CONF_MULT7 },
811     { NULL, CONF_IDENT }
812 };
813
814 /* Boolean keywords -- all the ways to say "true" and "false" in amanda.conf */
815 keytab_t bool_keytable[] = {
816     { "Y", CONF_ATRUE },
817     { "YES", CONF_ATRUE },
818     { "T", CONF_ATRUE },
819     { "TRUE", CONF_ATRUE },
820     { "ON", CONF_ATRUE },
821     { "N", CONF_AFALSE },
822     { "NO", CONF_AFALSE },
823     { "F", CONF_AFALSE },
824     { "FALSE", CONF_AFALSE },
825     { "OFF", CONF_AFALSE },
826     { NULL, CONF_IDENT }
827 };
828
829 /* Now, the parser tables for client and server global parameters, and for
830  * each of the server subsections */
831 conf_var_t client_var [] = {
832    { CONF_CONF               , CONFTYPE_STR     , read_str     , CNF_CONF               , NULL },
833    { CONF_INDEX_SERVER       , CONFTYPE_STR     , read_str     , CNF_INDEX_SERVER       , NULL },
834    { CONF_TAPE_SERVER        , CONFTYPE_STR     , read_str     , CNF_TAPE_SERVER        , NULL },
835    { CONF_TAPEDEV            , CONFTYPE_STR     , read_str     , CNF_TAPEDEV            , NULL },
836    { CONF_AUTH               , CONFTYPE_STR     , read_str     , CNF_AUTH               , NULL },
837    { CONF_SSH_KEYS           , CONFTYPE_STR     , read_str     , CNF_SSH_KEYS           , NULL },
838    { CONF_AMANDAD_PATH       , CONFTYPE_STR     , read_str     , CNF_AMANDAD_PATH       , NULL },
839    { CONF_CLIENT_USERNAME    , CONFTYPE_STR     , read_str     , CNF_CLIENT_USERNAME    , NULL },
840    { CONF_GNUTAR_LIST_DIR    , CONFTYPE_STR     , read_str     , CNF_GNUTAR_LIST_DIR    , NULL },
841    { CONF_AMANDATES          , CONFTYPE_STR     , read_str     , CNF_AMANDATES          , NULL },
842    { CONF_KRB5KEYTAB         , CONFTYPE_STR     , read_str     , CNF_KRB5KEYTAB         , NULL },
843    { CONF_KRB5PRINCIPAL      , CONFTYPE_STR     , read_str     , CNF_KRB5PRINCIPAL      , NULL },
844    { CONF_CONNECT_TRIES      , CONFTYPE_INT     , read_int     , CNF_CONNECT_TRIES      , validate_positive },
845    { CONF_REP_TRIES          , CONFTYPE_INT     , read_int     , CNF_REP_TRIES          , validate_positive },
846    { CONF_REQ_TRIES          , CONFTYPE_INT     , read_int     , CNF_REQ_TRIES          , validate_positive },
847    { CONF_DEBUG_AMANDAD      , CONFTYPE_INT     , read_int     , CNF_DEBUG_AMANDAD      , validate_debug },
848    { CONF_DEBUG_AMIDXTAPED   , CONFTYPE_INT     , read_int     , CNF_DEBUG_AMIDXTAPED   , validate_debug },
849    { CONF_DEBUG_AMINDEXD     , CONFTYPE_INT     , read_int     , CNF_DEBUG_AMINDEXD     , validate_debug },
850    { CONF_DEBUG_AMRECOVER    , CONFTYPE_INT     , read_int     , CNF_DEBUG_AMRECOVER    , validate_debug },
851    { CONF_DEBUG_AUTH         , CONFTYPE_INT     , read_int     , CNF_DEBUG_AUTH         , validate_debug },
852    { CONF_DEBUG_EVENT        , CONFTYPE_INT     , read_int     , CNF_DEBUG_EVENT        , validate_debug },
853    { CONF_DEBUG_HOLDING      , CONFTYPE_INT     , read_int     , CNF_DEBUG_HOLDING      , validate_debug },
854    { CONF_DEBUG_PROTOCOL     , CONFTYPE_INT     , read_int     , CNF_DEBUG_PROTOCOL     , validate_debug },
855    { CONF_DEBUG_PLANNER      , CONFTYPE_INT     , read_int     , CNF_DEBUG_PLANNER      , validate_debug },
856    { CONF_DEBUG_DRIVER       , CONFTYPE_INT     , read_int     , CNF_DEBUG_DRIVER       , validate_debug },
857    { CONF_DEBUG_DUMPER       , CONFTYPE_INT     , read_int     , CNF_DEBUG_DUMPER       , validate_debug },
858    { CONF_DEBUG_CHUNKER      , CONFTYPE_INT     , read_int     , CNF_DEBUG_CHUNKER      , validate_debug },
859    { CONF_DEBUG_TAPER        , CONFTYPE_INT     , read_int     , CNF_DEBUG_TAPER        , validate_debug },
860    { CONF_DEBUG_SELFCHECK    , CONFTYPE_INT     , read_int     , CNF_DEBUG_SELFCHECK    , validate_debug },
861    { CONF_DEBUG_SENDSIZE     , CONFTYPE_INT     , read_int     , CNF_DEBUG_SENDSIZE     , validate_debug },
862    { CONF_DEBUG_SENDBACKUP   , CONFTYPE_INT     , read_int     , CNF_DEBUG_SENDBACKUP   , validate_debug },
863    { CONF_RESERVED_UDP_PORT  , CONFTYPE_INTRANGE, read_intrange, CNF_RESERVED_UDP_PORT  , validate_reserved_port_range },
864    { CONF_RESERVED_TCP_PORT  , CONFTYPE_INTRANGE, read_intrange, CNF_RESERVED_TCP_PORT  , validate_reserved_port_range },
865    { CONF_UNRESERVED_TCP_PORT, CONFTYPE_INTRANGE, read_intrange, CNF_UNRESERVED_TCP_PORT, validate_unreserved_port_range },
866    { CONF_UNKNOWN            , CONFTYPE_INT     , NULL         , CNF_CNF                , NULL }
867 };
868
869 conf_var_t server_var [] = {
870    { CONF_ORG                  , CONFTYPE_STR      , read_str         , CNF_ORG                  , NULL },
871    { CONF_MAILTO               , CONFTYPE_STR      , read_str         , CNF_MAILTO               , NULL },
872    { CONF_DUMPUSER             , CONFTYPE_STR      , read_str         , CNF_DUMPUSER             , NULL },
873    { CONF_PRINTER              , CONFTYPE_STR      , read_str         , CNF_PRINTER              , NULL },
874    { CONF_TAPEDEV              , CONFTYPE_STR      , read_str         , CNF_TAPEDEV              , NULL },
875    { CONF_DEVICE_PROPERTY      , CONFTYPE_PROPLIST , read_property    , CNF_DEVICE_PROPERTY      , NULL },
876    { CONF_TPCHANGER            , CONFTYPE_STR      , read_str         , CNF_TPCHANGER            , NULL },
877    { CONF_CHANGERDEV           , CONFTYPE_STR      , read_str         , CNF_CHANGERDEV           , NULL },
878    { CONF_CHANGERFILE          , CONFTYPE_STR      , read_str         , CNF_CHANGERFILE          , NULL },
879    { CONF_LABELSTR             , CONFTYPE_STR      , read_str         , CNF_LABELSTR             , NULL },
880    { CONF_TAPELIST             , CONFTYPE_STR      , read_str         , CNF_TAPELIST             , NULL },
881    { CONF_DISKFILE             , CONFTYPE_STR      , read_str         , CNF_DISKFILE             , NULL },
882    { CONF_INFOFILE             , CONFTYPE_STR      , read_str         , CNF_INFOFILE             , NULL },
883    { CONF_LOGDIR               , CONFTYPE_STR      , read_str         , CNF_LOGDIR               , NULL },
884    { CONF_INDEXDIR             , CONFTYPE_STR      , read_str         , CNF_INDEXDIR             , NULL },
885    { CONF_TAPETYPE             , CONFTYPE_IDENT    , read_ident       , CNF_TAPETYPE             , NULL },
886    { CONF_DUMPCYCLE            , CONFTYPE_INT      , read_int         , CNF_DUMPCYCLE            , validate_nonnegative },
887    { CONF_RUNSPERCYCLE         , CONFTYPE_INT      , read_int         , CNF_RUNSPERCYCLE         , validate_runspercycle },
888    { CONF_RUNTAPES             , CONFTYPE_INT      , read_int         , CNF_RUNTAPES             , validate_nonnegative },
889    { CONF_TAPECYCLE            , CONFTYPE_INT      , read_int         , CNF_TAPECYCLE            , validate_positive },
890    { CONF_BUMPDAYS             , CONFTYPE_INT      , read_int         , CNF_BUMPDAYS             , validate_positive },
891    { CONF_BUMPSIZE             , CONFTYPE_AM64     , read_am64        , CNF_BUMPSIZE             , validate_positive },
892    { CONF_BUMPPERCENT          , CONFTYPE_INT      , read_int         , CNF_BUMPPERCENT          , validate_bumppercent },
893    { CONF_BUMPMULT             , CONFTYPE_REAL     , read_real        , CNF_BUMPMULT             , validate_bumpmult },
894    { CONF_NETUSAGE             , CONFTYPE_INT      , read_int         , CNF_NETUSAGE             , validate_positive },
895    { CONF_INPARALLEL           , CONFTYPE_INT      , read_int         , CNF_INPARALLEL           , validate_inparallel },
896    { CONF_DUMPORDER            , CONFTYPE_STR      , read_str         , CNF_DUMPORDER            , NULL },
897    { CONF_MAXDUMPS             , CONFTYPE_INT      , read_int         , CNF_MAXDUMPS             , validate_positive },
898    { CONF_ETIMEOUT             , CONFTYPE_INT      , read_int         , CNF_ETIMEOUT             , NULL },
899    { CONF_DTIMEOUT             , CONFTYPE_INT      , read_int         , CNF_DTIMEOUT             , validate_positive },
900    { CONF_CTIMEOUT             , CONFTYPE_INT      , read_int         , CNF_CTIMEOUT             , validate_positive },
901    { CONF_TAPEBUFS             , CONFTYPE_INT      , read_int         , CNF_TAPEBUFS             , validate_positive },
902    { CONF_DEVICE_OUTPUT_BUFFER_SIZE, CONFTYPE_SIZE , read_size        , CNF_DEVICE_OUTPUT_BUFFER_SIZE, validate_positive },
903    { CONF_COLUMNSPEC           , CONFTYPE_STR      , read_str         , CNF_COLUMNSPEC           , NULL },
904    { CONF_TAPERALGO            , CONFTYPE_TAPERALGO, read_taperalgo   , CNF_TAPERALGO            , NULL },
905    { CONF_FLUSH_THRESHOLD_DUMPED, CONFTYPE_INT     , read_int         , CNF_FLUSH_THRESHOLD_DUMPED, validate_nonnegative },
906    { CONF_FLUSH_THRESHOLD_SCHEDULED, CONFTYPE_INT  , read_int         , CNF_FLUSH_THRESHOLD_SCHEDULED, validate_nonnegative },
907    { CONF_TAPERFLUSH           , CONFTYPE_INT      , read_int         , CNF_TAPERFLUSH           , validate_nonnegative },
908    { CONF_DISPLAYUNIT          , CONFTYPE_STR      , read_str         , CNF_DISPLAYUNIT          , validate_displayunit },
909    { CONF_AUTOFLUSH            , CONFTYPE_BOOLEAN  , read_bool        , CNF_AUTOFLUSH            , NULL },
910    { CONF_RESERVE              , CONFTYPE_INT      , read_int         , CNF_RESERVE              , validate_reserve },
911    { CONF_MAXDUMPSIZE          , CONFTYPE_AM64     , read_am64        , CNF_MAXDUMPSIZE          , NULL },
912    { CONF_KRB5KEYTAB           , CONFTYPE_STR      , read_str         , CNF_KRB5KEYTAB           , NULL },
913    { CONF_KRB5PRINCIPAL        , CONFTYPE_STR      , read_str         , CNF_KRB5PRINCIPAL        , NULL },
914    { CONF_LABEL_NEW_TAPES      , CONFTYPE_STR      , read_str         , CNF_LABEL_NEW_TAPES      , NULL },
915    { CONF_USETIMESTAMPS        , CONFTYPE_BOOLEAN  , read_bool        , CNF_USETIMESTAMPS        , NULL },
916    { CONF_AMRECOVER_DO_FSF     , CONFTYPE_BOOLEAN  , read_bool        , CNF_AMRECOVER_DO_FSF     , NULL },
917    { CONF_AMRECOVER_CHANGER    , CONFTYPE_STR      , read_str         , CNF_AMRECOVER_CHANGER    , NULL },
918    { CONF_AMRECOVER_CHECK_LABEL, CONFTYPE_BOOLEAN  , read_bool        , CNF_AMRECOVER_CHECK_LABEL, NULL },
919    { CONF_CONNECT_TRIES        , CONFTYPE_INT      , read_int         , CNF_CONNECT_TRIES        , validate_positive },
920    { CONF_REP_TRIES            , CONFTYPE_INT      , read_int         , CNF_REP_TRIES            , validate_positive },
921    { CONF_REQ_TRIES            , CONFTYPE_INT      , read_int         , CNF_REQ_TRIES            , validate_positive },
922    { CONF_DEBUG_AMANDAD        , CONFTYPE_INT      , read_int         , CNF_DEBUG_AMANDAD        , validate_debug },
923    { CONF_DEBUG_AMIDXTAPED     , CONFTYPE_INT      , read_int         , CNF_DEBUG_AMIDXTAPED     , validate_debug },
924    { CONF_DEBUG_AMINDEXD       , CONFTYPE_INT      , read_int         , CNF_DEBUG_AMINDEXD       , validate_debug },
925    { CONF_DEBUG_AMRECOVER      , CONFTYPE_INT      , read_int         , CNF_DEBUG_AMRECOVER      , validate_debug },
926    { CONF_DEBUG_AUTH           , CONFTYPE_INT      , read_int         , CNF_DEBUG_AUTH           , validate_debug },
927    { CONF_DEBUG_EVENT          , CONFTYPE_INT      , read_int         , CNF_DEBUG_EVENT          , validate_debug },
928    { CONF_DEBUG_HOLDING        , CONFTYPE_INT      , read_int         , CNF_DEBUG_HOLDING        , validate_debug },
929    { CONF_DEBUG_PROTOCOL       , CONFTYPE_INT      , read_int         , CNF_DEBUG_PROTOCOL       , validate_debug },
930    { CONF_DEBUG_PLANNER        , CONFTYPE_INT      , read_int         , CNF_DEBUG_PLANNER        , validate_debug },
931    { CONF_DEBUG_DRIVER         , CONFTYPE_INT      , read_int         , CNF_DEBUG_DRIVER         , validate_debug },
932    { CONF_DEBUG_DUMPER         , CONFTYPE_INT      , read_int         , CNF_DEBUG_DUMPER         , validate_debug },
933    { CONF_DEBUG_CHUNKER        , CONFTYPE_INT      , read_int         , CNF_DEBUG_CHUNKER        , validate_debug },
934    { CONF_DEBUG_TAPER          , CONFTYPE_INT      , read_int         , CNF_DEBUG_TAPER          , validate_debug },
935    { CONF_DEBUG_SELFCHECK      , CONFTYPE_INT      , read_int         , CNF_DEBUG_SELFCHECK      , validate_debug },
936    { CONF_DEBUG_SENDSIZE       , CONFTYPE_INT      , read_int         , CNF_DEBUG_SENDSIZE       , validate_debug },
937    { CONF_DEBUG_SENDBACKUP     , CONFTYPE_INT      , read_int         , CNF_DEBUG_SENDBACKUP     , validate_debug },
938    { CONF_RESERVED_UDP_PORT    , CONFTYPE_INTRANGE , read_intrange    , CNF_RESERVED_UDP_PORT    , validate_reserved_port_range },
939    { CONF_RESERVED_TCP_PORT    , CONFTYPE_INTRANGE , read_intrange    , CNF_RESERVED_TCP_PORT    , validate_reserved_port_range },
940    { CONF_UNRESERVED_TCP_PORT  , CONFTYPE_INTRANGE , read_intrange    , CNF_UNRESERVED_TCP_PORT  , validate_unreserved_port_range },
941    { CONF_UNKNOWN              , CONFTYPE_INT      , NULL             , CNF_CNF                  , NULL }
942 };
943
944 conf_var_t tapetype_var [] = {
945    { CONF_COMMENT       , CONFTYPE_STR     , read_str   , TAPETYPE_COMMENT      , NULL },
946    { CONF_LBL_TEMPL     , CONFTYPE_STR     , read_str   , TAPETYPE_LBL_TEMPL    , NULL },
947    { CONF_BLOCKSIZE     , CONFTYPE_SIZE    , read_size  , TAPETYPE_BLOCKSIZE    , validate_blocksize },
948    { CONF_READBLOCKSIZE , CONFTYPE_SIZE    , read_size  , TAPETYPE_READBLOCKSIZE, validate_blocksize },
949    { CONF_LENGTH        , CONFTYPE_AM64    , read_am64  , TAPETYPE_LENGTH       , validate_nonnegative },
950    { CONF_FILEMARK      , CONFTYPE_AM64    , read_am64  , TAPETYPE_FILEMARK     , NULL },
951    { CONF_SPEED         , CONFTYPE_INT     , read_int   , TAPETYPE_SPEED        , validate_nonnegative },
952    { CONF_FILE_PAD      , CONFTYPE_BOOLEAN , read_bool  , TAPETYPE_FILE_PAD     , NULL },
953    { CONF_UNKNOWN       , CONFTYPE_INT     , NULL       , TAPETYPE_TAPETYPE     , NULL }
954 };
955
956 conf_var_t dumptype_var [] = {
957    { CONF_COMMENT           , CONFTYPE_STR      , read_str      , DUMPTYPE_COMMENT           , NULL },
958    { CONF_AUTH              , CONFTYPE_STR      , read_str      , DUMPTYPE_SECURITY_DRIVER   , NULL },
959    { CONF_BUMPDAYS          , CONFTYPE_INT      , read_int      , DUMPTYPE_BUMPDAYS          , NULL },
960    { CONF_BUMPMULT          , CONFTYPE_REAL     , read_real     , DUMPTYPE_BUMPMULT          , NULL },
961    { CONF_BUMPSIZE          , CONFTYPE_AM64     , read_am64     , DUMPTYPE_BUMPSIZE          , NULL },
962    { CONF_BUMPPERCENT       , CONFTYPE_INT      , read_int      , DUMPTYPE_BUMPPERCENT       , NULL },
963    { CONF_COMPRATE          , CONFTYPE_REAL     , read_rate     , DUMPTYPE_COMPRATE          , NULL },
964    { CONF_COMPRESS          , CONFTYPE_INT      , read_compress , DUMPTYPE_COMPRESS          , NULL },
965    { CONF_ENCRYPT           , CONFTYPE_INT      , read_encrypt  , DUMPTYPE_ENCRYPT           , NULL },
966    { CONF_DUMPCYCLE         , CONFTYPE_INT      , read_int      , DUMPTYPE_DUMPCYCLE         , validate_nonnegative },
967    { CONF_EXCLUDE           , CONFTYPE_EXINCLUDE, read_exinclude, DUMPTYPE_EXCLUDE           , NULL },
968    { CONF_INCLUDE           , CONFTYPE_EXINCLUDE, read_exinclude, DUMPTYPE_INCLUDE           , NULL },
969    { CONF_IGNORE            , CONFTYPE_BOOLEAN  , read_bool     , DUMPTYPE_IGNORE            , NULL },
970    { CONF_HOLDING           , CONFTYPE_HOLDING  , read_holding  , DUMPTYPE_HOLDINGDISK       , NULL },
971    { CONF_INDEX             , CONFTYPE_BOOLEAN  , read_bool     , DUMPTYPE_INDEX             , NULL },
972    { CONF_KENCRYPT          , CONFTYPE_BOOLEAN  , read_bool     , DUMPTYPE_KENCRYPT          , NULL },
973    { CONF_MAXDUMPS          , CONFTYPE_INT      , read_int      , DUMPTYPE_MAXDUMPS          , validate_positive },
974    { CONF_MAXPROMOTEDAY     , CONFTYPE_INT      , read_int      , DUMPTYPE_MAXPROMOTEDAY     , validate_nonnegative },
975    { CONF_PRIORITY          , CONFTYPE_PRIORITY , read_priority , DUMPTYPE_PRIORITY          , NULL },
976    { CONF_PROGRAM           , CONFTYPE_STR      , read_str      , DUMPTYPE_PROGRAM           , NULL },
977    { CONF_RECORD            , CONFTYPE_BOOLEAN  , read_bool     , DUMPTYPE_RECORD            , NULL },
978    { CONF_SKIP_FULL         , CONFTYPE_BOOLEAN  , read_bool     , DUMPTYPE_SKIP_FULL         , NULL },
979    { CONF_SKIP_INCR         , CONFTYPE_BOOLEAN  , read_bool     , DUMPTYPE_SKIP_INCR         , NULL },
980    { CONF_STARTTIME         , CONFTYPE_TIME     , read_time     , DUMPTYPE_STARTTIME         , NULL },
981    { CONF_STRATEGY          , CONFTYPE_INT      , read_strategy , DUMPTYPE_STRATEGY          , NULL },
982    { CONF_TAPE_SPLITSIZE    , CONFTYPE_AM64     , read_am64     , DUMPTYPE_TAPE_SPLITSIZE    , validate_nonnegative },
983    { CONF_SPLIT_DISKBUFFER  , CONFTYPE_STR      , read_str      , DUMPTYPE_SPLIT_DISKBUFFER  , NULL },
984    { CONF_ESTIMATE          , CONFTYPE_INT      , read_estimate , DUMPTYPE_ESTIMATE          , NULL },
985    { CONF_SRV_ENCRYPT       , CONFTYPE_STR      , read_str      , DUMPTYPE_SRV_ENCRYPT       , NULL },
986    { CONF_CLNT_ENCRYPT      , CONFTYPE_STR      , read_str      , DUMPTYPE_CLNT_ENCRYPT      , NULL },
987    { CONF_AMANDAD_PATH      , CONFTYPE_STR      , read_str      , DUMPTYPE_AMANDAD_PATH      , NULL },
988    { CONF_CLIENT_USERNAME   , CONFTYPE_STR      , read_str      , DUMPTYPE_CLIENT_USERNAME   , NULL },
989    { CONF_SSH_KEYS          , CONFTYPE_STR      , read_str      , DUMPTYPE_SSH_KEYS          , NULL },
990    { CONF_SRVCOMPPROG       , CONFTYPE_STR      , read_str      , DUMPTYPE_SRVCOMPPROG       , NULL },
991    { CONF_CLNTCOMPPROG      , CONFTYPE_STR      , read_str      , DUMPTYPE_CLNTCOMPPROG      , NULL },
992    { CONF_FALLBACK_SPLITSIZE, CONFTYPE_AM64     , read_am64     , DUMPTYPE_FALLBACK_SPLITSIZE, NULL },
993    { CONF_SRV_DECRYPT_OPT   , CONFTYPE_STR      , read_str      , DUMPTYPE_SRV_DECRYPT_OPT   , NULL },
994    { CONF_CLNT_DECRYPT_OPT  , CONFTYPE_STR      , read_str      , DUMPTYPE_CLNT_DECRYPT_OPT  , NULL },
995    { CONF_UNKNOWN           , CONFTYPE_INT      , NULL          , DUMPTYPE_DUMPTYPE          , NULL }
996 };
997
998 conf_var_t holding_var [] = {
999    { CONF_DIRECTORY, CONFTYPE_STR   , read_str   , HOLDING_DISKDIR  , NULL },
1000    { CONF_COMMENT  , CONFTYPE_STR   , read_str   , HOLDING_COMMENT  , NULL },
1001    { CONF_USE      , CONFTYPE_AM64  , read_am64  , HOLDING_DISKSIZE , validate_use },
1002    { CONF_CHUNKSIZE, CONFTYPE_AM64  , read_am64  , HOLDING_CHUNKSIZE, validate_chunksize },
1003    { CONF_UNKNOWN  , CONFTYPE_INT   , NULL       , HOLDING_HOLDING  , NULL }
1004 };
1005
1006 conf_var_t interface_var [] = {
1007    { CONF_COMMENT, CONFTYPE_STR   , read_str   , INTER_COMMENT , NULL },
1008    { CONF_USE    , CONFTYPE_INT   , read_int   , INTER_MAXUSAGE, validate_positive },
1009    { CONF_UNKNOWN, CONFTYPE_INT   , NULL       , INTER_INTER   , NULL }
1010 };
1011
1012
1013 /*
1014  * Lexical Analysis Implementation
1015  */
1016
1017 static char *
1018 get_token_name(
1019     tok_t token)
1020 {
1021     keytab_t *kt;
1022
1023     if (keytable == NULL) {
1024         error(_("keytable == NULL"));
1025         /*NOTREACHED*/
1026     }
1027
1028     for(kt = keytable; kt->token != CONF_UNKNOWN; kt++)
1029         if(kt->token == token) break;
1030
1031     if(kt->token == CONF_UNKNOWN)
1032         return("");
1033     return(kt->keyword);
1034 }
1035
1036 static tok_t
1037 lookup_keyword(
1038     char *      str)
1039 {
1040     keytab_t *kwp;
1041
1042     for(kwp = keytable; kwp->keyword != NULL; kwp++) {
1043         if (strcasecmp(kwp->keyword, str) == 0) break;
1044     }
1045     return kwp->token;
1046 }
1047
1048 static void
1049 get_conftoken(
1050     tok_t       exp)
1051 {
1052     int ch, d;
1053     off_t am64;
1054     char *buf;
1055     char *tmps;
1056     int token_overflow;
1057     int inquote = 0;
1058     int escape = 0;
1059     int sign;
1060
1061     if (token_pushed) {
1062         token_pushed = 0;
1063         tok = pushed_tok;
1064
1065         /*
1066         ** If it looked like a keyword before then look it
1067         ** up again in the current keyword table.
1068         */
1069         switch(tok) {
1070         case CONF_AM64:    case CONF_SIZE:
1071         case CONF_INT:     case CONF_REAL:    case CONF_STRING:
1072         case CONF_LBRACE:  case CONF_RBRACE:  case CONF_COMMA:
1073         case CONF_NL:      case CONF_END:     case CONF_UNKNOWN:
1074         case CONF_TIME:
1075             break; /* not a keyword */
1076
1077         default:
1078             if (exp == CONF_IDENT)
1079                 tok = CONF_IDENT;
1080             else
1081                 tok = lookup_keyword(tokenval.v.s);
1082             break;
1083         }
1084     }
1085     else {
1086         ch = conftoken_getc();
1087
1088         while(ch != EOF && ch != '\n' && isspace(ch))
1089             ch = conftoken_getc();
1090         if (ch == '#') {        /* comment - eat everything but eol/eof */
1091             while((ch = conftoken_getc()) != EOF && ch != '\n') {
1092                 (void)ch; /* Quiet empty loop complaints */     
1093             }
1094         }
1095
1096         if (isalpha(ch)) {              /* identifier */
1097             buf = tkbuf;
1098             token_overflow = 0;
1099             do {
1100                 if (buf < tkbuf+sizeof(tkbuf)-1) {
1101                     *buf++ = (char)ch;
1102                 } else {
1103                     *buf = '\0';
1104                     if (!token_overflow) {
1105                         conf_parserror(_("token too long: %.20s..."), tkbuf);
1106                     }
1107                     token_overflow = 1;
1108                 }
1109                 ch = conftoken_getc();
1110             } while(isalnum(ch) || ch == '_' || ch == '-');
1111
1112             if (ch != EOF && conftoken_ungetc(ch) == EOF) {
1113                 if (ferror(current_file)) {
1114                     conf_parserror(_("Pushback of '%c' failed: %s"),
1115                                    ch, strerror(ferror(current_file)));
1116                 } else {
1117                     conf_parserror(_("Pushback of '%c' failed: EOF"), ch);
1118                 }
1119             }
1120             *buf = '\0';
1121
1122             tokenval.v.s = tkbuf;
1123
1124             if (token_overflow) tok = CONF_UNKNOWN;
1125             else if (exp == CONF_IDENT) tok = CONF_IDENT;
1126             else tok = lookup_keyword(tokenval.v.s);
1127         }
1128         else if (isdigit(ch)) { /* integer */
1129             sign = 1;
1130
1131 negative_number: /* look for goto negative_number below sign is set there */
1132             am64 = 0;
1133             do {
1134                 am64 = am64 * 10 + (ch - '0');
1135                 ch = conftoken_getc();
1136             } while (isdigit(ch));
1137
1138             if (ch != '.') {
1139                 if (exp == CONF_INT) {
1140                     tok = CONF_INT;
1141                     tokenval.v.i = sign * (int)am64;
1142                 } else if (exp != CONF_REAL) {
1143                     tok = CONF_AM64;
1144                     tokenval.v.am64 = (off_t)sign * am64;
1145                 } else {
1146                     /* automatically convert to real when expected */
1147                     tokenval.v.r = (double)sign * (double)am64;
1148                     tok = CONF_REAL;
1149                 }
1150             } else {
1151                 /* got a real number, not an int */
1152                 tokenval.v.r = sign * (double) am64;
1153                 am64 = 0;
1154                 d = 1;
1155                 ch = conftoken_getc();
1156                 while (isdigit(ch)) {
1157                     am64 = am64 * 10 + (ch - '0');
1158                     d = d * 10;
1159                     ch = conftoken_getc();
1160                 }
1161                 tokenval.v.r += sign * ((double)am64) / d;
1162                 tok = CONF_REAL;
1163             }
1164
1165             if (ch != EOF &&  conftoken_ungetc(ch) == EOF) {
1166                 if (ferror(current_file)) {
1167                     conf_parserror(_("Pushback of '%c' failed: %s"),
1168                                    ch, strerror(ferror(current_file)));
1169                 } else {
1170                     conf_parserror(_("Pushback of '%c' failed: EOF"), ch);
1171                 }
1172             }
1173         } else switch(ch) {
1174         case '"':                       /* string */
1175             buf = tkbuf;
1176             token_overflow = 0;
1177             inquote = 1;
1178             *buf++ = (char)ch;
1179             while (inquote && ((ch = conftoken_getc()) != EOF)) {
1180                 if (ch == '\n') {
1181                     if (!escape)
1182                         break;
1183                     escape = 0;
1184                     buf--; /* Consume escape in buffer */
1185                 } else if (ch == '\\') {
1186                     escape = 1;
1187                 } else {
1188                     if (ch == '"') {
1189                         if (!escape)
1190                             inquote = 0;
1191                     }
1192                     escape = 0;
1193                 }
1194
1195                 if(buf >= &tkbuf[sizeof(tkbuf) - 1]) {
1196                     if (!token_overflow) {
1197                         conf_parserror(_("string too long: %.20s..."), tkbuf);
1198                     }
1199                     token_overflow = 1;
1200                     break;
1201                 }
1202                 *buf++ = (char)ch;
1203             }
1204             *buf = '\0';
1205
1206             /*
1207              * A little manuver to leave a fully unquoted, unallocated  string
1208              * in tokenval.v.s
1209              */
1210             tmps = unquote_string(tkbuf);
1211             strncpy(tkbuf, tmps, sizeof(tkbuf));
1212             amfree(tmps);
1213             tokenval.v.s = tkbuf;
1214
1215             tok = (token_overflow) ? CONF_UNKNOWN :
1216                         (exp == CONF_IDENT) ? CONF_IDENT : CONF_STRING;
1217             break;
1218
1219         case '-':
1220             ch = conftoken_getc();
1221             if (isdigit(ch)) {
1222                 sign = -1;
1223                 goto negative_number;
1224             }
1225             else {
1226                 if (ch != EOF && conftoken_ungetc(ch) == EOF) {
1227                     if (ferror(current_file)) {
1228                         conf_parserror(_("Pushback of '%c' failed: %s"),
1229                                        ch, strerror(ferror(current_file)));
1230                     } else {
1231                         conf_parserror(_("Pushback of '%c' failed: EOF"), ch);
1232                     }
1233                 }
1234                 tok = CONF_UNKNOWN;
1235             }
1236             break;
1237
1238         case ',':
1239             tok = CONF_COMMA;
1240             break;
1241
1242         case '{':
1243             tok = CONF_LBRACE;
1244             break;
1245
1246         case '}':
1247             tok = CONF_RBRACE;
1248             break;
1249
1250         case '\n':
1251             tok = CONF_NL;
1252             break;
1253
1254         case EOF:
1255             tok = CONF_END;
1256             break;
1257
1258         default:
1259             tok = CONF_UNKNOWN;
1260             break;
1261         }
1262     }
1263
1264     if (exp != CONF_ANY && tok != exp) {
1265         char *str;
1266         keytab_t *kwp;
1267
1268         switch(exp) {
1269         case CONF_LBRACE:
1270             str = "\"{\"";
1271             break;
1272
1273         case CONF_RBRACE:
1274             str = "\"}\"";
1275             break;
1276
1277         case CONF_COMMA:
1278             str = "\",\"";
1279             break;
1280
1281         case CONF_NL:
1282             str = _("end of line");
1283             break;
1284
1285         case CONF_END:
1286             str = _("end of file");
1287             break;
1288
1289         case CONF_INT:
1290             str = _("an integer");
1291             break;
1292
1293         case CONF_REAL:
1294             str = _("a real number");
1295             break;
1296
1297         case CONF_STRING:
1298             str = _("a quoted string");
1299             break;
1300
1301         case CONF_IDENT:
1302             str = _("an identifier");
1303             break;
1304
1305         default:
1306             for(kwp = keytable; kwp->keyword != NULL; kwp++) {
1307                 if (exp == kwp->token)
1308                     break;
1309             }
1310             if (kwp->keyword == NULL)
1311                 str = _("token not");
1312             else
1313                 str = kwp->keyword;
1314             break;
1315         }
1316         conf_parserror(_("%s is expected"), str);
1317         tok = exp;
1318         if (tok == CONF_INT)
1319             tokenval.v.i = 0;
1320         else
1321             tokenval.v.s = "";
1322     }
1323 }
1324
1325 static void
1326 unget_conftoken(void)
1327 {
1328     assert(!token_pushed);
1329     token_pushed = 1;
1330     pushed_tok = tok;
1331     tok = CONF_UNKNOWN;
1332 }
1333
1334 static int
1335 conftoken_getc(void)
1336 {
1337     if(current_line == NULL)
1338         return getc(current_file);
1339     if(*current_char == '\0')
1340         return -1;
1341     return(*current_char++);
1342 }
1343
1344 static int
1345 conftoken_ungetc(
1346     int c)
1347 {
1348     if(current_line == NULL)
1349         return ungetc(c, current_file);
1350     else if(current_char > current_line) {
1351         if(c == -1)
1352             return c;
1353         current_char--;
1354         if(*current_char != c) {
1355             error(_("*current_char != c   : %c %c"), *current_char, c);
1356             /* NOTREACHED */
1357         }
1358     } else {
1359         error(_("current_char == current_line"));
1360         /* NOTREACHED */
1361     }
1362     return c;
1363 }
1364
1365 /*
1366  * Parser Implementation
1367  */
1368
1369 static gboolean
1370 read_conffile(
1371     char *filename,
1372     gboolean is_client)
1373 {
1374     /* Save global locations. */
1375     FILE *save_file     = current_file;
1376     char *save_filename = current_filename;
1377     int  save_line_num  = current_line_num;
1378     int rc;
1379
1380     if (is_client) {
1381         keytable = client_keytab;
1382         parsetable = client_var;
1383     } else {
1384         keytable = server_keytab;
1385         parsetable = server_var;
1386     }
1387     current_filename = config_dir_relative(filename);
1388
1389     if ((current_file = fopen(current_filename, "r")) == NULL) {
1390         /* client conf files are optional, and this fprintf ends up sending this message back
1391          * to the server without proper auth encapsulation, leading to "invalid size: could not
1392          * open .."  This is fixed in TRUNK by completely rewriting this module's error-handling
1393          * code. */
1394         if (!is_client) {
1395             g_fprintf(stderr, _("could not open conf file \"%s\": %s\n"), current_filename,
1396                 strerror(errno));
1397         }
1398         got_parserror = TRUE;
1399         goto finish;
1400     }
1401
1402     current_line_num = 0;
1403
1404     do {
1405         /* read_confline() can invoke us recursively via "includefile" */
1406         rc = read_confline(is_client);
1407     } while (rc != 0);
1408
1409     afclose(current_file);
1410
1411 finish:
1412     amfree(current_filename);
1413
1414     /* Restore servers */
1415     current_line_num = save_line_num;
1416     current_file     = save_file;
1417     current_filename = save_filename;
1418
1419     return !got_parserror;
1420 }
1421
1422 static gboolean
1423 read_confline(
1424     gboolean is_client)
1425 {
1426     conf_var_t *np;
1427
1428     current_line_num += 1;
1429     get_conftoken(CONF_ANY);
1430     switch(tok) {
1431     case CONF_INCLUDEFILE:
1432         get_conftoken(CONF_STRING);
1433         if (!read_conffile(tokenval.v.s, is_client))
1434             return 0;
1435         break;
1436
1437     case CONF_HOLDING:
1438         if (is_client) {
1439             handle_invalid_keyword(tokenval.v.s);
1440         } else {
1441             get_holdingdisk();
1442         }
1443         break;
1444
1445     case CONF_DEFINE:
1446         if (is_client) {
1447             handle_invalid_keyword(tokenval.v.s);
1448         } else {
1449             get_conftoken(CONF_ANY);
1450             if(tok == CONF_DUMPTYPE) get_dumptype();
1451             else if(tok == CONF_TAPETYPE) get_tapetype();
1452             else if(tok == CONF_INTERFACE) get_interface();
1453             else conf_parserror(_("DUMPTYPE, INTERFACE or TAPETYPE expected"));
1454         }
1455         break;
1456
1457     case CONF_NL:       /* empty line */
1458         break;
1459
1460     case CONF_END:      /* end of file */
1461         return 0;
1462
1463     /* if it's not a known punctuation mark, then check the parse table and use the
1464      * read_function we find there. */
1465     default:
1466         {
1467             for(np = parsetable; np->token != CONF_UNKNOWN; np++) 
1468                 if(np->token == tok) break;
1469
1470             if(np->token == CONF_UNKNOWN) {
1471                 handle_invalid_keyword(tokenval.v.s);
1472             } else {
1473                 np->read_function(np, &conf_data[np->parm]);
1474                 if(np->validate_function)
1475                     np->validate_function(np, &conf_data[np->parm]);
1476             }
1477         }
1478     }
1479     if(tok != CONF_NL)
1480         get_conftoken(CONF_NL);
1481     return 1;
1482 }
1483
1484 static void
1485 handle_invalid_keyword(
1486     const char * token)
1487 {
1488     /* Procedure for deprecated keywords:
1489      * 1) At time of deprecation, add to warning_deprecated below.
1490      *    Note the date of deprecation.
1491      * 2) After two years, move the keyword to error_deprecated below.
1492      *    Note the date of the move.
1493      * 3) After two more years, drop the token entirely. */
1494
1495     static const char * warning_deprecated[] = {
1496         "rawtapedev",  /* 2007-01-23 */
1497         "tapebufs",    /* 2007-10-15 */
1498         "netusage",    /* historical since 1997-08-11, deprecated 2007-10-23 */
1499         NULL
1500     };
1501     static const char * error_deprecated[] = {
1502         NULL
1503     };
1504     const char ** s;
1505
1506     for (s = warning_deprecated; *s != NULL; s ++) {
1507         if (strcmp(*s, token) == 0) {
1508             conf_parswarn(_("warning: Keyword %s is deprecated."),
1509                            token);
1510             break;
1511         }
1512     }
1513     if (*s == NULL) {
1514         for (s = error_deprecated; *s != NULL; s ++) {
1515             if (strcmp(*s, token) == 0) {
1516                 conf_parserror(_("error: Keyword %s is deprecated."),
1517                                token);
1518                 return;
1519             }
1520         }
1521     }
1522     if (*s == NULL) {
1523         conf_parserror(_("configuration keyword expected"));
1524     }
1525
1526     for (;;) {
1527         char c = conftoken_getc();
1528         if (c == '\n' || c == -1) {
1529             conftoken_ungetc(c);
1530             return;
1531         }
1532     }
1533
1534     g_assert_not_reached();
1535 }
1536
1537 static void
1538 read_block(
1539     conf_var_t    *read_var,
1540     val_t    *valarray,
1541     char     *errormsg,
1542     int       read_brace,
1543     void      (*copy_function)(void))
1544 {
1545     conf_var_t *np;
1546     int    done;
1547
1548     if(read_brace) {
1549         get_conftoken(CONF_LBRACE);
1550         get_conftoken(CONF_NL);
1551     }
1552
1553     done = 0;
1554     do {
1555         current_line_num += 1;
1556         get_conftoken(CONF_ANY);
1557         switch(tok) {
1558         case CONF_RBRACE:
1559             done = 1;
1560             break;
1561         case CONF_NL:   /* empty line */
1562             break;
1563         case CONF_END:  /* end of file */
1564             done = 1;
1565             break;
1566
1567         /* inherit from a "parent" */
1568         case CONF_IDENT:
1569         case CONF_STRING:
1570             if(copy_function) 
1571                 copy_function();
1572             else
1573                 conf_parserror(_("ident not expected"));
1574             break;
1575         default:
1576             {
1577                 for(np = read_var; np->token != CONF_UNKNOWN; np++)
1578                     if(np->token == tok) break;
1579
1580                 if(np->token == CONF_UNKNOWN)
1581                     conf_parserror("%s", errormsg);
1582                 else {
1583                     np->read_function(np, &valarray[np->parm]);
1584                     if(np->validate_function)
1585                         np->validate_function(np, &valarray[np->parm]);
1586                 }
1587             }
1588         }
1589         if(tok != CONF_NL && tok != CONF_END && tok != CONF_RBRACE)
1590             get_conftoken(CONF_NL);
1591     } while(!done);
1592 }
1593
1594 static void
1595 get_holdingdisk(
1596     void)
1597 {
1598     int save_overwrites;
1599
1600     save_overwrites = allow_overwrites;
1601     allow_overwrites = 1;
1602
1603     init_holdingdisk_defaults();
1604
1605     get_conftoken(CONF_IDENT);
1606     hdcur.name = stralloc(tokenval.v.s);
1607     hdcur.seen = current_line_num;
1608
1609     read_block(holding_var, hdcur.value,
1610                _("holding disk parameter expected"), 1, NULL);
1611     get_conftoken(CONF_NL);
1612     save_holdingdisk();
1613
1614     allow_overwrites = save_overwrites;
1615 }
1616
1617 static void
1618 init_holdingdisk_defaults(
1619     void)
1620 {
1621     conf_init_str(&hdcur.value[HOLDING_COMMENT]  , "");
1622     conf_init_str(&hdcur.value[HOLDING_DISKDIR]  , "");
1623     conf_init_am64(&hdcur.value[HOLDING_DISKSIZE] , (off_t)0);
1624                     /* 1 Gb = 1M counted in 1Kb blocks */
1625     conf_init_am64(&hdcur.value[HOLDING_CHUNKSIZE], (off_t)1024*1024);
1626 }
1627
1628 static void
1629 save_holdingdisk(
1630     void)
1631 {
1632     holdingdisk_t *hp;
1633
1634     hp = alloc(sizeof(holdingdisk_t));
1635     *hp = hdcur;
1636     hp->next = holdinglist;
1637     holdinglist = hp;
1638 }
1639
1640
1641 /* WARNING:
1642  * This function is called both from this module and from diskfile.c. Modify
1643  * with caution. */
1644 dumptype_t *
1645 read_dumptype(
1646     char *name,
1647     FILE *from,
1648     char *fname,
1649     int *linenum)
1650 {
1651     int save_overwrites;
1652     FILE *saved_conf = NULL;
1653     char *saved_fname = NULL;
1654
1655     if (from) {
1656         saved_conf = current_file;
1657         current_file = from;
1658     }
1659
1660     if (fname) {
1661         saved_fname = current_filename;
1662         current_filename = fname;
1663     }
1664
1665     if (linenum)
1666         current_line_num = *linenum;
1667
1668     save_overwrites = allow_overwrites;
1669     allow_overwrites = 1;
1670
1671     init_dumptype_defaults();
1672     if (name) {
1673         dpcur.name = name;
1674     } else {
1675         get_conftoken(CONF_IDENT);
1676         dpcur.name = stralloc(tokenval.v.s);
1677     }
1678     dpcur.seen = current_line_num;
1679
1680     read_block(dumptype_var, dpcur.value,
1681                _("dumptype parameter expected"),
1682                (name == NULL), copy_dumptype);
1683
1684     if(!name) /* !name => reading disklist, not conffile */
1685         get_conftoken(CONF_NL);
1686
1687     /* XXX - there was a stupidity check in here for skip-incr and
1688     ** skip-full.  This check should probably be somewhere else. */
1689
1690     save_dumptype();
1691
1692     allow_overwrites = save_overwrites;
1693
1694     if (linenum)
1695         *linenum = current_line_num;
1696
1697     if (fname)
1698         current_filename = saved_fname;
1699
1700     if (from)
1701         current_file = saved_conf;
1702
1703     return lookup_dumptype(dpcur.name);
1704 }
1705
1706 static void
1707 get_dumptype(void)
1708 {
1709     read_dumptype(NULL, NULL, NULL, NULL);
1710 }
1711
1712 static void
1713 init_dumptype_defaults(void)
1714 {
1715     dpcur.name = NULL;
1716     conf_init_str   (&dpcur.value[DUMPTYPE_COMMENT]           , "");
1717     conf_init_str   (&dpcur.value[DUMPTYPE_PROGRAM]           , "DUMP");
1718     conf_init_str   (&dpcur.value[DUMPTYPE_SRVCOMPPROG]       , "");
1719     conf_init_str   (&dpcur.value[DUMPTYPE_CLNTCOMPPROG]      , "");
1720     conf_init_str   (&dpcur.value[DUMPTYPE_SRV_ENCRYPT]       , "");
1721     conf_init_str   (&dpcur.value[DUMPTYPE_CLNT_ENCRYPT]      , "");
1722     conf_init_str   (&dpcur.value[DUMPTYPE_AMANDAD_PATH]      , "X");
1723     conf_init_str   (&dpcur.value[DUMPTYPE_CLIENT_USERNAME]   , "X");
1724     conf_init_str   (&dpcur.value[DUMPTYPE_SSH_KEYS]          , "X");
1725     conf_init_str   (&dpcur.value[DUMPTYPE_SECURITY_DRIVER]   , "BSD");
1726     conf_init_exinclude(&dpcur.value[DUMPTYPE_EXCLUDE]);
1727     conf_init_exinclude(&dpcur.value[DUMPTYPE_INCLUDE]);
1728     conf_init_priority (&dpcur.value[DUMPTYPE_PRIORITY]          , 1);
1729     conf_init_int      (&dpcur.value[DUMPTYPE_DUMPCYCLE]         , conf_data[CNF_DUMPCYCLE].v.i);
1730     conf_init_int      (&dpcur.value[DUMPTYPE_MAXDUMPS]          , conf_data[CNF_MAXDUMPS].v.i);
1731     conf_init_int      (&dpcur.value[DUMPTYPE_MAXPROMOTEDAY]     , 10000);
1732     conf_init_int      (&dpcur.value[DUMPTYPE_BUMPPERCENT]       , conf_data[CNF_BUMPPERCENT].v.i);
1733     conf_init_am64     (&dpcur.value[DUMPTYPE_BUMPSIZE]          , conf_data[CNF_BUMPSIZE].v.am64);
1734     conf_init_int      (&dpcur.value[DUMPTYPE_BUMPDAYS]          , conf_data[CNF_BUMPDAYS].v.i);
1735     conf_init_real     (&dpcur.value[DUMPTYPE_BUMPMULT]          , conf_data[CNF_BUMPMULT].v.r);
1736     conf_init_time     (&dpcur.value[DUMPTYPE_STARTTIME]         , (time_t)0);
1737     conf_init_strategy (&dpcur.value[DUMPTYPE_STRATEGY]          , DS_STANDARD);
1738     conf_init_estimate (&dpcur.value[DUMPTYPE_ESTIMATE]          , ES_CLIENT);
1739     conf_init_compress (&dpcur.value[DUMPTYPE_COMPRESS]          , COMP_FAST);
1740     conf_init_encrypt  (&dpcur.value[DUMPTYPE_ENCRYPT]           , ENCRYPT_NONE);
1741     conf_init_str   (&dpcur.value[DUMPTYPE_SRV_DECRYPT_OPT]   , "-d");
1742     conf_init_str   (&dpcur.value[DUMPTYPE_CLNT_DECRYPT_OPT]  , "-d");
1743     conf_init_rate     (&dpcur.value[DUMPTYPE_COMPRATE]          , 0.50, 0.50);
1744     conf_init_am64     (&dpcur.value[DUMPTYPE_TAPE_SPLITSIZE]    , (off_t)0);
1745     conf_init_am64     (&dpcur.value[DUMPTYPE_FALLBACK_SPLITSIZE], (off_t)10 * 1024);
1746     conf_init_str   (&dpcur.value[DUMPTYPE_SPLIT_DISKBUFFER]  , NULL);
1747     conf_init_bool     (&dpcur.value[DUMPTYPE_RECORD]            , 1);
1748     conf_init_bool     (&dpcur.value[DUMPTYPE_SKIP_INCR]         , 0);
1749     conf_init_bool     (&dpcur.value[DUMPTYPE_SKIP_FULL]         , 0);
1750     conf_init_holding  (&dpcur.value[DUMPTYPE_HOLDINGDISK]       , HOLD_AUTO);
1751     conf_init_bool     (&dpcur.value[DUMPTYPE_KENCRYPT]          , 0);
1752     conf_init_bool     (&dpcur.value[DUMPTYPE_IGNORE]            , 0);
1753     conf_init_bool     (&dpcur.value[DUMPTYPE_INDEX]             , 1);
1754 }
1755
1756 static void
1757 save_dumptype(void)
1758 {
1759     dumptype_t *dp, *dp1;;
1760
1761     dp = lookup_dumptype(dpcur.name);
1762
1763     if(dp != (dumptype_t *)0) {
1764         conf_parserror(_("dumptype %s already defined on line %d"), dp->name, dp->seen);
1765         return;
1766     }
1767
1768     dp = alloc(sizeof(dumptype_t));
1769     *dp = dpcur;
1770     dp->next = NULL;
1771     /* add at end of list */
1772     if(!dumplist)
1773         dumplist = dp;
1774     else {
1775         dp1 = dumplist;
1776         while (dp1->next != NULL) {
1777              dp1 = dp1->next;
1778         }
1779         dp1->next = dp;
1780     }
1781 }
1782
1783 static void
1784 copy_dumptype(void)
1785 {
1786     dumptype_t *dt;
1787     int i;
1788
1789     dt = lookup_dumptype(tokenval.v.s);
1790
1791     if(dt == NULL) {
1792         conf_parserror(_("dumptype parameter expected"));
1793         return;
1794     }
1795
1796     for(i=0; i < DUMPTYPE_DUMPTYPE; i++) {
1797         if(dt->value[i].seen) {
1798             free_val_t(&dpcur.value[i]);
1799             copy_val_t(&dpcur.value[i], &dt->value[i]);
1800         }
1801     }
1802 }
1803
1804 static void
1805 get_tapetype(void)
1806 {
1807     int save_overwrites;
1808
1809     save_overwrites = allow_overwrites;
1810     allow_overwrites = 1;
1811
1812     init_tapetype_defaults();
1813
1814     get_conftoken(CONF_IDENT);
1815     tpcur.name = stralloc(tokenval.v.s);
1816     tpcur.seen = current_line_num;
1817
1818     read_block(tapetype_var, tpcur.value,
1819                _("tapetype parameter expected"), 1, copy_tapetype);
1820     get_conftoken(CONF_NL);
1821
1822     if (tapetype_get_readblocksize(&tpcur) <
1823         tapetype_get_blocksize(&tpcur)) {
1824         conf_init_size(&tpcur.value[TAPETYPE_READBLOCKSIZE],
1825                        tapetype_get_blocksize(&tpcur));
1826     }
1827     save_tapetype();
1828
1829     allow_overwrites = save_overwrites;
1830 }
1831
1832 static void
1833 init_tapetype_defaults(void)
1834 {
1835     conf_init_str(&tpcur.value[TAPETYPE_COMMENT]      , "");
1836     conf_init_str(&tpcur.value[TAPETYPE_LBL_TEMPL]    , "");
1837     conf_init_size  (&tpcur.value[TAPETYPE_BLOCKSIZE]    , DISK_BLOCK_KB);
1838     conf_init_size  (&tpcur.value[TAPETYPE_READBLOCKSIZE], MAX_TAPE_BLOCK_KB);
1839     conf_init_am64  (&tpcur.value[TAPETYPE_LENGTH]       , ((off_t)2000 * 1024));
1840     conf_init_am64  (&tpcur.value[TAPETYPE_FILEMARK]     , (off_t)1000);
1841     conf_init_int   (&tpcur.value[TAPETYPE_SPEED]        , 200);
1842     conf_init_bool  (&tpcur.value[TAPETYPE_FILE_PAD]     , 1);
1843 }
1844
1845 static void
1846 save_tapetype(void)
1847 {
1848     tapetype_t *tp, *tp1;
1849
1850     tp = lookup_tapetype(tpcur.name);
1851
1852     if(tp != (tapetype_t *)0) {
1853         amfree(tpcur.name);
1854         conf_parserror(_("tapetype %s already defined on line %d"), tp->name, tp->seen);
1855         return;
1856     }
1857
1858     tp = alloc(sizeof(tapetype_t));
1859     *tp = tpcur;
1860     /* add at end of list */
1861     if(!tapelist)
1862         tapelist = tp;
1863     else {
1864         tp1 = tapelist;
1865         while (tp1->next != NULL) {
1866             tp1 = tp1->next;
1867         }
1868         tp1->next = tp;
1869     }
1870 }
1871
1872 static void
1873 copy_tapetype(void)
1874 {
1875     tapetype_t *tp;
1876     int i;
1877
1878     tp = lookup_tapetype(tokenval.v.s);
1879
1880     if(tp == NULL) {
1881         conf_parserror(_("tape type parameter expected"));
1882         return;
1883     }
1884
1885     for(i=0; i < TAPETYPE_TAPETYPE; i++) {
1886         if(tp->value[i].seen) {
1887             free_val_t(&tpcur.value[i]);
1888             copy_val_t(&tpcur.value[i], &tp->value[i]);
1889         }
1890     }
1891 }
1892
1893 static void
1894 get_interface(void)
1895 {
1896     int save_overwrites;
1897
1898     save_overwrites = allow_overwrites;
1899     allow_overwrites = 1;
1900
1901     init_interface_defaults();
1902
1903     get_conftoken(CONF_IDENT);
1904     ifcur.name = stralloc(tokenval.v.s);
1905     ifcur.seen = current_line_num;
1906
1907     read_block(interface_var, ifcur.value,
1908                _("interface parameter expected"), 1, copy_interface);
1909     get_conftoken(CONF_NL);
1910
1911     save_interface();
1912
1913     allow_overwrites = save_overwrites;
1914
1915     return;
1916 }
1917
1918 static void
1919 init_interface_defaults(void)
1920 {
1921     conf_init_str(&ifcur.value[INTER_COMMENT] , "");
1922     conf_init_int   (&ifcur.value[INTER_MAXUSAGE], 8000);
1923 }
1924
1925 static void
1926 save_interface(void)
1927 {
1928     interface_t *ip, *ip1;
1929
1930     ip = lookup_interface(ifcur.name);
1931
1932     if(ip != (interface_t *)0) {
1933         conf_parserror(_("interface %s already defined on line %d"), ip->name,
1934                        ip->seen);
1935         return;
1936     }
1937
1938     ip = alloc(sizeof(interface_t));
1939     *ip = ifcur;
1940     /* add at end of list */
1941     if(!interface_list) {
1942         interface_list = ip;
1943     } else {
1944         ip1 = interface_list;
1945         while (ip1->next != NULL) {
1946             ip1 = ip1->next;
1947         }
1948         ip1->next = ip;
1949     }
1950 }
1951
1952 static void
1953 copy_interface(void)
1954 {
1955     interface_t *ip;
1956     int i;
1957
1958     ip = lookup_interface(tokenval.v.s);
1959
1960     if(ip == NULL) {
1961         conf_parserror(_("interface parameter expected"));
1962         return;
1963     }
1964
1965     for(i=0; i < INTER_INTER; i++) {
1966         if(ip->value[i].seen) {
1967             free_val_t(&ifcur.value[i]);
1968             copy_val_t(&ifcur.value[i], &ip->value[i]);
1969         }
1970     }
1971 }
1972
1973 /* Read functions */
1974
1975 static void
1976 read_int(
1977     conf_var_t *np G_GNUC_UNUSED,
1978     val_t *val)
1979 {
1980     ckseen(&val->seen);
1981     val_t__int(val) = get_int();
1982 }
1983
1984 static void
1985 read_am64(
1986     conf_var_t *np G_GNUC_UNUSED,
1987     val_t *val)
1988 {
1989     ckseen(&val->seen);
1990     val_t__am64(val) = get_am64_t();
1991 }
1992
1993 static void
1994 read_real(
1995     conf_var_t *np G_GNUC_UNUSED,
1996     val_t *val)
1997 {
1998     ckseen(&val->seen);
1999     get_conftoken(CONF_REAL);
2000     val_t__real(val) = tokenval.v.r;
2001 }
2002
2003 static void
2004 read_str(
2005     conf_var_t *np G_GNUC_UNUSED,
2006     val_t *val)
2007 {
2008     ckseen(&val->seen);
2009     get_conftoken(CONF_STRING);
2010     val->v.s = newstralloc(val->v.s, tokenval.v.s);
2011 }
2012
2013 static void
2014 read_ident(
2015     conf_var_t *np G_GNUC_UNUSED,
2016     val_t *val)
2017 {
2018     ckseen(&val->seen);
2019     get_conftoken(CONF_IDENT);
2020     val->v.s = newstralloc(val->v.s, tokenval.v.s);
2021 }
2022
2023 static void
2024 read_time(
2025     conf_var_t *np G_GNUC_UNUSED,
2026     val_t *val)
2027 {
2028     ckseen(&val->seen);
2029     val_t__time(val) = get_time();
2030 }
2031
2032 static void
2033 read_size(
2034     conf_var_t *np G_GNUC_UNUSED,
2035     val_t *val)
2036 {
2037     ckseen(&val->seen);
2038     val_t__size(val) = get_size();
2039 }
2040
2041 static void
2042 read_bool(
2043     conf_var_t *np G_GNUC_UNUSED,
2044     val_t *val)
2045 {
2046     ckseen(&val->seen);
2047     val_t__boolean(val) = get_bool();
2048 }
2049
2050 static void
2051 read_compress(
2052     conf_var_t *np G_GNUC_UNUSED,
2053     val_t *val)
2054 {
2055     int serv, clie, none, fast, best, custom;
2056     int done;
2057     comp_t comp;
2058
2059     ckseen(&val->seen);
2060
2061     serv = clie = none = fast = best = custom  = 0;
2062
2063     done = 0;
2064     do {
2065         get_conftoken(CONF_ANY);
2066         switch(tok) {
2067         case CONF_NONE:   none = 1; break;
2068         case CONF_FAST:   fast = 1; break;
2069         case CONF_BEST:   best = 1; break;
2070         case CONF_CLIENT: clie = 1; break;
2071         case CONF_SERVER: serv = 1; break;
2072         case CONF_CUSTOM: custom=1; break;
2073         case CONF_NL:     done = 1; break;
2074         case CONF_END:    done = 1; break;
2075         default:
2076             done = 1;
2077             serv = clie = 1; /* force an error */
2078         }
2079     } while(!done);
2080
2081     if(serv + clie == 0) clie = 1;      /* default to client */
2082     if(none + fast + best + custom  == 0) fast = 1; /* default to fast */
2083
2084     comp = -1;
2085
2086     if(!serv && clie) {
2087         if(none && !fast && !best && !custom) comp = COMP_NONE;
2088         if(!none && fast && !best && !custom) comp = COMP_FAST;
2089         if(!none && !fast && best && !custom) comp = COMP_BEST;
2090         if(!none && !fast && !best && custom) comp = COMP_CUST;
2091     }
2092
2093     if(serv && !clie) {
2094         if(none && !fast && !best && !custom) comp = COMP_NONE;
2095         if(!none && fast && !best && !custom) comp = COMP_SERVER_FAST;
2096         if(!none && !fast && best && !custom) comp = COMP_SERVER_BEST;
2097         if(!none && !fast && !best && custom) comp = COMP_SERVER_CUST;
2098     }
2099
2100     if((int)comp == -1) {
2101         conf_parserror(_("NONE, CLIENT FAST, CLIENT BEST, CLIENT CUSTOM, SERVER FAST, SERVER BEST or SERVER CUSTOM expected"));
2102         comp = COMP_NONE;
2103     }
2104
2105     val_t__compress(val) = (int)comp;
2106 }
2107
2108 static void
2109 read_encrypt(
2110     conf_var_t *np G_GNUC_UNUSED,
2111     val_t *val)
2112 {
2113    encrypt_t encrypt;
2114
2115    ckseen(&val->seen);
2116
2117    get_conftoken(CONF_ANY);
2118    switch(tok) {
2119    case CONF_NONE:  
2120      encrypt = ENCRYPT_NONE; 
2121      break;
2122
2123    case CONF_CLIENT:  
2124      encrypt = ENCRYPT_CUST;
2125      break;
2126
2127    case CONF_SERVER: 
2128      encrypt = ENCRYPT_SERV_CUST;
2129      break;
2130
2131    default:
2132      conf_parserror(_("NONE, CLIENT or SERVER expected"));
2133      encrypt = ENCRYPT_NONE;
2134      break;
2135    }
2136
2137    val_t__encrypt(val) = (int)encrypt;
2138 }
2139
2140 static void
2141 read_holding(
2142     conf_var_t *np G_GNUC_UNUSED,
2143     val_t *val)
2144 {
2145    dump_holdingdisk_t holding;
2146
2147    ckseen(&val->seen);
2148
2149    get_conftoken(CONF_ANY);
2150    switch(tok) {
2151    case CONF_NEVER:  
2152      holding = HOLD_NEVER; 
2153      break;
2154
2155    case CONF_AUTO:  
2156      holding = HOLD_AUTO;
2157      break;
2158
2159    case CONF_REQUIRED: 
2160      holding = HOLD_REQUIRED;
2161      break;
2162
2163    default: /* can be a BOOLEAN */
2164      unget_conftoken();
2165      holding =  (dump_holdingdisk_t)get_bool();
2166      if (holding == 0)
2167         holding = HOLD_NEVER;
2168      else if (holding == 1 || holding == 2)
2169         holding = HOLD_AUTO;
2170      else
2171         conf_parserror(_("NEVER, AUTO or REQUIRED expected"));
2172      break;
2173    }
2174
2175    val_t__holding(val) = (int)holding;
2176 }
2177
2178 static void
2179 read_estimate(
2180     conf_var_t *np G_GNUC_UNUSED,
2181     val_t *val)
2182 {
2183     int estime;
2184
2185     ckseen(&val->seen);
2186
2187     get_conftoken(CONF_ANY);
2188     switch(tok) {
2189     case CONF_CLIENT:
2190         estime = ES_CLIENT;
2191         break;
2192     case CONF_SERVER:
2193         estime = ES_SERVER;
2194         break;
2195     case CONF_CALCSIZE:
2196         estime = ES_CALCSIZE;
2197         break;
2198     default:
2199         conf_parserror(_("CLIENT, SERVER or CALCSIZE expected"));
2200         estime = ES_CLIENT;
2201     }
2202     val_t__estimate(val) = estime;
2203 }
2204
2205 static void
2206 read_strategy(
2207     conf_var_t *np G_GNUC_UNUSED,
2208     val_t *val)
2209 {
2210     int strat;
2211
2212     ckseen(&val->seen);
2213
2214     get_conftoken(CONF_ANY);
2215     switch(tok) {
2216     case CONF_SKIP:
2217         strat = DS_SKIP;
2218         break;
2219     case CONF_STANDARD:
2220         strat = DS_STANDARD;
2221         break;
2222     case CONF_NOFULL:
2223         strat = DS_NOFULL;
2224         break;
2225     case CONF_NOINC:
2226         strat = DS_NOINC;
2227         break;
2228     case CONF_HANOI:
2229         strat = DS_HANOI;
2230         break;
2231     case CONF_INCRONLY:
2232         strat = DS_INCRONLY;
2233         break;
2234     default:
2235         conf_parserror(_("dump strategy expected"));
2236         strat = DS_STANDARD;
2237     }
2238     val_t__strategy(val) = strat;
2239 }
2240
2241 static void
2242 read_taperalgo(
2243     conf_var_t *np G_GNUC_UNUSED,
2244     val_t *val)
2245 {
2246     ckseen(&val->seen);
2247
2248     get_conftoken(CONF_ANY);
2249     switch(tok) {
2250     case CONF_FIRST:      val_t__taperalgo(val) = ALGO_FIRST;      break;
2251     case CONF_FIRSTFIT:   val_t__taperalgo(val) = ALGO_FIRSTFIT;   break;
2252     case CONF_LARGEST:    val_t__taperalgo(val) = ALGO_LARGEST;    break;
2253     case CONF_LARGESTFIT: val_t__taperalgo(val) = ALGO_LARGESTFIT; break;
2254     case CONF_SMALLEST:   val_t__taperalgo(val) = ALGO_SMALLEST;   break;
2255     case CONF_LAST:       val_t__taperalgo(val) = ALGO_LAST;       break;
2256     default:
2257         conf_parserror(_("FIRST, FIRSTFIT, LARGEST, LARGESTFIT, SMALLEST or LAST expected"));
2258     }
2259 }
2260
2261 static void
2262 read_priority(
2263     conf_var_t *np G_GNUC_UNUSED,
2264     val_t *val)
2265 {
2266     int pri;
2267
2268     ckseen(&val->seen);
2269
2270     get_conftoken(CONF_ANY);
2271     switch(tok) {
2272     case CONF_LOW: pri = 0; break;
2273     case CONF_MEDIUM: pri = 1; break;
2274     case CONF_HIGH: pri = 2; break;
2275     case CONF_INT: pri = tokenval.v.i; break;
2276     default:
2277         conf_parserror(_("LOW, MEDIUM, HIGH or integer expected"));
2278         pri = 0;
2279     }
2280     val_t__priority(val) = pri;
2281 }
2282
2283 static void
2284 read_rate(
2285     conf_var_t *np G_GNUC_UNUSED,
2286     val_t *val)
2287 {
2288     get_conftoken(CONF_REAL);
2289     val_t__rate(val)[0] = tokenval.v.r;
2290     val_t__rate(val)[1] = tokenval.v.r;
2291     val->seen = tokenval.seen;
2292     if(tokenval.v.r < 0) {
2293         conf_parserror(_("full compression rate must be >= 0"));
2294     }
2295
2296     get_conftoken(CONF_ANY);
2297     switch(tok) {
2298     case CONF_NL:
2299         return;
2300
2301     case CONF_END:
2302         return;
2303
2304     case CONF_COMMA:
2305         break;
2306
2307     default:
2308         unget_conftoken();
2309     }
2310
2311     get_conftoken(CONF_REAL);
2312     val_t__rate(val)[1] = tokenval.v.r;
2313     if(tokenval.v.r < 0) {
2314         conf_parserror(_("incremental compression rate must be >= 0"));
2315     }
2316 }
2317
2318 static void
2319 read_exinclude(
2320     conf_var_t *np G_GNUC_UNUSED,
2321     val_t *val)
2322 {
2323     int file, got_one = 0;
2324     sl_t *exclude;
2325     int optional = 0;
2326
2327     get_conftoken(CONF_ANY);
2328     if(tok == CONF_LIST) {
2329         file = 0;
2330         get_conftoken(CONF_ANY);
2331         exclude = val_t__exinclude(val).sl_list;
2332     }
2333     else {
2334         file = 1;
2335         if(tok == CONF_EFILE) get_conftoken(CONF_ANY);
2336         exclude = val_t__exinclude(val).sl_file;
2337     }
2338     ckseen(&val->seen);
2339
2340     if(tok == CONF_OPTIONAL) {
2341         get_conftoken(CONF_ANY);
2342         optional = 1;
2343     }
2344
2345     if(tok == CONF_APPEND) {
2346         get_conftoken(CONF_ANY);
2347     }
2348     else {
2349         free_sl(exclude);
2350         exclude = NULL;
2351     }
2352
2353     while(tok == CONF_STRING) {
2354         exclude = append_sl(exclude, tokenval.v.s);
2355         got_one = 1;
2356         get_conftoken(CONF_ANY);
2357     }
2358     unget_conftoken();
2359
2360     if(got_one == 0) { free_sl(exclude); exclude = NULL; }
2361
2362     if (file == 0)
2363         val_t__exinclude(val).sl_list = exclude;
2364     else
2365         val_t__exinclude(val).sl_file = exclude;
2366     val_t__exinclude(val).optional = optional;
2367 }
2368
2369 static void
2370 read_intrange(
2371     conf_var_t *np G_GNUC_UNUSED,
2372     val_t *val)
2373 {
2374     get_conftoken(CONF_INT);
2375     val_t__intrange(val)[0] = tokenval.v.i;
2376     val_t__intrange(val)[1] = tokenval.v.i;
2377     val->seen = tokenval.seen;
2378
2379     get_conftoken(CONF_ANY);
2380     switch(tok) {
2381     case CONF_NL:
2382         return;
2383
2384     case CONF_END:
2385         return;
2386
2387     case CONF_COMMA:
2388         break;
2389
2390     default:
2391         unget_conftoken();
2392     }
2393
2394     get_conftoken(CONF_INT);
2395     val_t__intrange(val)[1] = tokenval.v.i;
2396 }
2397
2398 static void
2399 read_property(
2400     conf_var_t *np G_GNUC_UNUSED,
2401     val_t *val)
2402 {
2403     char *key, *value;
2404     get_conftoken(CONF_STRING);
2405     key = strdup(tokenval.v.s);
2406     get_conftoken(CONF_STRING);
2407     value = strdup(tokenval.v.s);
2408
2409     g_hash_table_insert(val_t__proplist(val), key, value);
2410 }
2411
2412 /* get_* functions */
2413
2414 static time_t
2415 get_time(void)
2416 {
2417     time_t hhmm;
2418
2419     get_conftoken(CONF_ANY);
2420     switch(tok) {
2421     case CONF_INT:
2422 #if SIZEOF_TIME_T < SIZEOF_INT
2423         if ((off_t)tokenval.v.i >= (off_t)TIME_MAX)
2424             conf_parserror(_("value too large"));
2425 #endif
2426         hhmm = (time_t)tokenval.v.i;
2427         break;
2428
2429     case CONF_SIZE:
2430 #if SIZEOF_TIME_T < SIZEOF_SSIZE_T
2431         if ((off_t)tokenval.v.size >= (off_t)TIME_MAX)
2432             conf_parserror(_("value too large"));
2433 #endif
2434         hhmm = (time_t)tokenval.v.size;
2435         break;
2436
2437     case CONF_AM64:
2438 #if SIZEOF_TIME_T < SIZEOF_LONG_LONG
2439         if ((off_t)tokenval.v.am64 >= (off_t)TIME_MAX)
2440             conf_parserror(_("value too large"));
2441 #endif
2442         hhmm = (time_t)tokenval.v.am64;
2443         break;
2444
2445     case CONF_AMINFINITY:
2446         hhmm = TIME_MAX;
2447         break;
2448
2449     default:
2450         conf_parserror(_("a time is expected"));
2451         hhmm = 0;
2452         break;
2453     }
2454     return hhmm;
2455 }
2456
2457 static int
2458 get_int(void)
2459 {
2460     int val;
2461     keytab_t *save_kt;
2462
2463     save_kt = keytable;
2464     keytable = numb_keytable;
2465
2466     get_conftoken(CONF_ANY);
2467     switch(tok) {
2468     case CONF_INT:
2469         val = tokenval.v.i;
2470         break;
2471
2472     case CONF_SIZE:
2473 #if SIZEOF_INT < SIZEOF_SSIZE_T
2474         if ((off_t)tokenval.v.size > (off_t)INT_MAX)
2475             conf_parserror(_("value too large"));
2476         if ((off_t)tokenval.v.size < (off_t)INT_MIN)
2477             conf_parserror(_("value too small"));
2478 #endif
2479         val = (int)tokenval.v.size;
2480         break;
2481
2482     case CONF_AM64:
2483 #if SIZEOF_INT < SIZEOF_LONG_LONG
2484         if (tokenval.v.am64 > (off_t)INT_MAX)
2485             conf_parserror(_("value too large"));
2486         if (tokenval.v.am64 < (off_t)INT_MIN)
2487             conf_parserror(_("value too small"));
2488 #endif
2489         val = (int)tokenval.v.am64;
2490         break;
2491
2492     case CONF_AMINFINITY:
2493         val = INT_MAX;
2494         break;
2495
2496     default:
2497         conf_parserror(_("an integer is expected"));
2498         val = 0;
2499         break;
2500     }
2501
2502     /* get multiplier, if any */
2503     get_conftoken(CONF_ANY);
2504     switch(tok) {
2505     case CONF_NL:                       /* multiply by one */
2506     case CONF_END:
2507     case CONF_MULT1:
2508     case CONF_MULT1K:
2509         break;
2510
2511     case CONF_MULT7:
2512         if (val > (INT_MAX / 7))
2513             conf_parserror(_("value too large"));
2514         if (val < (INT_MIN / 7))
2515             conf_parserror(_("value too small"));
2516         val *= 7;
2517         break;
2518
2519     case CONF_MULT1M:
2520         if (val > (INT_MAX / 1024))
2521             conf_parserror(_("value too large"));
2522         if (val < (INT_MIN / 1024))
2523             conf_parserror(_("value too small"));
2524         val *= 1024;
2525         break;
2526
2527     case CONF_MULT1G:
2528         if (val > (INT_MAX / (1024 * 1024)))
2529             conf_parserror(_("value too large"));
2530         if (val < (INT_MIN / (1024 * 1024)))
2531             conf_parserror(_("value too small"));
2532         val *= 1024 * 1024;
2533         break;
2534
2535     default:    /* it was not a multiplier */
2536         unget_conftoken();
2537         break;
2538     }
2539
2540     keytable = save_kt;
2541     return val;
2542 }
2543
2544 static ssize_t
2545 get_size(void)
2546 {
2547     ssize_t val;
2548     keytab_t *save_kt;
2549
2550     save_kt = keytable;
2551     keytable = numb_keytable;
2552
2553     get_conftoken(CONF_ANY);
2554
2555     switch(tok) {
2556     case CONF_SIZE:
2557         val = tokenval.v.size;
2558         break;
2559
2560     case CONF_INT:
2561 #if SIZEOF_SIZE_T < SIZEOF_INT
2562         if ((off_t)tokenval.v.i > (off_t)SSIZE_MAX)
2563             conf_parserror(_("value too large"));
2564         if ((off_t)tokenval.v.i < (off_t)SSIZE_MIN)
2565             conf_parserror(_("value too small"));
2566 #endif
2567         val = (ssize_t)tokenval.v.i;
2568         break;
2569
2570     case CONF_AM64:
2571 #if SIZEOF_SIZE_T < SIZEOF_LONG_LONG
2572         if (tokenval.v.am64 > (off_t)SSIZE_MAX)
2573             conf_parserror(_("value too large"));
2574         if (tokenval.v.am64 < (off_t)SSIZE_MIN)
2575             conf_parserror(_("value too small"));
2576 #endif
2577         val = (ssize_t)tokenval.v.am64;
2578         break;
2579
2580     case CONF_AMINFINITY:
2581         val = (ssize_t)SSIZE_MAX;
2582         break;
2583
2584     default:
2585         conf_parserror(_("an integer is expected"));
2586         val = 0;
2587         break;
2588     }
2589
2590     /* get multiplier, if any */
2591     get_conftoken(CONF_ANY);
2592
2593     switch(tok) {
2594     case CONF_NL:                       /* multiply by one */
2595     case CONF_MULT1:
2596     case CONF_MULT1K:
2597         break;
2598
2599     case CONF_MULT7:
2600         if (val > (ssize_t)(SSIZE_MAX / 7))
2601             conf_parserror(_("value too large"));
2602         if (val < (ssize_t)(SSIZE_MIN / 7))
2603             conf_parserror(_("value too small"));
2604         val *= (ssize_t)7;
2605         break;
2606
2607     case CONF_MULT1M:
2608         if (val > (ssize_t)(SSIZE_MAX / (ssize_t)1024))
2609             conf_parserror(_("value too large"));
2610         if (val < (ssize_t)(SSIZE_MIN / (ssize_t)1024))
2611             conf_parserror(_("value too small"));
2612         val *= (ssize_t)1024;
2613         break;
2614
2615     case CONF_MULT1G:
2616         if (val > (ssize_t)(SSIZE_MAX / (1024 * 1024)))
2617             conf_parserror(_("value too large"));
2618         if (val < (ssize_t)(SSIZE_MIN / (1024 * 1024)))
2619             conf_parserror(_("value too small"));
2620         val *= (ssize_t)(1024 * 1024);
2621         break;
2622
2623     default:    /* it was not a multiplier */
2624         unget_conftoken();
2625         break;
2626     }
2627
2628     keytable = save_kt;
2629     return val;
2630 }
2631
2632 static off_t
2633 get_am64_t(void)
2634 {
2635     off_t val;
2636     keytab_t *save_kt;
2637
2638     save_kt = keytable;
2639     keytable = numb_keytable;
2640
2641     get_conftoken(CONF_ANY);
2642
2643     switch(tok) {
2644     case CONF_INT:
2645         val = (off_t)tokenval.v.i;
2646         break;
2647
2648     case CONF_SIZE:
2649         val = (off_t)tokenval.v.size;
2650         break;
2651
2652     case CONF_AM64:
2653         val = tokenval.v.am64;
2654         break;
2655
2656     case CONF_AMINFINITY:
2657         val = AM64_MAX;
2658         break;
2659
2660     default:
2661         conf_parserror(_("an integer is expected"));
2662         val = 0;
2663         break;
2664     }
2665
2666     /* get multiplier, if any */
2667     get_conftoken(CONF_ANY);
2668
2669     switch(tok) {
2670     case CONF_NL:                       /* multiply by one */
2671     case CONF_MULT1:
2672     case CONF_MULT1K:
2673         break;
2674
2675     case CONF_MULT7:
2676         if (val > AM64_MAX/7 || val < AM64_MIN/7)
2677             conf_parserror(_("value too large"));
2678         val *= 7;
2679         break;
2680
2681     case CONF_MULT1M:
2682         if (val > AM64_MAX/1024 || val < AM64_MIN/1024)
2683             conf_parserror(_("value too large"));
2684         val *= 1024;
2685         break;
2686
2687     case CONF_MULT1G:
2688         if (val > AM64_MAX/(1024*1024) || val < AM64_MIN/(1024*1024))
2689             conf_parserror(_("value too large"));
2690         val *= 1024*1024;
2691         break;
2692
2693     default:    /* it was not a multiplier */
2694         unget_conftoken();
2695         break;
2696     }
2697
2698     keytable = save_kt;
2699
2700     return val;
2701 }
2702
2703 static int
2704 get_bool(void)
2705 {
2706     int val;
2707     keytab_t *save_kt;
2708
2709     save_kt = keytable;
2710     keytable = bool_keytable;
2711
2712     get_conftoken(CONF_ANY);
2713
2714     switch(tok) {
2715     case CONF_INT:
2716         if (tokenval.v.i != 0)
2717             val = 1;
2718         else
2719             val = 0;
2720         break;
2721
2722     case CONF_SIZE:
2723         if (tokenval.v.size != (size_t)0)
2724             val = 1;
2725         else
2726             val = 0;
2727         break;
2728
2729     case CONF_AM64:
2730         if (tokenval.v.am64 != (off_t)0)
2731             val = 1;
2732         else
2733             val = 0;
2734         break;
2735
2736     case CONF_ATRUE:
2737         val = 1;
2738         break;
2739
2740     case CONF_AFALSE:
2741         val = 0;
2742         break;
2743
2744     case CONF_NL:
2745         unget_conftoken();
2746         val = 2; /* no argument - most likely TRUE */
2747         break;
2748     default:
2749         unget_conftoken();
2750         val = 3; /* a bad argument - most likely TRUE */
2751         conf_parserror(_("YES, NO, TRUE, FALSE, ON, OFF expected"));
2752         break;
2753     }
2754
2755     keytable = save_kt;
2756     return val;
2757 }
2758
2759 void
2760 ckseen(
2761     int *seen)
2762 {
2763     if (*seen && !allow_overwrites && current_line_num != -2) {
2764         conf_parserror(_("duplicate parameter, prev def on line %d"), *seen);
2765     }
2766     *seen = current_line_num;
2767 }
2768
2769 /* Validation functions */
2770
2771 static void
2772 validate_nonnegative(
2773     struct conf_var_s *np,
2774     val_t        *val)
2775 {
2776     switch(val->type) {
2777     case CONFTYPE_INT:
2778         if(val_t__int(val) < 0)
2779             conf_parserror(_("%s must be nonnegative"), get_token_name(np->token));
2780         break;
2781     case CONFTYPE_AM64:
2782         if(val_t__am64(val) < 0)
2783             conf_parserror(_("%s must be nonnegative"), get_token_name(np->token));
2784         break;
2785     case CONFTYPE_SIZE:
2786         if(val_t__size(val) < 0)
2787             conf_parserror(_("%s must be positive"), get_token_name(np->token));
2788         break;
2789     default:
2790         conf_parserror(_("validate_nonnegative invalid type %d\n"), val->type);
2791     }
2792 }
2793
2794 static void
2795 validate_positive(
2796     struct conf_var_s *np,
2797     val_t        *val)
2798 {
2799     switch(val->type) {
2800     case CONFTYPE_INT:
2801         if(val_t__int(val) < 1)
2802             conf_parserror(_("%s must be positive"), get_token_name(np->token));
2803         break;
2804     case CONFTYPE_AM64:
2805         if(val_t__am64(val) < 1)
2806             conf_parserror(_("%s must be positive"), get_token_name(np->token));
2807         break;
2808     case CONFTYPE_TIME:
2809         if(val_t__time(val) < 1)
2810             conf_parserror(_("%s must be positive"), get_token_name(np->token));
2811         break;
2812     case CONFTYPE_SIZE:
2813         if(val_t__size(val) < 1)
2814             conf_parserror(_("%s must be positive"), get_token_name(np->token));
2815         break;
2816     default:
2817         conf_parserror(_("validate_positive invalid type %d\n"), val->type);
2818     }
2819 }
2820
2821 static void
2822 validate_runspercycle(
2823     struct conf_var_s *np G_GNUC_UNUSED,
2824     val_t        *val)
2825 {
2826     if(val_t__int(val) < -1)
2827         conf_parserror(_("runspercycle must be >= -1"));
2828 }
2829
2830 static void
2831 validate_bumppercent(
2832     struct conf_var_s *np G_GNUC_UNUSED,
2833     val_t        *val)
2834 {
2835     if(val_t__int(val) < 0 || val_t__int(val) > 100)
2836         conf_parserror(_("bumppercent must be between 0 and 100"));
2837 }
2838
2839 static void
2840 validate_inparallel(
2841     struct conf_var_s *np G_GNUC_UNUSED,
2842     val_t        *val)
2843 {
2844     if(val_t__int(val) < 1 || val_t__int(val) >MAX_DUMPERS)
2845         conf_parserror(_("inparallel must be between 1 and MAX_DUMPERS (%d)"),
2846                        MAX_DUMPERS);
2847 }
2848
2849 static void
2850 validate_bumpmult(
2851     struct conf_var_s *np G_GNUC_UNUSED,
2852     val_t        *val)
2853 {
2854     if(val_t__real(val) < 0.999) {
2855         conf_parserror(_("bumpmult must one or more"));
2856     }
2857 }
2858
2859 static void
2860 validate_displayunit(
2861     struct conf_var_s *np G_GNUC_UNUSED,
2862     val_t        *val G_GNUC_UNUSED)
2863 {
2864     char *s = val_t__str(val);
2865     if (strlen(s) == 1) {
2866         switch (s[0]) {
2867             case 'K':
2868             case 'M':
2869             case 'G':
2870             case 'T':
2871                 return; /* all good */
2872
2873             /* lower-case values should get folded to upper case */
2874             case 'k':
2875             case 'm':
2876             case 'g':
2877             case 't':
2878                 s[0] = toupper(s[0]);
2879                 return;
2880
2881             default:    /* bad */
2882                 break;
2883         }
2884     }
2885     conf_parserror(_("displayunit must be k,m,g or t."));
2886 }
2887
2888 static void
2889 validate_reserve(
2890     struct conf_var_s *np G_GNUC_UNUSED,
2891     val_t        *val)
2892 {
2893     if(val_t__int(val) < 0 || val_t__int(val) > 100)
2894         conf_parserror(_("reserve must be between 0 and 100"));
2895 }
2896
2897 static void
2898 validate_use(
2899     struct conf_var_s *np G_GNUC_UNUSED,
2900     val_t        *val)
2901 {
2902     val_t__am64(val) = am_floor(val_t__am64(val), DISK_BLOCK_KB);
2903 }
2904
2905 static void
2906 validate_chunksize(
2907     struct conf_var_s *np G_GNUC_UNUSED,
2908     val_t        *val)
2909 {
2910     /* NOTE: this function modifies the target value (rounding) */
2911     if(val_t__am64(val) == 0) {
2912         val_t__am64(val) = ((AM64_MAX / 1024) - (2 * DISK_BLOCK_KB));
2913     }
2914     else if(val_t__am64(val) < 0) {
2915         conf_parserror(_("Negative chunksize (%lld) is no longer supported"), (long long)val_t__am64(val));
2916     }
2917     val_t__am64(val) = am_floor(val_t__am64(val), (off_t)DISK_BLOCK_KB);
2918     if (val_t__am64(val) < 2*DISK_BLOCK_KB) {
2919         conf_parserror("chunksize must be at least %dkb", 2*DISK_BLOCK_KB);
2920     }
2921 }
2922
2923 static void
2924 validate_blocksize(
2925     struct conf_var_s *np G_GNUC_UNUSED,
2926     val_t        *val)
2927 {
2928     if(val_t__size(val) < DISK_BLOCK_KB) {
2929         conf_parserror(_("Tape blocksize must be at least %d KBytes"),
2930                   DISK_BLOCK_KB);
2931     }
2932 }
2933
2934 static void
2935 validate_debug(
2936     struct conf_var_s *np G_GNUC_UNUSED,
2937     val_t        *val)
2938 {
2939     if(val_t__int(val) < 0 || val_t__int(val) > 9) {
2940         conf_parserror(_("Debug must be between 0 and 9"));
2941     }
2942 }
2943
2944 static void
2945 validate_port_range(
2946     val_t        *val,
2947     int          smallest,
2948     int          largest)
2949 {
2950     int i;
2951     /* check both values are in range */
2952     for (i = 0; i < 2; i++) {
2953         if(val_t__intrange(val)[0] < smallest || val_t__intrange(val)[0] > largest) {
2954             conf_parserror(_("portrange must be in the range %d to %d, inclusive"), smallest, largest);
2955         }
2956      }
2957
2958     /* and check they're in the right order and not equal */
2959     if (val_t__intrange(val)[0] > val_t__intrange(val)[1]) {
2960         conf_parserror(_("portranges must be in order from low to high"));
2961     }
2962 }
2963
2964 static void
2965 validate_reserved_port_range(
2966     struct conf_var_s *np G_GNUC_UNUSED,
2967     val_t        *val)
2968 {
2969     validate_port_range(val, 1, IPPORT_RESERVED-1);
2970 }
2971
2972 static void
2973 validate_unreserved_port_range(
2974     struct conf_var_s *np G_GNUC_UNUSED,
2975     val_t        *val)
2976 {
2977     validate_port_range(val, IPPORT_RESERVED, 65535);
2978 }
2979
2980 /*
2981  * Initialization Implementation
2982  */
2983
2984 gboolean
2985 config_init(
2986     config_init_flags flags,
2987     char *arg_config_name)
2988 {
2989     if (!(flags & CONFIG_INIT_OVERLAY)) {
2990         /* Clear out anything that's already in there */
2991         config_uninit();
2992
2993         /* and set everything to default values */
2994         init_defaults();
2995
2996         allow_overwrites = FALSE;
2997     } else {
2998         if (!config_initialized) {
2999             error(_("Attempt to overlay configuration with no existing configuration"));
3000             /* NOTREACHED */
3001         }
3002
3003         allow_overwrites = TRUE;
3004     }
3005
3006     /* store away our client-ness for later reference */
3007     config_client = flags & CONFIG_INIT_CLIENT;
3008
3009     if ((flags & CONFIG_INIT_EXPLICIT_NAME) && arg_config_name) {
3010         config_name = newstralloc(config_name, arg_config_name);
3011         config_dir = newvstralloc(config_dir, CONFIG_DIR, "/", arg_config_name, NULL);
3012     } else if (flags & CONFIG_INIT_USE_CWD) {
3013         char * cwd;
3014         
3015         cwd = get_original_cwd();
3016         if (!cwd) {
3017             /* (this isn't a config error, so it's always fatal) */
3018             error(_("Cannot determine current working directory"));
3019             /* NOTREACHED */
3020         }
3021
3022         config_dir = stralloc2(cwd, "/");
3023         if ((config_name = strrchr(cwd, '/')) != NULL) {
3024             config_name = stralloc(config_name + 1);
3025         }
3026
3027         amfree(cwd);
3028     } else if (flags & CONFIG_INIT_CLIENT) {
3029         amfree(config_name);
3030         config_dir = newstralloc(config_dir, CONFIG_DIR);
3031     } else {
3032         /* ok, then, we won't read anything (for e.g., amrestore) */
3033         amfree(config_name);
3034         amfree(config_dir);
3035     }
3036
3037     /* If we have a config_dir, we can try reading something */
3038     if (config_dir) {
3039         if (flags & CONFIG_INIT_CLIENT) {
3040             config_filename = newvstralloc(config_filename, config_dir, "/amanda-client.conf", NULL);
3041         } else {
3042             config_filename = newvstralloc(config_filename, config_dir, "/amanda.conf", NULL);
3043         }
3044
3045         /* try to read the file, and handle parse errors */
3046         if (!read_conffile(config_filename, flags & CONFIG_INIT_CLIENT)) {
3047             if (flags & CONFIG_INIT_FATAL) {
3048                 error(_("errors processing config file \"%s\""), config_filename);
3049                 /* NOTREACHED */
3050             } else {
3051                 g_warning(_("errors processing config file \"%s\" (non-fatal)"), config_filename);
3052                 return FALSE;
3053             }
3054         }
3055     } else {
3056         amfree(config_filename);
3057     }
3058
3059     update_derived_values(flags & CONFIG_INIT_CLIENT);
3060
3061     return TRUE;
3062 }
3063
3064 void
3065 config_uninit(void)
3066 {
3067     holdingdisk_t    *hp, *hpnext;
3068     dumptype_t       *dp, *dpnext;
3069     tapetype_t       *tp, *tpnext;
3070     interface_t      *ip, *ipnext;
3071     int               i;
3072
3073     if (!config_initialized) return;
3074
3075     for(hp=holdinglist; hp != NULL; hp = hpnext) {
3076         amfree(hp->name);
3077         for(i=0; i<HOLDING_HOLDING-1; i++) {
3078            free_val_t(&hp->value[i]);
3079         }
3080         hpnext = hp->next;
3081         amfree(hp);
3082     }
3083     holdinglist = NULL;
3084
3085     for(dp=dumplist; dp != NULL; dp = dpnext) {
3086         amfree(dp->name);
3087         for(i=0; i<DUMPTYPE_DUMPTYPE-1; i++) {
3088            free_val_t(&dp->value[i]);
3089         }
3090         dpnext = dp->next;
3091         amfree(dp);
3092     }
3093     dumplist = NULL;
3094
3095     for(tp=tapelist; tp != NULL; tp = tpnext) {
3096         amfree(tp->name);
3097         for(i=0; i<TAPETYPE_TAPETYPE-1; i++) {
3098            free_val_t(&tp->value[i]);
3099         }
3100         tpnext = tp->next;
3101         amfree(tp);
3102     }
3103     tapelist = NULL;
3104
3105     for(ip=interface_list; ip != NULL; ip = ipnext) {
3106         amfree(ip->name);
3107         for(i=0; i<INTER_INTER-1; i++) {
3108            free_val_t(&ip->value[i]);
3109         }
3110         ipnext = ip->next;
3111         amfree(ip);
3112     }
3113     interface_list = NULL;
3114
3115     for(i=0; i<CNF_CNF-1; i++)
3116         free_val_t(&conf_data[i]);
3117
3118     if (applied_config_overwrites) {
3119         free_config_overwrites(applied_config_overwrites);
3120         applied_config_overwrites = NULL;
3121     }
3122
3123     amfree(config_name);
3124     amfree(config_dir);
3125
3126     config_client = FALSE;
3127
3128     config_initialized = FALSE;
3129 }
3130
3131 static void
3132 init_defaults(
3133     void)
3134 {
3135     assert(!config_initialized);
3136
3137     /* defaults for exported variables */
3138     conf_init_str(&conf_data[CNF_ORG], DEFAULT_CONFIG);
3139     conf_init_str(&conf_data[CNF_CONF], DEFAULT_CONFIG);
3140     conf_init_str(&conf_data[CNF_INDEX_SERVER], DEFAULT_SERVER);
3141     conf_init_str(&conf_data[CNF_TAPE_SERVER], DEFAULT_TAPE_SERVER);
3142     conf_init_str(&conf_data[CNF_AUTH], "bsd");
3143     conf_init_str(&conf_data[CNF_SSH_KEYS], "");
3144     conf_init_str(&conf_data[CNF_AMANDAD_PATH], "");
3145     conf_init_str(&conf_data[CNF_CLIENT_USERNAME], "");
3146     conf_init_str(&conf_data[CNF_GNUTAR_LIST_DIR], GNUTAR_LISTED_INCREMENTAL_DIR);
3147     conf_init_str(&conf_data[CNF_AMANDATES], DEFAULT_AMANDATES_FILE);
3148     conf_init_str(&conf_data[CNF_MAILTO], "operators");
3149     conf_init_str(&conf_data[CNF_DUMPUSER], CLIENT_LOGIN);
3150     conf_init_str(&conf_data[CNF_TAPEDEV], DEFAULT_TAPE_DEVICE);
3151     conf_init_proplist(&conf_data[CNF_DEVICE_PROPERTY]);
3152     conf_init_str(&conf_data[CNF_CHANGERDEV], DEFAULT_CHANGER_DEVICE);
3153     conf_init_str(&conf_data[CNF_CHANGERFILE], "/usr/adm/amanda/changer-status");
3154     conf_init_str   (&conf_data[CNF_LABELSTR]             , ".*");
3155     conf_init_str   (&conf_data[CNF_TAPELIST]             , "tapelist");
3156     conf_init_str   (&conf_data[CNF_DISKFILE]             , "disklist");
3157     conf_init_str   (&conf_data[CNF_INFOFILE]             , "/usr/adm/amanda/curinfo");
3158     conf_init_str   (&conf_data[CNF_LOGDIR]               , "/usr/adm/amanda");
3159     conf_init_str   (&conf_data[CNF_INDEXDIR]             , "/usr/adm/amanda/index");
3160     conf_init_ident    (&conf_data[CNF_TAPETYPE]             , "EXABYTE");
3161     conf_init_int      (&conf_data[CNF_DUMPCYCLE]            , 10);
3162     conf_init_int      (&conf_data[CNF_RUNSPERCYCLE]         , 0);
3163     conf_init_int      (&conf_data[CNF_TAPECYCLE]            , 15);
3164     conf_init_int      (&conf_data[CNF_NETUSAGE]             , 8000);
3165     conf_init_int      (&conf_data[CNF_INPARALLEL]           , 10);
3166     conf_init_str   (&conf_data[CNF_DUMPORDER]            , "ttt");
3167     conf_init_int      (&conf_data[CNF_BUMPPERCENT]          , 0);
3168     conf_init_am64     (&conf_data[CNF_BUMPSIZE]             , (off_t)10*1024);
3169     conf_init_real     (&conf_data[CNF_BUMPMULT]             , 1.5);
3170     conf_init_int      (&conf_data[CNF_BUMPDAYS]             , 2);
3171     conf_init_str   (&conf_data[CNF_TPCHANGER]            , "");
3172     conf_init_int      (&conf_data[CNF_RUNTAPES]             , 1);
3173     conf_init_int      (&conf_data[CNF_MAXDUMPS]             , 1);
3174     conf_init_int      (&conf_data[CNF_ETIMEOUT]             , 300);
3175     conf_init_int      (&conf_data[CNF_DTIMEOUT]             , 1800);
3176     conf_init_int      (&conf_data[CNF_CTIMEOUT]             , 30);
3177     conf_init_int      (&conf_data[CNF_TAPEBUFS]             , 20);
3178     conf_init_size     (&conf_data[CNF_DEVICE_OUTPUT_BUFFER_SIZE], 40*32768);
3179     conf_init_str   (&conf_data[CNF_PRINTER]              , "");
3180     conf_init_bool     (&conf_data[CNF_AUTOFLUSH]            , 0);
3181     conf_init_int      (&conf_data[CNF_RESERVE]              , 100);
3182     conf_init_am64     (&conf_data[CNF_MAXDUMPSIZE]          , (off_t)-1);
3183     conf_init_str   (&conf_data[CNF_COLUMNSPEC]           , "");
3184     conf_init_bool     (&conf_data[CNF_AMRECOVER_DO_FSF]     , 1);
3185     conf_init_str   (&conf_data[CNF_AMRECOVER_CHANGER]    , "");
3186     conf_init_bool     (&conf_data[CNF_AMRECOVER_CHECK_LABEL], 1);
3187     conf_init_taperalgo(&conf_data[CNF_TAPERALGO]            , 0);
3188     conf_init_int      (&conf_data[CNF_FLUSH_THRESHOLD_DUMPED]   , 0);
3189     conf_init_int      (&conf_data[CNF_FLUSH_THRESHOLD_SCHEDULED], 0);
3190     conf_init_int      (&conf_data[CNF_TAPERFLUSH]               , 0);
3191     conf_init_str   (&conf_data[CNF_DISPLAYUNIT]          , "k");
3192     conf_init_str   (&conf_data[CNF_KRB5KEYTAB]           , "/.amanda-v5-keytab");
3193     conf_init_str   (&conf_data[CNF_KRB5PRINCIPAL]        , "service/amanda");
3194     conf_init_str   (&conf_data[CNF_LABEL_NEW_TAPES]      , "");
3195     conf_init_bool     (&conf_data[CNF_USETIMESTAMPS]        , 1);
3196     conf_init_int      (&conf_data[CNF_CONNECT_TRIES]        , 3);
3197     conf_init_int      (&conf_data[CNF_REP_TRIES]            , 5);
3198     conf_init_int      (&conf_data[CNF_REQ_TRIES]            , 3);
3199     conf_init_int      (&conf_data[CNF_DEBUG_AMANDAD]        , 0);
3200     conf_init_int      (&conf_data[CNF_DEBUG_AMIDXTAPED]     , 0);
3201     conf_init_int      (&conf_data[CNF_DEBUG_AMINDEXD]       , 0);
3202     conf_init_int      (&conf_data[CNF_DEBUG_AMRECOVER]      , 0);
3203     conf_init_int      (&conf_data[CNF_DEBUG_AUTH]           , 0);
3204     conf_init_int      (&conf_data[CNF_DEBUG_EVENT]          , 0);
3205     conf_init_int      (&conf_data[CNF_DEBUG_HOLDING]        , 0);
3206     conf_init_int      (&conf_data[CNF_DEBUG_PROTOCOL]       , 0);
3207     conf_init_int      (&conf_data[CNF_DEBUG_PLANNER]        , 0);
3208     conf_init_int      (&conf_data[CNF_DEBUG_DRIVER]         , 0);
3209     conf_init_int      (&conf_data[CNF_DEBUG_DUMPER]         , 0);
3210     conf_init_int      (&conf_data[CNF_DEBUG_CHUNKER]        , 0);
3211     conf_init_int      (&conf_data[CNF_DEBUG_TAPER]          , 0);
3212     conf_init_int      (&conf_data[CNF_DEBUG_SELFCHECK]      , 0);
3213     conf_init_int      (&conf_data[CNF_DEBUG_SENDSIZE]       , 0);
3214     conf_init_int      (&conf_data[CNF_DEBUG_SENDBACKUP]     , 0);
3215 #ifdef UDPPORTRANGE
3216     conf_init_intrange (&conf_data[CNF_RESERVED_UDP_PORT]    , UDPPORTRANGE);
3217 #else
3218     conf_init_intrange (&conf_data[CNF_RESERVED_UDP_PORT]    , 512, IPPORT_RESERVED-1);
3219 #endif
3220 #ifdef LOW_TCPPORTRANGE
3221     conf_init_intrange (&conf_data[CNF_RESERVED_TCP_PORT]    , LOW_TCPPORTRANGE);
3222 #else
3223     conf_init_intrange (&conf_data[CNF_RESERVED_TCP_PORT]    , 512, IPPORT_RESERVED-1);
3224 #endif
3225 #ifdef TCPPORTRANGE
3226     conf_init_intrange (&conf_data[CNF_UNRESERVED_TCP_PORT]  , TCPPORTRANGE);
3227 #else
3228     conf_init_intrange (&conf_data[CNF_UNRESERVED_TCP_PORT]  , IPPORT_RESERVED, 65535);
3229 #endif
3230
3231     /* reset internal variables */
3232     got_parserror = FALSE;
3233     allow_overwrites = 0;
3234     token_pushed = 0;
3235
3236     /* create some predefined dumptypes for backwards compatability */
3237     init_dumptype_defaults();
3238     dpcur.name = stralloc("NO-COMPRESS");
3239     dpcur.seen = -1;
3240     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
3241     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_NONE;
3242     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]) = -1;
3243     save_dumptype();
3244
3245     init_dumptype_defaults();
3246     dpcur.name = stralloc("COMPRESS-FAST");
3247     dpcur.seen = -1;
3248     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
3249     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_FAST;
3250     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]) = -1;
3251     save_dumptype();
3252
3253     init_dumptype_defaults();
3254     dpcur.name = stralloc("COMPRESS-BEST");
3255     dpcur.seen = -1;
3256     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
3257     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_BEST;
3258     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]) = -1;
3259     save_dumptype();
3260
3261     init_dumptype_defaults();
3262     dpcur.name = stralloc("COMPRESS-CUST");
3263     dpcur.seen = -1;
3264     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
3265     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_CUST;
3266     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]) = -1;
3267     save_dumptype();
3268
3269     init_dumptype_defaults();
3270     dpcur.name = stralloc("SRVCOMPRESS");
3271     dpcur.seen = -1;
3272     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
3273     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_SERVER_FAST;
3274     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]) = -1;
3275     save_dumptype();
3276
3277     init_dumptype_defaults();
3278     dpcur.name = stralloc("BSD-AUTH");
3279     dpcur.seen = -1;
3280     free_val_t(&dpcur.value[DUMPTYPE_SECURITY_DRIVER]);
3281     val_t__str(&dpcur.value[DUMPTYPE_SECURITY_DRIVER]) = stralloc("BSD");
3282     val_t__seen(&dpcur.value[DUMPTYPE_SECURITY_DRIVER]) = -1;
3283     save_dumptype();
3284
3285     init_dumptype_defaults();
3286     dpcur.name = stralloc("KRB4-AUTH");
3287     dpcur.seen = -1;
3288     free_val_t(&dpcur.value[DUMPTYPE_SECURITY_DRIVER]);
3289     val_t__str(&dpcur.value[DUMPTYPE_SECURITY_DRIVER]) = stralloc("KRB4");
3290     val_t__seen(&dpcur.value[DUMPTYPE_SECURITY_DRIVER]) = -1;
3291     save_dumptype();
3292
3293     init_dumptype_defaults();
3294     dpcur.name = stralloc("NO-RECORD");
3295     dpcur.seen = -1;
3296     free_val_t(&dpcur.value[DUMPTYPE_RECORD]);
3297     val_t__int(&dpcur.value[DUMPTYPE_RECORD]) = 0;
3298     val_t__seen(&dpcur.value[DUMPTYPE_RECORD]) = -1;
3299     save_dumptype();
3300
3301     init_dumptype_defaults();
3302     dpcur.name = stralloc("NO-HOLD");
3303     dpcur.seen = -1;
3304     free_val_t(&dpcur.value[DUMPTYPE_HOLDINGDISK]);
3305     val_t__holding(&dpcur.value[DUMPTYPE_HOLDINGDISK]) = HOLD_NEVER;
3306     val_t__seen(&dpcur.value[DUMPTYPE_HOLDINGDISK]) = -1;
3307     save_dumptype();
3308
3309     init_dumptype_defaults();
3310     dpcur.name = stralloc("NO-FULL");
3311     dpcur.seen = -1;
3312     free_val_t(&dpcur.value[DUMPTYPE_STRATEGY]);
3313     val_t__strategy(&dpcur.value[DUMPTYPE_STRATEGY]) = DS_NOFULL;
3314     val_t__seen(&dpcur.value[DUMPTYPE_STRATEGY]) = -1;
3315     save_dumptype();
3316
3317     /* And we're initialized! */
3318     config_initialized = 1;
3319 }
3320
3321 char **
3322 get_config_options(
3323     int first)
3324 {
3325     char             **config_options;
3326     char             **config_option;
3327     int              n_applied_config_overwrites = 0;
3328     int              i;
3329
3330     if (applied_config_overwrites)
3331         n_applied_config_overwrites = applied_config_overwrites->n_used;
3332
3333     config_options = alloc((first+n_applied_config_overwrites+1)*SIZEOF(char *));
3334     config_option = config_options + first;
3335
3336     for (i = 0; i < n_applied_config_overwrites; i++) {
3337         char *key = applied_config_overwrites->ovr[i].key;
3338         char *value = applied_config_overwrites->ovr[i].value;
3339         *config_option = vstralloc("-o", key, "=", value, NULL);
3340         config_option++;
3341     }
3342
3343     *config_option = NULL; /* add terminating sentinel */
3344
3345     return config_options;
3346 }
3347
3348 static void
3349 update_derived_values(
3350     gboolean is_client)
3351 {
3352     interface_t *ip;
3353
3354     if (!is_client) {
3355         /* Add a 'default' interface if one doesn't already exist */
3356         if (!(ip = lookup_interface("default"))) {
3357             init_interface_defaults();
3358             ifcur.name = stralloc("default");
3359             ifcur.seen = getconf_seen(CNF_NETUSAGE);
3360             save_interface();
3361
3362             ip = lookup_interface("default");
3363         }
3364
3365         /* .. and set its maxusage from 'netusage' */
3366         if (!interface_seen(ip, INTER_MAXUSAGE)) {
3367             val_t *v;
3368
3369             v = interface_getconf(ip, INTER_COMMENT);
3370             free_val_t(v);
3371             val_t__str(v) = stralloc(_("implicit from NETUSAGE"));
3372             val_t__seen(v) = getconf_seen(CNF_NETUSAGE);
3373
3374             v = interface_getconf(ip, INTER_MAXUSAGE);
3375             free_val_t(v);
3376             val_t__int(v) = getconf_int(CNF_NETUSAGE);
3377             val_t__seen(v) = getconf_seen(CNF_NETUSAGE);
3378         }
3379
3380         /* Check the tapetype is defined */
3381         if (lookup_tapetype(getconf_str(CNF_TAPETYPE)) == NULL) {
3382             /* Create a default tapetype */
3383             if (!getconf_seen(CNF_TAPETYPE) &&
3384                 strcmp(getconf_str(CNF_TAPETYPE), "EXABYTE") == 0 &&
3385                 !lookup_tapetype("EXABYTE")) {
3386                 init_tapetype_defaults();
3387                 tpcur.name = stralloc("EXABYTE");
3388                 tpcur.seen = -1;
3389                 save_tapetype();
3390             } else {
3391                 conf_parserror(_("tapetype %s is not defined"),
3392                                getconf_str(CNF_TAPETYPE));
3393             }
3394         }
3395     }
3396
3397     /* fill in the debug_* values */
3398     debug_amandad    = getconf_int(CNF_DEBUG_AMANDAD);
3399     debug_amidxtaped = getconf_int(CNF_DEBUG_AMIDXTAPED);
3400     debug_amindexd   = getconf_int(CNF_DEBUG_AMINDEXD);
3401     debug_amrecover  = getconf_int(CNF_DEBUG_AMRECOVER);
3402     debug_auth       = getconf_int(CNF_DEBUG_AUTH);
3403     debug_event      = getconf_int(CNF_DEBUG_EVENT);
3404     debug_holding    = getconf_int(CNF_DEBUG_HOLDING);
3405     debug_protocol   = getconf_int(CNF_DEBUG_PROTOCOL);
3406     debug_planner    = getconf_int(CNF_DEBUG_PLANNER);
3407     debug_driver     = getconf_int(CNF_DEBUG_DRIVER);
3408     debug_dumper     = getconf_int(CNF_DEBUG_DUMPER);
3409     debug_chunker    = getconf_int(CNF_DEBUG_CHUNKER);
3410     debug_taper      = getconf_int(CNF_DEBUG_TAPER);
3411     debug_selfcheck  = getconf_int(CNF_DEBUG_SELFCHECK);
3412     debug_sendsize   = getconf_int(CNF_DEBUG_SENDSIZE);
3413     debug_sendbackup = getconf_int(CNF_DEBUG_SENDBACKUP);
3414
3415     /* And finally, display unit */
3416     switch (getconf_str(CNF_DISPLAYUNIT)[0]) {
3417         case 'k':
3418         case 'K':
3419             unit_divisor = 1;
3420             break;
3421
3422         case 'm':
3423         case 'M':
3424             unit_divisor = 1024;
3425             break;
3426
3427         case 'g':
3428         case 'G':
3429             unit_divisor = 1024*1024;
3430             break;
3431
3432         case 't':
3433         case 'T':
3434             unit_divisor = 1024*1024*1024;
3435             break;
3436
3437         default:
3438             error(_("Invalid displayunit missed by validate_displayunit"));
3439             /* NOTREACHED */
3440     }
3441 }
3442
3443 static void
3444 conf_init_int(
3445     val_t *val,
3446     int    i)
3447 {
3448     val->seen = 0;
3449     val->type = CONFTYPE_INT;
3450     val_t__int(val) = i;
3451 }
3452
3453 static void
3454 conf_init_am64(
3455     val_t *val,
3456     off_t   l)
3457 {
3458     val->seen = 0;
3459     val->type = CONFTYPE_AM64;
3460     val_t__am64(val) = l;
3461 }
3462
3463 static void
3464 conf_init_real(
3465     val_t  *val,
3466     float r)
3467 {
3468     val->seen = 0;
3469     val->type = CONFTYPE_REAL;
3470     val_t__real(val) = r;
3471 }
3472
3473 static void
3474 conf_init_str(
3475     val_t *val,
3476     char  *s)
3477 {
3478     val->seen = 0;
3479     val->type = CONFTYPE_STR;
3480     if(s)
3481         val->v.s = stralloc(s);
3482     else
3483         val->v.s = NULL;
3484 }
3485
3486 static void
3487 conf_init_ident(
3488     val_t *val,
3489     char  *s)
3490 {
3491     val->seen = 0;
3492     val->type = CONFTYPE_IDENT;
3493     if(s)
3494         val->v.s = stralloc(s);
3495     else
3496         val->v.s = NULL;
3497 }
3498
3499 static void
3500 conf_init_time(
3501     val_t *val,
3502     time_t   t)
3503 {
3504     val->seen = 0;
3505     val->type = CONFTYPE_TIME;
3506     val_t__time(val) = t;
3507 }
3508
3509 static void
3510 conf_init_size(
3511     val_t *val,
3512     ssize_t   sz)
3513 {
3514     val->seen = 0;
3515     val->type = CONFTYPE_SIZE;
3516     val_t__size(val) = sz;
3517 }
3518
3519 static void
3520 conf_init_bool(
3521     val_t *val,
3522     int    i)
3523 {
3524     val->seen = 0;
3525     val->type = CONFTYPE_BOOLEAN;
3526     val_t__boolean(val) = i;
3527 }
3528
3529 static void
3530 conf_init_compress(
3531     val_t *val,
3532     comp_t    i)
3533 {
3534     val->seen = 0;
3535     val->type = CONFTYPE_COMPRESS;
3536     val_t__compress(val) = (int)i;
3537 }
3538
3539 static void
3540 conf_init_encrypt(
3541     val_t *val,
3542     encrypt_t    i)
3543 {
3544     val->seen = 0;
3545     val->type = CONFTYPE_ENCRYPT;
3546     val_t__encrypt(val) = (int)i;
3547 }
3548
3549 static void
3550 conf_init_holding(
3551     val_t              *val,
3552     dump_holdingdisk_t  i)
3553 {
3554     val->seen = 0;
3555     val->type = CONFTYPE_HOLDING;
3556     val_t__holding(val) = (int)i;
3557 }
3558
3559 static void
3560 conf_init_estimate(
3561     val_t *val,
3562     estimate_t    i)
3563 {
3564     val->seen = 0;
3565     val->type = CONFTYPE_ESTIMATE;
3566     val_t__estimate(val) = i;
3567 }
3568
3569 static void
3570 conf_init_strategy(
3571     val_t *val,
3572     strategy_t    i)
3573 {
3574     val->seen = 0;
3575     val->type = CONFTYPE_STRATEGY;
3576     val_t__strategy(val) = i;
3577 }
3578
3579 static void
3580 conf_init_taperalgo(
3581     val_t *val,
3582     taperalgo_t    i)
3583 {
3584     val->seen = 0;
3585     val->type = CONFTYPE_TAPERALGO;
3586     val_t__taperalgo(val) = i;
3587 }
3588
3589 static void
3590 conf_init_priority(
3591     val_t *val,
3592     int    i)
3593 {
3594     val->seen = 0;
3595     val->type = CONFTYPE_PRIORITY;
3596     val_t__priority(val) = i;
3597 }
3598
3599 static void
3600 conf_init_rate(
3601     val_t  *val,
3602     float r1,
3603     float r2)
3604 {
3605     val->seen = 0;
3606     val->type = CONFTYPE_RATE;
3607     val_t__rate(val)[0] = r1;
3608     val_t__rate(val)[1] = r2;
3609 }
3610
3611 static void
3612 conf_init_exinclude(
3613     val_t *val)
3614 {
3615     val->seen = 0;
3616     val->type = CONFTYPE_EXINCLUDE;
3617     val_t__exinclude(val).optional = 0;
3618     val_t__exinclude(val).sl_list = NULL;
3619     val_t__exinclude(val).sl_file = NULL;
3620 }
3621
3622 static void
3623 conf_init_intrange(
3624     val_t *val,
3625     int    i1,
3626     int    i2)
3627 {
3628     val->seen = 0;
3629     val->type = CONFTYPE_INTRANGE;
3630     val_t__intrange(val)[0] = i1;
3631     val_t__intrange(val)[1] = i2;
3632 }
3633
3634 static void
3635 conf_init_proplist(
3636     val_t *val)
3637 {
3638     val->seen = 0;
3639     val->type = CONFTYPE_PROPLIST;
3640     val_t__proplist(val) =
3641         g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
3642 }
3643
3644 /*
3645  * Config access implementation
3646  */
3647
3648 val_t *
3649 getconf(confparm_key key)
3650 {
3651     assert(key < CNF_CNF);
3652     return &conf_data[key];
3653 }
3654
3655 GSList *
3656 getconf_list(
3657     char *listname)
3658 {
3659     tapetype_t *tp;
3660     dumptype_t *dp;
3661     interface_t *ip;
3662     holdingdisk_t *hp;
3663     GSList *rv = NULL;
3664
3665     if (strcasecmp(listname,"tapetype") == 0) {
3666         for(tp = tapelist; tp != NULL; tp=tp->next) {
3667             rv = g_slist_append(rv, tp->name);
3668         }
3669     } else if (strcasecmp(listname,"dumptype") == 0) {
3670         for(dp = dumplist; dp != NULL; dp=dp->next) {
3671             rv = g_slist_append(rv, dp->name);
3672         }
3673     } else if (strcasecmp(listname,"holdingdisk") == 0) {
3674         for(hp = holdinglist; hp != NULL; hp=hp->next) {
3675             rv = g_slist_append(rv, hp->name);
3676         }
3677     } else if (strcasecmp(listname,"interface") == 0) {
3678         for(ip = interface_list; ip != NULL; ip=ip->next) {
3679             rv = g_slist_append(rv, ip->name);
3680         }
3681     }
3682     return rv;
3683 }
3684
3685 val_t *
3686 getconf_byname(
3687     char *key)
3688 {
3689     val_t *rv = NULL;
3690
3691     if (!parm_key_info(key, NULL, &rv))
3692         return NULL;
3693
3694     return rv;
3695 }
3696
3697 tapetype_t *
3698 lookup_tapetype(
3699     char *str)
3700 {
3701     tapetype_t *p;
3702
3703     for(p = tapelist; p != NULL; p = p->next) {
3704         if(strcasecmp(p->name, str) == 0) return p;
3705     }
3706     return NULL;
3707 }
3708
3709 val_t *
3710 tapetype_getconf(
3711     tapetype_t *ttyp,
3712     tapetype_key key)
3713 {
3714     assert(ttyp != NULL);
3715     assert(key < TAPETYPE_TAPETYPE);
3716     return &ttyp->value[key];
3717 }
3718
3719 char *
3720 tapetype_name(
3721     tapetype_t *ttyp)
3722 {
3723     assert(ttyp != NULL);
3724     return ttyp->name;
3725 }
3726
3727 dumptype_t *
3728 lookup_dumptype(
3729     char *str)
3730 {
3731     dumptype_t *p;
3732
3733     for(p = dumplist; p != NULL; p = p->next) {
3734         if(strcasecmp(p->name, str) == 0) return p;
3735     }
3736     return NULL;
3737 }
3738
3739 val_t *
3740 dumptype_getconf(
3741     dumptype_t *dtyp,
3742     dumptype_key key)
3743 {
3744     assert(dtyp != NULL);
3745     assert(key < DUMPTYPE_DUMPTYPE);
3746     return &dtyp->value[key];
3747 }
3748
3749 char *
3750 dumptype_name(
3751     dumptype_t *dtyp)
3752 {
3753     assert(dtyp != NULL);
3754     return dtyp->name;
3755 }
3756
3757 interface_t *
3758 lookup_interface(
3759     char *str)
3760 {
3761     interface_t *p;
3762
3763     for(p = interface_list; p != NULL; p = p->next) {
3764         if(strcasecmp(p->name, str) == 0) return p;
3765     }
3766     return NULL;
3767 }
3768
3769 val_t *
3770 interface_getconf(
3771     interface_t *iface,
3772     interface_key key)
3773 {
3774     assert(iface != NULL);
3775     assert(key < INTER_INTER);
3776     return &iface->value[key];
3777 }
3778
3779 char *
3780 interface_name(
3781     interface_t *iface)
3782 {
3783     assert(iface != NULL);
3784     return iface->name;
3785 }
3786
3787 holdingdisk_t *
3788 lookup_holdingdisk(
3789     char *str)
3790 {
3791     holdingdisk_t *p;
3792
3793     for(p = holdinglist; p != NULL; p = p->next) {
3794         if(strcasecmp(p->name, str) == 0) return p;
3795     }
3796     return NULL;
3797 }
3798
3799 holdingdisk_t *
3800 getconf_holdingdisks(
3801     void)
3802 {
3803     return holdinglist;
3804 }
3805
3806 holdingdisk_t *
3807 holdingdisk_next(
3808     holdingdisk_t *hdisk)
3809 {
3810     if (hdisk) return hdisk->next;
3811     return NULL;
3812 }
3813
3814 val_t *
3815 holdingdisk_getconf(
3816     holdingdisk_t *hdisk,
3817     holdingdisk_key key)
3818 {
3819     assert(hdisk != NULL);
3820     assert(key < HOLDING_HOLDING);
3821     return &hdisk->value[key];
3822 }
3823
3824 char *
3825 holdingdisk_name(
3826     holdingdisk_t *hdisk)
3827 {
3828     assert(hdisk != NULL);
3829     return hdisk->name;
3830 }
3831
3832 long int
3833 getconf_unit_divisor(void)
3834 {
3835     return unit_divisor;
3836 }
3837
3838 /*
3839  * Command-line Handling Implementation
3840  */
3841
3842 config_overwrites_t *
3843 new_config_overwrites(
3844     int size_estimate)
3845 {
3846     config_overwrites_t *co;
3847
3848     co = alloc(sizeof(*co));
3849     co->ovr = alloc(sizeof(*co->ovr) * size_estimate);
3850     co->n_allocated = size_estimate;
3851     co->n_used = 0;
3852
3853     return co;
3854 }
3855
3856 void
3857 free_config_overwrites(
3858     config_overwrites_t *co)
3859 {
3860     int i;
3861
3862     if (!co) return;
3863     for (i = 0; i < co->n_used; i++) {
3864         amfree(co->ovr[i].key);
3865         amfree(co->ovr[i].value);
3866     }
3867     amfree(co->ovr);
3868     amfree(co);
3869 }
3870
3871 void add_config_overwrite(
3872     config_overwrites_t *co,
3873     char *key,
3874     char *value)
3875 {
3876     /* reallocate if necessary */
3877     if (co->n_used == co->n_allocated) {
3878         co->n_allocated *= 2;
3879         co->ovr = realloc(co->ovr, co->n_allocated * sizeof(*co->ovr));
3880         if (!co->ovr) {
3881             error(_("Cannot realloc; out of memory"));
3882             /* NOTREACHED */
3883         }
3884     }
3885
3886     co->ovr[co->n_used].key = stralloc(key);
3887     co->ovr[co->n_used].value = stralloc(value);
3888     co->n_used++;
3889 }
3890
3891 void
3892 add_config_overwrite_opt(
3893     config_overwrites_t *co,
3894     char *optarg)
3895 {
3896     char *value;
3897     assert(optarg != NULL);
3898
3899     value = index(optarg, '=');
3900     if (value == NULL) {
3901         error(_("Must specify a value for %s."), optarg);
3902         /* NOTREACHED */
3903     }
3904
3905     *value = '\0';
3906     add_config_overwrite(co, optarg, value+1);
3907     *value = '=';
3908 }
3909
3910 config_overwrites_t *
3911 extract_commandline_config_overwrites(
3912     int *argc,
3913     char ***argv)
3914 {
3915     int i, j, moveup;
3916     config_overwrites_t *co = new_config_overwrites(*argc/2);
3917
3918     i = 0;
3919     while (i<*argc) {
3920         if(strncmp((*argv)[i],"-o",2) == 0) {
3921             if(strlen((*argv)[i]) > 2) {
3922                 add_config_overwrite_opt(co, (*argv)[i]+2);
3923                 moveup = 1;
3924             }
3925             else {
3926                 if (i+1 >= *argc) error(_("expect something after -o"));
3927                 add_config_overwrite_opt(co, (*argv)[i+1]);
3928                 moveup = 2;
3929             }
3930
3931             /* move up remaining argment array */
3932             for (j = i; j+moveup<*argc; j++) {
3933                 (*argv)[j] = (*argv)[j+moveup];
3934             }
3935             *argc -= moveup;
3936         } else {
3937             i++;
3938         }
3939     }
3940
3941     return co;
3942 }
3943
3944 void
3945 apply_config_overwrites(
3946     config_overwrites_t *co)
3947 {
3948     int i;
3949
3950     if(!co) return;
3951     assert(keytable != NULL);
3952     assert(parsetable != NULL);
3953
3954     for (i = 0; i < co->n_used; i++) {
3955         char *key = co->ovr[i].key;
3956         char *value = co->ovr[i].value;
3957         val_t *key_val;
3958         conf_var_t *key_parm;
3959
3960         if (!parm_key_info(key, &key_parm, &key_val)) {
3961             error(_("unknown parameter '%s'"), key);
3962         }
3963
3964         /* now set up a fake line and use the relevant read_function to
3965          * parse it.  This is sneaky! */
3966
3967         if (key_parm->type == CONFTYPE_STR) {
3968             current_line = vstralloc("\"", value, "\"", NULL);
3969         } else {
3970             current_line = stralloc(value);
3971         }
3972
3973         current_char = current_line;
3974         token_pushed = 0;
3975         current_line_num = -2;
3976         allow_overwrites = 1;
3977         got_parserror = 0;
3978
3979         key_parm->read_function(key_parm, key_val);
3980         if ((key_parm)->validate_function)
3981             key_parm->validate_function(key_parm, key_val);
3982
3983         amfree(current_line);
3984         current_char = NULL;
3985
3986         if (got_parserror) {
3987             error(_("parse error in configuration overwrites"));
3988             /* NOTREACHED */
3989         }
3990     }
3991
3992     /* merge these overwrites with previous overwrites, if necessary */
3993     if (applied_config_overwrites) {
3994         for (i = 0; i < co->n_used; i++) {
3995             char *key = co->ovr[i].key;
3996             char *value = co->ovr[i].value;
3997
3998             add_config_overwrite(applied_config_overwrites, key, value);
3999         }
4000         free_config_overwrites(co);
4001     } else {
4002         applied_config_overwrites = co;
4003     }
4004
4005     update_derived_values(config_client);
4006 }
4007
4008 /*
4009  * val_t Management Implementation
4010  */
4011
4012 int
4013 val_t_to_int(
4014     val_t *val)
4015 {
4016     if (val->type != CONFTYPE_INT) {
4017         error(_("val_t_to_int: val.type is not CONFTYPE_INT"));
4018         /*NOTREACHED*/
4019     }
4020     return val_t__int(val);
4021 }
4022
4023 off_t
4024 val_t_to_am64(
4025     val_t *val)
4026 {
4027     if (val->type != CONFTYPE_AM64) {
4028         error(_("val_t_to_am64: val.type is not CONFTYPE_AM64"));
4029         /*NOTREACHED*/
4030     }
4031     return val_t__am64(val);
4032 }
4033
4034 float
4035 val_t_to_real(
4036     val_t *val)
4037 {
4038     if (val->type != CONFTYPE_REAL) {
4039         error(_("val_t_to_real: val.type is not CONFTYPE_REAL"));
4040         /*NOTREACHED*/
4041     }
4042     return val_t__real(val);
4043 }
4044
4045 char *
4046 val_t_to_str(
4047     val_t *val)
4048 {
4049     /* support CONFTYPE_IDENT, too */
4050     if (val->type != CONFTYPE_STR && val->type != CONFTYPE_IDENT) {
4051         error(_("val_t_to_str: val.type is not CONFTYPE_STR nor CONFTYPE_IDENT"));
4052         /*NOTREACHED*/
4053     }
4054     return val_t__str(val);
4055 }
4056
4057 char *
4058 val_t_to_ident(
4059     val_t *val)
4060 {
4061     /* support CONFTYPE_STR, too */
4062     if (val->type != CONFTYPE_STR && val->type != CONFTYPE_IDENT) {
4063         error(_("val_t_to_ident: val.type is not CONFTYPE_IDENT nor CONFTYPE_STR"));
4064         /*NOTREACHED*/
4065     }
4066     return val_t__str(val);
4067 }
4068
4069 time_t
4070 val_t_to_time(
4071     val_t *val)
4072 {
4073     if (val->type != CONFTYPE_TIME) {
4074         error(_("val_t_to_time: val.type is not CONFTYPE_TIME"));
4075         /*NOTREACHED*/
4076     }
4077     return val_t__time(val);
4078 }
4079
4080 ssize_t
4081 val_t_to_size(
4082     val_t *val)
4083 {
4084     if (val->type != CONFTYPE_SIZE) {
4085         error(_("val_t_to_size: val.type is not CONFTYPE_SIZE"));
4086         /*NOTREACHED*/
4087     }
4088     return val_t__size(val);
4089 }
4090
4091 int
4092 val_t_to_boolean(
4093     val_t *val)
4094 {
4095     if (val->type != CONFTYPE_BOOLEAN) {
4096         error(_("val_t_to_bool: val.type is not CONFTYPE_BOOLEAN"));
4097         /*NOTREACHED*/
4098     }
4099     return val_t__boolean(val);
4100 }
4101
4102 comp_t
4103 val_t_to_compress(
4104     val_t *val)
4105 {
4106     if (val->type != CONFTYPE_COMPRESS) {
4107         error(_("val_t_to_compress: val.type is not CONFTYPE_COMPRESS"));
4108         /*NOTREACHED*/
4109     }
4110     return val_t__compress(val);
4111 }
4112
4113 encrypt_t
4114 val_t_to_encrypt(
4115     val_t *val)
4116 {
4117     if (val->type != CONFTYPE_ENCRYPT) {
4118         error(_("val_t_to_encrypt: val.type is not CONFTYPE_ENCRYPT"));
4119         /*NOTREACHED*/
4120     }
4121     return val_t__encrypt(val);
4122 }
4123
4124 dump_holdingdisk_t
4125 val_t_to_holding(
4126     val_t *val)
4127 {
4128     if (val->type != CONFTYPE_HOLDING) {
4129         error(_("val_t_to_hold: val.type is not CONFTYPE_HOLDING"));
4130         /*NOTREACHED*/
4131     }
4132     return val_t__holding(val);
4133 }
4134
4135 estimate_t
4136 val_t_to_estimate(
4137     val_t *val)
4138 {
4139     if (val->type != CONFTYPE_ESTIMATE) {
4140         error(_("val_t_to_extimate: val.type is not CONFTYPE_ESTIMATE"));
4141         /*NOTREACHED*/
4142     }
4143     return val_t__estimate(val);
4144 }
4145
4146 strategy_t
4147 val_t_to_strategy(
4148     val_t *val)
4149 {
4150     if (val->type != CONFTYPE_STRATEGY) {
4151         error(_("val_t_to_strategy: val.type is not CONFTYPE_STRATEGY"));
4152         /*NOTREACHED*/
4153     }
4154     return val_t__strategy(val);
4155 }
4156
4157 taperalgo_t
4158 val_t_to_taperalgo(
4159     val_t *val)
4160 {
4161     if (val->type != CONFTYPE_TAPERALGO) {
4162         error(_("val_t_to_taperalgo: val.type is not CONFTYPE_TAPERALGO"));
4163         /*NOTREACHED*/
4164     }
4165     return val_t__taperalgo(val);
4166 }
4167
4168 int
4169 val_t_to_priority(
4170     val_t *val)
4171 {
4172     if (val->type != CONFTYPE_PRIORITY) {
4173         error(_("val_t_to_priority: val.type is not CONFTYPE_PRIORITY"));
4174         /*NOTREACHED*/
4175     }
4176     return val_t__priority(val);
4177 }
4178
4179 float *
4180 val_t_to_rate(
4181     val_t *val)
4182 {
4183     if (val->type != CONFTYPE_RATE) {
4184         error(_("val_t_to_rate: val.type is not CONFTYPE_RATE"));
4185         /*NOTREACHED*/
4186     }
4187     return val_t__rate(val);
4188 }
4189
4190 exinclude_t
4191 val_t_to_exinclude(
4192     val_t *val)
4193 {
4194     if (val->type != CONFTYPE_EXINCLUDE) {
4195         error(_("val_t_to_exinclude: val.type is not CONFTYPE_EXINCLUDE"));
4196         /*NOTREACHED*/
4197     }
4198     return val_t__exinclude(val);
4199 }
4200
4201
4202 int *
4203 val_t_to_intrange(
4204     val_t *val)
4205 {
4206     if (val->type != CONFTYPE_INTRANGE) {
4207         error(_("val_t_to_intrange: val.type is not CONFTYPE_INTRANGE"));
4208         /*NOTREACHED*/
4209     }
4210     return val_t__intrange(val);
4211 }
4212
4213 proplist_t
4214 val_t_to_proplist(
4215     val_t *val)
4216 {
4217     if (val->type != CONFTYPE_PROPLIST) {
4218         error(_("val_t_to_proplist: val.type is not CONFTYPE_PROPLIST"));
4219         /*NOTREACHED*/
4220     }
4221     return val_t__proplist(val);
4222 }
4223
4224 static void
4225 copy_val_t(
4226     val_t *valdst,
4227     val_t *valsrc)
4228 {
4229     if(valsrc->seen) {
4230         valdst->type = valsrc->type;
4231         valdst->seen = valsrc->seen;
4232         switch(valsrc->type) {
4233         case CONFTYPE_INT:
4234         case CONFTYPE_BOOLEAN:
4235         case CONFTYPE_COMPRESS:
4236         case CONFTYPE_ENCRYPT:
4237         case CONFTYPE_HOLDING:
4238         case CONFTYPE_ESTIMATE:
4239         case CONFTYPE_STRATEGY:
4240         case CONFTYPE_TAPERALGO:
4241         case CONFTYPE_PRIORITY:
4242             valdst->v.i = valsrc->v.i;
4243             break;
4244
4245         case CONFTYPE_SIZE:
4246             valdst->v.size = valsrc->v.size;
4247             break;
4248
4249         case CONFTYPE_AM64:
4250             valdst->v.am64 = valsrc->v.am64;
4251             break;
4252
4253         case CONFTYPE_REAL:
4254             valdst->v.r = valsrc->v.r;
4255             break;
4256
4257         case CONFTYPE_RATE:
4258             valdst->v.rate[0] = valsrc->v.rate[0];
4259             valdst->v.rate[1] = valsrc->v.rate[1];
4260             break;
4261
4262         case CONFTYPE_IDENT:
4263         case CONFTYPE_STR:
4264             valdst->v.s = stralloc(valsrc->v.s);
4265             break;
4266
4267         case CONFTYPE_TIME:
4268             valdst->v.t = valsrc->v.t;
4269             break;
4270
4271         case CONFTYPE_EXINCLUDE:
4272             valdst->v.exinclude.optional = valsrc->v.exinclude.optional;
4273             valdst->v.exinclude.sl_list = duplicate_sl(valsrc->v.exinclude.sl_list);
4274             valdst->v.exinclude.sl_file = duplicate_sl(valsrc->v.exinclude.sl_file);
4275             break;
4276
4277         case CONFTYPE_INTRANGE:
4278             valdst->v.intrange[0] = valsrc->v.intrange[0];
4279             valdst->v.intrange[1] = valsrc->v.intrange[1];
4280             break;
4281
4282         case CONFTYPE_PROPLIST:
4283             g_assert_not_reached();
4284             break;
4285         }
4286     }
4287 }
4288
4289 static void
4290 free_val_t(
4291     val_t *val)
4292 {
4293     switch(val->type) {
4294         case CONFTYPE_INT:
4295         case CONFTYPE_BOOLEAN:
4296         case CONFTYPE_COMPRESS:
4297         case CONFTYPE_ENCRYPT:
4298         case CONFTYPE_HOLDING:
4299         case CONFTYPE_ESTIMATE:
4300         case CONFTYPE_STRATEGY:
4301         case CONFTYPE_SIZE:
4302         case CONFTYPE_TAPERALGO:
4303         case CONFTYPE_PRIORITY:
4304         case CONFTYPE_AM64:
4305         case CONFTYPE_REAL:
4306         case CONFTYPE_RATE:
4307         case CONFTYPE_INTRANGE:
4308             break;
4309
4310         case CONFTYPE_IDENT:
4311         case CONFTYPE_STR:
4312             amfree(val->v.s);
4313             break;
4314
4315         case CONFTYPE_TIME:
4316             break;
4317
4318         case CONFTYPE_EXINCLUDE:
4319             free_sl(val_t__exinclude(val).sl_list);
4320             free_sl(val_t__exinclude(val).sl_file);
4321             break;
4322
4323         case CONFTYPE_PROPLIST:
4324             g_hash_table_destroy(val_t__proplist(val));
4325             break;
4326     }
4327     val->seen = 0;
4328 }
4329
4330 /*
4331  * Utilities Implementation
4332  */
4333
4334 char *
4335 generic_get_security_conf(
4336         char *string,
4337         void *arg)
4338 {
4339         arg = arg;
4340         if(!string || !*string)
4341                 return(NULL);
4342
4343         if(strcmp(string, "krb5principal")==0) {
4344                 return(getconf_str(CNF_KRB5PRINCIPAL));
4345         } else if(strcmp(string, "krb5keytab")==0) {
4346                 return(getconf_str(CNF_KRB5KEYTAB));
4347         }
4348         return(NULL);
4349 }
4350
4351 char *
4352 generic_client_get_security_conf(
4353     char *      string,
4354     void *      arg)
4355 {
4356         (void)arg;      /* Quiet unused parameter warning */
4357
4358         if(!string || !*string)
4359                 return(NULL);
4360
4361         if(strcmp(string, "conf")==0) {
4362                 return(getconf_str(CNF_CONF));
4363         } else if(strcmp(string, "index_server")==0) {
4364                 return(getconf_str(CNF_INDEX_SERVER));
4365         } else if(strcmp(string, "tape_server")==0) {
4366                 return(getconf_str(CNF_TAPE_SERVER));
4367         } else if(strcmp(string, "tapedev")==0) {
4368                 return(getconf_str(CNF_TAPEDEV));
4369         } else if(strcmp(string, "auth")==0) {
4370                 return(getconf_str(CNF_AUTH));
4371         } else if(strcmp(string, "ssh_keys")==0) {
4372                 return(getconf_str(CNF_SSH_KEYS));
4373         } else if(strcmp(string, "amandad_path")==0) {
4374                 return(getconf_str(CNF_AMANDAD_PATH));
4375         } else if(strcmp(string, "client_username")==0) {
4376                 return(getconf_str(CNF_CLIENT_USERNAME));
4377         } else if(strcmp(string, "gnutar_list_dir")==0) {
4378                 return(getconf_str(CNF_GNUTAR_LIST_DIR));
4379         } else if(strcmp(string, "amandates")==0) {
4380                 return(getconf_str(CNF_AMANDATES));
4381         } else if(strcmp(string, "krb5principal")==0) {
4382                 return(getconf_str(CNF_KRB5PRINCIPAL));
4383         } else if(strcmp(string, "krb5keytab")==0) {
4384                 return(getconf_str(CNF_KRB5KEYTAB));
4385         }
4386         return(NULL);
4387 }
4388
4389 void
4390 dump_configuration(void)
4391 {
4392     tapetype_t *tp;
4393     dumptype_t *dp;
4394     interface_t *ip;
4395     holdingdisk_t *hp;
4396     int i;
4397     conf_var_t *np;
4398     keytab_t *kt;
4399     char *prefix;
4400
4401     if (config_client) {
4402         error(_("Don't know how to dump client configurations."));
4403         /* NOTREACHED */
4404     }
4405
4406     g_printf(_("# AMANDA CONFIGURATION FROM FILE \"%s\":\n\n"), config_filename);
4407
4408     for(np=server_var; np->token != CONF_UNKNOWN; np++) {
4409         for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) 
4410             if (np->token == kt->token) break;
4411
4412         if(kt->token == CONF_UNKNOWN)
4413             error(_("server bad token"));
4414
4415         val_t_print_token(stdout, NULL, "%-21s ", kt, &conf_data[np->parm]);
4416     }
4417
4418     for(hp = holdinglist; hp != NULL; hp = hp->next) {
4419         g_printf("\nHOLDINGDISK %s {\n", hp->name);
4420         for(i=0; i < HOLDING_HOLDING; i++) {
4421             for(np=holding_var; np->token != CONF_UNKNOWN; np++) {
4422                 if(np->parm == i)
4423                         break;
4424             }
4425             if(np->token == CONF_UNKNOWN)
4426                 error(_("holding bad value"));
4427
4428             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) {
4429                 if(kt->token == np->token)
4430                     break;
4431             }
4432             if(kt->token == CONF_UNKNOWN)
4433                 error(_("holding bad token"));
4434
4435             val_t_print_token(stdout, NULL, "      %-9s ", kt, &hp->value[i]);
4436         }
4437         g_printf("}\n");
4438     }
4439
4440     for(tp = tapelist; tp != NULL; tp = tp->next) {
4441         if(tp->seen == -1)
4442             prefix = "#";
4443         else
4444             prefix = "";
4445         g_printf("\n%sDEFINE TAPETYPE %s {\n", prefix, tp->name);
4446         for(i=0; i < TAPETYPE_TAPETYPE; i++) {
4447             for(np=tapetype_var; np->token != CONF_UNKNOWN; np++)
4448                 if(np->parm == i) break;
4449             if(np->token == CONF_UNKNOWN)
4450                 error(_("tapetype bad value"));
4451
4452             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
4453                 if(kt->token == np->token) break;
4454             if(kt->token == CONF_UNKNOWN)
4455                 error(_("tapetype bad token"));
4456
4457             val_t_print_token(stdout, prefix, "      %-9s ", kt, &tp->value[i]);
4458         }
4459         g_printf("%s}\n", prefix);
4460     }
4461
4462     for(dp = dumplist; dp != NULL; dp = dp->next) {
4463         if (strncmp_const(dp->name, "custom(") != 0) { /* don't dump disklist-derived dumptypes */
4464             if(dp->seen == -1)
4465                 prefix = "#";
4466             else
4467                 prefix = "";
4468             g_printf("\n%sDEFINE DUMPTYPE %s {\n", prefix, dp->name);
4469             for(i=0; i < DUMPTYPE_DUMPTYPE; i++) {
4470                 for(np=dumptype_var; np->token != CONF_UNKNOWN; np++)
4471                     if(np->parm == i) break;
4472                 if(np->token == CONF_UNKNOWN)
4473                     error(_("dumptype bad value"));
4474
4475                 for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
4476                     if(kt->token == np->token) break;
4477                 if(kt->token == CONF_UNKNOWN)
4478                     error(_("dumptype bad token"));
4479
4480                 val_t_print_token(stdout, prefix, "      %-19s ", kt, &dp->value[i]);
4481             }
4482             g_printf("%s}\n", prefix);
4483         }
4484     }
4485
4486     for(ip = interface_list; ip != NULL; ip = ip->next) {
4487         if(strcmp(ip->name,"default") == 0)
4488             prefix = "#";
4489         else
4490             prefix = "";
4491         g_printf("\n%sDEFINE INTERFACE %s {\n", prefix, ip->name);
4492         for(i=0; i < INTER_INTER; i++) {
4493             for(np=interface_var; np->token != CONF_UNKNOWN; np++)
4494                 if(np->parm == i) break;
4495             if(np->token == CONF_UNKNOWN)
4496                 error(_("interface bad value"));
4497
4498             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
4499                 if(kt->token == np->token) break;
4500             if(kt->token == CONF_UNKNOWN)
4501                 error(_("interface bad token"));
4502
4503             val_t_print_token(stdout, prefix, "      %-19s ", kt, &ip->value[i]);
4504         }
4505         g_printf("%s}\n",prefix);
4506     }
4507
4508 }
4509
4510 static void
4511 val_t_print_token(
4512     FILE     *output,
4513     char     *prefix,
4514     char     *format,
4515     keytab_t *kt,
4516     val_t    *val)
4517 {
4518     char       **dispstrs, **dispstr;
4519     dispstrs = val_t_display_strs(val, 1);
4520
4521     /* For most configuration types, this outputs
4522      *   PREFIX KEYWORD DISPSTR
4523      * for each of the display strings.  For identifiers, however, it
4524      * simply prints the first line of the display string.
4525      */
4526
4527     /* Print the keyword for anything that is not itself an identifier */
4528     if (kt->token != CONF_IDENT) {
4529         for(dispstr=dispstrs; *dispstr!=NULL; dispstr++) {
4530             if (prefix)
4531                 g_fprintf(output, "%s", prefix);
4532             g_fprintf(output, format, kt->keyword);
4533             g_fprintf(output, "%s\n", *dispstr);
4534         }
4535     } else {
4536         /* for identifiers, assume there's at most one display string */
4537         assert(g_strv_length(dispstrs) <= 1);
4538         if (*dispstrs) {
4539             g_fprintf(output, "%s\n", *dispstrs);
4540         }
4541     }
4542
4543     g_strfreev(dispstrs);
4544 }
4545
4546 char **
4547 val_t_display_strs(
4548     val_t *val,
4549     int    str_need_quote)
4550 {
4551     char **buf;
4552     buf = malloc(3*SIZEOF(char *));
4553     buf[0] = NULL;
4554     buf[1] = NULL;
4555     buf[2] = NULL;
4556
4557     switch(val->type) {
4558     case CONFTYPE_INT:
4559         buf[0] = vstrallocf("%d", val_t__int(val));
4560         break;
4561
4562     case CONFTYPE_SIZE:
4563         buf[0] = vstrallocf("%zd", (ssize_t)val_t__size(val));
4564         break;
4565
4566     case CONFTYPE_AM64:
4567         buf[0] = vstrallocf("%lld", (long long)val_t__am64(val));
4568         break;
4569
4570     case CONFTYPE_REAL:
4571         buf[0] = vstrallocf("%0.5f", val_t__real(val));
4572         break;
4573
4574     case CONFTYPE_RATE:
4575         buf[0] = vstrallocf("%0.5f %0.5f", val_t__rate(val)[0], val_t__rate(val)[1]);
4576         break;
4577
4578     case CONFTYPE_INTRANGE:
4579         buf[0] = vstrallocf("%d,%d", val_t__intrange(val)[0], val_t__intrange(val)[1]);
4580         break;
4581
4582     case CONFTYPE_IDENT:
4583         if(val->v.s) {
4584             buf[0] = stralloc(val->v.s);
4585         } else {
4586             buf[0] = stralloc("");
4587         }
4588         break;
4589
4590     case CONFTYPE_STR:
4591         if(str_need_quote) {
4592             if(val->v.s) {
4593                 buf[0] = vstrallocf("\"%s\"", val->v.s);
4594             } else {
4595                 buf[0] = stralloc("\"\"");
4596             }
4597         } else {
4598             if(val->v.s) {
4599                 buf[0] = stralloc(val->v.s);
4600             } else {
4601                 buf[0] = stralloc("");
4602             }
4603         }
4604         break;
4605
4606     case CONFTYPE_TIME:
4607         buf[0] = vstrallocf("%2d%02d",
4608                          (int)val_t__time(val)/100, (int)val_t__time(val) % 100);
4609         break;
4610
4611     case CONFTYPE_EXINCLUDE: {
4612         buf[0] = exinclude_display_str(val, 0);
4613         buf[1] = exinclude_display_str(val, 1);
4614         break;
4615     }
4616
4617     case CONFTYPE_BOOLEAN:
4618         if(val_t__boolean(val))
4619             buf[0] = stralloc("yes");
4620         else
4621             buf[0] = stralloc("no");
4622         break;
4623
4624     case CONFTYPE_STRATEGY:
4625         switch(val_t__strategy(val)) {
4626         case DS_SKIP:
4627             buf[0] = vstrallocf("SKIP");
4628             break;
4629
4630         case DS_STANDARD:
4631             buf[0] = vstrallocf("STANDARD");
4632             break;
4633
4634         case DS_NOFULL:
4635             buf[0] = vstrallocf("NOFULL");
4636             break;
4637
4638         case DS_NOINC:
4639             buf[0] = vstrallocf("NOINC");
4640             break;
4641
4642         case DS_HANOI:
4643             buf[0] = vstrallocf("HANOI");
4644             break;
4645
4646         case DS_INCRONLY:
4647             buf[0] = vstrallocf("INCRONLY");
4648             break;
4649         }
4650         break;
4651
4652     case CONFTYPE_COMPRESS:
4653         switch(val_t__compress(val)) {
4654         case COMP_NONE:
4655             buf[0] = vstrallocf("NONE");
4656             break;
4657
4658         case COMP_FAST:
4659             buf[0] = vstrallocf("CLIENT FAST");
4660             break;
4661
4662         case COMP_BEST:
4663             buf[0] = vstrallocf("CLIENT BEST");
4664             break;
4665
4666         case COMP_CUST:
4667             buf[0] = vstrallocf("CLIENT CUSTOM");
4668             break;
4669
4670         case COMP_SERVER_FAST:
4671             buf[0] = vstrallocf("SERVER FAST");
4672             break;
4673
4674         case COMP_SERVER_BEST:
4675             buf[0] = vstrallocf("SERVER BEST");
4676             break;
4677
4678         case COMP_SERVER_CUST:
4679             buf[0] = vstrallocf("SERVER CUSTOM");
4680             break;
4681         }
4682         break;
4683
4684     case CONFTYPE_ESTIMATE:
4685         switch(val_t__estimate(val)) {
4686         case ES_CLIENT:
4687             buf[0] = vstrallocf("CLIENT");
4688             break;
4689
4690         case ES_SERVER:
4691             buf[0] = vstrallocf("SERVER");
4692             break;
4693
4694         case ES_CALCSIZE:
4695             buf[0] = vstrallocf("CALCSIZE");
4696             break;
4697         }
4698         break;
4699
4700      case CONFTYPE_ENCRYPT:
4701         switch(val_t__encrypt(val)) {
4702         case ENCRYPT_NONE:
4703             buf[0] = vstrallocf("NONE");
4704             break;
4705
4706         case ENCRYPT_CUST:
4707             buf[0] = vstrallocf("CLIENT");
4708             break;
4709
4710         case ENCRYPT_SERV_CUST:
4711             buf[0] = vstrallocf("SERVER");
4712             break;
4713         }
4714         break;
4715
4716      case CONFTYPE_HOLDING:
4717         switch(val_t__holding(val)) {
4718         case HOLD_NEVER:
4719             buf[0] = vstrallocf("NEVER");
4720             break;
4721
4722         case HOLD_AUTO:
4723             buf[0] = vstrallocf("AUTO");
4724             break;
4725
4726         case HOLD_REQUIRED:
4727             buf[0] = vstrallocf("REQUIRED");
4728             break;
4729         }
4730         break;
4731
4732      case CONFTYPE_TAPERALGO:
4733         buf[0] = vstrallocf("%s", taperalgo2str(val_t__taperalgo(val)));
4734         break;
4735
4736      case CONFTYPE_PRIORITY:
4737         switch(val_t__priority(val)) {
4738         case 0:
4739             buf[0] = vstrallocf("LOW");
4740             break;
4741
4742         case 1:
4743             buf[0] = vstrallocf("MEDIUM");
4744             break;
4745
4746         case 2:
4747             buf[0] = vstrallocf("HIGH");
4748             break;
4749         }
4750         break;
4751
4752     case CONFTYPE_PROPLIST: {
4753         int    nb_property;
4754         char **mybuf;
4755
4756         nb_property = g_hash_table_size(val_t__proplist(val));
4757         amfree(buf);
4758         buf = malloc((nb_property+1)*SIZEOF(char*));
4759         buf[nb_property] = NULL;
4760         mybuf = buf;
4761         g_hash_table_foreach(val_t__proplist(val), proplist_display_str_foreach_fn, &mybuf);
4762         break;
4763     }
4764     }
4765     return buf;
4766 }
4767
4768 static void
4769 proplist_display_str_foreach_fn(
4770     gpointer key_p,
4771     gpointer value_p,
4772     gpointer user_data_p)
4773 {
4774     char *property_s = key_p;
4775     char *value_s    = value_p;
4776     char ***msg      = (char ***)user_data_p;
4777
4778     **msg = vstralloc("\"", property_s, "\" \"", value_s, "\"", NULL);
4779     (*msg)++;
4780 }
4781
4782 static char *
4783 exinclude_display_str(
4784     val_t *val,
4785     int    file)
4786 {
4787     sl_t  *sl;
4788     sle_t *excl;
4789     char *rval;
4790
4791     assert(val->type == CONFTYPE_EXINCLUDE);
4792
4793     rval = stralloc("");
4794
4795     if (file == 0) {
4796         sl = val_t__exinclude(val).sl_list;
4797         strappend(rval, "LIST");
4798     } else {
4799         sl = val_t__exinclude(val).sl_file;
4800         strappend(rval, "FILE");
4801     }
4802
4803     if (val_t__exinclude(val).optional == 1) {
4804         strappend(rval, " OPTIONAL");
4805     }
4806
4807     if (sl != NULL) {
4808         for(excl = sl->first; excl != NULL; excl = excl->next) {
4809             vstrextend(&rval, " \"", excl->name, "\"", NULL);
4810         }
4811     }
4812
4813     return rval;
4814 }
4815
4816 char *
4817 taperalgo2str(
4818     taperalgo_t taperalgo)
4819 {
4820     if(taperalgo == ALGO_FIRST) return "FIRST";
4821     if(taperalgo == ALGO_FIRSTFIT) return "FIRSTFIT";
4822     if(taperalgo == ALGO_LARGEST) return "LARGEST";
4823     if(taperalgo == ALGO_LARGESTFIT) return "LARGESTFIT";
4824     if(taperalgo == ALGO_SMALLEST) return "SMALLEST";
4825     if(taperalgo == ALGO_LAST) return "LAST";
4826     return "UNKNOWN";
4827 }
4828
4829 char *
4830 config_dir_relative(
4831     char *filename)
4832 {
4833     if (*filename == '/' || config_dir == NULL) {
4834         return stralloc(filename);
4835     } else {
4836         if (config_dir[strlen(config_dir)-1] == '/') {
4837             return vstralloc(config_dir, filename, NULL);
4838         } else {
4839             return vstralloc(config_dir, "/", filename, NULL);
4840         }
4841     }
4842 }
4843
4844 static int
4845 parm_key_info(
4846     char *key,
4847     conf_var_t **parm,
4848     val_t **val)
4849 {
4850     conf_var_t *np;
4851     keytab_t *kt;
4852     char *s;
4853     char ch;
4854     char *subsec_type;
4855     char *subsec_name;
4856     char *subsec_key;
4857     tapetype_t *tp;
4858     dumptype_t *dp;
4859     interface_t *ip;
4860     holdingdisk_t *hp;
4861     int success = FALSE;
4862
4863     /* WARNING: assumes globals keytable and parsetable are set correctly. */
4864     assert(keytable != NULL);
4865     assert(parsetable != NULL);
4866
4867     /* make a copy we can stomp on */
4868     key = stralloc(key);
4869
4870     /* uppercase the key */
4871     s = key;
4872     for (s = key; (ch = *s) != 0; s++) {
4873         if(islower((int)ch))
4874             *s = (char)toupper(ch);
4875     }
4876
4877     subsec_name = strchr(key, ':');
4878     if (subsec_name) {
4879         subsec_type = key;
4880
4881         *subsec_name = '\0';
4882         subsec_name++;
4883
4884         subsec_key = strchr(subsec_name,':');
4885         if(!subsec_key) goto out; /* failure */
4886
4887         *subsec_key = '\0';
4888         subsec_key++;
4889
4890         /* If the keyword doesn't exist, there's no need to look up the
4891          * subsection -- we know it's invalid */
4892         for(kt = keytable; kt->token != CONF_UNKNOWN; kt++) {
4893             if(kt->keyword && strcmp(kt->keyword, subsec_key) == 0)
4894                 break;
4895         }
4896         if(kt->token == CONF_UNKNOWN) goto out;
4897
4898         /* Otherwise, figure out which kind of subsection we're dealing with,
4899          * and parse against that. */
4900         if (strcmp(subsec_type, "TAPETYPE") == 0) {
4901             tp = lookup_tapetype(subsec_name);
4902             if (!tp) goto out;
4903             for(np = tapetype_var; np->token != CONF_UNKNOWN; np++) {
4904                 if(np->token == kt->token)
4905                    break;
4906             }
4907             if (np->token == CONF_UNKNOWN) goto out;
4908
4909             if (val) *val = &tp->value[np->parm];
4910             if (parm) *parm = np;
4911             success = TRUE;
4912         } else if (strcmp(subsec_type, "DUMPTYPE") == 0) {
4913             dp = lookup_dumptype(subsec_name);
4914             if (!dp) goto out;
4915             for(np = dumptype_var; np->token != CONF_UNKNOWN; np++) {
4916                 if(np->token == kt->token)
4917                    break;
4918             }
4919             if (np->token == CONF_UNKNOWN) goto out;
4920
4921             if (val) *val = &dp->value[np->parm];
4922             if (parm) *parm = np;
4923             success = TRUE;
4924         } else if (strcmp(subsec_type, "HOLDINGDISK") == 0) {
4925             hp = lookup_holdingdisk(subsec_name);
4926             if (!hp) goto out;
4927             for(np = holding_var; np->token != CONF_UNKNOWN; np++) {
4928                 if(np->token == kt->token)
4929                    break;
4930             }
4931             if (np->token == CONF_UNKNOWN) goto out;
4932
4933             if (val) *val = &hp->value[np->parm];
4934             if (parm) *parm = np;
4935             success = TRUE;
4936         } else if (strcmp(subsec_type, "INTERFACE") == 0) {
4937             ip = lookup_interface(subsec_name);
4938             if (!ip) goto out;
4939             for(np = interface_var; np->token != CONF_UNKNOWN; np++) {
4940                 if(np->token == kt->token)
4941                    break;
4942             }
4943             if (np->token == CONF_UNKNOWN) goto out;
4944
4945             if (val) *val = &ip->value[np->parm];
4946             if (parm) *parm = np;
4947             success = TRUE;
4948         } 
4949
4950     /* No delimiters -- we're referencing a global config parameter */
4951     } else {
4952         /* look up the keyword */
4953         for(kt = keytable; kt->token != CONF_UNKNOWN; kt++) {
4954             if(kt->keyword && strcmp(kt->keyword, key) == 0)
4955                 break;
4956         }
4957         if(kt->token == CONF_UNKNOWN) goto out;
4958
4959         /* and then look that up in the parse table */
4960         for(np = parsetable; np->token != CONF_UNKNOWN; np++) {
4961             if(np->token == kt->token)
4962                 break;
4963         }
4964         if(np->token == CONF_UNKNOWN) goto out;
4965
4966         if (val) *val = &conf_data[np->parm];
4967         if (parm) *parm = np;
4968         success = TRUE;
4969     }
4970
4971 out:
4972     amfree(key);
4973     return success;
4974 }
4975
4976 gint64 
4977 find_multiplier(
4978     char * casestr)
4979 {
4980     keytab_t * table_entry;
4981     char * str = g_utf8_strup(casestr, -1);
4982     g_strstrip(str);
4983
4984     if (*str == '\0') {
4985         g_free(str);
4986         return 1;
4987     }
4988     
4989     for (table_entry = numb_keytable; table_entry->keyword != NULL;
4990          table_entry ++) {
4991         if (strcmp(casestr, table_entry->keyword) == 0) {
4992             g_free(str);
4993             switch (table_entry->token) {
4994             case CONF_MULT1K:
4995                 return 1024;
4996             case CONF_MULT1M:
4997                 return 1024*1024;
4998             case CONF_MULT1G:
4999                 return 1024*1024*1024;
5000             case CONF_MULT7:
5001                 return 7;
5002             case CONF_AMINFINITY:
5003                 return G_MAXINT64;
5004             case CONF_MULT1:
5005             case CONF_IDENT:
5006                 return 1;
5007             default:
5008                 /* Should not happen. */
5009                 return 0;
5010             }
5011         }
5012     }
5013
5014     /* None found; this is an error. */
5015     g_free(str);
5016     return 0;
5017 }
5018
5019 /*
5020  * Error Handling Implementaiton
5021  */
5022
5023 static void print_parse_problem(const char * format, va_list argp) {
5024     const char *xlated_fmt = gettext(format);
5025
5026     if(current_line)
5027         g_fprintf(stderr, _("argument \"%s\": "), current_line);
5028     else if (current_filename && current_line_num > 0)
5029         g_fprintf(stderr, "\"%s\", line %d: ", current_filename, current_line_num);
5030     else
5031         g_fprintf(stderr, _("parse error: "));
5032     
5033     g_vfprintf(stderr, xlated_fmt, argp);
5034     fputc('\n', stderr);
5035 }
5036
5037 printf_arglist_function(void conf_parserror, const char *, format)
5038 {
5039     va_list argp;
5040     
5041     arglist_start(argp, format);
5042     print_parse_problem(format, argp);
5043     arglist_end(argp);
5044
5045     got_parserror = TRUE;
5046 }
5047
5048 printf_arglist_function(void conf_parswarn, const char *, format) {
5049     va_list argp;
5050     
5051     arglist_start(argp, format);
5052     print_parse_problem(format, argp);
5053     arglist_end(argp);
5054 }