Imported Upstream version 2.6.0
[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     save_tapetype();
1818
1819     allow_overwrites = save_overwrites;
1820 }
1821
1822 static void
1823 init_tapetype_defaults(void)
1824 {
1825     conf_init_str(&tpcur.value[TAPETYPE_COMMENT]      , "");
1826     conf_init_str(&tpcur.value[TAPETYPE_LBL_TEMPL]    , "");
1827     conf_init_size  (&tpcur.value[TAPETYPE_BLOCKSIZE]    , DISK_BLOCK_KB);
1828     conf_init_size  (&tpcur.value[TAPETYPE_READBLOCKSIZE], MAX_TAPE_BLOCK_KB);
1829     conf_init_am64  (&tpcur.value[TAPETYPE_LENGTH]       , ((off_t)2000 * 1024));
1830     conf_init_am64  (&tpcur.value[TAPETYPE_FILEMARK]     , (off_t)1000);
1831     conf_init_int   (&tpcur.value[TAPETYPE_SPEED]        , 200);
1832     conf_init_bool  (&tpcur.value[TAPETYPE_FILE_PAD]     , 1);
1833 }
1834
1835 static void
1836 save_tapetype(void)
1837 {
1838     tapetype_t *tp, *tp1;
1839
1840     tp = lookup_tapetype(tpcur.name);
1841
1842     if(tp != (tapetype_t *)0) {
1843         amfree(tpcur.name);
1844         conf_parserror(_("tapetype %s already defined on line %d"), tp->name, tp->seen);
1845         return;
1846     }
1847
1848     tp = alloc(sizeof(tapetype_t));
1849     *tp = tpcur;
1850     /* add at end of list */
1851     if(!tapelist)
1852         tapelist = tp;
1853     else {
1854         tp1 = tapelist;
1855         while (tp1->next != NULL) {
1856             tp1 = tp1->next;
1857         }
1858         tp1->next = tp;
1859     }
1860 }
1861
1862 static void
1863 copy_tapetype(void)
1864 {
1865     tapetype_t *tp;
1866     int i;
1867
1868     tp = lookup_tapetype(tokenval.v.s);
1869
1870     if(tp == NULL) {
1871         conf_parserror(_("tape type parameter expected"));
1872         return;
1873     }
1874
1875     for(i=0; i < TAPETYPE_TAPETYPE; i++) {
1876         if(tp->value[i].seen) {
1877             free_val_t(&tpcur.value[i]);
1878             copy_val_t(&tpcur.value[i], &tp->value[i]);
1879         }
1880     }
1881 }
1882
1883 static void
1884 get_interface(void)
1885 {
1886     int save_overwrites;
1887
1888     save_overwrites = allow_overwrites;
1889     allow_overwrites = 1;
1890
1891     init_interface_defaults();
1892
1893     get_conftoken(CONF_IDENT);
1894     ifcur.name = stralloc(tokenval.v.s);
1895     ifcur.seen = current_line_num;
1896
1897     read_block(interface_var, ifcur.value,
1898                _("interface parameter expected"), 1, copy_interface);
1899     get_conftoken(CONF_NL);
1900
1901     save_interface();
1902
1903     allow_overwrites = save_overwrites;
1904
1905     return;
1906 }
1907
1908 static void
1909 init_interface_defaults(void)
1910 {
1911     conf_init_str(&ifcur.value[INTER_COMMENT] , "");
1912     conf_init_int   (&ifcur.value[INTER_MAXUSAGE], 8000);
1913 }
1914
1915 static void
1916 save_interface(void)
1917 {
1918     interface_t *ip, *ip1;
1919
1920     ip = lookup_interface(ifcur.name);
1921
1922     if(ip != (interface_t *)0) {
1923         conf_parserror(_("interface %s already defined on line %d"), ip->name,
1924                        ip->seen);
1925         return;
1926     }
1927
1928     ip = alloc(sizeof(interface_t));
1929     *ip = ifcur;
1930     /* add at end of list */
1931     if(!interface_list) {
1932         interface_list = ip;
1933     } else {
1934         ip1 = interface_list;
1935         while (ip1->next != NULL) {
1936             ip1 = ip1->next;
1937         }
1938         ip1->next = ip;
1939     }
1940 }
1941
1942 static void
1943 copy_interface(void)
1944 {
1945     interface_t *ip;
1946     int i;
1947
1948     ip = lookup_interface(tokenval.v.s);
1949
1950     if(ip == NULL) {
1951         conf_parserror(_("interface parameter expected"));
1952         return;
1953     }
1954
1955     for(i=0; i < INTER_INTER; i++) {
1956         if(ip->value[i].seen) {
1957             free_val_t(&ifcur.value[i]);
1958             copy_val_t(&ifcur.value[i], &ip->value[i]);
1959         }
1960     }
1961 }
1962
1963 /* Read functions */
1964
1965 static void
1966 read_int(
1967     conf_var_t *np G_GNUC_UNUSED,
1968     val_t *val)
1969 {
1970     ckseen(&val->seen);
1971     val_t__int(val) = get_int();
1972 }
1973
1974 static void
1975 read_am64(
1976     conf_var_t *np G_GNUC_UNUSED,
1977     val_t *val)
1978 {
1979     ckseen(&val->seen);
1980     val_t__am64(val) = get_am64_t();
1981 }
1982
1983 static void
1984 read_real(
1985     conf_var_t *np G_GNUC_UNUSED,
1986     val_t *val)
1987 {
1988     ckseen(&val->seen);
1989     get_conftoken(CONF_REAL);
1990     val_t__real(val) = tokenval.v.r;
1991 }
1992
1993 static void
1994 read_str(
1995     conf_var_t *np G_GNUC_UNUSED,
1996     val_t *val)
1997 {
1998     ckseen(&val->seen);
1999     get_conftoken(CONF_STRING);
2000     val->v.s = newstralloc(val->v.s, tokenval.v.s);
2001 }
2002
2003 static void
2004 read_ident(
2005     conf_var_t *np G_GNUC_UNUSED,
2006     val_t *val)
2007 {
2008     ckseen(&val->seen);
2009     get_conftoken(CONF_IDENT);
2010     val->v.s = newstralloc(val->v.s, tokenval.v.s);
2011 }
2012
2013 static void
2014 read_time(
2015     conf_var_t *np G_GNUC_UNUSED,
2016     val_t *val)
2017 {
2018     ckseen(&val->seen);
2019     val_t__time(val) = get_time();
2020 }
2021
2022 static void
2023 read_size(
2024     conf_var_t *np G_GNUC_UNUSED,
2025     val_t *val)
2026 {
2027     ckseen(&val->seen);
2028     val_t__size(val) = get_size();
2029 }
2030
2031 static void
2032 read_bool(
2033     conf_var_t *np G_GNUC_UNUSED,
2034     val_t *val)
2035 {
2036     ckseen(&val->seen);
2037     val_t__boolean(val) = get_bool();
2038 }
2039
2040 static void
2041 read_compress(
2042     conf_var_t *np G_GNUC_UNUSED,
2043     val_t *val)
2044 {
2045     int serv, clie, none, fast, best, custom;
2046     int done;
2047     comp_t comp;
2048
2049     ckseen(&val->seen);
2050
2051     serv = clie = none = fast = best = custom  = 0;
2052
2053     done = 0;
2054     do {
2055         get_conftoken(CONF_ANY);
2056         switch(tok) {
2057         case CONF_NONE:   none = 1; break;
2058         case CONF_FAST:   fast = 1; break;
2059         case CONF_BEST:   best = 1; break;
2060         case CONF_CLIENT: clie = 1; break;
2061         case CONF_SERVER: serv = 1; break;
2062         case CONF_CUSTOM: custom=1; break;
2063         case CONF_NL:     done = 1; break;
2064         case CONF_END:    done = 1; break;
2065         default:
2066             done = 1;
2067             serv = clie = 1; /* force an error */
2068         }
2069     } while(!done);
2070
2071     if(serv + clie == 0) clie = 1;      /* default to client */
2072     if(none + fast + best + custom  == 0) fast = 1; /* default to fast */
2073
2074     comp = -1;
2075
2076     if(!serv && clie) {
2077         if(none && !fast && !best && !custom) comp = COMP_NONE;
2078         if(!none && fast && !best && !custom) comp = COMP_FAST;
2079         if(!none && !fast && best && !custom) comp = COMP_BEST;
2080         if(!none && !fast && !best && custom) comp = COMP_CUST;
2081     }
2082
2083     if(serv && !clie) {
2084         if(none && !fast && !best && !custom) comp = COMP_NONE;
2085         if(!none && fast && !best && !custom) comp = COMP_SERVER_FAST;
2086         if(!none && !fast && best && !custom) comp = COMP_SERVER_BEST;
2087         if(!none && !fast && !best && custom) comp = COMP_SERVER_CUST;
2088     }
2089
2090     if((int)comp == -1) {
2091         conf_parserror(_("NONE, CLIENT FAST, CLIENT BEST, CLIENT CUSTOM, SERVER FAST, SERVER BEST or SERVER CUSTOM expected"));
2092         comp = COMP_NONE;
2093     }
2094
2095     val_t__compress(val) = (int)comp;
2096 }
2097
2098 static void
2099 read_encrypt(
2100     conf_var_t *np G_GNUC_UNUSED,
2101     val_t *val)
2102 {
2103    encrypt_t encrypt;
2104
2105    ckseen(&val->seen);
2106
2107    get_conftoken(CONF_ANY);
2108    switch(tok) {
2109    case CONF_NONE:  
2110      encrypt = ENCRYPT_NONE; 
2111      break;
2112
2113    case CONF_CLIENT:  
2114      encrypt = ENCRYPT_CUST;
2115      break;
2116
2117    case CONF_SERVER: 
2118      encrypt = ENCRYPT_SERV_CUST;
2119      break;
2120
2121    default:
2122      conf_parserror(_("NONE, CLIENT or SERVER expected"));
2123      encrypt = ENCRYPT_NONE;
2124      break;
2125    }
2126
2127    val_t__encrypt(val) = (int)encrypt;
2128 }
2129
2130 static void
2131 read_holding(
2132     conf_var_t *np G_GNUC_UNUSED,
2133     val_t *val)
2134 {
2135    dump_holdingdisk_t holding;
2136
2137    ckseen(&val->seen);
2138
2139    get_conftoken(CONF_ANY);
2140    switch(tok) {
2141    case CONF_NEVER:  
2142      holding = HOLD_NEVER; 
2143      break;
2144
2145    case CONF_AUTO:  
2146      holding = HOLD_AUTO;
2147      break;
2148
2149    case CONF_REQUIRED: 
2150      holding = HOLD_REQUIRED;
2151      break;
2152
2153    default: /* can be a BOOLEAN */
2154      unget_conftoken();
2155      holding =  (dump_holdingdisk_t)get_bool();
2156      if (holding == 0)
2157         holding = HOLD_NEVER;
2158      else if (holding == 1 || holding == 2)
2159         holding = HOLD_AUTO;
2160      else
2161         conf_parserror(_("NEVER, AUTO or REQUIRED expected"));
2162      break;
2163    }
2164
2165    val_t__holding(val) = (int)holding;
2166 }
2167
2168 static void
2169 read_estimate(
2170     conf_var_t *np G_GNUC_UNUSED,
2171     val_t *val)
2172 {
2173     int estime;
2174
2175     ckseen(&val->seen);
2176
2177     get_conftoken(CONF_ANY);
2178     switch(tok) {
2179     case CONF_CLIENT:
2180         estime = ES_CLIENT;
2181         break;
2182     case CONF_SERVER:
2183         estime = ES_SERVER;
2184         break;
2185     case CONF_CALCSIZE:
2186         estime = ES_CALCSIZE;
2187         break;
2188     default:
2189         conf_parserror(_("CLIENT, SERVER or CALCSIZE expected"));
2190         estime = ES_CLIENT;
2191     }
2192     val_t__estimate(val) = estime;
2193 }
2194
2195 static void
2196 read_strategy(
2197     conf_var_t *np G_GNUC_UNUSED,
2198     val_t *val)
2199 {
2200     int strat;
2201
2202     ckseen(&val->seen);
2203
2204     get_conftoken(CONF_ANY);
2205     switch(tok) {
2206     case CONF_SKIP:
2207         strat = DS_SKIP;
2208         break;
2209     case CONF_STANDARD:
2210         strat = DS_STANDARD;
2211         break;
2212     case CONF_NOFULL:
2213         strat = DS_NOFULL;
2214         break;
2215     case CONF_NOINC:
2216         strat = DS_NOINC;
2217         break;
2218     case CONF_HANOI:
2219         strat = DS_HANOI;
2220         break;
2221     case CONF_INCRONLY:
2222         strat = DS_INCRONLY;
2223         break;
2224     default:
2225         conf_parserror(_("dump strategy expected"));
2226         strat = DS_STANDARD;
2227     }
2228     val_t__strategy(val) = strat;
2229 }
2230
2231 static void
2232 read_taperalgo(
2233     conf_var_t *np G_GNUC_UNUSED,
2234     val_t *val)
2235 {
2236     ckseen(&val->seen);
2237
2238     get_conftoken(CONF_ANY);
2239     switch(tok) {
2240     case CONF_FIRST:      val_t__taperalgo(val) = ALGO_FIRST;      break;
2241     case CONF_FIRSTFIT:   val_t__taperalgo(val) = ALGO_FIRSTFIT;   break;
2242     case CONF_LARGEST:    val_t__taperalgo(val) = ALGO_LARGEST;    break;
2243     case CONF_LARGESTFIT: val_t__taperalgo(val) = ALGO_LARGESTFIT; break;
2244     case CONF_SMALLEST:   val_t__taperalgo(val) = ALGO_SMALLEST;   break;
2245     case CONF_LAST:       val_t__taperalgo(val) = ALGO_LAST;       break;
2246     default:
2247         conf_parserror(_("FIRST, FIRSTFIT, LARGEST, LARGESTFIT, SMALLEST or LAST expected"));
2248     }
2249 }
2250
2251 static void
2252 read_priority(
2253     conf_var_t *np G_GNUC_UNUSED,
2254     val_t *val)
2255 {
2256     int pri;
2257
2258     ckseen(&val->seen);
2259
2260     get_conftoken(CONF_ANY);
2261     switch(tok) {
2262     case CONF_LOW: pri = 0; break;
2263     case CONF_MEDIUM: pri = 1; break;
2264     case CONF_HIGH: pri = 2; break;
2265     case CONF_INT: pri = tokenval.v.i; break;
2266     default:
2267         conf_parserror(_("LOW, MEDIUM, HIGH or integer expected"));
2268         pri = 0;
2269     }
2270     val_t__priority(val) = pri;
2271 }
2272
2273 static void
2274 read_rate(
2275     conf_var_t *np G_GNUC_UNUSED,
2276     val_t *val)
2277 {
2278     get_conftoken(CONF_REAL);
2279     val_t__rate(val)[0] = tokenval.v.r;
2280     val_t__rate(val)[1] = tokenval.v.r;
2281     val->seen = tokenval.seen;
2282     if(tokenval.v.r < 0) {
2283         conf_parserror(_("full compression rate must be >= 0"));
2284     }
2285
2286     get_conftoken(CONF_ANY);
2287     switch(tok) {
2288     case CONF_NL:
2289         return;
2290
2291     case CONF_END:
2292         return;
2293
2294     case CONF_COMMA:
2295         break;
2296
2297     default:
2298         unget_conftoken();
2299     }
2300
2301     get_conftoken(CONF_REAL);
2302     val_t__rate(val)[1] = tokenval.v.r;
2303     if(tokenval.v.r < 0) {
2304         conf_parserror(_("incremental compression rate must be >= 0"));
2305     }
2306 }
2307
2308 static void
2309 read_exinclude(
2310     conf_var_t *np G_GNUC_UNUSED,
2311     val_t *val)
2312 {
2313     int file, got_one = 0;
2314     sl_t *exclude;
2315     int optional = 0;
2316
2317     get_conftoken(CONF_ANY);
2318     if(tok == CONF_LIST) {
2319         file = 0;
2320         get_conftoken(CONF_ANY);
2321         exclude = val_t__exinclude(val).sl_list;
2322     }
2323     else {
2324         file = 1;
2325         if(tok == CONF_EFILE) get_conftoken(CONF_ANY);
2326         exclude = val_t__exinclude(val).sl_file;
2327     }
2328     ckseen(&val->seen);
2329
2330     if(tok == CONF_OPTIONAL) {
2331         get_conftoken(CONF_ANY);
2332         optional = 1;
2333     }
2334
2335     if(tok == CONF_APPEND) {
2336         get_conftoken(CONF_ANY);
2337     }
2338     else {
2339         free_sl(exclude);
2340         exclude = NULL;
2341     }
2342
2343     while(tok == CONF_STRING) {
2344         exclude = append_sl(exclude, tokenval.v.s);
2345         got_one = 1;
2346         get_conftoken(CONF_ANY);
2347     }
2348     unget_conftoken();
2349
2350     if(got_one == 0) { free_sl(exclude); exclude = NULL; }
2351
2352     if (file == 0)
2353         val_t__exinclude(val).sl_list = exclude;
2354     else
2355         val_t__exinclude(val).sl_file = exclude;
2356     val_t__exinclude(val).optional = optional;
2357 }
2358
2359 static void
2360 read_intrange(
2361     conf_var_t *np G_GNUC_UNUSED,
2362     val_t *val)
2363 {
2364     get_conftoken(CONF_INT);
2365     val_t__intrange(val)[0] = tokenval.v.i;
2366     val_t__intrange(val)[1] = tokenval.v.i;
2367     val->seen = tokenval.seen;
2368
2369     get_conftoken(CONF_ANY);
2370     switch(tok) {
2371     case CONF_NL:
2372         return;
2373
2374     case CONF_END:
2375         return;
2376
2377     case CONF_COMMA:
2378         break;
2379
2380     default:
2381         unget_conftoken();
2382     }
2383
2384     get_conftoken(CONF_INT);
2385     val_t__intrange(val)[1] = tokenval.v.i;
2386 }
2387
2388 static void
2389 read_property(
2390     conf_var_t *np G_GNUC_UNUSED,
2391     val_t *val)
2392 {
2393     char *key, *value;
2394     get_conftoken(CONF_STRING);
2395     key = strdup(tokenval.v.s);
2396     get_conftoken(CONF_STRING);
2397     value = strdup(tokenval.v.s);
2398
2399     g_hash_table_insert(val_t__proplist(val), key, value);
2400 }
2401
2402 /* get_* functions */
2403
2404 static time_t
2405 get_time(void)
2406 {
2407     time_t hhmm;
2408
2409     get_conftoken(CONF_ANY);
2410     switch(tok) {
2411     case CONF_INT:
2412 #if SIZEOF_TIME_T < SIZEOF_INT
2413         if ((off_t)tokenval.v.i >= (off_t)TIME_MAX)
2414             conf_parserror(_("value too large"));
2415 #endif
2416         hhmm = (time_t)tokenval.v.i;
2417         break;
2418
2419     case CONF_SIZE:
2420 #if SIZEOF_TIME_T < SIZEOF_SSIZE_T
2421         if ((off_t)tokenval.v.size >= (off_t)TIME_MAX)
2422             conf_parserror(_("value too large"));
2423 #endif
2424         hhmm = (time_t)tokenval.v.size;
2425         break;
2426
2427     case CONF_AM64:
2428 #if SIZEOF_TIME_T < SIZEOF_LONG_LONG
2429         if ((off_t)tokenval.v.am64 >= (off_t)TIME_MAX)
2430             conf_parserror(_("value too large"));
2431 #endif
2432         hhmm = (time_t)tokenval.v.am64;
2433         break;
2434
2435     case CONF_AMINFINITY:
2436         hhmm = TIME_MAX;
2437         break;
2438
2439     default:
2440         conf_parserror(_("a time is expected"));
2441         hhmm = 0;
2442         break;
2443     }
2444     return hhmm;
2445 }
2446
2447 static int
2448 get_int(void)
2449 {
2450     int val;
2451     keytab_t *save_kt;
2452
2453     save_kt = keytable;
2454     keytable = numb_keytable;
2455
2456     get_conftoken(CONF_ANY);
2457     switch(tok) {
2458     case CONF_INT:
2459         val = tokenval.v.i;
2460         break;
2461
2462     case CONF_SIZE:
2463 #if SIZEOF_INT < SIZEOF_SSIZE_T
2464         if ((off_t)tokenval.v.size > (off_t)INT_MAX)
2465             conf_parserror(_("value too large"));
2466         if ((off_t)tokenval.v.size < (off_t)INT_MIN)
2467             conf_parserror(_("value too small"));
2468 #endif
2469         val = (int)tokenval.v.size;
2470         break;
2471
2472     case CONF_AM64:
2473 #if SIZEOF_INT < SIZEOF_LONG_LONG
2474         if (tokenval.v.am64 > (off_t)INT_MAX)
2475             conf_parserror(_("value too large"));
2476         if (tokenval.v.am64 < (off_t)INT_MIN)
2477             conf_parserror(_("value too small"));
2478 #endif
2479         val = (int)tokenval.v.am64;
2480         break;
2481
2482     case CONF_AMINFINITY:
2483         val = INT_MAX;
2484         break;
2485
2486     default:
2487         conf_parserror(_("an integer is expected"));
2488         val = 0;
2489         break;
2490     }
2491
2492     /* get multiplier, if any */
2493     get_conftoken(CONF_ANY);
2494     switch(tok) {
2495     case CONF_NL:                       /* multiply by one */
2496     case CONF_END:
2497     case CONF_MULT1:
2498     case CONF_MULT1K:
2499         break;
2500
2501     case CONF_MULT7:
2502         if (val > (INT_MAX / 7))
2503             conf_parserror(_("value too large"));
2504         if (val < (INT_MIN / 7))
2505             conf_parserror(_("value too small"));
2506         val *= 7;
2507         break;
2508
2509     case CONF_MULT1M:
2510         if (val > (INT_MAX / 1024))
2511             conf_parserror(_("value too large"));
2512         if (val < (INT_MIN / 1024))
2513             conf_parserror(_("value too small"));
2514         val *= 1024;
2515         break;
2516
2517     case CONF_MULT1G:
2518         if (val > (INT_MAX / (1024 * 1024)))
2519             conf_parserror(_("value too large"));
2520         if (val < (INT_MIN / (1024 * 1024)))
2521             conf_parserror(_("value too small"));
2522         val *= 1024 * 1024;
2523         break;
2524
2525     default:    /* it was not a multiplier */
2526         unget_conftoken();
2527         break;
2528     }
2529
2530     keytable = save_kt;
2531     return val;
2532 }
2533
2534 static ssize_t
2535 get_size(void)
2536 {
2537     ssize_t val;
2538     keytab_t *save_kt;
2539
2540     save_kt = keytable;
2541     keytable = numb_keytable;
2542
2543     get_conftoken(CONF_ANY);
2544
2545     switch(tok) {
2546     case CONF_SIZE:
2547         val = tokenval.v.size;
2548         break;
2549
2550     case CONF_INT:
2551 #if SIZEOF_SIZE_T < SIZEOF_INT
2552         if ((off_t)tokenval.v.i > (off_t)SSIZE_MAX)
2553             conf_parserror(_("value too large"));
2554         if ((off_t)tokenval.v.i < (off_t)SSIZE_MIN)
2555             conf_parserror(_("value too small"));
2556 #endif
2557         val = (ssize_t)tokenval.v.i;
2558         break;
2559
2560     case CONF_AM64:
2561 #if SIZEOF_SIZE_T < SIZEOF_LONG_LONG
2562         if (tokenval.v.am64 > (off_t)SSIZE_MAX)
2563             conf_parserror(_("value too large"));
2564         if (tokenval.v.am64 < (off_t)SSIZE_MIN)
2565             conf_parserror(_("value too small"));
2566 #endif
2567         val = (ssize_t)tokenval.v.am64;
2568         break;
2569
2570     case CONF_AMINFINITY:
2571         val = (ssize_t)SSIZE_MAX;
2572         break;
2573
2574     default:
2575         conf_parserror(_("an integer is expected"));
2576         val = 0;
2577         break;
2578     }
2579
2580     /* get multiplier, if any */
2581     get_conftoken(CONF_ANY);
2582
2583     switch(tok) {
2584     case CONF_NL:                       /* multiply by one */
2585     case CONF_MULT1:
2586     case CONF_MULT1K:
2587         break;
2588
2589     case CONF_MULT7:
2590         if (val > (ssize_t)(SSIZE_MAX / 7))
2591             conf_parserror(_("value too large"));
2592         if (val < (ssize_t)(SSIZE_MIN / 7))
2593             conf_parserror(_("value too small"));
2594         val *= (ssize_t)7;
2595         break;
2596
2597     case CONF_MULT1M:
2598         if (val > (ssize_t)(SSIZE_MAX / (ssize_t)1024))
2599             conf_parserror(_("value too large"));
2600         if (val < (ssize_t)(SSIZE_MIN / (ssize_t)1024))
2601             conf_parserror(_("value too small"));
2602         val *= (ssize_t)1024;
2603         break;
2604
2605     case CONF_MULT1G:
2606         if (val > (ssize_t)(SSIZE_MAX / (1024 * 1024)))
2607             conf_parserror(_("value too large"));
2608         if (val < (ssize_t)(SSIZE_MIN / (1024 * 1024)))
2609             conf_parserror(_("value too small"));
2610         val *= (ssize_t)(1024 * 1024);
2611         break;
2612
2613     default:    /* it was not a multiplier */
2614         unget_conftoken();
2615         break;
2616     }
2617
2618     keytable = save_kt;
2619     return val;
2620 }
2621
2622 static off_t
2623 get_am64_t(void)
2624 {
2625     off_t val;
2626     keytab_t *save_kt;
2627
2628     save_kt = keytable;
2629     keytable = numb_keytable;
2630
2631     get_conftoken(CONF_ANY);
2632
2633     switch(tok) {
2634     case CONF_INT:
2635         val = (off_t)tokenval.v.i;
2636         break;
2637
2638     case CONF_SIZE:
2639         val = (off_t)tokenval.v.size;
2640         break;
2641
2642     case CONF_AM64:
2643         val = tokenval.v.am64;
2644         break;
2645
2646     case CONF_AMINFINITY:
2647         val = AM64_MAX;
2648         break;
2649
2650     default:
2651         conf_parserror(_("an integer is expected"));
2652         val = 0;
2653         break;
2654     }
2655
2656     /* get multiplier, if any */
2657     get_conftoken(CONF_ANY);
2658
2659     switch(tok) {
2660     case CONF_NL:                       /* multiply by one */
2661     case CONF_MULT1:
2662     case CONF_MULT1K:
2663         break;
2664
2665     case CONF_MULT7:
2666         if (val > AM64_MAX/7 || val < AM64_MIN/7)
2667             conf_parserror(_("value too large"));
2668         val *= 7;
2669         break;
2670
2671     case CONF_MULT1M:
2672         if (val > AM64_MAX/1024 || val < AM64_MIN/1024)
2673             conf_parserror(_("value too large"));
2674         val *= 1024;
2675         break;
2676
2677     case CONF_MULT1G:
2678         if (val > AM64_MAX/(1024*1024) || val < AM64_MIN/(1024*1024))
2679             conf_parserror(_("value too large"));
2680         val *= 1024*1024;
2681         break;
2682
2683     default:    /* it was not a multiplier */
2684         unget_conftoken();
2685         break;
2686     }
2687
2688     keytable = save_kt;
2689
2690     return val;
2691 }
2692
2693 static int
2694 get_bool(void)
2695 {
2696     int val;
2697     keytab_t *save_kt;
2698
2699     save_kt = keytable;
2700     keytable = bool_keytable;
2701
2702     get_conftoken(CONF_ANY);
2703
2704     switch(tok) {
2705     case CONF_INT:
2706         if (tokenval.v.i != 0)
2707             val = 1;
2708         else
2709             val = 0;
2710         break;
2711
2712     case CONF_SIZE:
2713         if (tokenval.v.size != (size_t)0)
2714             val = 1;
2715         else
2716             val = 0;
2717         break;
2718
2719     case CONF_AM64:
2720         if (tokenval.v.am64 != (off_t)0)
2721             val = 1;
2722         else
2723             val = 0;
2724         break;
2725
2726     case CONF_ATRUE:
2727         val = 1;
2728         break;
2729
2730     case CONF_AFALSE:
2731         val = 0;
2732         break;
2733
2734     case CONF_NL:
2735         unget_conftoken();
2736         val = 2; /* no argument - most likely TRUE */
2737         break;
2738     default:
2739         unget_conftoken();
2740         val = 3; /* a bad argument - most likely TRUE */
2741         conf_parserror(_("YES, NO, TRUE, FALSE, ON, OFF expected"));
2742         break;
2743     }
2744
2745     keytable = save_kt;
2746     return val;
2747 }
2748
2749 void
2750 ckseen(
2751     int *seen)
2752 {
2753     if (*seen && !allow_overwrites && current_line_num != -2) {
2754         conf_parserror(_("duplicate parameter, prev def on line %d"), *seen);
2755     }
2756     *seen = current_line_num;
2757 }
2758
2759 /* Validation functions */
2760
2761 static void
2762 validate_nonnegative(
2763     struct conf_var_s *np,
2764     val_t        *val)
2765 {
2766     switch(val->type) {
2767     case CONFTYPE_INT:
2768         if(val_t__int(val) < 0)
2769             conf_parserror(_("%s must be nonnegative"), get_token_name(np->token));
2770         break;
2771     case CONFTYPE_AM64:
2772         if(val_t__am64(val) < 0)
2773             conf_parserror(_("%s must be nonnegative"), get_token_name(np->token));
2774         break;
2775     case CONFTYPE_SIZE:
2776         if(val_t__size(val) < 0)
2777             conf_parserror(_("%s must be positive"), get_token_name(np->token));
2778         break;
2779     default:
2780         conf_parserror(_("validate_nonnegative invalid type %d\n"), val->type);
2781     }
2782 }
2783
2784 static void
2785 validate_positive(
2786     struct conf_var_s *np,
2787     val_t        *val)
2788 {
2789     switch(val->type) {
2790     case CONFTYPE_INT:
2791         if(val_t__int(val) < 1)
2792             conf_parserror(_("%s must be positive"), get_token_name(np->token));
2793         break;
2794     case CONFTYPE_AM64:
2795         if(val_t__am64(val) < 1)
2796             conf_parserror(_("%s must be positive"), get_token_name(np->token));
2797         break;
2798     case CONFTYPE_TIME:
2799         if(val_t__time(val) < 1)
2800             conf_parserror(_("%s must be positive"), get_token_name(np->token));
2801         break;
2802     case CONFTYPE_SIZE:
2803         if(val_t__size(val) < 1)
2804             conf_parserror(_("%s must be positive"), get_token_name(np->token));
2805         break;
2806     default:
2807         conf_parserror(_("validate_positive invalid type %d\n"), val->type);
2808     }
2809 }
2810
2811 static void
2812 validate_runspercycle(
2813     struct conf_var_s *np G_GNUC_UNUSED,
2814     val_t        *val)
2815 {
2816     if(val_t__int(val) < -1)
2817         conf_parserror(_("runspercycle must be >= -1"));
2818 }
2819
2820 static void
2821 validate_bumppercent(
2822     struct conf_var_s *np G_GNUC_UNUSED,
2823     val_t        *val)
2824 {
2825     if(val_t__int(val) < 0 || val_t__int(val) > 100)
2826         conf_parserror(_("bumppercent must be between 0 and 100"));
2827 }
2828
2829 static void
2830 validate_inparallel(
2831     struct conf_var_s *np G_GNUC_UNUSED,
2832     val_t        *val)
2833 {
2834     if(val_t__int(val) < 1 || val_t__int(val) >MAX_DUMPERS)
2835         conf_parserror(_("inparallel must be between 1 and MAX_DUMPERS (%d)"),
2836                        MAX_DUMPERS);
2837 }
2838
2839 static void
2840 validate_bumpmult(
2841     struct conf_var_s *np G_GNUC_UNUSED,
2842     val_t        *val)
2843 {
2844     if(val_t__real(val) < 0.999) {
2845         conf_parserror(_("bumpmult must one or more"));
2846     }
2847 }
2848
2849 static void
2850 validate_displayunit(
2851     struct conf_var_s *np G_GNUC_UNUSED,
2852     val_t        *val G_GNUC_UNUSED)
2853 {
2854     char *s = val_t__str(val);
2855     if (strlen(s) == 1) {
2856         switch (s[0]) {
2857             case 'K':
2858             case 'M':
2859             case 'G':
2860             case 'T':
2861                 return; /* all good */
2862
2863             /* lower-case values should get folded to upper case */
2864             case 'k':
2865             case 'm':
2866             case 'g':
2867             case 't':
2868                 s[0] = toupper(s[0]);
2869                 return;
2870
2871             default:    /* bad */
2872                 break;
2873         }
2874     }
2875     conf_parserror(_("displayunit must be k,m,g or t."));
2876 }
2877
2878 static void
2879 validate_reserve(
2880     struct conf_var_s *np G_GNUC_UNUSED,
2881     val_t        *val)
2882 {
2883     if(val_t__int(val) < 0 || val_t__int(val) > 100)
2884         conf_parserror(_("reserve must be between 0 and 100"));
2885 }
2886
2887 static void
2888 validate_use(
2889     struct conf_var_s *np G_GNUC_UNUSED,
2890     val_t        *val)
2891 {
2892     val_t__am64(val) = am_floor(val_t__am64(val), DISK_BLOCK_KB);
2893 }
2894
2895 static void
2896 validate_chunksize(
2897     struct conf_var_s *np G_GNUC_UNUSED,
2898     val_t        *val)
2899 {
2900     /* NOTE: this function modifies the target value (rounding) */
2901     if(val_t__am64(val) == 0) {
2902         val_t__am64(val) = ((AM64_MAX / 1024) - (2 * DISK_BLOCK_KB));
2903     }
2904     else if(val_t__am64(val) < 0) {
2905         conf_parserror(_("Negative chunksize (%lld) is no longer supported"), (long long)val_t__am64(val));
2906     }
2907     val_t__am64(val) = am_floor(val_t__am64(val), (off_t)DISK_BLOCK_KB);
2908     if (val_t__am64(val) < 2*DISK_BLOCK_KB) {
2909         conf_parserror("chunksize must be at least %dkb", 2*DISK_BLOCK_KB);
2910     }
2911 }
2912
2913 static void
2914 validate_blocksize(
2915     struct conf_var_s *np G_GNUC_UNUSED,
2916     val_t        *val)
2917 {
2918     if(val_t__size(val) < DISK_BLOCK_KB) {
2919         conf_parserror(_("Tape blocksize must be at least %d KBytes"),
2920                   DISK_BLOCK_KB);
2921     } else if(val_t__size(val) > MAX_TAPE_BLOCK_KB) {
2922         conf_parserror(_("Tape blocksize must not be larger than %d KBytes"),
2923                   MAX_TAPE_BLOCK_KB);
2924     }
2925 }
2926
2927 static void
2928 validate_debug(
2929     struct conf_var_s *np G_GNUC_UNUSED,
2930     val_t        *val)
2931 {
2932     if(val_t__int(val) < 0 || val_t__int(val) > 9) {
2933         conf_parserror(_("Debug must be between 0 and 9"));
2934     }
2935 }
2936
2937 static void
2938 validate_port_range(
2939     val_t        *val,
2940     int          smallest,
2941     int          largest)
2942 {
2943     int i;
2944     /* check both values are in range */
2945     for (i = 0; i < 2; i++) {
2946         if(val_t__intrange(val)[0] < smallest || val_t__intrange(val)[0] > largest) {
2947             conf_parserror(_("portrange must be in the range %d to %d, inclusive"), smallest, largest);
2948         }
2949      }
2950
2951     /* and check they're in the right order and not equal */
2952     if (val_t__intrange(val)[0] > val_t__intrange(val)[1]) {
2953         conf_parserror(_("portranges must be in order from low to high"));
2954     }
2955 }
2956
2957 static void
2958 validate_reserved_port_range(
2959     struct conf_var_s *np G_GNUC_UNUSED,
2960     val_t        *val)
2961 {
2962     validate_port_range(val, 1, IPPORT_RESERVED-1);
2963 }
2964
2965 static void
2966 validate_unreserved_port_range(
2967     struct conf_var_s *np G_GNUC_UNUSED,
2968     val_t        *val)
2969 {
2970     validate_port_range(val, IPPORT_RESERVED, 65535);
2971 }
2972
2973 /*
2974  * Initialization Implementation
2975  */
2976
2977 gboolean
2978 config_init(
2979     config_init_flags flags,
2980     char *arg_config_name)
2981 {
2982     if (!(flags & CONFIG_INIT_OVERLAY)) {
2983         /* Clear out anything that's already in there */
2984         config_uninit();
2985
2986         /* and set everything to default values */
2987         init_defaults();
2988
2989         allow_overwrites = FALSE;
2990     } else {
2991         if (!config_initialized) {
2992             error(_("Attempt to overlay configuration with no existing configuration"));
2993             /* NOTREACHED */
2994         }
2995
2996         allow_overwrites = TRUE;
2997     }
2998
2999     /* store away our client-ness for later reference */
3000     config_client = flags & CONFIG_INIT_CLIENT;
3001
3002     if ((flags & CONFIG_INIT_EXPLICIT_NAME) && arg_config_name) {
3003         config_name = newstralloc(config_name, arg_config_name);
3004         config_dir = newvstralloc(config_dir, CONFIG_DIR, "/", arg_config_name, NULL);
3005     } else if (flags & CONFIG_INIT_USE_CWD) {
3006         char * cwd;
3007         
3008         cwd = get_original_cwd();
3009         if (!cwd) {
3010             /* (this isn't a config error, so it's always fatal) */
3011             error(_("Cannot determine current working directory"));
3012             /* NOTREACHED */
3013         }
3014
3015         config_dir = stralloc2(cwd, "/");
3016         if ((config_name = strrchr(cwd, '/')) != NULL) {
3017             config_name = stralloc(config_name + 1);
3018         }
3019
3020         amfree(cwd);
3021     } else if (flags & CONFIG_INIT_CLIENT) {
3022         amfree(config_name);
3023         config_dir = newstralloc(config_dir, CONFIG_DIR);
3024     } else {
3025         /* ok, then, we won't read anything (for e.g., amrestore) */
3026         amfree(config_name);
3027         amfree(config_dir);
3028     }
3029
3030     /* If we have a config_dir, we can try reading something */
3031     if (config_dir) {
3032         if (flags & CONFIG_INIT_CLIENT) {
3033             config_filename = newvstralloc(config_filename, config_dir, "/amanda-client.conf", NULL);
3034         } else {
3035             config_filename = newvstralloc(config_filename, config_dir, "/amanda.conf", NULL);
3036         }
3037
3038         /* try to read the file, and handle parse errors */
3039         if (!read_conffile(config_filename, flags & CONFIG_INIT_CLIENT)) {
3040             if (flags & CONFIG_INIT_FATAL) {
3041                 error(_("errors processing config file \"%s\""), config_filename);
3042                 /* NOTREACHED */
3043             } else {
3044                 g_warning(_("errors processing config file \"%s\" (non-fatal)"), config_filename);
3045                 return FALSE;
3046             }
3047         }
3048     } else {
3049         amfree(config_filename);
3050     }
3051
3052     update_derived_values(flags & CONFIG_INIT_CLIENT);
3053
3054     return TRUE;
3055 }
3056
3057 void
3058 config_uninit(void)
3059 {
3060     holdingdisk_t    *hp, *hpnext;
3061     dumptype_t       *dp, *dpnext;
3062     tapetype_t       *tp, *tpnext;
3063     interface_t      *ip, *ipnext;
3064     int               i;
3065
3066     if (!config_initialized) return;
3067
3068     for(hp=holdinglist; hp != NULL; hp = hpnext) {
3069         amfree(hp->name);
3070         for(i=0; i<HOLDING_HOLDING-1; i++) {
3071            free_val_t(&hp->value[i]);
3072         }
3073         hpnext = hp->next;
3074         amfree(hp);
3075     }
3076     holdinglist = NULL;
3077
3078     for(dp=dumplist; dp != NULL; dp = dpnext) {
3079         amfree(dp->name);
3080         for(i=0; i<DUMPTYPE_DUMPTYPE-1; i++) {
3081            free_val_t(&dp->value[i]);
3082         }
3083         dpnext = dp->next;
3084         amfree(dp);
3085     }
3086     dumplist = NULL;
3087
3088     for(tp=tapelist; tp != NULL; tp = tpnext) {
3089         amfree(tp->name);
3090         for(i=0; i<TAPETYPE_TAPETYPE-1; i++) {
3091            free_val_t(&tp->value[i]);
3092         }
3093         tpnext = tp->next;
3094         amfree(tp);
3095     }
3096     tapelist = NULL;
3097
3098     for(ip=interface_list; ip != NULL; ip = ipnext) {
3099         amfree(ip->name);
3100         for(i=0; i<INTER_INTER-1; i++) {
3101            free_val_t(&ip->value[i]);
3102         }
3103         ipnext = ip->next;
3104         amfree(ip);
3105     }
3106     interface_list = NULL;
3107
3108     for(i=0; i<CNF_CNF-1; i++)
3109         free_val_t(&conf_data[i]);
3110
3111     if (applied_config_overwrites) {
3112         free_config_overwrites(applied_config_overwrites);
3113         applied_config_overwrites = NULL;
3114     }
3115
3116     amfree(config_name);
3117     amfree(config_dir);
3118
3119     config_client = FALSE;
3120
3121     config_initialized = FALSE;
3122 }
3123
3124 static void
3125 init_defaults(
3126     void)
3127 {
3128     assert(!config_initialized);
3129
3130     /* defaults for exported variables */
3131     conf_init_str(&conf_data[CNF_ORG], DEFAULT_CONFIG);
3132     conf_init_str(&conf_data[CNF_CONF], DEFAULT_CONFIG);
3133     conf_init_str(&conf_data[CNF_INDEX_SERVER], DEFAULT_SERVER);
3134     conf_init_str(&conf_data[CNF_TAPE_SERVER], DEFAULT_TAPE_SERVER);
3135     conf_init_str(&conf_data[CNF_AUTH], "bsd");
3136     conf_init_str(&conf_data[CNF_SSH_KEYS], "");
3137     conf_init_str(&conf_data[CNF_AMANDAD_PATH], "");
3138     conf_init_str(&conf_data[CNF_CLIENT_USERNAME], "");
3139     conf_init_str(&conf_data[CNF_GNUTAR_LIST_DIR], GNUTAR_LISTED_INCREMENTAL_DIR);
3140     conf_init_str(&conf_data[CNF_AMANDATES], DEFAULT_AMANDATES_FILE);
3141     conf_init_str(&conf_data[CNF_MAILTO], "operators");
3142     conf_init_str(&conf_data[CNF_DUMPUSER], CLIENT_LOGIN);
3143     conf_init_str(&conf_data[CNF_TAPEDEV], DEFAULT_TAPE_DEVICE);
3144     conf_init_proplist(&conf_data[CNF_DEVICE_PROPERTY]);
3145     conf_init_str(&conf_data[CNF_CHANGERDEV], DEFAULT_CHANGER_DEVICE);
3146     conf_init_str(&conf_data[CNF_CHANGERFILE], "/usr/adm/amanda/changer-status");
3147     conf_init_str   (&conf_data[CNF_LABELSTR]             , ".*");
3148     conf_init_str   (&conf_data[CNF_TAPELIST]             , "tapelist");
3149     conf_init_str   (&conf_data[CNF_DISKFILE]             , "disklist");
3150     conf_init_str   (&conf_data[CNF_INFOFILE]             , "/usr/adm/amanda/curinfo");
3151     conf_init_str   (&conf_data[CNF_LOGDIR]               , "/usr/adm/amanda");
3152     conf_init_str   (&conf_data[CNF_INDEXDIR]             , "/usr/adm/amanda/index");
3153     conf_init_ident    (&conf_data[CNF_TAPETYPE]             , "EXABYTE");
3154     conf_init_int      (&conf_data[CNF_DUMPCYCLE]            , 10);
3155     conf_init_int      (&conf_data[CNF_RUNSPERCYCLE]         , 0);
3156     conf_init_int      (&conf_data[CNF_TAPECYCLE]            , 15);
3157     conf_init_int      (&conf_data[CNF_NETUSAGE]             , 8000);
3158     conf_init_int      (&conf_data[CNF_INPARALLEL]           , 10);
3159     conf_init_str   (&conf_data[CNF_DUMPORDER]            , "ttt");
3160     conf_init_int      (&conf_data[CNF_BUMPPERCENT]          , 0);
3161     conf_init_am64     (&conf_data[CNF_BUMPSIZE]             , (off_t)10*1024);
3162     conf_init_real     (&conf_data[CNF_BUMPMULT]             , 1.5);
3163     conf_init_int      (&conf_data[CNF_BUMPDAYS]             , 2);
3164     conf_init_str   (&conf_data[CNF_TPCHANGER]            , "");
3165     conf_init_int      (&conf_data[CNF_RUNTAPES]             , 1);
3166     conf_init_int      (&conf_data[CNF_MAXDUMPS]             , 1);
3167     conf_init_int      (&conf_data[CNF_ETIMEOUT]             , 300);
3168     conf_init_int      (&conf_data[CNF_DTIMEOUT]             , 1800);
3169     conf_init_int      (&conf_data[CNF_CTIMEOUT]             , 30);
3170     conf_init_int      (&conf_data[CNF_TAPEBUFS]             , 20);
3171     conf_init_size     (&conf_data[CNF_DEVICE_OUTPUT_BUFFER_SIZE], 40*32768);
3172     conf_init_str   (&conf_data[CNF_PRINTER]              , "");
3173     conf_init_bool     (&conf_data[CNF_AUTOFLUSH]            , 0);
3174     conf_init_int      (&conf_data[CNF_RESERVE]              , 100);
3175     conf_init_am64     (&conf_data[CNF_MAXDUMPSIZE]          , (off_t)-1);
3176     conf_init_str   (&conf_data[CNF_COLUMNSPEC]           , "");
3177     conf_init_bool     (&conf_data[CNF_AMRECOVER_DO_FSF]     , 1);
3178     conf_init_str   (&conf_data[CNF_AMRECOVER_CHANGER]    , "");
3179     conf_init_bool     (&conf_data[CNF_AMRECOVER_CHECK_LABEL], 1);
3180     conf_init_taperalgo(&conf_data[CNF_TAPERALGO]            , 0);
3181     conf_init_int      (&conf_data[CNF_FLUSH_THRESHOLD_DUMPED]   , 0);
3182     conf_init_int      (&conf_data[CNF_FLUSH_THRESHOLD_SCHEDULED], 0);
3183     conf_init_int      (&conf_data[CNF_TAPERFLUSH]               , 0);
3184     conf_init_str   (&conf_data[CNF_DISPLAYUNIT]          , "k");
3185     conf_init_str   (&conf_data[CNF_KRB5KEYTAB]           , "/.amanda-v5-keytab");
3186     conf_init_str   (&conf_data[CNF_KRB5PRINCIPAL]        , "service/amanda");
3187     conf_init_str   (&conf_data[CNF_LABEL_NEW_TAPES]      , "");
3188     conf_init_bool     (&conf_data[CNF_USETIMESTAMPS]        , 1);
3189     conf_init_int      (&conf_data[CNF_CONNECT_TRIES]        , 3);
3190     conf_init_int      (&conf_data[CNF_REP_TRIES]            , 5);
3191     conf_init_int      (&conf_data[CNF_REQ_TRIES]            , 3);
3192     conf_init_int      (&conf_data[CNF_DEBUG_AMANDAD]        , 0);
3193     conf_init_int      (&conf_data[CNF_DEBUG_AMIDXTAPED]     , 0);
3194     conf_init_int      (&conf_data[CNF_DEBUG_AMINDEXD]       , 0);
3195     conf_init_int      (&conf_data[CNF_DEBUG_AMRECOVER]      , 0);
3196     conf_init_int      (&conf_data[CNF_DEBUG_AUTH]           , 0);
3197     conf_init_int      (&conf_data[CNF_DEBUG_EVENT]          , 0);
3198     conf_init_int      (&conf_data[CNF_DEBUG_HOLDING]        , 0);
3199     conf_init_int      (&conf_data[CNF_DEBUG_PROTOCOL]       , 0);
3200     conf_init_int      (&conf_data[CNF_DEBUG_PLANNER]        , 0);
3201     conf_init_int      (&conf_data[CNF_DEBUG_DRIVER]         , 0);
3202     conf_init_int      (&conf_data[CNF_DEBUG_DUMPER]         , 0);
3203     conf_init_int      (&conf_data[CNF_DEBUG_CHUNKER]        , 0);
3204     conf_init_int      (&conf_data[CNF_DEBUG_TAPER]          , 0);
3205     conf_init_int      (&conf_data[CNF_DEBUG_SELFCHECK]      , 0);
3206     conf_init_int      (&conf_data[CNF_DEBUG_SENDSIZE]       , 0);
3207     conf_init_int      (&conf_data[CNF_DEBUG_SENDBACKUP]     , 0);
3208 #ifdef UDPPORTRANGE
3209     conf_init_intrange (&conf_data[CNF_RESERVED_UDP_PORT]    , UDPPORTRANGE);
3210 #else
3211     conf_init_intrange (&conf_data[CNF_RESERVED_UDP_PORT]    , 512, IPPORT_RESERVED-1);
3212 #endif
3213 #ifdef LOW_TCPPORTRANGE
3214     conf_init_intrange (&conf_data[CNF_RESERVED_TCP_PORT]    , LOW_TCPPORTRANGE);
3215 #else
3216     conf_init_intrange (&conf_data[CNF_RESERVED_TCP_PORT]    , 512, IPPORT_RESERVED-1);
3217 #endif
3218 #ifdef TCPPORTRANGE
3219     conf_init_intrange (&conf_data[CNF_UNRESERVED_TCP_PORT]  , TCPPORTRANGE);
3220 #else
3221     conf_init_intrange (&conf_data[CNF_UNRESERVED_TCP_PORT]  , IPPORT_RESERVED, 65535);
3222 #endif
3223
3224     /* reset internal variables */
3225     got_parserror = FALSE;
3226     allow_overwrites = 0;
3227     token_pushed = 0;
3228
3229     /* create some predefined dumptypes for backwards compatability */
3230     init_dumptype_defaults();
3231     dpcur.name = stralloc("NO-COMPRESS");
3232     dpcur.seen = -1;
3233     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
3234     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_NONE;
3235     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]) = -1;
3236     save_dumptype();
3237
3238     init_dumptype_defaults();
3239     dpcur.name = stralloc("COMPRESS-FAST");
3240     dpcur.seen = -1;
3241     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
3242     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_FAST;
3243     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]) = -1;
3244     save_dumptype();
3245
3246     init_dumptype_defaults();
3247     dpcur.name = stralloc("COMPRESS-BEST");
3248     dpcur.seen = -1;
3249     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
3250     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_BEST;
3251     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]) = -1;
3252     save_dumptype();
3253
3254     init_dumptype_defaults();
3255     dpcur.name = stralloc("COMPRESS-CUST");
3256     dpcur.seen = -1;
3257     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
3258     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_CUST;
3259     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]) = -1;
3260     save_dumptype();
3261
3262     init_dumptype_defaults();
3263     dpcur.name = stralloc("SRVCOMPRESS");
3264     dpcur.seen = -1;
3265     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
3266     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_SERVER_FAST;
3267     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]) = -1;
3268     save_dumptype();
3269
3270     init_dumptype_defaults();
3271     dpcur.name = stralloc("BSD-AUTH");
3272     dpcur.seen = -1;
3273     free_val_t(&dpcur.value[DUMPTYPE_SECURITY_DRIVER]);
3274     val_t__str(&dpcur.value[DUMPTYPE_SECURITY_DRIVER]) = stralloc("BSD");
3275     val_t__seen(&dpcur.value[DUMPTYPE_SECURITY_DRIVER]) = -1;
3276     save_dumptype();
3277
3278     init_dumptype_defaults();
3279     dpcur.name = stralloc("KRB4-AUTH");
3280     dpcur.seen = -1;
3281     free_val_t(&dpcur.value[DUMPTYPE_SECURITY_DRIVER]);
3282     val_t__str(&dpcur.value[DUMPTYPE_SECURITY_DRIVER]) = stralloc("KRB4");
3283     val_t__seen(&dpcur.value[DUMPTYPE_SECURITY_DRIVER]) = -1;
3284     save_dumptype();
3285
3286     init_dumptype_defaults();
3287     dpcur.name = stralloc("NO-RECORD");
3288     dpcur.seen = -1;
3289     free_val_t(&dpcur.value[DUMPTYPE_RECORD]);
3290     val_t__int(&dpcur.value[DUMPTYPE_RECORD]) = 0;
3291     val_t__seen(&dpcur.value[DUMPTYPE_RECORD]) = -1;
3292     save_dumptype();
3293
3294     init_dumptype_defaults();
3295     dpcur.name = stralloc("NO-HOLD");
3296     dpcur.seen = -1;
3297     free_val_t(&dpcur.value[DUMPTYPE_HOLDINGDISK]);
3298     val_t__holding(&dpcur.value[DUMPTYPE_HOLDINGDISK]) = HOLD_NEVER;
3299     val_t__seen(&dpcur.value[DUMPTYPE_HOLDINGDISK]) = -1;
3300     save_dumptype();
3301
3302     init_dumptype_defaults();
3303     dpcur.name = stralloc("NO-FULL");
3304     dpcur.seen = -1;
3305     free_val_t(&dpcur.value[DUMPTYPE_STRATEGY]);
3306     val_t__strategy(&dpcur.value[DUMPTYPE_STRATEGY]) = DS_NOFULL;
3307     val_t__seen(&dpcur.value[DUMPTYPE_STRATEGY]) = -1;
3308     save_dumptype();
3309
3310     /* And we're initialized! */
3311     config_initialized = 1;
3312 }
3313
3314 char **
3315 get_config_options(
3316     int first)
3317 {
3318     char             **config_options;
3319     char             **config_option;
3320     int              n_applied_config_overwrites = 0;
3321     int              i;
3322
3323     if (applied_config_overwrites)
3324         n_applied_config_overwrites = applied_config_overwrites->n_used;
3325
3326     config_options = alloc((first+n_applied_config_overwrites+1)*SIZEOF(char *));
3327     config_option = config_options + first;
3328
3329     for (i = 0; i < n_applied_config_overwrites; i++) {
3330         char *key = applied_config_overwrites->ovr[i].key;
3331         char *value = applied_config_overwrites->ovr[i].value;
3332         *config_option = vstralloc("-o", key, "=", value, NULL);
3333         config_option++;
3334     }
3335
3336     *config_option = NULL; /* add terminating sentinel */
3337
3338     return config_options;
3339 }
3340
3341 static void
3342 update_derived_values(
3343     gboolean is_client)
3344 {
3345     interface_t *ip;
3346
3347     if (!is_client) {
3348         /* Add a 'default' interface if one doesn't already exist */
3349         if (!(ip = lookup_interface("default"))) {
3350             init_interface_defaults();
3351             ifcur.name = stralloc("default");
3352             ifcur.seen = getconf_seen(CNF_NETUSAGE);
3353             save_interface();
3354
3355             ip = lookup_interface("default");
3356         }
3357
3358         /* .. and set its maxusage from 'netusage' */
3359         if (!interface_seen(ip, INTER_MAXUSAGE)) {
3360             val_t *v;
3361
3362             v = interface_getconf(ip, INTER_COMMENT);
3363             free_val_t(v);
3364             val_t__str(v) = stralloc(_("implicit from NETUSAGE"));
3365             val_t__seen(v) = getconf_seen(CNF_NETUSAGE);
3366
3367             v = interface_getconf(ip, INTER_MAXUSAGE);
3368             free_val_t(v);
3369             val_t__int(v) = getconf_int(CNF_NETUSAGE);
3370             val_t__seen(v) = getconf_seen(CNF_NETUSAGE);
3371         }
3372     }
3373
3374     /* fill in the debug_* values */
3375     debug_amandad    = getconf_int(CNF_DEBUG_AMANDAD);
3376     debug_amidxtaped = getconf_int(CNF_DEBUG_AMIDXTAPED);
3377     debug_amindexd   = getconf_int(CNF_DEBUG_AMINDEXD);
3378     debug_amrecover  = getconf_int(CNF_DEBUG_AMRECOVER);
3379     debug_auth       = getconf_int(CNF_DEBUG_AUTH);
3380     debug_event      = getconf_int(CNF_DEBUG_EVENT);
3381     debug_holding    = getconf_int(CNF_DEBUG_HOLDING);
3382     debug_protocol   = getconf_int(CNF_DEBUG_PROTOCOL);
3383     debug_planner    = getconf_int(CNF_DEBUG_PLANNER);
3384     debug_driver     = getconf_int(CNF_DEBUG_DRIVER);
3385     debug_dumper     = getconf_int(CNF_DEBUG_DUMPER);
3386     debug_chunker    = getconf_int(CNF_DEBUG_CHUNKER);
3387     debug_taper      = getconf_int(CNF_DEBUG_TAPER);
3388     debug_selfcheck  = getconf_int(CNF_DEBUG_SELFCHECK);
3389     debug_sendsize   = getconf_int(CNF_DEBUG_SENDSIZE);
3390     debug_sendbackup = getconf_int(CNF_DEBUG_SENDBACKUP);
3391
3392     /* And finally, display unit */
3393     switch (getconf_str(CNF_DISPLAYUNIT)[0]) {
3394         case 'k':
3395         case 'K':
3396             unit_divisor = 1;
3397             break;
3398
3399         case 'm':
3400         case 'M':
3401             unit_divisor = 1024;
3402             break;
3403
3404         case 'g':
3405         case 'G':
3406             unit_divisor = 1024*1024;
3407             break;
3408
3409         case 't':
3410         case 'T':
3411             unit_divisor = 1024*1024*1024;
3412             break;
3413
3414         default:
3415             error(_("Invalid displayunit missed by validate_displayunit"));
3416             /* NOTREACHED */
3417     }
3418 }
3419
3420 static void
3421 conf_init_int(
3422     val_t *val,
3423     int    i)
3424 {
3425     val->seen = 0;
3426     val->type = CONFTYPE_INT;
3427     val_t__int(val) = i;
3428 }
3429
3430 static void
3431 conf_init_am64(
3432     val_t *val,
3433     off_t   l)
3434 {
3435     val->seen = 0;
3436     val->type = CONFTYPE_AM64;
3437     val_t__am64(val) = l;
3438 }
3439
3440 static void
3441 conf_init_real(
3442     val_t  *val,
3443     float r)
3444 {
3445     val->seen = 0;
3446     val->type = CONFTYPE_REAL;
3447     val_t__real(val) = r;
3448 }
3449
3450 static void
3451 conf_init_str(
3452     val_t *val,
3453     char  *s)
3454 {
3455     val->seen = 0;
3456     val->type = CONFTYPE_STR;
3457     if(s)
3458         val->v.s = stralloc(s);
3459     else
3460         val->v.s = NULL;
3461 }
3462
3463 static void
3464 conf_init_ident(
3465     val_t *val,
3466     char  *s)
3467 {
3468     val->seen = 0;
3469     val->type = CONFTYPE_IDENT;
3470     if(s)
3471         val->v.s = stralloc(s);
3472     else
3473         val->v.s = NULL;
3474 }
3475
3476 static void
3477 conf_init_time(
3478     val_t *val,
3479     time_t   t)
3480 {
3481     val->seen = 0;
3482     val->type = CONFTYPE_TIME;
3483     val_t__time(val) = t;
3484 }
3485
3486 static void
3487 conf_init_size(
3488     val_t *val,
3489     ssize_t   sz)
3490 {
3491     val->seen = 0;
3492     val->type = CONFTYPE_SIZE;
3493     val_t__size(val) = sz;
3494 }
3495
3496 static void
3497 conf_init_bool(
3498     val_t *val,
3499     int    i)
3500 {
3501     val->seen = 0;
3502     val->type = CONFTYPE_BOOLEAN;
3503     val_t__boolean(val) = i;
3504 }
3505
3506 static void
3507 conf_init_compress(
3508     val_t *val,
3509     comp_t    i)
3510 {
3511     val->seen = 0;
3512     val->type = CONFTYPE_COMPRESS;
3513     val_t__compress(val) = (int)i;
3514 }
3515
3516 static void
3517 conf_init_encrypt(
3518     val_t *val,
3519     encrypt_t    i)
3520 {
3521     val->seen = 0;
3522     val->type = CONFTYPE_ENCRYPT;
3523     val_t__encrypt(val) = (int)i;
3524 }
3525
3526 static void
3527 conf_init_holding(
3528     val_t              *val,
3529     dump_holdingdisk_t  i)
3530 {
3531     val->seen = 0;
3532     val->type = CONFTYPE_HOLDING;
3533     val_t__holding(val) = (int)i;
3534 }
3535
3536 static void
3537 conf_init_estimate(
3538     val_t *val,
3539     estimate_t    i)
3540 {
3541     val->seen = 0;
3542     val->type = CONFTYPE_ESTIMATE;
3543     val_t__estimate(val) = i;
3544 }
3545
3546 static void
3547 conf_init_strategy(
3548     val_t *val,
3549     strategy_t    i)
3550 {
3551     val->seen = 0;
3552     val->type = CONFTYPE_STRATEGY;
3553     val_t__strategy(val) = i;
3554 }
3555
3556 static void
3557 conf_init_taperalgo(
3558     val_t *val,
3559     taperalgo_t    i)
3560 {
3561     val->seen = 0;
3562     val->type = CONFTYPE_TAPERALGO;
3563     val_t__taperalgo(val) = i;
3564 }
3565
3566 static void
3567 conf_init_priority(
3568     val_t *val,
3569     int    i)
3570 {
3571     val->seen = 0;
3572     val->type = CONFTYPE_PRIORITY;
3573     val_t__priority(val) = i;
3574 }
3575
3576 static void
3577 conf_init_rate(
3578     val_t  *val,
3579     float r1,
3580     float r2)
3581 {
3582     val->seen = 0;
3583     val->type = CONFTYPE_RATE;
3584     val_t__rate(val)[0] = r1;
3585     val_t__rate(val)[1] = r2;
3586 }
3587
3588 static void
3589 conf_init_exinclude(
3590     val_t *val)
3591 {
3592     val->seen = 0;
3593     val->type = CONFTYPE_EXINCLUDE;
3594     val_t__exinclude(val).optional = 0;
3595     val_t__exinclude(val).sl_list = NULL;
3596     val_t__exinclude(val).sl_file = NULL;
3597 }
3598
3599 static void
3600 conf_init_intrange(
3601     val_t *val,
3602     int    i1,
3603     int    i2)
3604 {
3605     val->seen = 0;
3606     val->type = CONFTYPE_INTRANGE;
3607     val_t__intrange(val)[0] = i1;
3608     val_t__intrange(val)[1] = i2;
3609 }
3610
3611 static void
3612 conf_init_proplist(
3613     val_t *val)
3614 {
3615     val->seen = 0;
3616     val->type = CONFTYPE_PROPLIST;
3617     val_t__proplist(val) =
3618         g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
3619 }
3620
3621 /*
3622  * Config access implementation
3623  */
3624
3625 val_t *
3626 getconf(confparm_key key)
3627 {
3628     assert(key < CNF_CNF);
3629     return &conf_data[key];
3630 }
3631
3632 GSList *
3633 getconf_list(
3634     char *listname)
3635 {
3636     tapetype_t *tp;
3637     dumptype_t *dp;
3638     interface_t *ip;
3639     holdingdisk_t *hp;
3640     GSList *rv = NULL;
3641
3642     if (strcasecmp(listname,"tapetype") == 0) {
3643         for(tp = tapelist; tp != NULL; tp=tp->next) {
3644             rv = g_slist_append(rv, tp->name);
3645         }
3646     } else if (strcasecmp(listname,"dumptype") == 0) {
3647         for(dp = dumplist; dp != NULL; dp=dp->next) {
3648             rv = g_slist_append(rv, dp->name);
3649         }
3650     } else if (strcasecmp(listname,"holdingdisk") == 0) {
3651         for(hp = holdinglist; hp != NULL; hp=hp->next) {
3652             rv = g_slist_append(rv, hp->name);
3653         }
3654     } else if (strcasecmp(listname,"interface") == 0) {
3655         for(ip = interface_list; ip != NULL; ip=ip->next) {
3656             rv = g_slist_append(rv, ip->name);
3657         }
3658     }
3659     return rv;
3660 }
3661
3662 val_t *
3663 getconf_byname(
3664     char *key)
3665 {
3666     val_t *rv = NULL;
3667
3668     if (!parm_key_info(key, NULL, &rv))
3669         return NULL;
3670
3671     return rv;
3672 }
3673
3674 tapetype_t *
3675 lookup_tapetype(
3676     char *str)
3677 {
3678     tapetype_t *p;
3679
3680     for(p = tapelist; p != NULL; p = p->next) {
3681         if(strcasecmp(p->name, str) == 0) return p;
3682     }
3683     return NULL;
3684 }
3685
3686 val_t *
3687 tapetype_getconf(
3688     tapetype_t *ttyp,
3689     tapetype_key key)
3690 {
3691     assert(ttyp != NULL);
3692     assert(key < TAPETYPE_TAPETYPE);
3693     return &ttyp->value[key];
3694 }
3695
3696 char *
3697 tapetype_name(
3698     tapetype_t *ttyp)
3699 {
3700     assert(ttyp != NULL);
3701     return ttyp->name;
3702 }
3703
3704 dumptype_t *
3705 lookup_dumptype(
3706     char *str)
3707 {
3708     dumptype_t *p;
3709
3710     for(p = dumplist; p != NULL; p = p->next) {
3711         if(strcasecmp(p->name, str) == 0) return p;
3712     }
3713     return NULL;
3714 }
3715
3716 val_t *
3717 dumptype_getconf(
3718     dumptype_t *dtyp,
3719     dumptype_key key)
3720 {
3721     assert(dtyp != NULL);
3722     assert(key < DUMPTYPE_DUMPTYPE);
3723     return &dtyp->value[key];
3724 }
3725
3726 char *
3727 dumptype_name(
3728     dumptype_t *dtyp)
3729 {
3730     assert(dtyp != NULL);
3731     return dtyp->name;
3732 }
3733
3734 interface_t *
3735 lookup_interface(
3736     char *str)
3737 {
3738     interface_t *p;
3739
3740     for(p = interface_list; p != NULL; p = p->next) {
3741         if(strcasecmp(p->name, str) == 0) return p;
3742     }
3743     return NULL;
3744 }
3745
3746 val_t *
3747 interface_getconf(
3748     interface_t *iface,
3749     interface_key key)
3750 {
3751     assert(iface != NULL);
3752     assert(key < INTER_INTER);
3753     return &iface->value[key];
3754 }
3755
3756 char *
3757 interface_name(
3758     interface_t *iface)
3759 {
3760     assert(iface != NULL);
3761     return iface->name;
3762 }
3763
3764 holdingdisk_t *
3765 lookup_holdingdisk(
3766     char *str)
3767 {
3768     holdingdisk_t *p;
3769
3770     for(p = holdinglist; p != NULL; p = p->next) {
3771         if(strcasecmp(p->name, str) == 0) return p;
3772     }
3773     return NULL;
3774 }
3775
3776 holdingdisk_t *
3777 getconf_holdingdisks(
3778     void)
3779 {
3780     return holdinglist;
3781 }
3782
3783 holdingdisk_t *
3784 holdingdisk_next(
3785     holdingdisk_t *hdisk)
3786 {
3787     if (hdisk) return hdisk->next;
3788     return NULL;
3789 }
3790
3791 val_t *
3792 holdingdisk_getconf(
3793     holdingdisk_t *hdisk,
3794     holdingdisk_key key)
3795 {
3796     assert(hdisk != NULL);
3797     assert(key < HOLDING_HOLDING);
3798     return &hdisk->value[key];
3799 }
3800
3801 char *
3802 holdingdisk_name(
3803     holdingdisk_t *hdisk)
3804 {
3805     assert(hdisk != NULL);
3806     return hdisk->name;
3807 }
3808
3809 long int
3810 getconf_unit_divisor(void)
3811 {
3812     return unit_divisor;
3813 }
3814
3815 /*
3816  * Command-line Handling Implementation
3817  */
3818
3819 config_overwrites_t *
3820 new_config_overwrites(
3821     int size_estimate)
3822 {
3823     config_overwrites_t *co;
3824
3825     co = alloc(sizeof(*co));
3826     co->ovr = alloc(sizeof(*co->ovr) * size_estimate);
3827     co->n_allocated = size_estimate;
3828     co->n_used = 0;
3829
3830     return co;
3831 }
3832
3833 void
3834 free_config_overwrites(
3835     config_overwrites_t *co)
3836 {
3837     int i;
3838
3839     if (!co) return;
3840     for (i = 0; i < co->n_used; i++) {
3841         amfree(co->ovr[i].key);
3842         amfree(co->ovr[i].value);
3843     }
3844     amfree(co->ovr);
3845     amfree(co);
3846 }
3847
3848 void add_config_overwrite(
3849     config_overwrites_t *co,
3850     char *key,
3851     char *value)
3852 {
3853     /* reallocate if necessary */
3854     if (co->n_used == co->n_allocated) {
3855         co->n_allocated *= 2;
3856         co->ovr = realloc(co->ovr, co->n_allocated * sizeof(*co->ovr));
3857         if (!co->ovr) {
3858             error(_("Cannot realloc; out of memory"));
3859             /* NOTREACHED */
3860         }
3861     }
3862
3863     co->ovr[co->n_used].key = stralloc(key);
3864     co->ovr[co->n_used].value = stralloc(value);
3865     co->n_used++;
3866 }
3867
3868 void
3869 add_config_overwrite_opt(
3870     config_overwrites_t *co,
3871     char *optarg)
3872 {
3873     char *value;
3874     assert(optarg != NULL);
3875
3876     value = index(optarg, '=');
3877     if (value == NULL) {
3878         error(_("Must specify a value for %s."), optarg);
3879         /* NOTREACHED */
3880     }
3881
3882     *value = '\0';
3883     add_config_overwrite(co, optarg, value+1);
3884     *value = '=';
3885 }
3886
3887 config_overwrites_t *
3888 extract_commandline_config_overwrites(
3889     int *argc,
3890     char ***argv)
3891 {
3892     int i, j, moveup;
3893     config_overwrites_t *co = new_config_overwrites(*argc/2);
3894
3895     i = 0;
3896     while (i<*argc) {
3897         if(strncmp((*argv)[i],"-o",2) == 0) {
3898             if(strlen((*argv)[i]) > 2) {
3899                 add_config_overwrite_opt(co, (*argv)[i]+2);
3900                 moveup = 1;
3901             }
3902             else {
3903                 if (i+1 >= *argc) error(_("expect something after -o"));
3904                 add_config_overwrite_opt(co, (*argv)[i+1]);
3905                 moveup = 2;
3906             }
3907
3908             /* move up remaining argment array */
3909             for (j = i; j+moveup<*argc; j++) {
3910                 (*argv)[j] = (*argv)[j+moveup];
3911             }
3912             *argc -= moveup;
3913         } else {
3914             i++;
3915         }
3916     }
3917
3918     return co;
3919 }
3920
3921 void
3922 apply_config_overwrites(
3923     config_overwrites_t *co)
3924 {
3925     int i;
3926
3927     if(!co) return;
3928     assert(keytable != NULL);
3929     assert(parsetable != NULL);
3930
3931     for (i = 0; i < co->n_used; i++) {
3932         char *key = co->ovr[i].key;
3933         char *value = co->ovr[i].value;
3934         val_t *key_val;
3935         conf_var_t *key_parm;
3936
3937         if (!parm_key_info(key, &key_parm, &key_val)) {
3938             error(_("unknown parameter '%s'"), key);
3939         }
3940
3941         /* now set up a fake line and use the relevant read_function to
3942          * parse it.  This is sneaky! */
3943
3944         if (key_parm->type == CONFTYPE_STR) {
3945             current_line = vstralloc("\"", value, "\"", NULL);
3946         } else {
3947             current_line = stralloc("");
3948         }
3949
3950         current_char = current_line;
3951         token_pushed = 0;
3952         current_line_num = -2;
3953         allow_overwrites = 1;
3954         got_parserror = 0;
3955
3956         key_parm->read_function(key_parm, key_val);
3957         if ((key_parm)->validate_function)
3958             key_parm->validate_function(key_parm, key_val);
3959
3960         amfree(current_line);
3961         current_char = NULL;
3962
3963         if (got_parserror) {
3964             error(_("parse error in configuration overwrites"));
3965             /* NOTREACHED */
3966         }
3967     }
3968
3969     /* merge these overwrites with previous overwrites, if necessary */
3970     if (applied_config_overwrites) {
3971         for (i = 0; i < co->n_used; i++) {
3972             char *key = co->ovr[i].key;
3973             char *value = co->ovr[i].value;
3974
3975             add_config_overwrite(applied_config_overwrites, key, value);
3976         }
3977         free_config_overwrites(co);
3978     } else {
3979         applied_config_overwrites = co;
3980     }
3981
3982     update_derived_values(config_client);
3983 }
3984
3985 /*
3986  * val_t Management Implementation
3987  */
3988
3989 int
3990 val_t_to_int(
3991     val_t *val)
3992 {
3993     if (val->type != CONFTYPE_INT) {
3994         error(_("val_t_to_int: val.type is not CONFTYPE_INT"));
3995         /*NOTREACHED*/
3996     }
3997     return val_t__int(val);
3998 }
3999
4000 off_t
4001 val_t_to_am64(
4002     val_t *val)
4003 {
4004     if (val->type != CONFTYPE_AM64) {
4005         error(_("val_t_to_am64: val.type is not CONFTYPE_AM64"));
4006         /*NOTREACHED*/
4007     }
4008     return val_t__am64(val);
4009 }
4010
4011 float
4012 val_t_to_real(
4013     val_t *val)
4014 {
4015     if (val->type != CONFTYPE_REAL) {
4016         error(_("val_t_to_real: val.type is not CONFTYPE_REAL"));
4017         /*NOTREACHED*/
4018     }
4019     return val_t__real(val);
4020 }
4021
4022 char *
4023 val_t_to_str(
4024     val_t *val)
4025 {
4026     /* support CONFTYPE_IDENT, too */
4027     if (val->type != CONFTYPE_STR && val->type != CONFTYPE_IDENT) {
4028         error(_("val_t_to_str: val.type is not CONFTYPE_STR nor CONFTYPE_IDENT"));
4029         /*NOTREACHED*/
4030     }
4031     return val_t__str(val);
4032 }
4033
4034 char *
4035 val_t_to_ident(
4036     val_t *val)
4037 {
4038     /* support CONFTYPE_STR, too */
4039     if (val->type != CONFTYPE_STR && val->type != CONFTYPE_IDENT) {
4040         error(_("val_t_to_ident: val.type is not CONFTYPE_IDENT nor CONFTYPE_STR"));
4041         /*NOTREACHED*/
4042     }
4043     return val_t__str(val);
4044 }
4045
4046 time_t
4047 val_t_to_time(
4048     val_t *val)
4049 {
4050     if (val->type != CONFTYPE_TIME) {
4051         error(_("val_t_to_time: val.type is not CONFTYPE_TIME"));
4052         /*NOTREACHED*/
4053     }
4054     return val_t__time(val);
4055 }
4056
4057 ssize_t
4058 val_t_to_size(
4059     val_t *val)
4060 {
4061     if (val->type != CONFTYPE_SIZE) {
4062         error(_("val_t_to_size: val.type is not CONFTYPE_SIZE"));
4063         /*NOTREACHED*/
4064     }
4065     return val_t__size(val);
4066 }
4067
4068 int
4069 val_t_to_boolean(
4070     val_t *val)
4071 {
4072     if (val->type != CONFTYPE_BOOLEAN) {
4073         error(_("val_t_to_bool: val.type is not CONFTYPE_BOOLEAN"));
4074         /*NOTREACHED*/
4075     }
4076     return val_t__boolean(val);
4077 }
4078
4079 comp_t
4080 val_t_to_compress(
4081     val_t *val)
4082 {
4083     if (val->type != CONFTYPE_COMPRESS) {
4084         error(_("val_t_to_compress: val.type is not CONFTYPE_COMPRESS"));
4085         /*NOTREACHED*/
4086     }
4087     return val_t__compress(val);
4088 }
4089
4090 encrypt_t
4091 val_t_to_encrypt(
4092     val_t *val)
4093 {
4094     if (val->type != CONFTYPE_ENCRYPT) {
4095         error(_("val_t_to_encrypt: val.type is not CONFTYPE_ENCRYPT"));
4096         /*NOTREACHED*/
4097     }
4098     return val_t__encrypt(val);
4099 }
4100
4101 dump_holdingdisk_t
4102 val_t_to_holding(
4103     val_t *val)
4104 {
4105     if (val->type != CONFTYPE_HOLDING) {
4106         error(_("val_t_to_hold: val.type is not CONFTYPE_HOLDING"));
4107         /*NOTREACHED*/
4108     }
4109     return val_t__holding(val);
4110 }
4111
4112 estimate_t
4113 val_t_to_estimate(
4114     val_t *val)
4115 {
4116     if (val->type != CONFTYPE_ESTIMATE) {
4117         error(_("val_t_to_extimate: val.type is not CONFTYPE_ESTIMATE"));
4118         /*NOTREACHED*/
4119     }
4120     return val_t__estimate(val);
4121 }
4122
4123 strategy_t
4124 val_t_to_strategy(
4125     val_t *val)
4126 {
4127     if (val->type != CONFTYPE_STRATEGY) {
4128         error(_("val_t_to_strategy: val.type is not CONFTYPE_STRATEGY"));
4129         /*NOTREACHED*/
4130     }
4131     return val_t__strategy(val);
4132 }
4133
4134 taperalgo_t
4135 val_t_to_taperalgo(
4136     val_t *val)
4137 {
4138     if (val->type != CONFTYPE_TAPERALGO) {
4139         error(_("val_t_to_taperalgo: val.type is not CONFTYPE_TAPERALGO"));
4140         /*NOTREACHED*/
4141     }
4142     return val_t__taperalgo(val);
4143 }
4144
4145 int
4146 val_t_to_priority(
4147     val_t *val)
4148 {
4149     if (val->type != CONFTYPE_PRIORITY) {
4150         error(_("val_t_to_priority: val.type is not CONFTYPE_PRIORITY"));
4151         /*NOTREACHED*/
4152     }
4153     return val_t__priority(val);
4154 }
4155
4156 float *
4157 val_t_to_rate(
4158     val_t *val)
4159 {
4160     if (val->type != CONFTYPE_RATE) {
4161         error(_("val_t_to_rate: val.type is not CONFTYPE_RATE"));
4162         /*NOTREACHED*/
4163     }
4164     return val_t__rate(val);
4165 }
4166
4167 exinclude_t
4168 val_t_to_exinclude(
4169     val_t *val)
4170 {
4171     if (val->type != CONFTYPE_EXINCLUDE) {
4172         error(_("val_t_to_exinclude: val.type is not CONFTYPE_EXINCLUDE"));
4173         /*NOTREACHED*/
4174     }
4175     return val_t__exinclude(val);
4176 }
4177
4178
4179 int *
4180 val_t_to_intrange(
4181     val_t *val)
4182 {
4183     if (val->type != CONFTYPE_INTRANGE) {
4184         error(_("val_t_to_intrange: val.type is not CONFTYPE_INTRANGE"));
4185         /*NOTREACHED*/
4186     }
4187     return val_t__intrange(val);
4188 }
4189
4190 proplist_t
4191 val_t_to_proplist(
4192     val_t *val)
4193 {
4194     if (val->type != CONFTYPE_PROPLIST) {
4195         error(_("val_t_to_proplist: val.type is not CONFTYPE_PROPLIST"));
4196         /*NOTREACHED*/
4197     }
4198     return val_t__proplist(val);
4199 }
4200
4201 static void
4202 copy_val_t(
4203     val_t *valdst,
4204     val_t *valsrc)
4205 {
4206     if(valsrc->seen) {
4207         valdst->type = valsrc->type;
4208         valdst->seen = valsrc->seen;
4209         switch(valsrc->type) {
4210         case CONFTYPE_INT:
4211         case CONFTYPE_BOOLEAN:
4212         case CONFTYPE_COMPRESS:
4213         case CONFTYPE_ENCRYPT:
4214         case CONFTYPE_HOLDING:
4215         case CONFTYPE_ESTIMATE:
4216         case CONFTYPE_STRATEGY:
4217         case CONFTYPE_TAPERALGO:
4218         case CONFTYPE_PRIORITY:
4219             valdst->v.i = valsrc->v.i;
4220             break;
4221
4222         case CONFTYPE_SIZE:
4223             valdst->v.size = valsrc->v.size;
4224             break;
4225
4226         case CONFTYPE_AM64:
4227             valdst->v.am64 = valsrc->v.am64;
4228             break;
4229
4230         case CONFTYPE_REAL:
4231             valdst->v.r = valsrc->v.r;
4232             break;
4233
4234         case CONFTYPE_RATE:
4235             valdst->v.rate[0] = valsrc->v.rate[0];
4236             valdst->v.rate[1] = valsrc->v.rate[1];
4237             break;
4238
4239         case CONFTYPE_IDENT:
4240         case CONFTYPE_STR:
4241             valdst->v.s = stralloc(valsrc->v.s);
4242             break;
4243
4244         case CONFTYPE_TIME:
4245             valdst->v.t = valsrc->v.t;
4246             break;
4247
4248         case CONFTYPE_EXINCLUDE:
4249             valdst->v.exinclude.optional = valsrc->v.exinclude.optional;
4250             valdst->v.exinclude.sl_list = duplicate_sl(valsrc->v.exinclude.sl_list);
4251             valdst->v.exinclude.sl_file = duplicate_sl(valsrc->v.exinclude.sl_file);
4252             break;
4253
4254         case CONFTYPE_INTRANGE:
4255             valdst->v.intrange[0] = valsrc->v.intrange[0];
4256             valdst->v.intrange[1] = valsrc->v.intrange[1];
4257             break;
4258
4259         case CONFTYPE_PROPLIST:
4260             g_assert_not_reached();
4261             break;
4262         }
4263     }
4264 }
4265
4266 static void
4267 free_val_t(
4268     val_t *val)
4269 {
4270     switch(val->type) {
4271         case CONFTYPE_INT:
4272         case CONFTYPE_BOOLEAN:
4273         case CONFTYPE_COMPRESS:
4274         case CONFTYPE_ENCRYPT:
4275         case CONFTYPE_HOLDING:
4276         case CONFTYPE_ESTIMATE:
4277         case CONFTYPE_STRATEGY:
4278         case CONFTYPE_SIZE:
4279         case CONFTYPE_TAPERALGO:
4280         case CONFTYPE_PRIORITY:
4281         case CONFTYPE_AM64:
4282         case CONFTYPE_REAL:
4283         case CONFTYPE_RATE:
4284         case CONFTYPE_INTRANGE:
4285             break;
4286
4287         case CONFTYPE_IDENT:
4288         case CONFTYPE_STR:
4289             amfree(val->v.s);
4290             break;
4291
4292         case CONFTYPE_TIME:
4293             break;
4294
4295         case CONFTYPE_EXINCLUDE:
4296             free_sl(val_t__exinclude(val).sl_list);
4297             free_sl(val_t__exinclude(val).sl_file);
4298             break;
4299
4300         case CONFTYPE_PROPLIST:
4301             g_hash_table_destroy(val_t__proplist(val));
4302             break;
4303     }
4304     val->seen = 0;
4305 }
4306
4307 /*
4308  * Utilities Implementation
4309  */
4310
4311 char *
4312 generic_get_security_conf(
4313         char *string,
4314         void *arg)
4315 {
4316         arg = arg;
4317         if(!string || !*string)
4318                 return(NULL);
4319
4320         if(strcmp(string, "krb5principal")==0) {
4321                 return(getconf_str(CNF_KRB5PRINCIPAL));
4322         } else if(strcmp(string, "krb5keytab")==0) {
4323                 return(getconf_str(CNF_KRB5KEYTAB));
4324         }
4325         return(NULL);
4326 }
4327
4328 char *
4329 generic_client_get_security_conf(
4330     char *      string,
4331     void *      arg)
4332 {
4333         (void)arg;      /* Quiet unused parameter warning */
4334
4335         if(!string || !*string)
4336                 return(NULL);
4337
4338         if(strcmp(string, "conf")==0) {
4339                 return(getconf_str(CNF_CONF));
4340         } else if(strcmp(string, "index_server")==0) {
4341                 return(getconf_str(CNF_INDEX_SERVER));
4342         } else if(strcmp(string, "tape_server")==0) {
4343                 return(getconf_str(CNF_TAPE_SERVER));
4344         } else if(strcmp(string, "tapedev")==0) {
4345                 return(getconf_str(CNF_TAPEDEV));
4346         } else if(strcmp(string, "auth")==0) {
4347                 return(getconf_str(CNF_AUTH));
4348         } else if(strcmp(string, "ssh_keys")==0) {
4349                 return(getconf_str(CNF_SSH_KEYS));
4350         } else if(strcmp(string, "amandad_path")==0) {
4351                 return(getconf_str(CNF_AMANDAD_PATH));
4352         } else if(strcmp(string, "client_username")==0) {
4353                 return(getconf_str(CNF_CLIENT_USERNAME));
4354         } else if(strcmp(string, "gnutar_list_dir")==0) {
4355                 return(getconf_str(CNF_GNUTAR_LIST_DIR));
4356         } else if(strcmp(string, "amandates")==0) {
4357                 return(getconf_str(CNF_AMANDATES));
4358         } else if(strcmp(string, "krb5principal")==0) {
4359                 return(getconf_str(CNF_KRB5PRINCIPAL));
4360         } else if(strcmp(string, "krb5keytab")==0) {
4361                 return(getconf_str(CNF_KRB5KEYTAB));
4362         }
4363         return(NULL);
4364 }
4365
4366 void
4367 dump_configuration(void)
4368 {
4369     tapetype_t *tp;
4370     dumptype_t *dp;
4371     interface_t *ip;
4372     holdingdisk_t *hp;
4373     int i;
4374     conf_var_t *np;
4375     keytab_t *kt;
4376     char *prefix;
4377
4378     if (config_client) {
4379         error(_("Don't know how to dump client configurations."));
4380         /* NOTREACHED */
4381     }
4382
4383     g_printf(_("# AMANDA CONFIGURATION FROM FILE \"%s\":\n\n"), config_filename);
4384
4385     for(np=server_var; np->token != CONF_UNKNOWN; np++) {
4386         for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) 
4387             if (np->token == kt->token) break;
4388
4389         if(kt->token == CONF_UNKNOWN)
4390             error(_("server bad token"));
4391
4392         val_t_print_token(stdout, NULL, "%-21s ", kt, &conf_data[np->parm]);
4393     }
4394
4395     for(hp = holdinglist; hp != NULL; hp = hp->next) {
4396         g_printf("\nHOLDINGDISK %s {\n", hp->name);
4397         for(i=0; i < HOLDING_HOLDING; i++) {
4398             for(np=holding_var; np->token != CONF_UNKNOWN; np++) {
4399                 if(np->parm == i)
4400                         break;
4401             }
4402             if(np->token == CONF_UNKNOWN)
4403                 error(_("holding bad value"));
4404
4405             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) {
4406                 if(kt->token == np->token)
4407                     break;
4408             }
4409             if(kt->token == CONF_UNKNOWN)
4410                 error(_("holding bad token"));
4411
4412             val_t_print_token(stdout, NULL, "      %-9s ", kt, &hp->value[i]);
4413         }
4414         g_printf("}\n");
4415     }
4416
4417     for(tp = tapelist; tp != NULL; tp = tp->next) {
4418         g_printf("\nDEFINE TAPETYPE %s {\n", tp->name);
4419         for(i=0; i < TAPETYPE_TAPETYPE; i++) {
4420             for(np=tapetype_var; np->token != CONF_UNKNOWN; np++)
4421                 if(np->parm == i) break;
4422             if(np->token == CONF_UNKNOWN)
4423                 error(_("tapetype bad value"));
4424
4425             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
4426                 if(kt->token == np->token) break;
4427             if(kt->token == CONF_UNKNOWN)
4428                 error(_("tapetype bad token"));
4429
4430             val_t_print_token(stdout, NULL, "      %-9s ", kt, &tp->value[i]);
4431         }
4432         g_printf("}\n");
4433     }
4434
4435     for(dp = dumplist; dp != NULL; dp = dp->next) {
4436         if (strncmp_const(dp->name, "custom(") != 0) { /* don't dump disklist-derived dumptypes */
4437             if(dp->seen == -1)
4438                 prefix = "#";
4439             else
4440                 prefix = "";
4441             g_printf("\n%sDEFINE DUMPTYPE %s {\n", prefix, dp->name);
4442             for(i=0; i < DUMPTYPE_DUMPTYPE; i++) {
4443                 for(np=dumptype_var; np->token != CONF_UNKNOWN; np++)
4444                     if(np->parm == i) break;
4445                 if(np->token == CONF_UNKNOWN)
4446                     error(_("dumptype bad value"));
4447
4448                 for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
4449                     if(kt->token == np->token) break;
4450                 if(kt->token == CONF_UNKNOWN)
4451                     error(_("dumptype bad token"));
4452
4453                 val_t_print_token(stdout, prefix, "      %-19s ", kt, &dp->value[i]);
4454             }
4455             g_printf("%s}\n", prefix);
4456         }
4457     }
4458
4459     for(ip = interface_list; ip != NULL; ip = ip->next) {
4460         if(strcmp(ip->name,"default") == 0)
4461             prefix = "#";
4462         else
4463             prefix = "";
4464         g_printf("\n%sDEFINE INTERFACE %s {\n", prefix, ip->name);
4465         for(i=0; i < INTER_INTER; i++) {
4466             for(np=interface_var; np->token != CONF_UNKNOWN; np++)
4467                 if(np->parm == i) break;
4468             if(np->token == CONF_UNKNOWN)
4469                 error(_("interface bad value"));
4470
4471             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
4472                 if(kt->token == np->token) break;
4473             if(kt->token == CONF_UNKNOWN)
4474                 error(_("interface bad token"));
4475
4476             val_t_print_token(stdout, prefix, "      %-19s ", kt, &ip->value[i]);
4477         }
4478         g_printf("%s}\n",prefix);
4479     }
4480
4481 }
4482
4483 static void
4484 val_t_print_token(
4485     FILE     *output,
4486     char     *prefix,
4487     char     *format,
4488     keytab_t *kt,
4489     val_t    *val)
4490 {
4491     char       **dispstrs, **dispstr;
4492     dispstrs = val_t_display_strs(val, 1);
4493
4494     /* For most configuration types, this outputs
4495      *   PREFIX KEYWORD DISPSTR
4496      * for each of the display strings.  For identifiers, however, it
4497      * simply prints the first line of the display string.
4498      */
4499
4500     /* Print the keyword for anything that is not itself an identifier */
4501     if (kt->token != CONF_IDENT) {
4502         for(dispstr=dispstrs; *dispstr!=NULL; dispstr++) {
4503             if (prefix)
4504                 g_fprintf(output, "%s", prefix);
4505             g_fprintf(output, format, kt->keyword);
4506             g_fprintf(output, "%s\n", *dispstr);
4507         }
4508     } else {
4509         /* for identifiers, assume there's at most one display string */
4510         assert(g_strv_length(dispstrs) <= 1);
4511         if (*dispstrs) {
4512             g_fprintf(output, "%s\n", *dispstrs);
4513         }
4514     }
4515
4516     g_strfreev(dispstrs);
4517 }
4518
4519 char **
4520 val_t_display_strs(
4521     val_t *val,
4522     int    str_need_quote)
4523 {
4524     char **buf;
4525     buf = malloc(3*SIZEOF(char *));
4526     buf[0] = NULL;
4527     buf[1] = NULL;
4528     buf[2] = NULL;
4529
4530     switch(val->type) {
4531     case CONFTYPE_INT:
4532         buf[0] = vstrallocf("%d", val_t__int(val));
4533         break;
4534
4535     case CONFTYPE_SIZE:
4536         buf[0] = vstrallocf("%zd", (ssize_t)val_t__size(val));
4537         break;
4538
4539     case CONFTYPE_AM64:
4540         buf[0] = vstrallocf("%lld", (long long)val_t__am64(val));
4541         break;
4542
4543     case CONFTYPE_REAL:
4544         buf[0] = vstrallocf("%0.5f", val_t__real(val));
4545         break;
4546
4547     case CONFTYPE_RATE:
4548         buf[0] = vstrallocf("%0.5f %0.5f", val_t__rate(val)[0], val_t__rate(val)[1]);
4549         break;
4550
4551     case CONFTYPE_INTRANGE:
4552         buf[0] = vstrallocf("%d,%d", val_t__intrange(val)[0], val_t__intrange(val)[1]);
4553         break;
4554
4555     case CONFTYPE_IDENT:
4556         if(val->v.s) {
4557             buf[0] = stralloc(val->v.s);
4558         } else {
4559             buf[0] = stralloc("");
4560         }
4561         break;
4562
4563     case CONFTYPE_STR:
4564         if(str_need_quote) {
4565             if(val->v.s) {
4566                 buf[0] = vstrallocf("\"%s\"", val->v.s);
4567             } else {
4568                 buf[0] = stralloc("\"\"");
4569             }
4570         } else {
4571             if(val->v.s) {
4572                 buf[0] = stralloc(val->v.s);
4573             } else {
4574                 buf[0] = stralloc("");
4575             }
4576         }
4577         break;
4578
4579     case CONFTYPE_TIME:
4580         buf[0] = vstrallocf("%2d%02d",
4581                          (int)val_t__time(val)/100, (int)val_t__time(val) % 100);
4582         break;
4583
4584     case CONFTYPE_EXINCLUDE: {
4585         buf[0] = exinclude_display_str(val, 0);
4586         buf[1] = exinclude_display_str(val, 1);
4587         break;
4588     }
4589
4590     case CONFTYPE_BOOLEAN:
4591         if(val_t__boolean(val))
4592             buf[0] = stralloc("yes");
4593         else
4594             buf[0] = stralloc("no");
4595         break;
4596
4597     case CONFTYPE_STRATEGY:
4598         switch(val_t__strategy(val)) {
4599         case DS_SKIP:
4600             buf[0] = vstrallocf("SKIP");
4601             break;
4602
4603         case DS_STANDARD:
4604             buf[0] = vstrallocf("STANDARD");
4605             break;
4606
4607         case DS_NOFULL:
4608             buf[0] = vstrallocf("NOFULL");
4609             break;
4610
4611         case DS_NOINC:
4612             buf[0] = vstrallocf("NOINC");
4613             break;
4614
4615         case DS_HANOI:
4616             buf[0] = vstrallocf("HANOI");
4617             break;
4618
4619         case DS_INCRONLY:
4620             buf[0] = vstrallocf("INCRONLY");
4621             break;
4622         }
4623         break;
4624
4625     case CONFTYPE_COMPRESS:
4626         switch(val_t__compress(val)) {
4627         case COMP_NONE:
4628             buf[0] = vstrallocf("NONE");
4629             break;
4630
4631         case COMP_FAST:
4632             buf[0] = vstrallocf("CLIENT FAST");
4633             break;
4634
4635         case COMP_BEST:
4636             buf[0] = vstrallocf("CLIENT BEST");
4637             break;
4638
4639         case COMP_CUST:
4640             buf[0] = vstrallocf("CLIENT CUSTOM");
4641             break;
4642
4643         case COMP_SERVER_FAST:
4644             buf[0] = vstrallocf("SERVER FAST");
4645             break;
4646
4647         case COMP_SERVER_BEST:
4648             buf[0] = vstrallocf("SERVER BEST");
4649             break;
4650
4651         case COMP_SERVER_CUST:
4652             buf[0] = vstrallocf("SERVER CUSTOM");
4653             break;
4654         }
4655         break;
4656
4657     case CONFTYPE_ESTIMATE:
4658         switch(val_t__estimate(val)) {
4659         case ES_CLIENT:
4660             buf[0] = vstrallocf("CLIENT");
4661             break;
4662
4663         case ES_SERVER:
4664             buf[0] = vstrallocf("SERVER");
4665             break;
4666
4667         case ES_CALCSIZE:
4668             buf[0] = vstrallocf("CALCSIZE");
4669             break;
4670         }
4671         break;
4672
4673      case CONFTYPE_ENCRYPT:
4674         switch(val_t__encrypt(val)) {
4675         case ENCRYPT_NONE:
4676             buf[0] = vstrallocf("NONE");
4677             break;
4678
4679         case ENCRYPT_CUST:
4680             buf[0] = vstrallocf("CLIENT");
4681             break;
4682
4683         case ENCRYPT_SERV_CUST:
4684             buf[0] = vstrallocf("SERVER");
4685             break;
4686         }
4687         break;
4688
4689      case CONFTYPE_HOLDING:
4690         switch(val_t__holding(val)) {
4691         case HOLD_NEVER:
4692             buf[0] = vstrallocf("NEVER");
4693             break;
4694
4695         case HOLD_AUTO:
4696             buf[0] = vstrallocf("AUTO");
4697             break;
4698
4699         case HOLD_REQUIRED:
4700             buf[0] = vstrallocf("REQUIRED");
4701             break;
4702         }
4703         break;
4704
4705      case CONFTYPE_TAPERALGO:
4706         buf[0] = vstrallocf("%s", taperalgo2str(val_t__taperalgo(val)));
4707         break;
4708
4709      case CONFTYPE_PRIORITY:
4710         switch(val_t__priority(val)) {
4711         case 0:
4712             buf[0] = vstrallocf("LOW");
4713             break;
4714
4715         case 1:
4716             buf[0] = vstrallocf("MEDIUM");
4717             break;
4718
4719         case 2:
4720             buf[0] = vstrallocf("HIGH");
4721             break;
4722         }
4723         break;
4724
4725     case CONFTYPE_PROPLIST: {
4726         int    nb_property;
4727         char **mybuf;
4728
4729         nb_property = g_hash_table_size(val_t__proplist(val));
4730         amfree(buf);
4731         buf = malloc((nb_property+1)*SIZEOF(char*));
4732         buf[nb_property] = NULL;
4733         mybuf = buf;
4734         g_hash_table_foreach(val_t__proplist(val), proplist_display_str_foreach_fn, &mybuf);
4735         break;
4736     }
4737     }
4738     return buf;
4739 }
4740
4741 static void
4742 proplist_display_str_foreach_fn(
4743     gpointer key_p,
4744     gpointer value_p,
4745     gpointer user_data_p)
4746 {
4747     char *property_s = key_p;
4748     char *value_s    = value_p;
4749     char ***msg      = (char ***)user_data_p;
4750
4751     **msg = vstralloc("\"", property_s, "\" \"", value_s, "\"", NULL);
4752     (*msg)++;
4753 }
4754
4755 static char *
4756 exinclude_display_str(
4757     val_t *val,
4758     int    file)
4759 {
4760     sl_t  *sl;
4761     sle_t *excl;
4762     char *rval;
4763
4764     assert(val->type == CONFTYPE_EXINCLUDE);
4765
4766     rval = stralloc("");
4767
4768     if (file == 0) {
4769         sl = val_t__exinclude(val).sl_list;
4770         strappend(rval, "LIST");
4771     } else {
4772         sl = val_t__exinclude(val).sl_file;
4773         strappend(rval, "FILE");
4774     }
4775
4776     if (val_t__exinclude(val).optional == 1) {
4777         strappend(rval, " OPTIONAL");
4778     }
4779
4780     if (sl != NULL) {
4781         for(excl = sl->first; excl != NULL; excl = excl->next) {
4782             vstrextend(&rval, " \"", excl->name, "\"", NULL);
4783         }
4784     }
4785
4786     return rval;
4787 }
4788
4789 char *
4790 taperalgo2str(
4791     taperalgo_t taperalgo)
4792 {
4793     if(taperalgo == ALGO_FIRST) return "FIRST";
4794     if(taperalgo == ALGO_FIRSTFIT) return "FIRSTFIT";
4795     if(taperalgo == ALGO_LARGEST) return "LARGEST";
4796     if(taperalgo == ALGO_LARGESTFIT) return "LARGESTFIT";
4797     if(taperalgo == ALGO_SMALLEST) return "SMALLEST";
4798     if(taperalgo == ALGO_LAST) return "LAST";
4799     return "UNKNOWN";
4800 }
4801
4802 char *
4803 config_dir_relative(
4804     char *filename)
4805 {
4806     if (*filename == '/' || config_dir == NULL) {
4807         return stralloc(filename);
4808     } else {
4809         if (config_dir[strlen(config_dir)-1] == '/') {
4810             return vstralloc(config_dir, filename, NULL);
4811         } else {
4812             return vstralloc(config_dir, "/", filename, NULL);
4813         }
4814     }
4815 }
4816
4817 static int
4818 parm_key_info(
4819     char *key,
4820     conf_var_t **parm,
4821     val_t **val)
4822 {
4823     conf_var_t *np;
4824     keytab_t *kt;
4825     char *s;
4826     char ch;
4827     char *subsec_type;
4828     char *subsec_name;
4829     char *subsec_key;
4830     tapetype_t *tp;
4831     dumptype_t *dp;
4832     interface_t *ip;
4833     holdingdisk_t *hp;
4834     int success = FALSE;
4835
4836     /* WARNING: assumes globals keytable and parsetable are set correctly. */
4837     assert(keytable != NULL);
4838     assert(parsetable != NULL);
4839
4840     /* make a copy we can stomp on */
4841     key = stralloc(key);
4842
4843     /* uppercase the key */
4844     s = key;
4845     for (s = key; (ch = *s) != 0; s++) {
4846         if(islower((int)ch))
4847             *s = (char)toupper(ch);
4848     }
4849
4850     subsec_name = strchr(key, ':');
4851     if (subsec_name) {
4852         subsec_type = key;
4853
4854         *subsec_name = '\0';
4855         subsec_name++;
4856
4857         subsec_key = strchr(subsec_name,':');
4858         if(!subsec_key) goto out; /* failure */
4859
4860         *subsec_key = '\0';
4861         subsec_key++;
4862
4863         /* If the keyword doesn't exist, there's no need to look up the
4864          * subsection -- we know it's invalid */
4865         for(kt = keytable; kt->token != CONF_UNKNOWN; kt++) {
4866             if(kt->keyword && strcmp(kt->keyword, subsec_key) == 0)
4867                 break;
4868         }
4869         if(kt->token == CONF_UNKNOWN) goto out;
4870
4871         /* Otherwise, figure out which kind of subsection we're dealing with,
4872          * and parse against that. */
4873         if (strcmp(subsec_type, "TAPETYPE") == 0) {
4874             tp = lookup_tapetype(subsec_name);
4875             if (!tp) goto out;
4876             for(np = tapetype_var; np->token != CONF_UNKNOWN; np++) {
4877                 if(np->token == kt->token)
4878                    break;
4879             }
4880             if (np->token == CONF_UNKNOWN) goto out;
4881
4882             if (val) *val = &tp->value[np->parm];
4883             if (parm) *parm = np;
4884             success = TRUE;
4885         } else if (strcmp(subsec_type, "DUMPTYPE") == 0) {
4886             dp = lookup_dumptype(subsec_name);
4887             if (!dp) goto out;
4888             for(np = dumptype_var; np->token != CONF_UNKNOWN; np++) {
4889                 if(np->token == kt->token)
4890                    break;
4891             }
4892             if (np->token == CONF_UNKNOWN) goto out;
4893
4894             if (val) *val = &dp->value[np->parm];
4895             if (parm) *parm = np;
4896             success = TRUE;
4897         } else if (strcmp(subsec_type, "HOLDINGDISK") == 0) {
4898             hp = lookup_holdingdisk(subsec_name);
4899             if (!hp) goto out;
4900             for(np = holding_var; np->token != CONF_UNKNOWN; np++) {
4901                 if(np->token == kt->token)
4902                    break;
4903             }
4904             if (np->token == CONF_UNKNOWN) goto out;
4905
4906             if (val) *val = &hp->value[np->parm];
4907             if (parm) *parm = np;
4908             success = TRUE;
4909         } else if (strcmp(subsec_type, "INTERFACE") == 0) {
4910             ip = lookup_interface(subsec_name);
4911             if (!ip) goto out;
4912             for(np = interface_var; np->token != CONF_UNKNOWN; np++) {
4913                 if(np->token == kt->token)
4914                    break;
4915             }
4916             if (np->token == CONF_UNKNOWN) goto out;
4917
4918             if (val) *val = &ip->value[np->parm];
4919             if (parm) *parm = np;
4920             success = TRUE;
4921         } 
4922
4923     /* No delimiters -- we're referencing a global config parameter */
4924     } else {
4925         /* look up the keyword */
4926         for(kt = keytable; kt->token != CONF_UNKNOWN; kt++) {
4927             if(kt->keyword && strcmp(kt->keyword, key) == 0)
4928                 break;
4929         }
4930         if(kt->token == CONF_UNKNOWN) goto out;
4931
4932         /* and then look that up in the parse table */
4933         for(np = parsetable; np->token != CONF_UNKNOWN; np++) {
4934             if(np->token == kt->token)
4935                 break;
4936         }
4937         if(np->token == CONF_UNKNOWN) goto out;
4938
4939         if (val) *val = &conf_data[np->parm];
4940         if (parm) *parm = np;
4941         success = TRUE;
4942     }
4943
4944 out:
4945     amfree(key);
4946     return success;
4947 }
4948
4949 gint64 
4950 find_multiplier(
4951     char * casestr)
4952 {
4953     keytab_t * table_entry;
4954     char * str = g_utf8_strup(casestr, -1);
4955     g_strstrip(str);
4956
4957     if (*str == '\0') {
4958         g_free(str);
4959         return 1;
4960     }
4961     
4962     for (table_entry = numb_keytable; table_entry->keyword != NULL;
4963          table_entry ++) {
4964         if (strcmp(casestr, table_entry->keyword) == 0) {
4965             g_free(str);
4966             switch (table_entry->token) {
4967             case CONF_MULT1K:
4968                 return 1024;
4969             case CONF_MULT1M:
4970                 return 1024*1024;
4971             case CONF_MULT1G:
4972                 return 1024*1024*1024;
4973             case CONF_MULT7:
4974                 return 7;
4975             case CONF_AMINFINITY:
4976                 return G_MAXINT64;
4977             case CONF_MULT1:
4978             case CONF_IDENT:
4979                 return 1;
4980             default:
4981                 /* Should not happen. */
4982                 return 0;
4983             }
4984         }
4985     }
4986
4987     /* None found; this is an error. */
4988     g_free(str);
4989     return 0;
4990 }
4991
4992 /*
4993  * Error Handling Implementaiton
4994  */
4995
4996 static void print_parse_problem(const char * format, va_list argp) {
4997     const char *xlated_fmt = gettext(format);
4998
4999     if(current_line)
5000         g_fprintf(stderr, _("argument \"%s\": "), current_line);
5001     else if (current_filename && current_line_num > 0)
5002         g_fprintf(stderr, "\"%s\", line %d: ", current_filename, current_line_num);
5003     else
5004         g_fprintf(stderr, _("parse error: "));
5005     
5006     g_vfprintf(stderr, xlated_fmt, argp);
5007     fputc('\n', stderr);
5008 }
5009
5010 printf_arglist_function(void conf_parserror, const char *, format)
5011 {
5012     va_list argp;
5013     
5014     arglist_start(argp, format);
5015     print_parse_problem(format, argp);
5016     arglist_end(argp);
5017
5018     got_parserror = TRUE;
5019 }
5020
5021 printf_arglist_function(void conf_parswarn, const char *, format) {
5022     va_list argp;
5023     
5024     arglist_start(argp, format);
5025     print_parse_problem(format, argp);
5026     arglist_end(argp);
5027 }