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