Imported Upstream version 3.2.1
[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 #include <glib.h>
39
40 /*
41  * Lexical analysis
42  */
43
44 /* This module implements its own quixotic lexer and parser, present for historical
45  * reasons.  If this were written from scratch, it would use flex/bison. */
46
47 /* An enumeration of the various tokens that might appear in a configuration file.
48  *
49  * - CONF_UNKNOWN has special meaning as an unrecognized token.
50  * - CONF_ANY can be used to request any token, rather than requiring a specific
51  *   token.
52  */
53 typedef enum {
54     CONF_UNKNOWN,               CONF_ANY,               CONF_COMMA,
55     CONF_LBRACE,                CONF_RBRACE,            CONF_NL,
56     CONF_END,                   CONF_IDENT,             CONF_INT,
57     CONF_INT64,                 CONF_BOOL,              CONF_REAL,
58     CONF_STRING,                CONF_TIME,              CONF_SIZE,
59
60     /* config parameters */
61     CONF_INCLUDEFILE,           CONF_ORG,               CONF_MAILTO,
62     CONF_DUMPUSER,              CONF_TAPECYCLE,         CONF_TAPEDEV,
63     CONF_CHANGERDEV,            CONF_CHANGERFILE,       CONF_LABELSTR,
64     CONF_BUMPPERCENT,           CONF_BUMPSIZE,          CONF_BUMPDAYS,
65     CONF_BUMPMULT,              CONF_ETIMEOUT,          CONF_DTIMEOUT,
66     CONF_CTIMEOUT,              CONF_TAPELIST,
67     CONF_DEVICE_OUTPUT_BUFFER_SIZE,
68     CONF_DISKFILE,              CONF_INFOFILE,          CONF_LOGDIR,
69     CONF_LOGFILE,               CONF_DISKDIR,           CONF_DISKSIZE,
70     CONF_INDEXDIR,              CONF_NETUSAGE,          CONF_INPARALLEL,
71     CONF_DUMPORDER,             CONF_TIMEOUT,           CONF_TPCHANGER,
72     CONF_RUNTAPES,              CONF_DEFINE,            CONF_DUMPTYPE,
73     CONF_TAPETYPE,              CONF_INTERFACE,         CONF_PRINTER,
74     CONF_MAILER,
75     CONF_AUTOFLUSH,             CONF_RESERVE,           CONF_MAXDUMPSIZE,
76     CONF_COLUMNSPEC,            CONF_AMRECOVER_DO_FSF,  CONF_AMRECOVER_CHECK_LABEL,
77     CONF_AMRECOVER_CHANGER,     CONF_LABEL_NEW_TAPES,   CONF_USETIMESTAMPS,
78     CONF_CHANGER,
79
80     CONF_TAPERALGO,             CONF_FIRST,             CONF_FIRSTFIT,
81     CONF_LARGEST,               CONF_LARGESTFIT,        CONF_SMALLEST,
82     CONF_LAST,                  CONF_DISPLAYUNIT,       CONF_RESERVED_UDP_PORT,
83     CONF_RESERVED_TCP_PORT,     CONF_UNRESERVED_TCP_PORT,
84     CONF_TAPERFLUSH,
85     CONF_FLUSH_THRESHOLD_DUMPED,
86     CONF_FLUSH_THRESHOLD_SCHEDULED,
87     CONF_DEVICE_PROPERTY,      CONF_PROPERTY,           CONF_PLUGIN,
88     CONF_APPLICATION,          CONF_APPLICATION_TOOL,
89     CONF_SCRIPT,               CONF_SCRIPT_TOOL,
90     CONF_EXECUTE_ON,           CONF_EXECUTE_WHERE,      CONF_SEND_AMREPORT_ON,
91     CONF_DEVICE,               CONF_ORDER,
92     CONF_DATA_PATH,            CONF_AMANDA,             CONF_DIRECTTCP,
93     CONF_TAPER_PARALLEL_WRITE,
94
95     /* execute on */
96     CONF_PRE_DLE_AMCHECK,      CONF_PRE_HOST_AMCHECK,
97     CONF_POST_DLE_AMCHECK,     CONF_POST_HOST_AMCHECK,
98     CONF_PRE_DLE_ESTIMATE,     CONF_PRE_HOST_ESTIMATE,
99     CONF_POST_DLE_ESTIMATE,    CONF_POST_HOST_ESTIMATE,
100     CONF_PRE_DLE_BACKUP,       CONF_PRE_HOST_BACKUP,
101     CONF_POST_DLE_BACKUP,      CONF_POST_HOST_BACKUP,
102     CONF_PRE_RECOVER,          CONF_POST_RECOVER,
103     CONF_PRE_LEVEL_RECOVER,    CONF_POST_LEVEL_RECOVER,
104     CONF_INTER_LEVEL_RECOVER,
105
106     /* kerberos 5 */
107     CONF_KRB5KEYTAB,            CONF_KRB5PRINCIPAL,
108
109     /* holding disk */
110     CONF_COMMENT,               CONF_DIRECTORY,         CONF_USE,
111     CONF_CHUNKSIZE,
112
113     /* dump type */
114     /*COMMENT,*/                CONF_PROGRAM,           CONF_DUMPCYCLE,
115     CONF_RUNSPERCYCLE,          CONF_MAXCYCLE,          CONF_MAXDUMPS,
116     CONF_OPTIONS,               CONF_PRIORITY,          CONF_FREQUENCY,
117     CONF_INDEX,                 CONF_MAXPROMOTEDAY,     CONF_STARTTIME,
118     CONF_COMPRESS,              CONF_ENCRYPT,           CONF_AUTH,
119     CONF_STRATEGY,              CONF_ESTIMATE,          CONF_SKIP_INCR,
120     CONF_SKIP_FULL,             CONF_RECORD,            CONF_HOLDING,
121     CONF_EXCLUDE,               CONF_INCLUDE,           CONF_KENCRYPT,
122     CONF_IGNORE,                CONF_COMPRATE,          CONF_TAPE_SPLITSIZE,
123     CONF_SPLIT_DISKBUFFER,      CONF_FALLBACK_SPLITSIZE,CONF_SRVCOMPPROG,
124     CONF_CLNTCOMPPROG,          CONF_SRV_ENCRYPT,       CONF_CLNT_ENCRYPT,
125     CONF_SRV_DECRYPT_OPT,       CONF_CLNT_DECRYPT_OPT,  CONF_AMANDAD_PATH,
126     CONF_CLIENT_USERNAME,       CONF_CLIENT_PORT,       CONF_ALLOW_SPLIT,
127
128     /* tape type */
129     /*COMMENT,*/                CONF_BLOCKSIZE,
130     CONF_LBL_TEMPL,             CONF_FILEMARK,          CONF_LENGTH,
131     CONF_SPEED,                 CONF_READBLOCKSIZE,
132
133     /* client conf */
134     CONF_CONF,                  CONF_INDEX_SERVER,      CONF_TAPE_SERVER,
135     CONF_SSH_KEYS,              CONF_GNUTAR_LIST_DIR,   CONF_AMANDATES,
136
137     /* protocol config */
138     CONF_REP_TRIES,             CONF_CONNECT_TRIES,     CONF_REQ_TRIES,
139
140     /* debug config */
141     CONF_DEBUG_DAYS,
142     CONF_DEBUG_AMANDAD,         CONF_DEBUG_AMIDXTAPED,  CONF_DEBUG_AMINDEXD,
143     CONF_DEBUG_AMRECOVER,       CONF_DEBUG_AUTH,        CONF_DEBUG_EVENT,
144     CONF_DEBUG_HOLDING,         CONF_DEBUG_PROTOCOL,    CONF_DEBUG_PLANNER,
145     CONF_DEBUG_DRIVER,          CONF_DEBUG_DUMPER,      CONF_DEBUG_CHUNKER,
146     CONF_DEBUG_TAPER,           CONF_DEBUG_SELFCHECK,   CONF_DEBUG_SENDSIZE,
147     CONF_DEBUG_SENDBACKUP,      CONF_DEBUG_RECOVERY,
148
149     /* network interface */
150     /* COMMENT, */              /* USE, */
151
152     /* dump options (obsolete) */
153     CONF_EXCLUDE_FILE,          CONF_EXCLUDE_LIST,
154
155     /* compress, estimate, encryption */
156     CONF_NONE,                  CONF_FAST,              CONF_BEST,
157     CONF_SERVER,                CONF_CLIENT,            CONF_CALCSIZE,
158     CONF_CUSTOM,
159
160     /* autolabel */
161     CONF_AUTOLABEL,             CONF_ANY_VOLUME,        CONF_OTHER_CONFIG,
162     CONF_NON_AMANDA,            CONF_VOLUME_ERROR,      CONF_EMPTY,
163
164     /* part_cache_type */
165     CONF_PART_SIZE,             CONF_PART_CACHE_TYPE,   CONF_PART_CACHE_DIR,
166     CONF_PART_CACHE_MAX_SIZE,   CONF_DISK,              CONF_MEMORY,
167
168     /* recovery-limit */
169     CONF_RECOVERY_LIMIT,        CONF_SAME_HOST,
170
171     /* holdingdisk */
172     CONF_NEVER,                 CONF_AUTO,              CONF_REQUIRED,
173
174     /* send_amreport */
175     CONF_ALL,                   CONF_STRANGE,           CONF_ERROR,
176
177     /* priority */
178     CONF_LOW,                   CONF_MEDIUM,            CONF_HIGH,
179
180     /* dump strategy */
181     CONF_SKIP,                  CONF_STANDARD,          CONF_NOFULL,
182     CONF_NOINC,                 CONF_HANOI,             CONF_INCRONLY,
183
184     /* exclude list */
185     CONF_LIST,                  CONF_EFILE,             CONF_APPEND,
186     CONF_OPTIONAL,
187
188     /* numbers */
189     CONF_AMINFINITY,            CONF_MULT1,             CONF_MULT7,
190     CONF_MULT1K,                CONF_MULT1M,            CONF_MULT1G,
191     CONF_MULT1T,
192
193     /* boolean */
194     CONF_ATRUE,                 CONF_AFALSE
195 } tok_t;
196
197 /* A keyword table entry, mapping the given keyword to the given token.
198  * Note that punctuation, integers, and quoted strings are handled 
199  * internally to the lexer, so they do not appear here. */
200 typedef struct {
201     char *keyword;
202     tok_t token;
203 } keytab_t;
204
205 /* The current keyword table, used by all token-related functions */
206 static keytab_t *keytable = NULL;
207
208 /* Has a token been "ungotten", and if so, what was it? */
209 static int token_pushed;
210 static tok_t pushed_tok;
211
212 /* The current token and its value.  Note that, unlike most other val_t*,
213  * tokenval's v.s points to statically allocated memory which cannot be
214  * free()'d. */
215 static tok_t tok;
216 static val_t tokenval;
217
218 /* The current input information: file, filename, line, and character 
219  * (which points somewhere within current_line) */
220 static FILE *current_file = NULL;
221 static char *current_filename = NULL;
222 static char *current_line = NULL;
223 static char *current_char = NULL;
224 static int current_line_num = 0; /* (technically, managed by the parser) */
225
226 /* A static buffer for storing tokens while they are being scanned. */
227 static char tkbuf[4096];
228
229 /* Return a token formated for output */
230 static char *str_keyword(keytab_t *kt);
231
232 static char *str_keyword(keytab_t *kt);
233 /* Look up the name of the given token in the current keytable */
234 static char *get_token_name(tok_t);
235
236 /* Look up a token in keytable, given a string, returning CONF_UNKNOWN 
237  * for unrecognized strings.  Search is case-insensitive. */
238 static tok_t lookup_keyword(char *str);
239
240 /* Get the next token.  If exp is anything but CONF_ANY, and the next token
241  * does not match, then a parse error is flagged.  This function reads from the
242  * current_* static variables, recognizes keywords against the keytable static
243  * variable, and places its result in tok and tokenval. */
244 static void get_conftoken(tok_t exp);
245
246 /* "Unget" the current token; this supports a 1-token lookahead. */
247 static void unget_conftoken(void);
248
249 /* Tokenizer character-by-character access. */
250 static int  conftoken_getc(void);
251 static int  conftoken_ungetc(int c);
252
253 static void merge_proplist_foreach_fn(gpointer key_p,
254                                       gpointer value_p,
255                                       gpointer user_data_p);
256 static void copy_proplist_foreach_fn(gpointer key_p,
257                                      gpointer value_p,
258                                      gpointer user_data_p);
259
260 /*
261  * Parser
262  */
263
264 /* A parser table entry.  Read as "<token> introduces parameter <parm>,
265  * the data for which will be read by <read_function> and validated by
266  * <validate_function> (if not NULL).  <type> is only used in formatting 
267  * config overwrites. */
268 typedef struct conf_var_s {
269     tok_t       token;
270     conftype_t  type;
271     void        (*read_function) (struct conf_var_s *, val_t*);
272     int         parm;
273     void        (*validate_function) (struct conf_var_s *, val_t *);
274 } conf_var_t;
275
276 /* This is a list of filenames that are used in 'seen_t' structs. */
277 static GSList *seen_filenames = NULL;
278
279 /* get a copy of filename that's stored in seen_filenames so that it won't go
280  * away until config_uninit. */
281 static char *get_seen_filename(char *filename);
282
283 /* If allow_overwrites is true, the a parameter which has already been
284  * seen will simply overwrite the old value, rather than triggering an 
285  * error.  Note that this does not apply to all parameters, e.g., 
286  * device_property */
287 static int allow_overwrites;
288
289 /* subsection structs
290  *
291  * The 'seen' fields in these structs are useless outside this module;
292  * they are only used to generate error messages for multiply defined
293  * subsections.
294  */
295 struct tapetype_s {
296     struct tapetype_s *next;
297     seen_t seen;
298     char *name;
299
300     val_t value[TAPETYPE_TAPETYPE];
301 };
302
303 struct dumptype_s {
304     struct dumptype_s *next;
305     seen_t seen;
306     char *name;
307
308     val_t value[DUMPTYPE_DUMPTYPE];
309 };
310
311 struct interface_s {
312     struct interface_s *next;
313     seen_t seen;
314     char *name;
315
316     val_t value[INTER_INTER];
317 };
318
319 struct holdingdisk_s {
320     seen_t seen;
321     char *name;
322
323     val_t value[HOLDING_HOLDING];
324 };
325
326 struct application_s {
327     struct application_s *next;
328     seen_t seen;
329     char *name;
330
331     val_t value[APPLICATION_APPLICATION];
332 };
333
334 struct pp_script_s {
335     struct pp_script_s *next;
336     seen_t seen;
337     char *name;
338
339     val_t value[PP_SCRIPT_PP_SCRIPT];
340 };
341
342 struct device_config_s {
343     struct device_config_s *next;
344     seen_t seen;
345     char *name;
346
347     val_t value[DEVICE_CONFIG_DEVICE_CONFIG];
348 };
349
350 struct changer_config_s {
351     struct changer_config_s *next;
352     int seen;
353     char *name;
354
355     val_t value[CHANGER_CONFIG_CHANGER_CONFIG];
356 };
357
358 /* The current parser table */
359 static conf_var_t *parsetable = NULL;
360
361 /* Read and parse a configuration file, recursively reading any included
362  * files.  This function sets the keytable and parsetable appropriately
363  * according to is_client.
364  *
365  * @param filename: configuration file to read
366  * @param is_client: true if this is a client
367  * @param missing_ok: is it OK if the file is missing?
368  */
369 static void read_conffile(char *filename,
370                           gboolean is_client,
371                           gboolean missing_ok);
372
373 /* Read and process a line of input from the current file, using the 
374  * current keytable and parsetable.  For blocks, this recursively
375  * reads the entire block.
376  *
377  * @param is_client: true if this is a client
378  * @returns: true on success, false on EOF
379  */
380 static gboolean read_confline(gboolean is_client);
381
382 /* Handle an invalid token, recognizing deprecated tokens as such,
383  * and producing an appropriate error message.
384  *
385  * @param token: the identifier
386  */
387 static void handle_invalid_keyword(const char * token);
388
389 /* Check whether token is deprecated, and issue a warning if it
390  * is.  This consults the global variables 'tok' and 'tokenval'
391  */
392 static void handle_deprecated_keyword(void);
393
394 /* Read a brace-delimited block using the given parse table.  This
395  * function is used to read brace-delimited subsections in the config
396  * files and also (via read_dumptype) to read dumptypes from
397  * the disklist.
398  *
399  * This function implements "inheritance" as follows: if a bare
400  * identifier occurs within the braces, it calls copy_function (if
401  * not NULL), which looks up an existing subsection using the
402  * identifier from tokenval and copies any values not already seen
403  * into valarray.
404  *
405  * @param read_var: the parse table to use
406  * @param valarray: the (pre-initialized) val_t array to fill in
407  * @param errormsg: error message to display for unrecognized keywords
408  * @param read_brace: if true, read the opening brace
409  * @param copy_function: function to copy configuration from
410  *     another subsection into this one.
411  */
412 static void read_block(conf_var_t *read_var, val_t *valarray, 
413                        char *errormsg, int read_brace,
414                        void (*copy_function)(void),
415                        char *type, char *name);
416
417 /* For each subsection type, we have a global and  four functions:
418  *  - foocur is a temporary struct used to assemble new subsections
419  *  - get_foo is called after reading "DEFINE FOO", and
420  *    is responsible for reading the entire block, using
421  *    read_block()
422  *  - init_foo_defaults initializes a new subsection struct
423  *    to its default values
424  *  - save_foo copies foocur to a newly allocated struct and
425  *    inserts that into the relevant list.
426  *  - copy_foo implements inheritance as described in read_block()
427  */
428 static holdingdisk_t hdcur;
429 static void get_holdingdisk(int is_define);
430 static void init_holdingdisk_defaults(void);
431 static void save_holdingdisk(void);
432 static void copy_holdingdisk(void);
433
434 static dumptype_t dpcur;
435 static void get_dumptype(void);
436 static void init_dumptype_defaults(void);
437 static void save_dumptype(void);
438 static void copy_dumptype(void);
439
440 static tapetype_t tpcur;
441 static void get_tapetype(void);
442 static void init_tapetype_defaults(void);
443 static void save_tapetype(void);
444 static void copy_tapetype(void);
445
446 static interface_t ifcur;
447 static void get_interface(void);
448 static void init_interface_defaults(void);
449 static void save_interface(void);
450 static void copy_interface(void);
451
452 static application_t apcur;
453 static void get_application(void);
454 static void init_application_defaults(void);
455 static void save_application(void);
456 static void copy_application(void);
457
458 static pp_script_t pscur;
459 static void get_pp_script(void);
460 static void init_pp_script_defaults(void);
461 static void save_pp_script(void);
462 static void copy_pp_script(void);
463
464 static device_config_t dccur;
465 static void get_device_config(void);
466 static void init_device_config_defaults(void);
467 static void save_device_config(void);
468 static void copy_device_config(void);
469
470 static changer_config_t cccur;
471 static void get_changer_config(void);
472 static void init_changer_config_defaults(void);
473 static void save_changer_config(void);
474 static void copy_changer_config(void);
475
476 /* read_functions -- these fit into the read_function slot in a parser
477  * table entry, and are responsible for calling getconf_token as necessary
478  * to consume their arguments, and setting their second argument with the
479  * result.  The first argument is a copy of the parser table entry, if
480  * needed. */
481 static void read_int(conf_var_t *, val_t *);
482 static void read_int64(conf_var_t *, val_t *);
483 static void read_real(conf_var_t *, val_t *);
484 static void read_str(conf_var_t *, val_t *);
485 static void read_ident(conf_var_t *, val_t *);
486 static void read_time(conf_var_t *, val_t *);
487 static void read_size(conf_var_t *, val_t *);
488 static void read_size_byte(conf_var_t *, val_t *);
489 static void read_bool(conf_var_t *, val_t *);
490 static void read_compress(conf_var_t *, val_t *);
491 static void read_encrypt(conf_var_t *, val_t *);
492 static void read_holding(conf_var_t *, val_t *);
493 static void read_estimatelist(conf_var_t *, val_t *);
494 static void read_strategy(conf_var_t *, val_t *);
495 static void read_taperalgo(conf_var_t *, val_t *);
496 static void read_send_amreport_on(conf_var_t *, val_t *);
497 static void read_data_path(conf_var_t *, val_t *);
498 static void read_priority(conf_var_t *, val_t *);
499 static void read_rate(conf_var_t *, val_t *);
500 static void read_exinclude(conf_var_t *, val_t *);
501 static void read_intrange(conf_var_t *, val_t *);
502 static void read_dapplication(conf_var_t *, val_t *);
503 static void read_dpp_script(conf_var_t *, val_t *);
504 static void read_property(conf_var_t *, val_t *);
505 static void read_execute_on(conf_var_t *, val_t *);
506 static void read_execute_where(conf_var_t *, val_t *);
507 static void read_holdingdisk(conf_var_t *, val_t *);
508 static void read_int_or_str(conf_var_t *, val_t *);
509 static void read_autolabel(conf_var_t *, val_t *);
510 static void read_part_cache_type(conf_var_t *, val_t *);
511 static void read_recovery_limit(conf_var_t *, val_t *);
512
513 /* Functions to get various types of values.  These are called by
514  * read_functions to take care of any variations in the way that these
515  * values can be written: integers can have units, boolean values can be
516  * specified with a number of names, etc.  They form utility functions
517  * for the read_functions, below. */
518 static time_t  get_time(void);
519 static int     get_int(void);
520 static ssize_t get_size(void);
521 static ssize_t get_size_byte(void);
522 static gint64  get_int64(void);
523 static int     get_bool(void);
524
525 /* Check the given 'seen', flagging an error if this value has already
526  * been seen and allow_overwrites is false.  Also marks the value as
527  * seen on the current line.
528  *
529  * @param seen: (in/out) seen value to adjust
530  */
531 static void ckseen(seen_t *seen);
532
533 /* validate_functions -- these fit into the validate_function solt in
534  * a parser table entry.  They call conf_parserror if the value in their
535  * second argument is invalid.  */
536 static void validate_nonnegative(conf_var_t *, val_t *);
537 static void validate_non_zero(conf_var_t *, val_t *);
538 static void validate_positive(conf_var_t *, val_t *);
539 static void validate_runspercycle(conf_var_t *, val_t *);
540 static void validate_bumppercent(conf_var_t *, val_t *);
541 static void validate_bumpmult(conf_var_t *, val_t *);
542 static void validate_inparallel(conf_var_t *, val_t *);
543 static void validate_displayunit(conf_var_t *, val_t *);
544 static void validate_reserve(conf_var_t *, val_t *);
545 static void validate_use(conf_var_t *, val_t *);
546 static void validate_chunksize(conf_var_t *, val_t *);
547 static void validate_blocksize(conf_var_t *, val_t *);
548 static void validate_debug(conf_var_t *, val_t *);
549 static void validate_port_range(val_t *, int, int);
550 static void validate_reserved_port_range(conf_var_t *, val_t *);
551 static void validate_unreserved_port_range(conf_var_t *, val_t *);
552 static void validate_program(conf_var_t *, val_t *);
553 gint compare_pp_script_order(gconstpointer a, gconstpointer b);
554
555 /*
556  * Initialization
557  */
558
559 /* The name of the configuration under which this application is running.
560  * This variable is initialized by config_init.
561  */
562 static char *config_name = NULL;
563
564 /* The directory containing the configuration for this application.  This
565  * variable is initialized by config_init
566  */
567 static char *config_dir = NULL;
568
569 /* The most recently read top-level configuration file.  This variable is
570  * initialized by config_init
571  */
572 static char *config_filename = NULL;
573
574 /* Has the config been initialized? */
575 static gboolean config_initialized = FALSE;
576
577 /* Are we running a client? (true if last init was
578  * with CONFIG_INIT_CLIENT) */
579 static gboolean config_client = FALSE;
580
581 /* What config overwrites to use? */
582 static config_overrides_t *config_overrides = NULL;
583
584 /* All global parameters */
585 static val_t conf_data[CNF_CNF];
586
587 /* Linked list of holding disks */
588 static GSList *holdinglist = NULL;
589 static dumptype_t *dumplist = NULL;
590 static tapetype_t *tapelist = NULL;
591 static interface_t *interface_list = NULL;
592 static application_t *application_list = NULL;
593 static pp_script_t *pp_script_list = NULL;
594 static device_config_t *device_config_list = NULL;
595 static changer_config_t *changer_config_list = NULL;
596
597 /* storage for derived values */
598 static long int unit_divisor = 1;
599
600 int debug_amandad    = 0;
601 int debug_recovery   = 0;
602 int debug_amidxtaped = 0;
603 int debug_amindexd   = 0;
604 int debug_amrecover  = 0;
605 int debug_auth       = 0;
606 int debug_event      = 0;
607 int debug_holding    = 0;
608 int debug_protocol   = 0;
609 int debug_planner    = 0;
610 int debug_driver     = 0;
611 int debug_dumper     = 0;
612 int debug_chunker    = 0;
613 int debug_taper      = 0;
614 int debug_selfcheck  = 0;
615 int debug_sendsize   = 0;
616 int debug_sendbackup = 0;
617
618 /* Reset all configuration values to their defaults (which, in many
619  * cases, come from --with-foo options at build time) */
620 static void init_defaults(void);
621
622 /* Update all dervied values based on the current configuration.  This
623  * function can be called multiple times, once after each adjustment
624  * to the current configuration.
625  *
626  * @param is_client: are we running a client?
627  */
628 static void update_derived_values(gboolean is_client);
629
630 static cfgerr_level_t apply_config_overrides(config_overrides_t *co,
631                                              char *key_ovr);
632
633 /* per-type conf_init functions, used as utilities for init_defaults
634  * and for each subsection's init_foo_defaults.
635  *
636  * These set the value's type and seen flags, as well as copying
637  * the relevant value into the 'v' field.
638  */
639 static void conf_init_int(val_t *val, int i);
640 static void conf_init_int64(val_t *val, gint64 l);
641 static void conf_init_real(val_t *val, float r);
642 static void conf_init_str(val_t *val, char *s);
643 static void conf_init_ident(val_t *val, char *s);
644 static void conf_init_identlist(val_t *val, char *s);
645 static void conf_init_time(val_t *val, time_t t);
646 static void conf_init_size(val_t *val, ssize_t sz);
647 static void conf_init_bool(val_t *val, int i);
648 static void conf_init_compress(val_t *val, comp_t i);
649 static void conf_init_encrypt(val_t *val, encrypt_t i);
650 static void conf_init_data_path(val_t *val, data_path_t i);
651 static void conf_init_holding(val_t *val, dump_holdingdisk_t i);
652 static void conf_init_estimatelist(val_t *val, estimate_t i);
653 static void conf_init_execute_on(val_t *, int);
654 static void conf_init_execute_where(val_t *, int);
655 static void conf_init_send_amreport(val_t *val, send_amreport_t i);
656 static void conf_init_strategy(val_t *val, strategy_t);
657 static void conf_init_taperalgo(val_t *val, taperalgo_t i);
658 static void conf_init_priority(val_t *val, int i);
659 static void conf_init_rate(val_t *val, float r1, float r2);
660 static void conf_init_exinclude(val_t *val); /* to empty list */
661 static void conf_init_intrange(val_t *val, int i1, int i2);
662 static void conf_init_proplist(val_t *val); /* to empty list */
663 static void conf_init_application(val_t *val);
664 static void conf_init_autolabel(val_t *val);
665 static void conf_init_part_cache_type(val_t *val, part_cache_type_t i);
666 static void conf_init_recovery_limit(val_t *val);
667
668 /*
669  * Command-line Handling
670  */
671
672 typedef struct config_override_s {
673     char     *key;
674     char     *value;
675     gboolean  applied;
676 } config_override_t;
677
678 struct config_overrides_s {
679     int n_allocated;
680     int n_used;
681     config_override_t *ovr;
682 };
683
684 /*
685  * val_t Management
686  */
687
688 static void merge_val_t(val_t *, val_t *);
689 static void copy_val_t(val_t *, val_t *);
690 static void free_val_t(val_t *);
691
692 /*
693  * Utilities
694  */
695
696 /* memory handling */
697 void free_property_t(gpointer p);
698
699 /* Utility functions/structs for val_t_display_strs */
700 static char *exinclude_display_str(val_t *val, int file);
701 static void proplist_display_str_foreach_fn(gpointer key_p, gpointer value_p, gpointer user_data_p);
702 static void val_t_print_token(FILE *output, char *prefix, char *format, keytab_t *kt, val_t *val);
703
704 /* Given a key name as used in config overwrites, return a pointer to the corresponding
705  * conf_var_t in the current parsetable, and the val_t representing that value.  This
706  * function will access subsections if key has the form  TYPE:SUBSEC:KEYWORD.  Returns
707  * false if the value does not exist.
708  *
709  * Assumes keytable and parsetable are set correctly, which is generally OK after 
710  * config_init has been called.
711  *
712  * @param key: the key to look up
713  * @param parm: (result) the parse table entry
714  * @param val: (result) the parameter value
715  * @returns: true on success
716  */
717 static int parm_key_info(char *key, conf_var_t **parm, val_t **val);
718
719 /*
720  * Error handling
721  */
722
723 /* Have we seen a parse error yet?  Parsing continues after an error, so this
724  * flag is checked after the parse is complete.
725  */
726 static cfgerr_level_t cfgerr_level;
727 static GSList *cfgerr_errors = NULL;
728
729 static void conf_error_common(cfgerr_level_t level, const char * format, va_list argp);
730 static void    conf_parserror(const char *format, ...)
731                 __attribute__ ((format (printf, 1, 2)));
732
733 static void    conf_parswarn(const char *format, ...)
734                 __attribute__ ((format (printf, 1, 2)));
735
736 /*
737  * Tables
738  */
739
740 /* First, the keyword tables for client and server */
741 keytab_t client_keytab[] = {
742     { "CONF", CONF_CONF },
743     { "INDEX_SERVER", CONF_INDEX_SERVER },
744     { "TAPE_SERVER", CONF_TAPE_SERVER },
745     { "TAPEDEV", CONF_TAPEDEV },
746     { "AUTH", CONF_AUTH },
747     { "SSH_KEYS", CONF_SSH_KEYS },
748     { "AMANDAD_PATH", CONF_AMANDAD_PATH },
749     { "CLIENT_USERNAME", CONF_CLIENT_USERNAME },
750     { "CLIENT_PORT", CONF_CLIENT_PORT },
751     { "GNUTAR_LIST_DIR", CONF_GNUTAR_LIST_DIR },
752     { "AMANDATES", CONF_AMANDATES },
753     { "KRB5KEYTAB", CONF_KRB5KEYTAB },
754     { "KRB5PRINCIPAL", CONF_KRB5PRINCIPAL },
755     { "INCLUDEFILE", CONF_INCLUDEFILE },
756     { "CONNECT_TRIES", CONF_CONNECT_TRIES },
757     { "REP_TRIES", CONF_REP_TRIES },
758     { "REQ_TRIES", CONF_REQ_TRIES },
759     { "CLIENT", CONF_CLIENT },
760     { "DEBUG_DAYS", CONF_DEBUG_DAYS },
761     { "DEBUG_AMANDAD", CONF_DEBUG_AMANDAD },
762     { "DEBUG_RECOVERY", CONF_DEBUG_RECOVERY },
763     { "DEBUG_AMIDXTAPED", CONF_DEBUG_AMIDXTAPED },
764     { "DEBUG_AMINDEXD", CONF_DEBUG_AMINDEXD },
765     { "DEBUG_AMRECOVER", CONF_DEBUG_AMRECOVER },
766     { "DEBUG_AUTH", CONF_DEBUG_AUTH },
767     { "DEBUG_EVENT", CONF_DEBUG_EVENT },
768     { "DEBUG_HOLDING", CONF_DEBUG_HOLDING },
769     { "DEBUG_PROTOCOL", CONF_DEBUG_PROTOCOL },
770     { "DEBUG_PLANNER", CONF_DEBUG_PLANNER },
771     { "DEBUG_DRIVER", CONF_DEBUG_DRIVER },
772     { "DEBUG_DUMPER", CONF_DEBUG_DUMPER },
773     { "DEBUG_CHUNKER", CONF_DEBUG_CHUNKER },
774     { "DEBUG_TAPER", CONF_DEBUG_TAPER },
775     { "DEBUG_SELFCHECK", CONF_DEBUG_SELFCHECK },
776     { "DEBUG_SENDSIZE", CONF_DEBUG_SENDSIZE },
777     { "DEBUG_SENDBACKUP", CONF_DEBUG_SENDBACKUP },
778     { "EXECUTE_ON", CONF_EXECUTE_ON },
779     { "EXECUTE_WHERE", CONF_EXECUTE_WHERE },
780     { "RESERVED_UDP_PORT", CONF_RESERVED_UDP_PORT },
781     { "RESERVED_TCP_PORT", CONF_RESERVED_TCP_PORT },
782     { "UNRESERVED_TCP_PORT", CONF_UNRESERVED_TCP_PORT },
783     { "DEFINE", CONF_DEFINE },
784     { "COMMENT", CONF_COMMENT },
785     { "MAILER", CONF_MAILER },
786     { "ORDER", CONF_ORDER },
787     { "SCRIPT", CONF_SCRIPT },
788     { "SCRIPT_TOOL", CONF_SCRIPT_TOOL },
789     { "PLUGIN", CONF_PLUGIN },
790     { "PRE_DLE_AMCHECK", CONF_PRE_DLE_AMCHECK },
791     { "PRE_HOST_AMCHECK", CONF_PRE_HOST_AMCHECK },
792     { "POST_DLE_AMCHECK", CONF_POST_DLE_AMCHECK },
793     { "POST_HOST_AMCHECK", CONF_POST_HOST_AMCHECK },
794     { "PRE_DLE_ESTIMATE", CONF_PRE_DLE_ESTIMATE },
795     { "PRE_HOST_ESTIMATE", CONF_PRE_HOST_ESTIMATE },
796     { "POST_DLE_ESTIMATE", CONF_POST_DLE_ESTIMATE },
797     { "POST_HOST_ESTIMATE", CONF_POST_HOST_ESTIMATE },
798     { "POST_DLE_BACKUP", CONF_POST_DLE_BACKUP },
799     { "POST_HOST_BACKUP", CONF_POST_HOST_BACKUP },
800     { "PRE_DLE_BACKUP", CONF_PRE_DLE_BACKUP },
801     { "PRE_HOST_BACKUP", CONF_PRE_HOST_BACKUP },
802     { "PRE_RECOVER", CONF_PRE_RECOVER },
803     { "POST_RECOVER", CONF_POST_RECOVER },
804     { "PRE_LEVEL_RECOVER", CONF_PRE_LEVEL_RECOVER },
805     { "POST_LEVEL_RECOVER", CONF_POST_LEVEL_RECOVER },
806     { "INTER_LEVEL_RECOVER", CONF_INTER_LEVEL_RECOVER },
807     { "PRIORITY", CONF_PRIORITY },
808     { "PROPERTY", CONF_PROPERTY },
809     { "APPLICATION", CONF_APPLICATION },
810     { "APPLICATION_TOOL", CONF_APPLICATION_TOOL },
811     { "SERVER", CONF_SERVER },
812     { "APPEND", CONF_APPEND },
813     { NULL, CONF_IDENT },
814     { NULL, CONF_UNKNOWN }
815 };
816
817 keytab_t server_keytab[] = {
818     { "ALL", CONF_ALL },
819     { "ALLOW_SPLIT", CONF_ALLOW_SPLIT },
820     { "AMANDA", CONF_AMANDA },
821     { "AMANDAD_PATH", CONF_AMANDAD_PATH },
822     { "AMRECOVER_CHANGER", CONF_AMRECOVER_CHANGER },
823     { "AMRECOVER_CHECK_LABEL", CONF_AMRECOVER_CHECK_LABEL },
824     { "AMRECOVER_DO_FSF", CONF_AMRECOVER_DO_FSF },
825     { "ANY", CONF_ANY_VOLUME },
826     { "APPEND", CONF_APPEND },
827     { "AUTH", CONF_AUTH },
828     { "AUTO", CONF_AUTO },
829     { "AUTOFLUSH", CONF_AUTOFLUSH },
830     { "AUTOLABEL", CONF_AUTOLABEL },
831     { "APPLICATION", CONF_APPLICATION },
832     { "APPLICATION_TOOL", CONF_APPLICATION_TOOL },
833     { "BEST", CONF_BEST },
834     { "BLOCKSIZE", CONF_BLOCKSIZE },
835     { "BUMPDAYS", CONF_BUMPDAYS },
836     { "BUMPMULT", CONF_BUMPMULT },
837     { "BUMPPERCENT", CONF_BUMPPERCENT },
838     { "BUMPSIZE", CONF_BUMPSIZE },
839     { "CALCSIZE", CONF_CALCSIZE },
840     { "CHANGER", CONF_CHANGER },
841     { "CHANGERDEV", CONF_CHANGERDEV },
842     { "CHANGERFILE", CONF_CHANGERFILE },
843     { "CHUNKSIZE", CONF_CHUNKSIZE },
844     { "CLIENT", CONF_CLIENT },
845     { "CLIENT_CUSTOM_COMPRESS", CONF_CLNTCOMPPROG },
846     { "CLIENT_DECRYPT_OPTION", CONF_CLNT_DECRYPT_OPT },
847     { "CLIENT_ENCRYPT", CONF_CLNT_ENCRYPT },
848     { "CLIENT_USERNAME", CONF_CLIENT_USERNAME },
849     { "COLUMNSPEC", CONF_COLUMNSPEC },
850     { "COMMENT", CONF_COMMENT },
851     { "COMPRATE", CONF_COMPRATE },
852     { "COMPRESS", CONF_COMPRESS },
853     { "CONNECT_TRIES", CONF_CONNECT_TRIES },
854     { "CTIMEOUT", CONF_CTIMEOUT },
855     { "CUSTOM", CONF_CUSTOM },
856     { "DATA_PATH", CONF_DATA_PATH },
857     { "DEBUG_DAYS"       , CONF_DEBUG_DAYS },
858     { "DEBUG_AMANDAD"    , CONF_DEBUG_AMANDAD },
859     { "DEBUG_RECOVERY"   , CONF_DEBUG_RECOVERY },
860     { "DEBUG_AMIDXTAPED" , CONF_DEBUG_AMIDXTAPED },
861     { "DEBUG_AMINDEXD"   , CONF_DEBUG_AMINDEXD },
862     { "DEBUG_AMRECOVER"  , CONF_DEBUG_AMRECOVER },
863     { "DEBUG_AUTH"       , CONF_DEBUG_AUTH },
864     { "DEBUG_EVENT"      , CONF_DEBUG_EVENT },
865     { "DEBUG_HOLDING"    , CONF_DEBUG_HOLDING },
866     { "DEBUG_PROTOCOL"   , CONF_DEBUG_PROTOCOL },
867     { "DEBUG_PLANNER"    , CONF_DEBUG_PLANNER },
868     { "DEBUG_DRIVER"     , CONF_DEBUG_DRIVER },
869     { "DEBUG_DUMPER"     , CONF_DEBUG_DUMPER },
870     { "DEBUG_CHUNKER"    , CONF_DEBUG_CHUNKER },
871     { "DEBUG_TAPER"      , CONF_DEBUG_TAPER },
872     { "DEBUG_SELFCHECK"  , CONF_DEBUG_SELFCHECK },
873     { "DEBUG_SENDSIZE"   , CONF_DEBUG_SENDSIZE },
874     { "DEBUG_SENDBACKUP" , CONF_DEBUG_SENDBACKUP },
875     { "DEFINE", CONF_DEFINE },
876     { "DEVICE", CONF_DEVICE },
877     { "DEVICE_PROPERTY", CONF_DEVICE_PROPERTY },
878     { "DIRECTORY", CONF_DIRECTORY },
879     { "DIRECTTCP", CONF_DIRECTTCP },
880     { "DISK", CONF_DISK },
881     { "DISKFILE", CONF_DISKFILE },
882     { "DISPLAYUNIT", CONF_DISPLAYUNIT },
883     { "DTIMEOUT", CONF_DTIMEOUT },
884     { "DUMPCYCLE", CONF_DUMPCYCLE },
885     { "DUMPORDER", CONF_DUMPORDER },
886     { "DUMPTYPE", CONF_DUMPTYPE },
887     { "DUMPUSER", CONF_DUMPUSER },
888     { "EMPTY", CONF_EMPTY },
889     { "ENCRYPT", CONF_ENCRYPT },
890     { "ERROR", CONF_ERROR },
891     { "ESTIMATE", CONF_ESTIMATE },
892     { "ETIMEOUT", CONF_ETIMEOUT },
893     { "EXCLUDE", CONF_EXCLUDE },
894     { "EXCLUDE_FILE", CONF_EXCLUDE_FILE },
895     { "EXCLUDE_LIST", CONF_EXCLUDE_LIST },
896     { "EXECUTE_ON", CONF_EXECUTE_ON },
897     { "EXECUTE_WHERE", CONF_EXECUTE_WHERE },
898     { "FALLBACK_SPLITSIZE", CONF_FALLBACK_SPLITSIZE },
899     { "FAST", CONF_FAST },
900     { "FILE", CONF_EFILE },
901     { "FILEMARK", CONF_FILEMARK },
902     { "FIRST", CONF_FIRST },
903     { "FIRSTFIT", CONF_FIRSTFIT },
904     { "HANOI", CONF_HANOI },
905     { "HIGH", CONF_HIGH },
906     { "HOLDINGDISK", CONF_HOLDING },
907     { "IGNORE", CONF_IGNORE },
908     { "INCLUDE", CONF_INCLUDE },
909     { "INCLUDEFILE", CONF_INCLUDEFILE },
910     { "INCRONLY", CONF_INCRONLY },
911     { "INDEX", CONF_INDEX },
912     { "INDEXDIR", CONF_INDEXDIR },
913     { "INFOFILE", CONF_INFOFILE },
914     { "INPARALLEL", CONF_INPARALLEL },
915     { "INTERFACE", CONF_INTERFACE },
916     { "KENCRYPT", CONF_KENCRYPT },
917     { "KRB5KEYTAB", CONF_KRB5KEYTAB },
918     { "KRB5PRINCIPAL", CONF_KRB5PRINCIPAL },
919     { "LABELSTR", CONF_LABELSTR },
920     { "LABEL_NEW_TAPES", CONF_LABEL_NEW_TAPES },
921     { "LARGEST", CONF_LARGEST },
922     { "LARGESTFIT", CONF_LARGESTFIT },
923     { "LAST", CONF_LAST },
924     { "LBL_TEMPL", CONF_LBL_TEMPL },
925     { "LENGTH", CONF_LENGTH },
926     { "LIST", CONF_LIST },
927     { "LOGDIR", CONF_LOGDIR },
928     { "LOW", CONF_LOW },
929     { "MAILER", CONF_MAILER },
930     { "MAILTO", CONF_MAILTO },
931     { "READBLOCKSIZE", CONF_READBLOCKSIZE },
932     { "MAXDUMPS", CONF_MAXDUMPS },
933     { "MAXDUMPSIZE", CONF_MAXDUMPSIZE },
934     { "MAXPROMOTEDAY", CONF_MAXPROMOTEDAY },
935     { "MEMORY", CONF_MEMORY },
936     { "MEDIUM", CONF_MEDIUM },
937     { "NETUSAGE", CONF_NETUSAGE },
938     { "NEVER", CONF_NEVER },
939     { "NOFULL", CONF_NOFULL },
940     { "NOINC", CONF_NOINC },
941     { "NONE", CONF_NONE },
942     { "NON_AMANDA", CONF_NON_AMANDA },
943     { "OPTIONAL", CONF_OPTIONAL },
944     { "ORDER", CONF_ORDER },
945     { "ORG", CONF_ORG },
946     { "OTHER_CONFIG", CONF_OTHER_CONFIG },
947     { "PART_CACHE_DIR", CONF_PART_CACHE_DIR },
948     { "PART_CACHE_MAX_SIZE", CONF_PART_CACHE_MAX_SIZE },
949     { "PART_CACHE_TYPE", CONF_PART_CACHE_TYPE },
950     { "PART_SIZE", CONF_PART_SIZE },
951     { "PLUGIN", CONF_PLUGIN },
952     { "PRE_DLE_AMCHECK", CONF_PRE_DLE_AMCHECK },
953     { "PRE_HOST_AMCHECK", CONF_PRE_HOST_AMCHECK },
954     { "POST_DLE_AMCHECK", CONF_POST_DLE_AMCHECK },
955     { "POST_HOST_AMCHECK", CONF_POST_HOST_AMCHECK },
956     { "PRE_DLE_ESTIMATE", CONF_PRE_DLE_ESTIMATE },
957     { "PRE_HOST_ESTIMATE", CONF_PRE_HOST_ESTIMATE },
958     { "POST_DLE_ESTIMATE", CONF_POST_DLE_ESTIMATE },
959     { "POST_HOST_ESTIMATE", CONF_POST_HOST_ESTIMATE },
960     { "POST_DLE_BACKUP", CONF_POST_DLE_BACKUP },
961     { "POST_HOST_BACKUP", CONF_POST_HOST_BACKUP },
962     { "PRE_DLE_BACKUP", CONF_PRE_DLE_BACKUP },
963     { "PRE_HOST_BACKUP", CONF_PRE_HOST_BACKUP },
964     { "PRE_RECOVER", CONF_PRE_RECOVER },
965     { "POST_RECOVER", CONF_POST_RECOVER },
966     { "PRE_LEVEL_RECOVER", CONF_PRE_LEVEL_RECOVER },
967     { "POST_LEVEL_RECOVER", CONF_POST_LEVEL_RECOVER },
968     { "INTER_LEVEL_RECOVER", CONF_INTER_LEVEL_RECOVER },
969     { "PRINTER", CONF_PRINTER },
970     { "PRIORITY", CONF_PRIORITY },
971     { "PROGRAM", CONF_PROGRAM },
972     { "PROPERTY", CONF_PROPERTY },
973     { "RECORD", CONF_RECORD },
974     { "RECOVERY_LIMIT", CONF_RECOVERY_LIMIT },
975     { "REP_TRIES", CONF_REP_TRIES },
976     { "REQ_TRIES", CONF_REQ_TRIES },
977     { "REQUIRED", CONF_REQUIRED },
978     { "RESERVE", CONF_RESERVE },
979     { "RESERVED_UDP_PORT", CONF_RESERVED_UDP_PORT },
980     { "RESERVED_TCP_PORT", CONF_RESERVED_TCP_PORT },
981     { "RUNSPERCYCLE", CONF_RUNSPERCYCLE },
982     { "RUNTAPES", CONF_RUNTAPES },
983     { "SAME_HOST", CONF_SAME_HOST },
984     { "SCRIPT", CONF_SCRIPT },
985     { "SCRIPT_TOOL", CONF_SCRIPT_TOOL },
986     { "SEND_AMREPORT_ON", CONF_SEND_AMREPORT_ON },
987     { "CLIENT_PORT", CONF_CLIENT_PORT },
988     { "SERVER", CONF_SERVER },
989     { "SERVER_CUSTOM_COMPRESS", CONF_SRVCOMPPROG },
990     { "SERVER_DECRYPT_OPTION", CONF_SRV_DECRYPT_OPT },
991     { "SERVER_ENCRYPT", CONF_SRV_ENCRYPT },
992     { "SKIP", CONF_SKIP },
993     { "SKIP_FULL", CONF_SKIP_FULL },
994     { "SKIP_INCR", CONF_SKIP_INCR },
995     { "SMALLEST", CONF_SMALLEST },
996     { "SPEED", CONF_SPEED },
997     { "SPLIT_DISKBUFFER", CONF_SPLIT_DISKBUFFER },
998     { "SSH_KEYS", CONF_SSH_KEYS },
999     { "STANDARD", CONF_STANDARD },
1000     { "STARTTIME", CONF_STARTTIME },
1001     { "STRANGE", CONF_STRANGE },
1002     { "STRATEGY", CONF_STRATEGY },
1003     { "DEVICE_OUTPUT_BUFFER_SIZE", CONF_DEVICE_OUTPUT_BUFFER_SIZE },
1004     { "TAPECYCLE", CONF_TAPECYCLE },
1005     { "TAPEDEV", CONF_TAPEDEV },
1006     { "TAPELIST", CONF_TAPELIST },
1007     { "TAPERALGO", CONF_TAPERALGO },
1008     { "TAPER_PARALLEL_WRITE", CONF_TAPER_PARALLEL_WRITE },
1009     { "FLUSH_THRESHOLD_DUMPED", CONF_FLUSH_THRESHOLD_DUMPED },
1010     { "FLUSH_THRESHOLD_SCHEDULED", CONF_FLUSH_THRESHOLD_SCHEDULED },
1011     { "TAPERFLUSH", CONF_TAPERFLUSH },
1012     { "TAPETYPE", CONF_TAPETYPE },
1013     { "TAPE_SPLITSIZE", CONF_TAPE_SPLITSIZE },
1014     { "TPCHANGER", CONF_TPCHANGER },
1015     { "UNRESERVED_TCP_PORT", CONF_UNRESERVED_TCP_PORT },
1016     { "USE", CONF_USE },
1017     { "USETIMESTAMPS", CONF_USETIMESTAMPS },
1018     { "VOLUME_ERROR", CONF_VOLUME_ERROR },
1019     { NULL, CONF_IDENT },
1020     { NULL, CONF_UNKNOWN }
1021 };
1022
1023 /* A keyword table for recognizing unit suffixes.  No distinction is made for kinds
1024  * of suffixes: 1024 weeks = 7 k. */
1025 keytab_t numb_keytable[] = {
1026     { "B", CONF_MULT1 },
1027     { "BPS", CONF_MULT1 },
1028     { "BYTE", CONF_MULT1 },
1029     { "BYTES", CONF_MULT1 },
1030     { "DAY", CONF_MULT1 },
1031     { "DAYS", CONF_MULT1 },
1032     { "INF", CONF_AMINFINITY },
1033     { "K", CONF_MULT1K },
1034     { "KB", CONF_MULT1K },
1035     { "KBPS", CONF_MULT1K },
1036     { "KBYTE", CONF_MULT1K },
1037     { "KBYTES", CONF_MULT1K },
1038     { "KILOBYTE", CONF_MULT1K },
1039     { "KILOBYTES", CONF_MULT1K },
1040     { "KPS", CONF_MULT1K },
1041     { "M", CONF_MULT1M },
1042     { "MB", CONF_MULT1M },
1043     { "MBPS", CONF_MULT1M },
1044     { "MBYTE", CONF_MULT1M },
1045     { "MBYTES", CONF_MULT1M },
1046     { "MEG", CONF_MULT1M },
1047     { "MEGABYTE", CONF_MULT1M },
1048     { "MEGABYTES", CONF_MULT1M },
1049     { "G", CONF_MULT1G },
1050     { "GB", CONF_MULT1G },
1051     { "GBPS", CONF_MULT1G },
1052     { "GBYTE", CONF_MULT1G },
1053     { "GBYTES", CONF_MULT1G },
1054     { "GIG", CONF_MULT1G },
1055     { "GIGABYTE", CONF_MULT1G },
1056     { "GIGABYTES", CONF_MULT1G },
1057     { "T", CONF_MULT1T },
1058     { "TB", CONF_MULT1T },
1059     { "TBPS", CONF_MULT1T },
1060     { "TBYTE", CONF_MULT1T },
1061     { "TBYTES", CONF_MULT1T },
1062     { "TERA", CONF_MULT1T },
1063     { "TERABYTE", CONF_MULT1T },
1064     { "TERABYTES", CONF_MULT1T },
1065     { "MPS", CONF_MULT1M },
1066     { "TAPE", CONF_MULT1 },
1067     { "TAPES", CONF_MULT1 },
1068     { "WEEK", CONF_MULT7 },
1069     { "WEEKS", CONF_MULT7 },
1070     { NULL, CONF_IDENT }
1071 };
1072
1073 /* Boolean keywords -- all the ways to say "true" and "false" in amanda.conf */
1074 keytab_t bool_keytable[] = {
1075     { "Y", CONF_ATRUE },
1076     { "YES", CONF_ATRUE },
1077     { "T", CONF_ATRUE },
1078     { "TRUE", CONF_ATRUE },
1079     { "ON", CONF_ATRUE },
1080     { "N", CONF_AFALSE },
1081     { "NO", CONF_AFALSE },
1082     { "F", CONF_AFALSE },
1083     { "FALSE", CONF_AFALSE },
1084     { "OFF", CONF_AFALSE },
1085     { NULL, CONF_IDENT }
1086 };
1087
1088 /* Now, the parser tables for client and server global parameters, and for
1089  * each of the server subsections */
1090 conf_var_t client_var [] = {
1091    { CONF_CONF               , CONFTYPE_STR     , read_str     , CNF_CONF               , NULL },
1092    { CONF_INDEX_SERVER       , CONFTYPE_STR     , read_str     , CNF_INDEX_SERVER       , NULL },
1093    { CONF_TAPE_SERVER        , CONFTYPE_STR     , read_str     , CNF_TAPE_SERVER        , NULL },
1094    { CONF_TAPEDEV            , CONFTYPE_STR     , read_str     , CNF_TAPEDEV            , NULL },
1095    { CONF_AUTH               , CONFTYPE_STR     , read_str     , CNF_AUTH               , NULL },
1096    { CONF_SSH_KEYS           , CONFTYPE_STR     , read_str     , CNF_SSH_KEYS           , NULL },
1097    { CONF_AMANDAD_PATH       , CONFTYPE_STR     , read_str     , CNF_AMANDAD_PATH       , NULL },
1098    { CONF_CLIENT_USERNAME    , CONFTYPE_STR     , read_str     , CNF_CLIENT_USERNAME    , NULL },
1099    { CONF_CLIENT_PORT        , CONFTYPE_STR     , read_int_or_str, CNF_CLIENT_PORT      , NULL },
1100    { CONF_GNUTAR_LIST_DIR    , CONFTYPE_STR     , read_str     , CNF_GNUTAR_LIST_DIR    , NULL },
1101    { CONF_AMANDATES          , CONFTYPE_STR     , read_str     , CNF_AMANDATES          , NULL },
1102    { CONF_MAILER             , CONFTYPE_STR     , read_str     , CNF_MAILER             , NULL },
1103    { CONF_KRB5KEYTAB         , CONFTYPE_STR     , read_str     , CNF_KRB5KEYTAB         , NULL },
1104    { CONF_KRB5PRINCIPAL      , CONFTYPE_STR     , read_str     , CNF_KRB5PRINCIPAL      , NULL },
1105    { CONF_CONNECT_TRIES      , CONFTYPE_INT     , read_int     , CNF_CONNECT_TRIES      , validate_positive },
1106    { CONF_REP_TRIES          , CONFTYPE_INT     , read_int     , CNF_REP_TRIES          , validate_positive },
1107    { CONF_REQ_TRIES          , CONFTYPE_INT     , read_int     , CNF_REQ_TRIES          , validate_positive },
1108    { CONF_DEBUG_DAYS         , CONFTYPE_INT     , read_int     , CNF_DEBUG_DAYS         , NULL },
1109    { CONF_DEBUG_AMANDAD      , CONFTYPE_INT     , read_int     , CNF_DEBUG_AMANDAD      , validate_debug },
1110    { CONF_DEBUG_RECOVERY     , CONFTYPE_INT     , read_int     , CNF_DEBUG_RECOVERY     , validate_debug },
1111    { CONF_DEBUG_AMIDXTAPED   , CONFTYPE_INT     , read_int     , CNF_DEBUG_AMIDXTAPED   , validate_debug },
1112    { CONF_DEBUG_AMINDEXD     , CONFTYPE_INT     , read_int     , CNF_DEBUG_AMINDEXD     , validate_debug },
1113    { CONF_DEBUG_AMRECOVER    , CONFTYPE_INT     , read_int     , CNF_DEBUG_AMRECOVER    , validate_debug },
1114    { CONF_DEBUG_AUTH         , CONFTYPE_INT     , read_int     , CNF_DEBUG_AUTH         , validate_debug },
1115    { CONF_DEBUG_EVENT        , CONFTYPE_INT     , read_int     , CNF_DEBUG_EVENT        , validate_debug },
1116    { CONF_DEBUG_HOLDING      , CONFTYPE_INT     , read_int     , CNF_DEBUG_HOLDING      , validate_debug },
1117    { CONF_DEBUG_PROTOCOL     , CONFTYPE_INT     , read_int     , CNF_DEBUG_PROTOCOL     , validate_debug },
1118    { CONF_DEBUG_PLANNER      , CONFTYPE_INT     , read_int     , CNF_DEBUG_PLANNER      , validate_debug },
1119    { CONF_DEBUG_DRIVER       , CONFTYPE_INT     , read_int     , CNF_DEBUG_DRIVER       , validate_debug },
1120    { CONF_DEBUG_DUMPER       , CONFTYPE_INT     , read_int     , CNF_DEBUG_DUMPER       , validate_debug },
1121    { CONF_DEBUG_CHUNKER      , CONFTYPE_INT     , read_int     , CNF_DEBUG_CHUNKER      , validate_debug },
1122    { CONF_DEBUG_TAPER        , CONFTYPE_INT     , read_int     , CNF_DEBUG_TAPER        , validate_debug },
1123    { CONF_DEBUG_SELFCHECK    , CONFTYPE_INT     , read_int     , CNF_DEBUG_SELFCHECK    , validate_debug },
1124    { CONF_DEBUG_SENDSIZE     , CONFTYPE_INT     , read_int     , CNF_DEBUG_SENDSIZE     , validate_debug },
1125    { CONF_DEBUG_SENDBACKUP   , CONFTYPE_INT     , read_int     , CNF_DEBUG_SENDBACKUP   , validate_debug },
1126    { CONF_RESERVED_UDP_PORT  , CONFTYPE_INTRANGE, read_intrange, CNF_RESERVED_UDP_PORT  , validate_reserved_port_range },
1127    { CONF_RESERVED_TCP_PORT  , CONFTYPE_INTRANGE, read_intrange, CNF_RESERVED_TCP_PORT  , validate_reserved_port_range },
1128    { CONF_UNRESERVED_TCP_PORT, CONFTYPE_INTRANGE, read_intrange, CNF_UNRESERVED_TCP_PORT, validate_unreserved_port_range },
1129    { CONF_PROPERTY           , CONFTYPE_PROPLIST, read_property, CNF_PROPERTY           , NULL },
1130    { CONF_APPLICATION        , CONFTYPE_STR     , read_dapplication, DUMPTYPE_APPLICATION, NULL },
1131    { CONF_SCRIPT             , CONFTYPE_STR     , read_dpp_script, DUMPTYPE_SCRIPTLIST, NULL },
1132    { CONF_UNKNOWN            , CONFTYPE_INT     , NULL         , CNF_CNF                , NULL }
1133 };
1134
1135 conf_var_t server_var [] = {
1136    { CONF_ORG                  , CONFTYPE_STR      , read_str         , CNF_ORG                  , NULL },
1137    { CONF_MAILTO               , CONFTYPE_STR      , read_str         , CNF_MAILTO               , NULL },
1138    { CONF_DUMPUSER             , CONFTYPE_STR      , read_str         , CNF_DUMPUSER             , NULL },
1139    { CONF_PRINTER              , CONFTYPE_STR      , read_str         , CNF_PRINTER              , NULL },
1140    { CONF_MAILER               , CONFTYPE_STR      , read_str         , CNF_MAILER               , NULL },
1141    { CONF_TAPEDEV              , CONFTYPE_STR      , read_str         , CNF_TAPEDEV              , NULL },
1142    { CONF_DEVICE_PROPERTY      , CONFTYPE_PROPLIST , read_property    , CNF_DEVICE_PROPERTY      , NULL },
1143    { CONF_PROPERTY             , CONFTYPE_PROPLIST , read_property    , CNF_PROPERTY             , NULL },
1144    { CONF_TPCHANGER            , CONFTYPE_STR      , read_str         , CNF_TPCHANGER            , NULL },
1145    { CONF_CHANGERDEV           , CONFTYPE_STR      , read_str         , CNF_CHANGERDEV           , NULL },
1146    { CONF_CHANGERFILE          , CONFTYPE_STR      , read_str         , CNF_CHANGERFILE          , NULL },
1147    { CONF_LABELSTR             , CONFTYPE_STR      , read_str         , CNF_LABELSTR             , NULL },
1148    { CONF_TAPELIST             , CONFTYPE_STR      , read_str         , CNF_TAPELIST             , NULL },
1149    { CONF_DISKFILE             , CONFTYPE_STR      , read_str         , CNF_DISKFILE             , NULL },
1150    { CONF_INFOFILE             , CONFTYPE_STR      , read_str         , CNF_INFOFILE             , NULL },
1151    { CONF_LOGDIR               , CONFTYPE_STR      , read_str         , CNF_LOGDIR               , NULL },
1152    { CONF_INDEXDIR             , CONFTYPE_STR      , read_str         , CNF_INDEXDIR             , NULL },
1153    { CONF_TAPETYPE             , CONFTYPE_IDENT    , read_ident       , CNF_TAPETYPE             , NULL },
1154    { CONF_HOLDING              , CONFTYPE_IDENTLIST, read_holdingdisk , CNF_HOLDINGDISK          , NULL },
1155    { CONF_DUMPCYCLE            , CONFTYPE_INT      , read_int         , CNF_DUMPCYCLE            , validate_nonnegative },
1156    { CONF_RUNSPERCYCLE         , CONFTYPE_INT      , read_int         , CNF_RUNSPERCYCLE         , validate_runspercycle },
1157    { CONF_RUNTAPES             , CONFTYPE_INT      , read_int         , CNF_RUNTAPES             , validate_nonnegative },
1158    { CONF_TAPECYCLE            , CONFTYPE_INT      , read_int         , CNF_TAPECYCLE            , validate_positive },
1159    { CONF_BUMPDAYS             , CONFTYPE_INT      , read_int         , CNF_BUMPDAYS             , validate_positive },
1160    { CONF_BUMPSIZE             , CONFTYPE_INT64    , read_int64       , CNF_BUMPSIZE             , validate_positive },
1161    { CONF_BUMPPERCENT          , CONFTYPE_INT      , read_int         , CNF_BUMPPERCENT          , validate_bumppercent },
1162    { CONF_BUMPMULT             , CONFTYPE_REAL     , read_real        , CNF_BUMPMULT             , validate_bumpmult },
1163    { CONF_NETUSAGE             , CONFTYPE_INT      , read_int         , CNF_NETUSAGE             , validate_positive },
1164    { CONF_INPARALLEL           , CONFTYPE_INT      , read_int         , CNF_INPARALLEL           , validate_inparallel },
1165    { CONF_DUMPORDER            , CONFTYPE_STR      , read_str         , CNF_DUMPORDER            , NULL },
1166    { CONF_MAXDUMPS             , CONFTYPE_INT      , read_int         , CNF_MAXDUMPS             , validate_positive },
1167    { CONF_ETIMEOUT             , CONFTYPE_INT      , read_int         , CNF_ETIMEOUT             , validate_non_zero },
1168    { CONF_DTIMEOUT             , CONFTYPE_INT      , read_int         , CNF_DTIMEOUT             , validate_positive },
1169    { CONF_CTIMEOUT             , CONFTYPE_INT      , read_int         , CNF_CTIMEOUT             , validate_positive },
1170    { CONF_DEVICE_OUTPUT_BUFFER_SIZE, CONFTYPE_SIZE , read_size_byte   , CNF_DEVICE_OUTPUT_BUFFER_SIZE, validate_positive },
1171    { CONF_COLUMNSPEC           , CONFTYPE_STR      , read_str         , CNF_COLUMNSPEC           , NULL },
1172    { CONF_TAPERALGO            , CONFTYPE_TAPERALGO, read_taperalgo   , CNF_TAPERALGO            , NULL },
1173    { CONF_TAPER_PARALLEL_WRITE , CONFTYPE_INT      , read_int         , CNF_TAPER_PARALLEL_WRITE , NULL },
1174    { CONF_SEND_AMREPORT_ON     , CONFTYPE_SEND_AMREPORT_ON, read_send_amreport_on, CNF_SEND_AMREPORT_ON       , NULL },
1175    { CONF_FLUSH_THRESHOLD_DUMPED, CONFTYPE_INT     , read_int         , CNF_FLUSH_THRESHOLD_DUMPED, validate_nonnegative },
1176    { CONF_FLUSH_THRESHOLD_SCHEDULED, CONFTYPE_INT  , read_int         , CNF_FLUSH_THRESHOLD_SCHEDULED, validate_nonnegative },
1177    { CONF_TAPERFLUSH           , CONFTYPE_INT      , read_int         , CNF_TAPERFLUSH           , validate_nonnegative },
1178    { CONF_DISPLAYUNIT          , CONFTYPE_STR      , read_str         , CNF_DISPLAYUNIT          , validate_displayunit },
1179    { CONF_AUTOFLUSH            , CONFTYPE_BOOLEAN  , read_bool        , CNF_AUTOFLUSH            , NULL },
1180    { CONF_RESERVE              , CONFTYPE_INT      , read_int         , CNF_RESERVE              , validate_reserve },
1181    { CONF_MAXDUMPSIZE          , CONFTYPE_INT64    , read_int64       , CNF_MAXDUMPSIZE          , NULL },
1182    { CONF_KRB5KEYTAB           , CONFTYPE_STR      , read_str         , CNF_KRB5KEYTAB           , NULL },
1183    { CONF_KRB5PRINCIPAL        , CONFTYPE_STR      , read_str         , CNF_KRB5PRINCIPAL        , NULL },
1184    { CONF_LABEL_NEW_TAPES      , CONFTYPE_STR      , read_str         , CNF_LABEL_NEW_TAPES      , NULL },
1185    { CONF_AUTOLABEL            , CONFTYPE_AUTOLABEL, read_autolabel   , CNF_AUTOLABEL            , NULL },
1186    { CONF_USETIMESTAMPS        , CONFTYPE_BOOLEAN  , read_bool        , CNF_USETIMESTAMPS        , NULL },
1187    { CONF_AMRECOVER_DO_FSF     , CONFTYPE_BOOLEAN  , read_bool        , CNF_AMRECOVER_DO_FSF     , NULL },
1188    { CONF_AMRECOVER_CHANGER    , CONFTYPE_STR      , read_str         , CNF_AMRECOVER_CHANGER    , NULL },
1189    { CONF_AMRECOVER_CHECK_LABEL, CONFTYPE_BOOLEAN  , read_bool        , CNF_AMRECOVER_CHECK_LABEL, NULL },
1190    { CONF_CONNECT_TRIES        , CONFTYPE_INT      , read_int         , CNF_CONNECT_TRIES        , validate_positive },
1191    { CONF_REP_TRIES            , CONFTYPE_INT      , read_int         , CNF_REP_TRIES            , validate_positive },
1192    { CONF_REQ_TRIES            , CONFTYPE_INT      , read_int         , CNF_REQ_TRIES            , validate_positive },
1193    { CONF_DEBUG_DAYS           , CONFTYPE_INT      , read_int         , CNF_DEBUG_DAYS           , NULL },
1194    { CONF_DEBUG_AMANDAD        , CONFTYPE_INT      , read_int         , CNF_DEBUG_AMANDAD        , validate_debug },
1195    { CONF_DEBUG_RECOVERY       , CONFTYPE_INT      , read_int         , CNF_DEBUG_RECOVERY       , validate_debug },
1196    { CONF_DEBUG_AMIDXTAPED     , CONFTYPE_INT      , read_int         , CNF_DEBUG_AMIDXTAPED     , validate_debug },
1197    { CONF_DEBUG_AMINDEXD       , CONFTYPE_INT      , read_int         , CNF_DEBUG_AMINDEXD       , validate_debug },
1198    { CONF_DEBUG_AMRECOVER      , CONFTYPE_INT      , read_int         , CNF_DEBUG_AMRECOVER      , validate_debug },
1199    { CONF_DEBUG_AUTH           , CONFTYPE_INT      , read_int         , CNF_DEBUG_AUTH           , validate_debug },
1200    { CONF_DEBUG_EVENT          , CONFTYPE_INT      , read_int         , CNF_DEBUG_EVENT          , validate_debug },
1201    { CONF_DEBUG_HOLDING        , CONFTYPE_INT      , read_int         , CNF_DEBUG_HOLDING        , validate_debug },
1202    { CONF_DEBUG_PROTOCOL       , CONFTYPE_INT      , read_int         , CNF_DEBUG_PROTOCOL       , validate_debug },
1203    { CONF_DEBUG_PLANNER        , CONFTYPE_INT      , read_int         , CNF_DEBUG_PLANNER        , validate_debug },
1204    { CONF_DEBUG_DRIVER         , CONFTYPE_INT      , read_int         , CNF_DEBUG_DRIVER         , validate_debug },
1205    { CONF_DEBUG_DUMPER         , CONFTYPE_INT      , read_int         , CNF_DEBUG_DUMPER         , validate_debug },
1206    { CONF_DEBUG_CHUNKER        , CONFTYPE_INT      , read_int         , CNF_DEBUG_CHUNKER        , validate_debug },
1207    { CONF_DEBUG_TAPER          , CONFTYPE_INT      , read_int         , CNF_DEBUG_TAPER          , validate_debug },
1208    { CONF_DEBUG_SELFCHECK      , CONFTYPE_INT      , read_int         , CNF_DEBUG_SELFCHECK      , validate_debug },
1209    { CONF_DEBUG_SENDSIZE       , CONFTYPE_INT      , read_int         , CNF_DEBUG_SENDSIZE       , validate_debug },
1210    { CONF_DEBUG_SENDBACKUP     , CONFTYPE_INT      , read_int         , CNF_DEBUG_SENDBACKUP     , validate_debug },
1211    { CONF_RESERVED_UDP_PORT    , CONFTYPE_INTRANGE , read_intrange    , CNF_RESERVED_UDP_PORT    , validate_reserved_port_range },
1212    { CONF_RESERVED_TCP_PORT    , CONFTYPE_INTRANGE , read_intrange    , CNF_RESERVED_TCP_PORT    , validate_reserved_port_range },
1213    { CONF_UNRESERVED_TCP_PORT  , CONFTYPE_INTRANGE , read_intrange    , CNF_UNRESERVED_TCP_PORT  , validate_unreserved_port_range },
1214    { CONF_RECOVERY_LIMIT       , CONFTYPE_RECOVERY_LIMIT, read_recovery_limit, CNF_RECOVERY_LIMIT, NULL },
1215    { CONF_UNKNOWN              , CONFTYPE_INT      , NULL             , CNF_CNF                  , NULL }
1216 };
1217
1218 conf_var_t tapetype_var [] = {
1219    { CONF_COMMENT              , CONFTYPE_STR     , read_str          , TAPETYPE_COMMENT         , NULL },
1220    { CONF_LBL_TEMPL            , CONFTYPE_STR     , read_str          , TAPETYPE_LBL_TEMPL       , NULL },
1221    { CONF_BLOCKSIZE            , CONFTYPE_SIZE    , read_size         , TAPETYPE_BLOCKSIZE       , validate_blocksize },
1222    { CONF_READBLOCKSIZE        , CONFTYPE_SIZE    , read_size         , TAPETYPE_READBLOCKSIZE   , validate_blocksize },
1223    { CONF_LENGTH               , CONFTYPE_INT64   , read_int64        , TAPETYPE_LENGTH          , validate_nonnegative },
1224    { CONF_FILEMARK             , CONFTYPE_INT64   , read_int64        , TAPETYPE_FILEMARK        , NULL },
1225    { CONF_SPEED                , CONFTYPE_INT     , read_int          , TAPETYPE_SPEED           , validate_nonnegative },
1226    { CONF_PART_SIZE            , CONFTYPE_INT64    , read_int64       , TAPETYPE_PART_SIZE       , validate_nonnegative },
1227    { CONF_PART_CACHE_TYPE      , CONFTYPE_PART_CACHE_TYPE, read_part_cache_type, TAPETYPE_PART_CACHE_TYPE, NULL },
1228    { CONF_PART_CACHE_DIR       , CONFTYPE_STR      , read_str         , TAPETYPE_PART_CACHE_DIR  , NULL },
1229    { CONF_PART_CACHE_MAX_SIZE  , CONFTYPE_INT64    , read_int64       , TAPETYPE_PART_CACHE_MAX_SIZE, validate_nonnegative },
1230    { CONF_UNKNOWN              , CONFTYPE_INT     , NULL              , TAPETYPE_TAPETYPE        , NULL }
1231 };
1232
1233 conf_var_t dumptype_var [] = {
1234    { CONF_COMMENT           , CONFTYPE_STR      , read_str      , DUMPTYPE_COMMENT           , NULL },
1235    { CONF_AUTH              , CONFTYPE_STR      , read_str      , DUMPTYPE_AUTH              , NULL },
1236    { CONF_BUMPDAYS          , CONFTYPE_INT      , read_int      , DUMPTYPE_BUMPDAYS          , NULL },
1237    { CONF_BUMPMULT          , CONFTYPE_REAL     , read_real     , DUMPTYPE_BUMPMULT          , NULL },
1238    { CONF_BUMPSIZE          , CONFTYPE_INT64    , read_int64    , DUMPTYPE_BUMPSIZE          , NULL },
1239    { CONF_BUMPPERCENT       , CONFTYPE_INT      , read_int      , DUMPTYPE_BUMPPERCENT       , NULL },
1240    { CONF_COMPRATE          , CONFTYPE_REAL     , read_rate     , DUMPTYPE_COMPRATE          , NULL },
1241    { CONF_COMPRESS          , CONFTYPE_INT      , read_compress , DUMPTYPE_COMPRESS          , NULL },
1242    { CONF_ENCRYPT           , CONFTYPE_INT      , read_encrypt  , DUMPTYPE_ENCRYPT           , NULL },
1243    { CONF_DUMPCYCLE         , CONFTYPE_INT      , read_int      , DUMPTYPE_DUMPCYCLE         , validate_nonnegative },
1244    { CONF_EXCLUDE           , CONFTYPE_EXINCLUDE, read_exinclude, DUMPTYPE_EXCLUDE           , NULL },
1245    { CONF_INCLUDE           , CONFTYPE_EXINCLUDE, read_exinclude, DUMPTYPE_INCLUDE           , NULL },
1246    { CONF_IGNORE            , CONFTYPE_BOOLEAN  , read_bool     , DUMPTYPE_IGNORE            , NULL },
1247    { CONF_HOLDING           , CONFTYPE_HOLDING  , read_holding  , DUMPTYPE_HOLDINGDISK       , NULL },
1248    { CONF_INDEX             , CONFTYPE_BOOLEAN  , read_bool     , DUMPTYPE_INDEX             , NULL },
1249    { CONF_KENCRYPT          , CONFTYPE_BOOLEAN  , read_bool     , DUMPTYPE_KENCRYPT          , NULL },
1250    { CONF_MAXDUMPS          , CONFTYPE_INT      , read_int      , DUMPTYPE_MAXDUMPS          , validate_positive },
1251    { CONF_MAXPROMOTEDAY     , CONFTYPE_INT      , read_int      , DUMPTYPE_MAXPROMOTEDAY     , validate_nonnegative },
1252    { CONF_PRIORITY          , CONFTYPE_PRIORITY , read_priority , DUMPTYPE_PRIORITY          , NULL },
1253    { CONF_PROGRAM           , CONFTYPE_STR      , read_str      , DUMPTYPE_PROGRAM           , validate_program },
1254    { CONF_PROPERTY          , CONFTYPE_PROPLIST , read_property , DUMPTYPE_PROPERTY          , NULL },
1255    { CONF_RECORD            , CONFTYPE_BOOLEAN  , read_bool     , DUMPTYPE_RECORD            , NULL },
1256    { CONF_SKIP_FULL         , CONFTYPE_BOOLEAN  , read_bool     , DUMPTYPE_SKIP_FULL         , NULL },
1257    { CONF_SKIP_INCR         , CONFTYPE_BOOLEAN  , read_bool     , DUMPTYPE_SKIP_INCR         , NULL },
1258    { CONF_STARTTIME         , CONFTYPE_TIME     , read_time     , DUMPTYPE_STARTTIME         , NULL },
1259    { CONF_STRATEGY          , CONFTYPE_INT      , read_strategy , DUMPTYPE_STRATEGY          , NULL },
1260    { CONF_TAPE_SPLITSIZE    , CONFTYPE_INT64    , read_int64    , DUMPTYPE_TAPE_SPLITSIZE    , validate_nonnegative },
1261    { CONF_SPLIT_DISKBUFFER  , CONFTYPE_STR      , read_str      , DUMPTYPE_SPLIT_DISKBUFFER  , NULL },
1262    { CONF_ESTIMATE          , CONFTYPE_ESTIMATELIST, read_estimatelist , DUMPTYPE_ESTIMATELIST  , NULL },
1263    { CONF_SRV_ENCRYPT       , CONFTYPE_STR      , read_str      , DUMPTYPE_SRV_ENCRYPT       , NULL },
1264    { CONF_CLNT_ENCRYPT      , CONFTYPE_STR      , read_str      , DUMPTYPE_CLNT_ENCRYPT      , NULL },
1265    { CONF_AMANDAD_PATH      , CONFTYPE_STR      , read_str      , DUMPTYPE_AMANDAD_PATH      , NULL },
1266    { CONF_CLIENT_USERNAME   , CONFTYPE_STR      , read_str      , DUMPTYPE_CLIENT_USERNAME   , NULL },
1267    { CONF_CLIENT_PORT       , CONFTYPE_STR      , read_int_or_str, DUMPTYPE_CLIENT_PORT      , NULL },
1268    { CONF_SSH_KEYS          , CONFTYPE_STR      , read_str      , DUMPTYPE_SSH_KEYS          , NULL },
1269    { CONF_SRVCOMPPROG       , CONFTYPE_STR      , read_str      , DUMPTYPE_SRVCOMPPROG       , NULL },
1270    { CONF_CLNTCOMPPROG      , CONFTYPE_STR      , read_str      , DUMPTYPE_CLNTCOMPPROG      , NULL },
1271    { CONF_FALLBACK_SPLITSIZE, CONFTYPE_INT64    , read_int64    , DUMPTYPE_FALLBACK_SPLITSIZE, NULL },
1272    { CONF_SRV_DECRYPT_OPT   , CONFTYPE_STR      , read_str      , DUMPTYPE_SRV_DECRYPT_OPT   , NULL },
1273    { CONF_CLNT_DECRYPT_OPT  , CONFTYPE_STR      , read_str      , DUMPTYPE_CLNT_DECRYPT_OPT  , NULL },
1274    { CONF_APPLICATION       , CONFTYPE_STR      , read_dapplication, DUMPTYPE_APPLICATION    , NULL },
1275    { CONF_SCRIPT            , CONFTYPE_STR      , read_dpp_script, DUMPTYPE_SCRIPTLIST       , NULL },
1276    { CONF_DATA_PATH         , CONFTYPE_DATA_PATH, read_data_path, DUMPTYPE_DATA_PATH         , NULL },
1277    { CONF_ALLOW_SPLIT       , CONFTYPE_BOOLEAN  , read_bool    , DUMPTYPE_ALLOW_SPLIT       , NULL },
1278    { CONF_RECOVERY_LIMIT    , CONFTYPE_RECOVERY_LIMIT, read_recovery_limit, DUMPTYPE_RECOVERY_LIMIT, NULL },
1279    { CONF_UNKNOWN           , CONFTYPE_INT      , NULL          , DUMPTYPE_DUMPTYPE          , NULL }
1280 };
1281
1282 conf_var_t holding_var [] = {
1283    { CONF_DIRECTORY, CONFTYPE_STR   , read_str   , HOLDING_DISKDIR  , NULL },
1284    { CONF_COMMENT  , CONFTYPE_STR   , read_str   , HOLDING_COMMENT  , NULL },
1285    { CONF_USE      , CONFTYPE_INT64 , read_int64 , HOLDING_DISKSIZE , validate_use },
1286    { CONF_CHUNKSIZE, CONFTYPE_INT64 , read_int64 , HOLDING_CHUNKSIZE, validate_chunksize },
1287    { CONF_UNKNOWN  , CONFTYPE_INT   , NULL       , HOLDING_HOLDING  , NULL }
1288 };
1289
1290 conf_var_t interface_var [] = {
1291    { CONF_COMMENT, CONFTYPE_STR   , read_str   , INTER_COMMENT , NULL },
1292    { CONF_USE    , CONFTYPE_INT   , read_int   , INTER_MAXUSAGE, validate_positive },
1293    { CONF_UNKNOWN, CONFTYPE_INT   , NULL       , INTER_INTER   , NULL }
1294 };
1295
1296
1297 conf_var_t application_var [] = {
1298    { CONF_COMMENT  , CONFTYPE_STR     , read_str     , APPLICATION_COMMENT    , NULL },
1299    { CONF_PLUGIN   , CONFTYPE_STR     , read_str     , APPLICATION_PLUGIN     , NULL },
1300    { CONF_PROPERTY , CONFTYPE_PROPLIST, read_property, APPLICATION_PROPERTY   , NULL },
1301    { CONF_UNKNOWN  , CONFTYPE_INT     , NULL         , APPLICATION_APPLICATION, NULL }
1302 };
1303
1304 conf_var_t pp_script_var [] = {
1305    { CONF_COMMENT      , CONFTYPE_STR     , read_str     , PP_SCRIPT_COMMENT      , NULL },
1306    { CONF_PLUGIN       , CONFTYPE_STR     , read_str     , PP_SCRIPT_PLUGIN       , NULL },
1307    { CONF_PROPERTY     , CONFTYPE_PROPLIST, read_property, PP_SCRIPT_PROPERTY     , NULL },
1308    { CONF_EXECUTE_ON   , CONFTYPE_EXECUTE_ON  , read_execute_on  , PP_SCRIPT_EXECUTE_ON   , NULL },
1309    { CONF_EXECUTE_WHERE, CONFTYPE_EXECUTE_WHERE  , read_execute_where  , PP_SCRIPT_EXECUTE_WHERE, NULL },
1310    { CONF_ORDER        , CONFTYPE_INT     , read_int     , PP_SCRIPT_ORDER        , NULL },
1311    { CONF_UNKNOWN      , CONFTYPE_INT     , NULL         , PP_SCRIPT_PP_SCRIPT    , NULL }
1312 };
1313
1314 conf_var_t device_config_var [] = {
1315    { CONF_COMMENT         , CONFTYPE_STR      , read_str      , DEVICE_CONFIG_COMMENT        , NULL },
1316    { CONF_DEVICE_PROPERTY , CONFTYPE_PROPLIST , read_property , DEVICE_CONFIG_DEVICE_PROPERTY, NULL },
1317    { CONF_TAPEDEV         , CONFTYPE_STR      , read_str      , DEVICE_CONFIG_TAPEDEV        , NULL },
1318    { CONF_UNKNOWN         , CONFTYPE_INT      , NULL          , DEVICE_CONFIG_DEVICE_CONFIG  , NULL }
1319 };
1320
1321 conf_var_t changer_config_var [] = {
1322    { CONF_COMMENT         , CONFTYPE_STR      , read_str      , CHANGER_CONFIG_COMMENT        , NULL },
1323    { CONF_TAPEDEV         , CONFTYPE_STR      , read_str      , CHANGER_CONFIG_TAPEDEV        , NULL },
1324    { CONF_TPCHANGER       , CONFTYPE_STR      , read_str      , CHANGER_CONFIG_TPCHANGER      , NULL },
1325    { CONF_CHANGERDEV      , CONFTYPE_STR      , read_str      , CHANGER_CONFIG_CHANGERDEV     , NULL },
1326    { CONF_CHANGERFILE     , CONFTYPE_STR      , read_str      , CHANGER_CONFIG_CHANGERFILE    , NULL },
1327    { CONF_PROPERTY        , CONFTYPE_PROPLIST , read_property , CHANGER_CONFIG_PROPERTY       , NULL },
1328    { CONF_DEVICE_PROPERTY , CONFTYPE_PROPLIST , read_property , CHANGER_CONFIG_DEVICE_PROPERTY, NULL },
1329    { CONF_UNKNOWN         , CONFTYPE_INT      , NULL          , CHANGER_CONFIG_CHANGER_CONFIG , NULL }
1330 };
1331
1332 /*
1333  * Lexical Analysis Implementation
1334  */
1335
1336 static char *
1337 get_token_name(
1338     tok_t token)
1339 {
1340     keytab_t *kt;
1341
1342     if (keytable == NULL) {
1343         error(_("keytable == NULL"));
1344         /*NOTREACHED*/
1345     }
1346
1347     for(kt = keytable; kt->token != CONF_UNKNOWN; kt++)
1348         if(kt->token == token) break;
1349
1350     if(kt->token == CONF_UNKNOWN)
1351         return("");
1352     return(kt->keyword);
1353 }
1354
1355 static tok_t
1356 lookup_keyword(
1357     char *      str)
1358 {
1359     keytab_t *kwp;
1360     char *str1 = stralloc(str);
1361     char *p = str1;
1362
1363     /* Fold '-' to '_' in the token.  Note that this modifies str1
1364      * in place. */
1365     while (*p) {
1366         if (*p == '-') *p = '_';
1367         p++;
1368     }
1369
1370     for(kwp = keytable; kwp->keyword != NULL; kwp++) {
1371         if (strcasecmp(kwp->keyword, str1) == 0) break;
1372     }
1373
1374     amfree(str1);
1375     return kwp->token;
1376 }
1377
1378 static void
1379 get_conftoken(
1380     tok_t       exp)
1381 {
1382     int ch, d;
1383     gint64 int64;
1384     char *buf;
1385     char *tmps;
1386     int token_overflow;
1387     int inquote = 0;
1388     int escape = 0;
1389     int sign;
1390
1391     if (token_pushed) {
1392         token_pushed = 0;
1393         tok = pushed_tok;
1394
1395         /*
1396         ** If it looked like a keyword before then look it
1397         ** up again in the current keyword table.
1398         */
1399         switch(tok) {
1400         case CONF_INT64:   case CONF_SIZE:
1401         case CONF_INT:     case CONF_REAL:    case CONF_STRING:
1402         case CONF_LBRACE:  case CONF_RBRACE:  case CONF_COMMA:
1403         case CONF_NL:      case CONF_END:     case CONF_UNKNOWN:
1404         case CONF_TIME:
1405             break; /* not a keyword */
1406
1407         default:
1408             if (exp == CONF_IDENT)
1409                 tok = CONF_IDENT;
1410             else
1411                 tok = lookup_keyword(tokenval.v.s);
1412             break;
1413         }
1414     }
1415     else {
1416         ch = conftoken_getc();
1417
1418         /* note that we're explicitly assuming this file is ASCII.  Someday
1419          * maybe we'll support UTF-8? */
1420         while(ch != EOF && ch != '\n' && g_ascii_isspace(ch))
1421             ch = conftoken_getc();
1422         if (ch == '#') {        /* comment - eat everything but eol/eof */
1423             while((ch = conftoken_getc()) != EOF && ch != '\n') {
1424                 (void)ch; /* Quiet empty loop complaints */     
1425             }
1426         }
1427
1428         if (isalpha(ch)) {              /* identifier */
1429             buf = tkbuf;
1430             token_overflow = 0;
1431             do {
1432                 if (buf < tkbuf+sizeof(tkbuf)-1) {
1433                     *buf++ = (char)ch;
1434                 } else {
1435                     *buf = '\0';
1436                     if (!token_overflow) {
1437                         conf_parserror(_("token too long: %.20s..."), tkbuf);
1438                     }
1439                     token_overflow = 1;
1440                 }
1441                 ch = conftoken_getc();
1442             } while(isalnum(ch) || ch == '_' || ch == '-');
1443
1444             if (ch != EOF && conftoken_ungetc(ch) == EOF) {
1445                 if (ferror(current_file)) {
1446                     conf_parserror(_("Pushback of '%c' failed: %s"),
1447                                    ch, strerror(ferror(current_file)));
1448                 } else {
1449                     conf_parserror(_("Pushback of '%c' failed: EOF"), ch);
1450                 }
1451             }
1452             *buf = '\0';
1453
1454             tokenval.v.s = tkbuf;
1455
1456             if (token_overflow) tok = CONF_UNKNOWN;
1457             else if (exp == CONF_IDENT) tok = CONF_IDENT;
1458             else tok = lookup_keyword(tokenval.v.s);
1459         }
1460         else if (isdigit(ch)) { /* integer */
1461             sign = 1;
1462
1463 negative_number: /* look for goto negative_number below sign is set there */
1464             int64 = 0;
1465             do {
1466                 int64 = int64 * 10 + (ch - '0');
1467                 ch = conftoken_getc();
1468             } while (isdigit(ch));
1469
1470             if (ch != '.') {
1471                 if (exp == CONF_INT) {
1472                     tok = CONF_INT;
1473                     tokenval.v.i = sign * (int)int64;
1474                 } else if (exp != CONF_REAL) {
1475                     tok = CONF_INT64;
1476                     tokenval.v.int64 = (gint64)sign * int64;
1477                 } else {
1478                     /* automatically convert to real when expected */
1479                     tokenval.v.r = (double)sign * (double)int64;
1480                     tok = CONF_REAL;
1481                 }
1482             } else {
1483                 /* got a real number, not an int */
1484                 tokenval.v.r = sign * (double) int64;
1485                 int64 = 0;
1486                 d = 1;
1487                 ch = conftoken_getc();
1488                 while (isdigit(ch)) {
1489                     int64 = int64 * 10 + (ch - '0');
1490                     d = d * 10;
1491                     ch = conftoken_getc();
1492                 }
1493                 tokenval.v.r += sign * ((double)int64) / d;
1494                 tok = CONF_REAL;
1495             }
1496
1497             if (ch != EOF &&  conftoken_ungetc(ch) == EOF) {
1498                 if (ferror(current_file)) {
1499                     conf_parserror(_("Pushback of '%c' failed: %s"),
1500                                    ch, strerror(ferror(current_file)));
1501                 } else {
1502                     conf_parserror(_("Pushback of '%c' failed: EOF"), ch);
1503                 }
1504             }
1505         } else switch(ch) {
1506         case '"':                       /* string */
1507             buf = tkbuf;
1508             token_overflow = 0;
1509             inquote = 1;
1510             *buf++ = (char)ch;
1511             while (inquote && ((ch = conftoken_getc()) != EOF)) {
1512                 if (ch == '\n') {
1513                     if (!escape)
1514                         break;
1515                     escape = 0;
1516                     buf--; /* Consume escape in buffer */
1517                 } else if (ch == '\\' && !escape) {
1518                     escape = 1;
1519                 } else {
1520                     if (ch == '"') {
1521                         if (!escape)
1522                             inquote = 0;
1523                     }
1524                     escape = 0;
1525                 }
1526
1527                 if(buf >= &tkbuf[sizeof(tkbuf) - 1]) {
1528                     if (!token_overflow) {
1529                         conf_parserror(_("string too long: %.20s..."), tkbuf);
1530                     }
1531                     token_overflow = 1;
1532                     break;
1533                 }
1534                 *buf++ = (char)ch;
1535             }
1536             *buf = '\0';
1537
1538             /*
1539              * A little manuver to leave a fully unquoted, unallocated  string
1540              * in tokenval.v.s
1541              */
1542             tmps = unquote_string(tkbuf);
1543             strncpy(tkbuf, tmps, sizeof(tkbuf));
1544             amfree(tmps);
1545             tokenval.v.s = tkbuf;
1546
1547             tok = (token_overflow) ? CONF_UNKNOWN :
1548                         (exp == CONF_IDENT) ? CONF_IDENT : CONF_STRING;
1549             break;
1550
1551         case '-':
1552             ch = conftoken_getc();
1553             if (isdigit(ch)) {
1554                 sign = -1;
1555                 goto negative_number;
1556             }
1557             else {
1558                 if (ch != EOF && conftoken_ungetc(ch) == EOF) {
1559                     if (ferror(current_file)) {
1560                         conf_parserror(_("Pushback of '%c' failed: %s"),
1561                                        ch, strerror(ferror(current_file)));
1562                     } else {
1563                         conf_parserror(_("Pushback of '%c' failed: EOF"), ch);
1564                     }
1565                 }
1566                 tok = CONF_UNKNOWN;
1567             }
1568             break;
1569
1570         case ',':
1571             tok = CONF_COMMA;
1572             break;
1573
1574         case '{':
1575             tok = CONF_LBRACE;
1576             break;
1577
1578         case '}':
1579             tok = CONF_RBRACE;
1580             break;
1581
1582         case '\n':
1583             tok = CONF_NL;
1584             break;
1585
1586         case EOF:
1587             tok = CONF_END;
1588             break;
1589
1590         default:
1591             tok = CONF_UNKNOWN;
1592             break;
1593         }
1594     }
1595
1596     if (exp != CONF_ANY && tok != exp) {
1597         char *str;
1598         keytab_t *kwp;
1599
1600         switch(exp) {
1601         case CONF_LBRACE:
1602             str = "\"{\"";
1603             break;
1604
1605         case CONF_RBRACE:
1606             str = "\"}\"";
1607             break;
1608
1609         case CONF_COMMA:
1610             str = "\",\"";
1611             break;
1612
1613         case CONF_NL:
1614             str = _("end of line");
1615             break;
1616
1617         case CONF_END:
1618             str = _("end of file");
1619             break;
1620
1621         case CONF_INT:
1622             str = _("an integer");
1623             break;
1624
1625         case CONF_REAL:
1626             str = _("a real number");
1627             break;
1628
1629         case CONF_STRING:
1630             str = _("a quoted string");
1631             break;
1632
1633         case CONF_IDENT:
1634             str = _("an identifier");
1635             break;
1636
1637         default:
1638             for(kwp = keytable; kwp->keyword != NULL; kwp++) {
1639                 if (exp == kwp->token)
1640                     break;
1641             }
1642             if (kwp->keyword == NULL)
1643                 str = _("token not");
1644             else
1645                 str = str_keyword(kwp);
1646             break;
1647         }
1648         conf_parserror(_("%s is expected"), str);
1649         tok = exp;
1650         if (tok == CONF_INT)
1651             tokenval.v.i = 0;
1652         else
1653             tokenval.v.s = "";
1654     }
1655 }
1656
1657 static void
1658 unget_conftoken(void)
1659 {
1660     assert(!token_pushed);
1661     token_pushed = 1;
1662     pushed_tok = tok;
1663     tok = CONF_UNKNOWN;
1664 }
1665
1666 static int
1667 conftoken_getc(void)
1668 {
1669     if(current_line == NULL)
1670         return getc(current_file);
1671     if(*current_char == '\0')
1672         return -1;
1673     return(*current_char++);
1674 }
1675
1676 static int
1677 conftoken_ungetc(
1678     int c)
1679 {
1680     if(current_line == NULL)
1681         return ungetc(c, current_file);
1682     else if(current_char > current_line) {
1683         if(c == -1)
1684             return c;
1685         current_char--;
1686         if(*current_char != c) {
1687             error(_("*current_char != c   : %c %c"), *current_char, c);
1688             /* NOTREACHED */
1689         }
1690     } else {
1691         error(_("current_char == current_line"));
1692         /* NOTREACHED */
1693     }
1694     return c;
1695 }
1696
1697 /*
1698  * Parser Implementation
1699  */
1700
1701 static void
1702 read_conffile(
1703     char *filename,
1704     gboolean is_client,
1705     gboolean missing_ok)
1706 {
1707     /* Save global locations. */
1708     FILE *save_file     = current_file;
1709     char *save_filename = current_filename;
1710     int  save_line_num  = current_line_num;
1711     int rc;
1712
1713     if (is_client) {
1714         keytable = client_keytab;
1715         parsetable = client_var;
1716     } else {
1717         keytable = server_keytab;
1718         parsetable = server_var;
1719     }
1720     filename = config_dir_relative(filename);
1721     current_filename = get_seen_filename(filename);
1722     amfree(filename);
1723
1724     if ((current_file = fopen(current_filename, "r")) == NULL) {
1725         if (!missing_ok)
1726             conf_parserror(_("could not open conf file \"%s\": %s"), 
1727                     current_filename, strerror(errno));
1728         goto finish;
1729     }
1730
1731     current_line_num = 0;
1732
1733     do {
1734         /* read_confline() can invoke us recursively via "includefile" */
1735         rc = read_confline(is_client);
1736     } while (rc != 0);
1737
1738     afclose(current_file);
1739
1740 finish:
1741
1742     /* Restore servers */
1743     current_line_num = save_line_num;
1744     current_file     = save_file;
1745     current_filename = save_filename;
1746 }
1747
1748 static gboolean
1749 read_confline(
1750     gboolean is_client)
1751 {
1752     conf_var_t *np;
1753
1754     current_line_num += 1;
1755     get_conftoken(CONF_ANY);
1756     handle_deprecated_keyword();
1757
1758     switch(tok) {
1759     case CONF_INCLUDEFILE:
1760         get_conftoken(CONF_STRING);
1761         read_conffile(tokenval.v.s, is_client, FALSE);
1762         break;
1763
1764     case CONF_DEFINE:
1765         if (is_client) {
1766             get_conftoken(CONF_ANY);
1767             /* accept application-tool here, too, for backward compatibility */
1768             if(tok == CONF_APPLICATION_TOOL || tok == CONF_APPLICATION) get_application();
1769             else if(tok == CONF_SCRIPT_TOOL || tok == CONF_SCRIPT) get_pp_script();
1770             else conf_parserror(_("APPLICATION-TOOL or SCRIPT-TOOL expected"));
1771         } else {
1772             get_conftoken(CONF_ANY);
1773             if(tok == CONF_DUMPTYPE) get_dumptype();
1774             else if(tok == CONF_TAPETYPE) get_tapetype();
1775             else if(tok == CONF_INTERFACE) get_interface();
1776             else if(tok == CONF_APPLICATION_TOOL || tok == CONF_APPLICATION) get_application();
1777             else if(tok == CONF_SCRIPT_TOOL || tok == CONF_SCRIPT) get_pp_script();
1778             else if(tok == CONF_DEVICE) get_device_config();
1779             else if(tok == CONF_CHANGER) get_changer_config();
1780             else if(tok == CONF_HOLDING) get_holdingdisk(1);
1781             else conf_parserror(_("DUMPTYPE, INTERFACE, TAPETYPE, HOLDINGDISK, APPLICATION-TOOL, SCRIPT-TOOL, DEVICE, or CHANGER expected"));
1782         }
1783         break;
1784
1785     case CONF_NL:       /* empty line */
1786         break;
1787
1788     case CONF_END:      /* end of file */
1789         return 0;
1790
1791     /* if it's not a known punctuation mark, then check the parse table and use the
1792      * read_function we find there. */
1793     default:
1794         {
1795             for(np = parsetable; np->token != CONF_UNKNOWN; np++) 
1796                 if(np->token == tok) break;
1797
1798             if(np->token == CONF_UNKNOWN) {
1799                 handle_invalid_keyword(tokenval.v.s);
1800             } else {
1801                 np->read_function(np, &conf_data[np->parm]);
1802                 if(np->validate_function)
1803                     np->validate_function(np, &conf_data[np->parm]);
1804             }
1805         }
1806     }
1807     if(tok != CONF_NL)
1808         get_conftoken(CONF_NL);
1809     return 1;
1810 }
1811
1812 static void
1813 handle_deprecated_keyword(void)
1814 {
1815     /* Procedure for deprecated keywords:
1816      *
1817      * 1) At time of deprecation, add to warning_deprecated below.  Note the
1818      *    version in which deprecation will expire.  The keyword will still be
1819      *    parsed, and can still be used from other parts of Amanda, during this
1820      *    time.
1821      * 2) After it has expired, move the keyword (as a string) to
1822      *    error_deprecated below. Remove the token (CONF_XXX) and
1823      *    config parameter (CNF_XXX) from the rest of the module.
1824      *    Note the date of the move.
1825      */
1826
1827     static struct { tok_t tok; gboolean warned; }
1828     warning_deprecated[] = {
1829         { CONF_LABEL_NEW_TAPES, 0 },    /* exp in Amanda-3.2 */
1830         { CONF_AMRECOVER_DO_FSF, 0 },   /* exp in Amanda-3.3 */
1831         { CONF_AMRECOVER_CHECK_LABEL, 0 }, /* exp in Amanda-3.3 */
1832         { CONF_TAPE_SPLITSIZE, 0 },     /* exp. in Amanda-3.3 */
1833         { CONF_SPLIT_DISKBUFFER, 0 },   /* exp. in Amanda-3.3 */
1834         { CONF_FALLBACK_SPLITSIZE, 0 }, /* exp. in Amanda-3.3 */
1835         { 0, 0 },
1836     }, *dep;
1837
1838     for (dep = warning_deprecated; dep->tok; dep++) {
1839         if (tok == dep->tok) {
1840             if (!dep->warned)
1841                 conf_parswarn(_("warning: Keyword %s is deprecated."),
1842                                tokenval.v.s);
1843             dep->warned = 1;
1844             break;
1845         }
1846     }
1847 }
1848
1849 static void
1850 handle_invalid_keyword(
1851     const char * token)
1852 {
1853     static const char * error_deprecated[] = {
1854         "rawtapedev",
1855         "tapebufs", /* deprecated: 2007-10-15; invalid: 2010-04-14 */
1856         "file-pad", /* deprecated: 2008-07-01; invalid: 2010-04-14 */
1857         NULL
1858     };
1859     const char ** s;
1860     char *folded_token, *p;
1861
1862     /* convert '_' to '-' in TOKEN */
1863     folded_token = g_strdup(token);
1864     for (p = folded_token; *p; p++) {
1865         if (*p == '_') *p = '-';
1866     }
1867
1868     for (s = error_deprecated; *s != NULL; s ++) {
1869         if (g_ascii_strcasecmp(*s, folded_token) == 0) {
1870             conf_parserror(_("error: Keyword %s is deprecated."),
1871                            token);
1872             g_free(folded_token);
1873             return;
1874         }
1875     }
1876     g_free(folded_token);
1877
1878     if (*s == NULL) {
1879         conf_parserror(_("configuration keyword expected"));
1880     }
1881
1882     for (;;) {
1883         char c = conftoken_getc();
1884         if (c == '\n' || c == -1) {
1885             conftoken_ungetc(c);
1886             return;
1887         }
1888     }
1889
1890     g_assert_not_reached();
1891 }
1892
1893 static char *
1894 get_seen_filename(
1895     char *filename)
1896 {
1897     GSList *iter;
1898     char *istr;
1899
1900     for (iter = seen_filenames; iter; iter = iter->next) {
1901         istr = iter->data;
1902         if (istr == filename || 0 == strcmp(istr, filename))
1903             return istr;
1904     }
1905
1906     istr = stralloc(filename);
1907     seen_filenames = g_slist_prepend(seen_filenames, istr);
1908     return istr;
1909 }
1910
1911 static void
1912 read_block(
1913     conf_var_t    *read_var,
1914     val_t    *valarray,
1915     char     *errormsg,
1916     int       read_brace,
1917     void      (*copy_function)(void),
1918     char     *type,
1919     char     *name)
1920 {
1921     conf_var_t *np;
1922     int         done;
1923     char       *key_ovr;
1924     int         i;
1925
1926     if(read_brace) {
1927         get_conftoken(CONF_LBRACE);
1928         get_conftoken(CONF_NL);
1929     }
1930
1931     done = 0;
1932     do {
1933         current_line_num += 1;
1934         get_conftoken(CONF_ANY);
1935         handle_deprecated_keyword();
1936
1937         switch(tok) {
1938         case CONF_RBRACE:
1939             done = 1;
1940             break;
1941         case CONF_NL:   /* empty line */
1942             break;
1943         case CONF_END:  /* end of file */
1944             done = 1;
1945             break;
1946
1947         /* inherit from a "parent" */
1948         case CONF_IDENT:
1949         case CONF_STRING:
1950             if(copy_function) 
1951                 copy_function();
1952             else
1953                 conf_parserror(_("ident not expected"));
1954             break;
1955         default:
1956             {
1957                 for(np = read_var; np->token != CONF_UNKNOWN; np++)
1958                     if(np->token == tok) break;
1959
1960                 if(np->token == CONF_UNKNOWN)
1961                     conf_parserror("%s", errormsg);
1962                 else {
1963                     np->read_function(np, &valarray[np->parm]);
1964                     if(np->validate_function)
1965                         np->validate_function(np, &valarray[np->parm]);
1966                 }
1967             }
1968         }
1969         if(tok != CONF_NL && tok != CONF_END && tok != CONF_RBRACE)
1970             get_conftoken(CONF_NL);
1971     } while(!done);
1972
1973     if (!config_overrides)
1974         return;
1975
1976     key_ovr = vstralloc(type, ":", name, NULL);
1977     for (i = 0; i < config_overrides->n_used; i++) {
1978         config_override_t *co = &config_overrides->ovr[i];
1979         char              *key = co->key;
1980         char              *keyword;
1981         char              *value;
1982         keytab_t          *kt;
1983
1984         if (key_ovr && strncasecmp(key_ovr, key, strlen(key_ovr)) != 0)
1985             continue;
1986
1987         if (strlen(key) <= strlen(key_ovr) + 1)
1988             continue;
1989
1990         keyword = key + strlen(key_ovr) + 1;
1991         value = co->value;
1992
1993         /* find the token in keytable */
1994         for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) {
1995             if (kt->keyword && strcasecmp(kt->keyword, keyword) == 0)
1996                 break;
1997         }
1998         if (kt->token == CONF_UNKNOWN)
1999              continue;
2000
2001         /* find the var in read_var */
2002         for (np = read_var; np->token != CONF_UNKNOWN; np++)
2003             if (np->token == kt->token) break;
2004         if (np->token == CONF_UNKNOWN)
2005             continue;
2006
2007         /* now set up a fake line and use the relevant read_function to
2008          * parse it.  This is sneaky! */
2009         if (np->type == CONFTYPE_STR) {
2010             current_line = quote_string_always(value);
2011         } else {
2012             current_line = stralloc(value);
2013         }
2014
2015         current_char = current_line;
2016         token_pushed = 0;
2017         current_line_num = -2;
2018         allow_overwrites = 1;
2019         co->applied = TRUE;
2020
2021         np->read_function(np, &valarray[np->parm]);
2022         if (np->validate_function)
2023             np->validate_function(np, &valarray[np->parm]);
2024
2025         amfree(current_line);
2026         current_char = NULL;
2027     }
2028     amfree(key_ovr);
2029
2030 }
2031
2032 static void
2033 read_holdingdisk(
2034     conf_var_t *np  G_GNUC_UNUSED,
2035     val_t      *val G_GNUC_UNUSED)
2036 {
2037     assert (val == &conf_data[CNF_HOLDINGDISK]);
2038     get_holdingdisk(0);
2039 }
2040
2041 static void
2042 get_holdingdisk(
2043     int is_define)
2044 {
2045     int save_overwrites;
2046
2047     save_overwrites = allow_overwrites;
2048     allow_overwrites = 1;
2049
2050     init_holdingdisk_defaults();
2051
2052     get_conftoken(CONF_IDENT);
2053     hdcur.name = stralloc(tokenval.v.s);
2054     hdcur.seen.filename = current_filename;
2055     hdcur.seen.linenum = current_line_num;
2056
2057     get_conftoken(CONF_ANY);
2058     if (tok == CONF_LBRACE) {
2059         holdingdisk_t *hd;
2060         hd = lookup_holdingdisk(hdcur.name);
2061         if (hd) {
2062             conf_parserror(_("holding disk '%s' already defined"),
2063                                hdcur.name);
2064         } else {
2065             unget_conftoken();
2066             read_block(holding_var, hdcur.value,
2067                      _("holding disk parameter expected"), 1, copy_holdingdisk,
2068                      "HOLDINGDISK", hdcur.name);
2069             get_conftoken(CONF_NL);
2070             save_holdingdisk();
2071             if (!is_define) {
2072                 conf_data[CNF_HOLDINGDISK].v.identlist = g_slist_append(
2073                                 conf_data[CNF_HOLDINGDISK].v.identlist,
2074                                 stralloc(hdcur.name));
2075             }
2076         }
2077     } else { /* use the already defined holding disk */
2078         unget_conftoken();
2079         if (is_define) {
2080             conf_parserror(_("holdingdisk definition must specify holdingdisk parameters"));
2081         }
2082         do {
2083             identlist_t il;
2084
2085             for (il = conf_data[CNF_HOLDINGDISK].v.identlist; il != NULL;
2086                                                               il = il->next) {
2087                 if (strcmp((char *)il->data, hdcur.name) == 0) {
2088                     break;
2089                 }
2090             }
2091             if (il) {
2092                 conf_parserror(_("holding disk '%s' already in use"),
2093                                hdcur.name);
2094             } else {
2095                 conf_data[CNF_HOLDINGDISK].v.identlist = g_slist_append(
2096                                 conf_data[CNF_HOLDINGDISK].v.identlist,
2097                                 stralloc(hdcur.name));
2098             }
2099             amfree(hdcur.name);
2100             get_conftoken(CONF_ANY);
2101             if (tok == CONF_IDENT || tok == CONF_STRING) {
2102                 hdcur.name = stralloc(tokenval.v.s);
2103             } else if (tok != CONF_NL) {
2104                 conf_parserror(_("IDENT or NL expected"));
2105             }
2106         } while (tok == CONF_IDENT || tok == CONF_STRING);
2107     }
2108
2109     allow_overwrites = save_overwrites;
2110 }
2111
2112 static void
2113 init_holdingdisk_defaults(
2114     void)
2115 {
2116     conf_init_str(&hdcur.value[HOLDING_COMMENT]  , "");
2117     conf_init_str(&hdcur.value[HOLDING_DISKDIR]  , "");
2118     conf_init_int64(&hdcur.value[HOLDING_DISKSIZE] , (gint64)0);
2119                     /* 1 Gb = 1M counted in 1Kb blocks */
2120     conf_init_int64(&hdcur.value[HOLDING_CHUNKSIZE], (gint64)1024*1024);
2121 }
2122
2123 static void
2124 save_holdingdisk(
2125     void)
2126 {
2127     holdingdisk_t *hp;
2128
2129     hp = alloc(sizeof(holdingdisk_t));
2130     *hp = hdcur;
2131     holdinglist = g_slist_append(holdinglist, hp);
2132 }
2133
2134 static void
2135 copy_holdingdisk(
2136     void)
2137 {
2138     holdingdisk_t *hp;
2139     int i;
2140
2141     hp = lookup_holdingdisk(tokenval.v.s);
2142
2143     if (hp == NULL) {
2144         conf_parserror(_("holdingdisk parameter expected"));
2145         return;
2146     }
2147
2148     for(i=0; i < HOLDING_HOLDING; i++) {
2149         if(hp->value[i].seen.linenum) {
2150             merge_val_t(&hdcur.value[i], &hp->value[i]);
2151         }
2152     }
2153
2154 }
2155
2156
2157 /* WARNING:
2158  * This function is called both from this module and from diskfile.c. Modify
2159  * with caution. */
2160 dumptype_t *
2161 read_dumptype(
2162     char *name,
2163     FILE *from,
2164     char *fname,
2165     int *linenum)
2166 {
2167     int save_overwrites;
2168     FILE *saved_conf = NULL;
2169     char *saved_fname = NULL;
2170
2171     if (from) {
2172         saved_conf = current_file;
2173         current_file = from;
2174     }
2175
2176     if (fname) {
2177         saved_fname = current_filename;
2178         current_filename = get_seen_filename(fname);
2179     }
2180
2181     if (linenum)
2182         current_line_num = *linenum;
2183
2184     save_overwrites = allow_overwrites;
2185     allow_overwrites = 1;
2186
2187     init_dumptype_defaults();
2188     if (name) {
2189         dpcur.name = name;
2190     } else {
2191         get_conftoken(CONF_IDENT);
2192         dpcur.name = stralloc(tokenval.v.s);
2193     }
2194     dpcur.seen.filename = current_filename;
2195     dpcur.seen.linenum = current_line_num;
2196
2197     read_block(dumptype_var, dpcur.value,
2198                _("dumptype parameter expected"),
2199                (name == NULL), copy_dumptype,
2200                "DUMPTYPE", dpcur.name);
2201
2202     if(!name) /* !name => reading disklist, not conffile */
2203         get_conftoken(CONF_NL);
2204
2205     /* XXX - there was a stupidity check in here for skip-incr and
2206     ** skip-full.  This check should probably be somewhere else. */
2207
2208     save_dumptype();
2209
2210     allow_overwrites = save_overwrites;
2211
2212     if (linenum)
2213         *linenum = current_line_num;
2214
2215     if (fname)
2216         current_filename = saved_fname;
2217
2218     if (from)
2219         current_file = saved_conf;
2220
2221     return lookup_dumptype(dpcur.name);
2222 }
2223
2224 static void
2225 get_dumptype(void)
2226 {
2227     read_dumptype(NULL, NULL, NULL, NULL);
2228 }
2229
2230 static void
2231 init_dumptype_defaults(void)
2232 {
2233     dpcur.name = NULL;
2234     conf_init_str   (&dpcur.value[DUMPTYPE_COMMENT]           , "");
2235     conf_init_str   (&dpcur.value[DUMPTYPE_PROGRAM]           , "DUMP");
2236     conf_init_str   (&dpcur.value[DUMPTYPE_SRVCOMPPROG]       , "");
2237     conf_init_str   (&dpcur.value[DUMPTYPE_CLNTCOMPPROG]      , "");
2238     conf_init_str   (&dpcur.value[DUMPTYPE_SRV_ENCRYPT]       , "");
2239     conf_init_str   (&dpcur.value[DUMPTYPE_CLNT_ENCRYPT]      , "");
2240     conf_init_str   (&dpcur.value[DUMPTYPE_AMANDAD_PATH]      , "");
2241     conf_init_str   (&dpcur.value[DUMPTYPE_CLIENT_USERNAME]   , "");
2242     conf_init_str   (&dpcur.value[DUMPTYPE_CLIENT_PORT]       , "");
2243     conf_init_str   (&dpcur.value[DUMPTYPE_SSH_KEYS]          , "");
2244     conf_init_str   (&dpcur.value[DUMPTYPE_AUTH]   , "BSD");
2245     conf_init_exinclude(&dpcur.value[DUMPTYPE_EXCLUDE]);
2246     conf_init_exinclude(&dpcur.value[DUMPTYPE_INCLUDE]);
2247     conf_init_priority (&dpcur.value[DUMPTYPE_PRIORITY]          , 1);
2248     conf_init_int      (&dpcur.value[DUMPTYPE_DUMPCYCLE]         , conf_data[CNF_DUMPCYCLE].v.i);
2249     conf_init_int      (&dpcur.value[DUMPTYPE_MAXDUMPS]          , conf_data[CNF_MAXDUMPS].v.i);
2250     conf_init_int      (&dpcur.value[DUMPTYPE_MAXPROMOTEDAY]     , 10000);
2251     conf_init_int      (&dpcur.value[DUMPTYPE_BUMPPERCENT]       , conf_data[CNF_BUMPPERCENT].v.i);
2252     conf_init_int64    (&dpcur.value[DUMPTYPE_BUMPSIZE]          , conf_data[CNF_BUMPSIZE].v.int64);
2253     conf_init_int      (&dpcur.value[DUMPTYPE_BUMPDAYS]          , conf_data[CNF_BUMPDAYS].v.i);
2254     conf_init_real     (&dpcur.value[DUMPTYPE_BUMPMULT]          , conf_data[CNF_BUMPMULT].v.r);
2255     conf_init_time     (&dpcur.value[DUMPTYPE_STARTTIME]         , (time_t)0);
2256     conf_init_strategy (&dpcur.value[DUMPTYPE_STRATEGY]          , DS_STANDARD);
2257     conf_init_estimatelist(&dpcur.value[DUMPTYPE_ESTIMATELIST]   , ES_CLIENT);
2258     conf_init_compress (&dpcur.value[DUMPTYPE_COMPRESS]          , COMP_FAST);
2259     conf_init_encrypt  (&dpcur.value[DUMPTYPE_ENCRYPT]           , ENCRYPT_NONE);
2260     conf_init_data_path(&dpcur.value[DUMPTYPE_DATA_PATH]         , DATA_PATH_AMANDA);
2261     conf_init_str   (&dpcur.value[DUMPTYPE_SRV_DECRYPT_OPT]   , "-d");
2262     conf_init_str   (&dpcur.value[DUMPTYPE_CLNT_DECRYPT_OPT]  , "-d");
2263     conf_init_rate     (&dpcur.value[DUMPTYPE_COMPRATE]          , 0.50, 0.50);
2264     conf_init_int64    (&dpcur.value[DUMPTYPE_TAPE_SPLITSIZE]    , (gint64)0);
2265     conf_init_int64    (&dpcur.value[DUMPTYPE_FALLBACK_SPLITSIZE], (gint64)10 * 1024);
2266     conf_init_str   (&dpcur.value[DUMPTYPE_SPLIT_DISKBUFFER]  , NULL);
2267     conf_init_bool     (&dpcur.value[DUMPTYPE_RECORD]            , 1);
2268     conf_init_bool     (&dpcur.value[DUMPTYPE_SKIP_INCR]         , 0);
2269     conf_init_bool     (&dpcur.value[DUMPTYPE_SKIP_FULL]         , 0);
2270     conf_init_holding  (&dpcur.value[DUMPTYPE_HOLDINGDISK]       , HOLD_AUTO);
2271     conf_init_bool     (&dpcur.value[DUMPTYPE_KENCRYPT]          , 0);
2272     conf_init_bool     (&dpcur.value[DUMPTYPE_IGNORE]            , 0);
2273     conf_init_bool     (&dpcur.value[DUMPTYPE_INDEX]             , 1);
2274     conf_init_application(&dpcur.value[DUMPTYPE_APPLICATION]);
2275     conf_init_identlist(&dpcur.value[DUMPTYPE_SCRIPTLIST], NULL);
2276     conf_init_proplist(&dpcur.value[DUMPTYPE_PROPERTY]);
2277     conf_init_bool     (&dpcur.value[DUMPTYPE_ALLOW_SPLIT]       , 1);
2278     conf_init_recovery_limit(&dpcur.value[DUMPTYPE_RECOVERY_LIMIT]);
2279 }
2280
2281 static void
2282 save_dumptype(void)
2283 {
2284     dumptype_t *dp, *dp1;;
2285
2286     dp = lookup_dumptype(dpcur.name);
2287
2288     if(dp != (dumptype_t *)0) {
2289         if (dp->seen.linenum == -1) {
2290             conf_parserror(_("dumptype %s is defined by default and cannot be redefined"), dp->name);
2291         } else {
2292             conf_parserror(_("dumptype %s already defined at %s:%d"), dp->name,
2293                            dp->seen.filename, dp->seen.linenum);
2294         }
2295         return;
2296     }
2297
2298     dp = alloc(sizeof(dumptype_t));
2299     *dp = dpcur;
2300     dp->next = NULL;
2301     /* add at end of list */
2302     if(!dumplist)
2303         dumplist = dp;
2304     else {
2305         dp1 = dumplist;
2306         while (dp1->next != NULL) {
2307              dp1 = dp1->next;
2308         }
2309         dp1->next = dp;
2310     }
2311 }
2312
2313 static void
2314 copy_dumptype(void)
2315 {
2316     dumptype_t *dt;
2317     int i;
2318
2319     dt = lookup_dumptype(tokenval.v.s);
2320
2321     if(dt == NULL) {
2322         conf_parserror(_("dumptype parameter expected"));
2323         return;
2324     }
2325
2326     for(i=0; i < DUMPTYPE_DUMPTYPE; i++) {
2327         if(dt->value[i].seen.linenum) {
2328             merge_val_t(&dpcur.value[i], &dt->value[i]);
2329             if (i == DUMPTYPE_SCRIPTLIST) {
2330                 /* sort in 'order' */
2331                 dpcur.value[i].v.identlist = g_slist_sort(dpcur.value[i].v.identlist, &compare_pp_script_order);
2332             }
2333         }
2334     }
2335 }
2336
2337 static void
2338 get_tapetype(void)
2339 {
2340     int save_overwrites;
2341
2342     save_overwrites = allow_overwrites;
2343     allow_overwrites = 1;
2344
2345     init_tapetype_defaults();
2346
2347     get_conftoken(CONF_IDENT);
2348     tpcur.name = stralloc(tokenval.v.s);
2349     tpcur.seen.filename = current_filename;
2350     tpcur.seen.linenum = current_line_num;
2351
2352     read_block(tapetype_var, tpcur.value,
2353                _("tapetype parameter expected"), 1, copy_tapetype,
2354                "TAPETYPE", tpcur.name);
2355     get_conftoken(CONF_NL);
2356
2357     if (tapetype_get_readblocksize(&tpcur) <
2358         tapetype_get_blocksize(&tpcur)) {
2359         conf_init_size(&tpcur.value[TAPETYPE_READBLOCKSIZE],
2360                        tapetype_get_blocksize(&tpcur));
2361     }
2362     save_tapetype();
2363
2364     allow_overwrites = save_overwrites;
2365 }
2366
2367 static void
2368 init_tapetype_defaults(void)
2369 {
2370     conf_init_str(&tpcur.value[TAPETYPE_COMMENT]      , "");
2371     conf_init_str(&tpcur.value[TAPETYPE_LBL_TEMPL]    , "");
2372     conf_init_size  (&tpcur.value[TAPETYPE_BLOCKSIZE]    , DISK_BLOCK_KB);
2373     conf_init_size  (&tpcur.value[TAPETYPE_READBLOCKSIZE], DISK_BLOCK_KB);
2374     conf_init_int64 (&tpcur.value[TAPETYPE_LENGTH]       , ((gint64)2000));
2375     conf_init_int64 (&tpcur.value[TAPETYPE_FILEMARK]     , (gint64)1);
2376     conf_init_int   (&tpcur.value[TAPETYPE_SPEED]        , 200);
2377     conf_init_int64(&tpcur.value[TAPETYPE_PART_SIZE], 0);
2378     conf_init_part_cache_type(&tpcur.value[TAPETYPE_PART_CACHE_TYPE], PART_CACHE_TYPE_NONE);
2379     conf_init_str(&tpcur.value[TAPETYPE_PART_CACHE_DIR], "");
2380     conf_init_int64(&tpcur.value[TAPETYPE_PART_CACHE_MAX_SIZE], 0);
2381 }
2382
2383 static void
2384 save_tapetype(void)
2385 {
2386     tapetype_t *tp, *tp1;
2387
2388     tp = lookup_tapetype(tpcur.name);
2389
2390     if(tp != (tapetype_t *)0) {
2391         amfree(tpcur.name);
2392         conf_parserror(_("tapetype %s already defined at %s:%d"),
2393                 tp->name, tp->seen.filename, tp->seen.linenum);
2394         return;
2395     }
2396
2397     tp = alloc(sizeof(tapetype_t));
2398     *tp = tpcur;
2399
2400     /* add at end of list */
2401     if(!tapelist)
2402         tapelist = tp;
2403     else {
2404         tp1 = tapelist;
2405         while (tp1->next != NULL) {
2406             tp1 = tp1->next;
2407         }
2408         tp1->next = tp;
2409     }
2410 }
2411
2412 static void
2413 copy_tapetype(void)
2414 {
2415     tapetype_t *tp;
2416     int i;
2417
2418     tp = lookup_tapetype(tokenval.v.s);
2419
2420     if(tp == NULL) {
2421         conf_parserror(_("tape type parameter expected"));
2422         return;
2423     }
2424
2425     for(i=0; i < TAPETYPE_TAPETYPE; i++) {
2426         if(tp->value[i].seen.linenum) {
2427             merge_val_t(&tpcur.value[i], &tp->value[i]);
2428         }
2429     }
2430 }
2431
2432 static void
2433 get_interface(void)
2434 {
2435     int save_overwrites;
2436
2437     save_overwrites = allow_overwrites;
2438     allow_overwrites = 1;
2439
2440     init_interface_defaults();
2441
2442     get_conftoken(CONF_IDENT);
2443     ifcur.name = stralloc(tokenval.v.s);
2444     ifcur.seen.filename = current_filename;
2445     ifcur.seen.linenum = current_line_num;
2446
2447     read_block(interface_var, ifcur.value,
2448                _("interface parameter expected"), 1, copy_interface,
2449                "INTERFACE", ifcur.name);
2450     get_conftoken(CONF_NL);
2451
2452     save_interface();
2453
2454     allow_overwrites = save_overwrites;
2455
2456     return;
2457 }
2458
2459 static void
2460 init_interface_defaults(void)
2461 {
2462     conf_init_str(&ifcur.value[INTER_COMMENT] , "");
2463     conf_init_int   (&ifcur.value[INTER_MAXUSAGE], 8000);
2464 }
2465
2466 static void
2467 save_interface(void)
2468 {
2469     interface_t *ip, *ip1;
2470
2471     ip = lookup_interface(ifcur.name);
2472
2473     if(ip != (interface_t *)0) {
2474         conf_parserror(_("interface %s already defined at %s:%d"),
2475                 ip->name, ip->seen.filename, ip->seen.linenum);
2476         return;
2477     }
2478
2479     ip = alloc(sizeof(interface_t));
2480     *ip = ifcur;
2481     /* add at end of list */
2482     if(!interface_list) {
2483         interface_list = ip;
2484     } else {
2485         ip1 = interface_list;
2486         while (ip1->next != NULL) {
2487             ip1 = ip1->next;
2488         }
2489         ip1->next = ip;
2490     }
2491 }
2492
2493 static void
2494 copy_interface(void)
2495 {
2496     interface_t *ip;
2497     int i;
2498
2499     ip = lookup_interface(tokenval.v.s);
2500
2501     if(ip == NULL) {
2502         conf_parserror(_("interface parameter expected"));
2503         return;
2504     }
2505
2506     for(i=0; i < INTER_INTER; i++) {
2507         if(ip->value[i].seen.linenum) {
2508             merge_val_t(&ifcur.value[i], &ip->value[i]);
2509         }
2510     }
2511 }
2512
2513
2514 application_t *
2515 read_application(
2516     char *name,
2517     FILE *from,
2518     char *fname,
2519     int *linenum)
2520 {
2521     int save_overwrites;
2522     FILE *saved_conf = NULL;
2523     char *saved_fname = NULL;
2524
2525     if (from) {
2526         saved_conf = current_file;
2527         current_file = from;
2528     }
2529
2530     if (fname) {
2531         saved_fname = current_filename;
2532         current_filename = get_seen_filename(fname);
2533     }
2534
2535     if (linenum)
2536         current_line_num = *linenum;
2537
2538     save_overwrites = allow_overwrites;
2539     allow_overwrites = 1;
2540
2541     init_application_defaults();
2542     if (name) {
2543         apcur.name = name;
2544     } else {
2545         get_conftoken(CONF_IDENT);
2546         apcur.name = stralloc(tokenval.v.s);
2547     }
2548     apcur.seen.filename = current_filename;
2549     apcur.seen.linenum = current_line_num;
2550
2551     read_block(application_var, apcur.value,
2552                _("application parameter expected"),
2553                (name == NULL), *copy_application,
2554                "APPLICATION", apcur.name);
2555     if(!name)
2556         get_conftoken(CONF_NL);
2557
2558     save_application();
2559
2560     allow_overwrites = save_overwrites;
2561
2562     if (linenum)
2563         *linenum = current_line_num;
2564
2565     if (fname)
2566         current_filename = saved_fname;
2567
2568     if (from)
2569         current_file = saved_conf;
2570
2571     return lookup_application(apcur.name);
2572 }
2573
2574 static void
2575 get_application(
2576     void)
2577 {
2578     read_application(NULL, NULL, NULL, NULL);
2579 }
2580
2581 static void
2582 init_application_defaults(
2583     void)
2584 {
2585     apcur.name = NULL;
2586     conf_init_str(&apcur.value[APPLICATION_COMMENT] , "");
2587     conf_init_str(&apcur.value[APPLICATION_PLUGIN]  , "");
2588     conf_init_proplist(&apcur.value[APPLICATION_PROPERTY]);
2589 }
2590
2591 static void
2592 save_application(
2593     void)
2594 {
2595     application_t *ap, *ap1;
2596
2597     ap = lookup_application(apcur.name);
2598
2599     if(ap != (application_t *)0) {
2600         conf_parserror(_("application %s already defined at %s:%d"),
2601                        ap->name, ap->seen.filename, ap->seen.linenum);
2602         return;
2603     }
2604
2605     ap = alloc(sizeof(application_t));
2606     *ap = apcur;
2607     ap->next = NULL;
2608     /* add at end of list */
2609     if (!application_list)
2610         application_list = ap;
2611     else {
2612         ap1 = application_list;
2613         while (ap1->next != NULL) {
2614             ap1 = ap1->next;
2615         }
2616         ap1->next = ap;
2617     }
2618 }
2619
2620 static void
2621 copy_application(void)
2622 {
2623     application_t *ap;
2624     int i;
2625
2626     ap = lookup_application(tokenval.v.s);
2627
2628     if(ap == NULL) {
2629         conf_parserror(_("application parameter expected"));
2630         return;
2631     }
2632
2633     for(i=0; i < APPLICATION_APPLICATION; i++) {
2634         if(ap->value[i].seen.linenum) {
2635             merge_val_t(&apcur.value[i], &ap->value[i]);
2636         }
2637     }
2638 }
2639
2640 pp_script_t *
2641 read_pp_script(
2642     char *name,
2643     FILE *from,
2644     char *fname,
2645     int *linenum)
2646 {
2647     int save_overwrites;
2648     FILE *saved_conf = NULL;
2649     char *saved_fname = NULL;
2650
2651     if (from) {
2652         saved_conf = current_file;
2653         current_file = from;
2654     }
2655
2656     if (fname) {
2657         saved_fname = current_filename;
2658         current_filename = get_seen_filename(fname);
2659     }
2660
2661     if (linenum)
2662         current_line_num = *linenum;
2663
2664     save_overwrites = allow_overwrites;
2665     allow_overwrites = 1;
2666
2667     init_pp_script_defaults();
2668     if (name) {
2669         pscur.name = name;
2670     } else {
2671         get_conftoken(CONF_IDENT);
2672         pscur.name = stralloc(tokenval.v.s);
2673     }
2674     pscur.seen.filename = current_filename;
2675     pscur.seen.linenum = current_line_num;
2676
2677     read_block(pp_script_var, pscur.value,
2678                _("script parameter expected"),
2679                (name == NULL), *copy_pp_script,
2680                "SCRIPT", pscur.name);
2681     if(!name)
2682         get_conftoken(CONF_NL);
2683
2684     save_pp_script();
2685
2686     allow_overwrites = save_overwrites;
2687
2688     if (linenum)
2689         *linenum = current_line_num;
2690
2691     if (fname)
2692         current_filename = saved_fname;
2693
2694     if (from)
2695         current_file = saved_conf;
2696
2697     return lookup_pp_script(pscur.name);
2698 }
2699
2700 static void
2701 get_pp_script(
2702     void)
2703 {
2704     read_pp_script(NULL, NULL, NULL, NULL);
2705 }
2706
2707 static void
2708 init_pp_script_defaults(
2709     void)
2710 {
2711     pscur.name = NULL;
2712     conf_init_str(&pscur.value[PP_SCRIPT_COMMENT] , "");
2713     conf_init_str(&pscur.value[PP_SCRIPT_PLUGIN]  , "");
2714     conf_init_proplist(&pscur.value[PP_SCRIPT_PROPERTY]);
2715     conf_init_execute_on(&pscur.value[PP_SCRIPT_EXECUTE_ON], 0);
2716     conf_init_execute_where(&pscur.value[PP_SCRIPT_EXECUTE_WHERE], ES_CLIENT);
2717     conf_init_int(&pscur.value[PP_SCRIPT_ORDER], 5000);
2718 }
2719
2720 static void
2721 save_pp_script(
2722     void)
2723 {
2724     pp_script_t *ps, *ps1;
2725
2726     ps = lookup_pp_script(pscur.name);
2727
2728     if(ps != (pp_script_t *)0) {
2729         conf_parserror(_("script %s already defined at %s:%d"),
2730                        ps->name, ps->seen.filename, ps->seen.linenum);
2731         return;
2732     }
2733
2734     ps = alloc(sizeof(pp_script_t));
2735     *ps = pscur;
2736     ps->next = NULL;
2737     /* add at end of list */
2738     if (!pp_script_list)
2739         pp_script_list = ps;
2740     else {
2741         ps1 = pp_script_list;
2742         while (ps1->next != NULL) {
2743             ps1 = ps1->next;
2744         }
2745         ps1->next = ps;
2746     }
2747 }
2748
2749 static void
2750 copy_pp_script(void)
2751 {
2752     pp_script_t *ps;
2753     int i;
2754
2755     ps = lookup_pp_script(tokenval.v.s);
2756
2757     if(ps == NULL) {
2758         conf_parserror(_("script parameter expected"));
2759         return;
2760     }
2761
2762     for(i=0; i < PP_SCRIPT_PP_SCRIPT; i++) {
2763         if(ps->value[i].seen.linenum) {
2764             merge_val_t(&pscur.value[i], &ps->value[i]);
2765         }
2766     }
2767 }
2768
2769 device_config_t *
2770 read_device_config(
2771     char *name,
2772     FILE *from,
2773     char *fname,
2774     int *linenum)
2775 {
2776     int save_overwrites;
2777     FILE *saved_conf = NULL;
2778     char *saved_fname = NULL;
2779
2780     if (from) {
2781         saved_conf = current_file;
2782         current_file = from;
2783     }
2784
2785     if (fname) {
2786         saved_fname = current_filename;
2787         current_filename = get_seen_filename(fname);
2788     }
2789
2790     if (linenum)
2791         current_line_num = *linenum;
2792
2793     save_overwrites = allow_overwrites;
2794     allow_overwrites = 1;
2795
2796     init_device_config_defaults();
2797     if (name) {
2798         dccur.name = name;
2799     } else {
2800         get_conftoken(CONF_IDENT);
2801         dccur.name = stralloc(tokenval.v.s);
2802     }
2803     dccur.seen.filename = current_filename;
2804     dccur.seen.linenum = current_line_num;
2805
2806     read_block(device_config_var, dccur.value,
2807                _("device parameter expected"),
2808                (name == NULL), *copy_device_config,
2809                "DEVICE", dccur.name);
2810     if(!name)
2811         get_conftoken(CONF_NL);
2812
2813     save_device_config();
2814
2815     allow_overwrites = save_overwrites;
2816
2817     if (linenum)
2818         *linenum = current_line_num;
2819
2820     if (fname)
2821         current_filename = saved_fname;
2822
2823     if (from)
2824         current_file = saved_conf;
2825
2826     return lookup_device_config(dccur.name);
2827 }
2828
2829 static void
2830 get_device_config(
2831     void)
2832 {
2833     read_device_config(NULL, NULL, NULL, NULL);
2834 }
2835
2836 static void
2837 init_device_config_defaults(
2838     void)
2839 {
2840     dccur.name = NULL;
2841     conf_init_str(&dccur.value[DEVICE_CONFIG_COMMENT] , "");
2842     conf_init_str(&dccur.value[DEVICE_CONFIG_TAPEDEV]  , "");
2843     conf_init_proplist(&dccur.value[DEVICE_CONFIG_DEVICE_PROPERTY]);
2844 }
2845
2846 static void
2847 save_device_config(
2848     void)
2849 {
2850     device_config_t *dc, *dc1;
2851
2852     dc = lookup_device_config(dccur.name);
2853
2854     if(dc != (device_config_t *)0) {
2855         conf_parserror(_("device %s already defined at %s:%d"),
2856                        dc->name, dc->seen.filename, dc->seen.linenum);
2857         return;
2858     }
2859
2860     dc = alloc(sizeof(device_config_t));
2861     *dc = dccur;
2862     dc->next = NULL;
2863     /* add at end of list */
2864     if (!device_config_list)
2865         device_config_list = dc;
2866     else {
2867         dc1 = device_config_list;
2868         while (dc1->next != NULL) {
2869             dc1 = dc1->next;
2870         }
2871         dc1->next = dc;
2872     }
2873 }
2874
2875 static void
2876 copy_device_config(void)
2877 {
2878     device_config_t *dc;
2879     int i;
2880
2881     dc = lookup_device_config(tokenval.v.s);
2882
2883     if(dc == NULL) {
2884         conf_parserror(_("device parameter expected"));
2885         return;
2886     }
2887
2888     for(i=0; i < DEVICE_CONFIG_DEVICE_CONFIG; i++) {
2889         if(dc->value[i].seen.linenum) {
2890             merge_val_t(&dccur.value[i], &dc->value[i]);
2891         }
2892     }
2893 }
2894
2895 changer_config_t *
2896 read_changer_config(
2897     char *name,
2898     FILE *from,
2899     char *fname,
2900     int *linenum)
2901 {
2902     int save_overwrites;
2903     FILE *saved_conf = NULL;
2904     char *saved_fname = NULL;
2905
2906     if (from) {
2907         saved_conf = current_file;
2908         current_file = from;
2909     }
2910
2911     if (fname) {
2912         saved_fname = current_filename;
2913         current_filename = fname;
2914     }
2915
2916     if (linenum)
2917         current_line_num = *linenum;
2918
2919     save_overwrites = allow_overwrites;
2920     allow_overwrites = 1;
2921
2922     init_changer_config_defaults();
2923     if (name) {
2924         cccur.name = name;
2925     } else {
2926         get_conftoken(CONF_IDENT);
2927         cccur.name = stralloc(tokenval.v.s);
2928     }
2929     cccur.seen = current_line_num;
2930
2931     read_block(changer_config_var, cccur.value,
2932                _("changer parameter expected"),
2933                (name == NULL), *copy_changer_config,
2934                "CHANGER", cccur.name);
2935     if(!name)
2936         get_conftoken(CONF_NL);
2937
2938     save_changer_config();
2939
2940     allow_overwrites = save_overwrites;
2941
2942     if (linenum)
2943         *linenum = current_line_num;
2944
2945     if (fname)
2946         current_filename = saved_fname;
2947
2948     if (from)
2949         current_file = saved_conf;
2950
2951     return lookup_changer_config(cccur.name);
2952 }
2953
2954 static void
2955 get_changer_config(
2956     void)
2957 {
2958     read_changer_config(NULL, NULL, NULL, NULL);
2959 }
2960
2961 static void
2962 init_changer_config_defaults(
2963     void)
2964 {
2965     cccur.name = NULL;
2966     conf_init_str(&cccur.value[CHANGER_CONFIG_COMMENT] , "");
2967     conf_init_str(&cccur.value[CHANGER_CONFIG_TAPEDEV]  , "");
2968     conf_init_str(&cccur.value[CHANGER_CONFIG_TPCHANGER]  , "");
2969     conf_init_str(&cccur.value[CHANGER_CONFIG_CHANGERDEV]  , "");
2970     conf_init_str(&cccur.value[CHANGER_CONFIG_CHANGERFILE]  , "");
2971     conf_init_proplist(&cccur.value[CHANGER_CONFIG_PROPERTY]);
2972     conf_init_proplist(&cccur.value[CHANGER_CONFIG_DEVICE_PROPERTY]);
2973 }
2974
2975 static void
2976 save_changer_config(
2977     void)
2978 {
2979     changer_config_t *dc, *dc1;
2980
2981     dc = lookup_changer_config(cccur.name);
2982
2983     if(dc != (changer_config_t *)0) {
2984         conf_parserror(_("changer %s already defined on line %d"),
2985                        dc->name, dc->seen);
2986         return;
2987     }
2988
2989     dc = alloc(sizeof(changer_config_t));
2990     *dc = cccur;
2991     dc->next = NULL;
2992     /* add at end of list */
2993     if (!changer_config_list)
2994         changer_config_list = dc;
2995     else {
2996         dc1 = changer_config_list;
2997         while (dc1->next != NULL) {
2998             dc1 = dc1->next;
2999         }
3000         dc1->next = dc;
3001     }
3002 }
3003
3004 static void
3005 copy_changer_config(void)
3006 {
3007     changer_config_t *dc;
3008     int i;
3009
3010     dc = lookup_changer_config(tokenval.v.s);
3011
3012     if(dc == NULL) {
3013         conf_parserror(_("changer parameter expected"));
3014         return;
3015     }
3016
3017     for(i=0; i < CHANGER_CONFIG_CHANGER_CONFIG; i++) {
3018         if(dc->value[i].seen.linenum) {
3019             merge_val_t(&cccur.value[i], &dc->value[i]);
3020         }
3021     }
3022 }
3023
3024 /* Read functions */
3025
3026 static void
3027 read_int(
3028     conf_var_t *np G_GNUC_UNUSED,
3029     val_t *val)
3030 {
3031     ckseen(&val->seen);
3032     val_t__int(val) = get_int();
3033 }
3034
3035 static void
3036 read_int64(
3037     conf_var_t *np G_GNUC_UNUSED,
3038     val_t *val)
3039 {
3040     ckseen(&val->seen);
3041     val_t__int64(val) = get_int64();
3042 }
3043
3044 static void
3045 read_real(
3046     conf_var_t *np G_GNUC_UNUSED,
3047     val_t *val)
3048 {
3049     ckseen(&val->seen);
3050     get_conftoken(CONF_REAL);
3051     val_t__real(val) = tokenval.v.r;
3052 }
3053
3054 static void
3055 read_str(
3056     conf_var_t *np G_GNUC_UNUSED,
3057     val_t *val)
3058 {
3059     ckseen(&val->seen);
3060     get_conftoken(CONF_STRING);
3061     val->v.s = newstralloc(val->v.s, tokenval.v.s);
3062 }
3063
3064 static void
3065 read_ident(
3066     conf_var_t *np G_GNUC_UNUSED,
3067     val_t *val)
3068 {
3069     ckseen(&val->seen);
3070     get_conftoken(CONF_IDENT);
3071     val->v.s = newstralloc(val->v.s, tokenval.v.s);
3072 }
3073
3074 static void
3075 read_time(
3076     conf_var_t *np G_GNUC_UNUSED,
3077     val_t *val)
3078 {
3079     ckseen(&val->seen);
3080     val_t__time(val) = get_time();
3081 }
3082
3083 static void
3084 read_size(
3085     conf_var_t *np G_GNUC_UNUSED,
3086     val_t *val)
3087 {
3088     ckseen(&val->seen);
3089     val_t__size(val) = get_size();
3090 }
3091
3092 static void
3093 read_size_byte(
3094     conf_var_t *np G_GNUC_UNUSED,
3095     val_t *val)
3096 {
3097     ckseen(&val->seen);
3098     val_t__size(val) = get_size_byte();
3099 }
3100
3101 static void
3102 read_bool(
3103     conf_var_t *np G_GNUC_UNUSED,
3104     val_t *val)
3105 {
3106     ckseen(&val->seen);
3107     val_t__boolean(val) = get_bool();
3108 }
3109
3110 static void
3111 read_compress(
3112     conf_var_t *np G_GNUC_UNUSED,
3113     val_t *val)
3114 {
3115     int serv, clie, none, fast, best, custom;
3116     int done;
3117     comp_t comp;
3118
3119     ckseen(&val->seen);
3120
3121     serv = clie = none = fast = best = custom  = 0;
3122
3123     done = 0;
3124     do {
3125         get_conftoken(CONF_ANY);
3126         switch(tok) {
3127         case CONF_NONE:   none = 1; break;
3128         case CONF_FAST:   fast = 1; break;
3129         case CONF_BEST:   best = 1; break;
3130         case CONF_CLIENT: clie = 1; break;
3131         case CONF_SERVER: serv = 1; break;
3132         case CONF_CUSTOM: custom=1; break;
3133         case CONF_NL:     done = 1; break;
3134         case CONF_END:    done = 1; break;
3135         default:
3136             done = 1;
3137             serv = clie = 1; /* force an error */
3138         }
3139     } while(!done);
3140
3141     if(serv + clie == 0) clie = 1;      /* default to client */
3142     if(none + fast + best + custom  == 0) fast = 1; /* default to fast */
3143
3144     comp = -1;
3145
3146     if(!serv && clie) {
3147         if(none && !fast && !best && !custom) comp = COMP_NONE;
3148         if(!none && fast && !best && !custom) comp = COMP_FAST;
3149         if(!none && !fast && best && !custom) comp = COMP_BEST;
3150         if(!none && !fast && !best && custom) comp = COMP_CUST;
3151     }
3152
3153     if(serv && !clie) {
3154         if(none && !fast && !best && !custom) comp = COMP_NONE;
3155         if(!none && fast && !best && !custom) comp = COMP_SERVER_FAST;
3156         if(!none && !fast && best && !custom) comp = COMP_SERVER_BEST;
3157         if(!none && !fast && !best && custom) comp = COMP_SERVER_CUST;
3158     }
3159
3160     if((int)comp == -1) {
3161         conf_parserror(_("NONE, CLIENT FAST, CLIENT BEST, CLIENT CUSTOM, SERVER FAST, SERVER BEST or SERVER CUSTOM expected"));
3162         comp = COMP_NONE;
3163     }
3164
3165     val_t__compress(val) = (int)comp;
3166 }
3167
3168 static void
3169 read_encrypt(
3170     conf_var_t *np G_GNUC_UNUSED,
3171     val_t *val)
3172 {
3173    encrypt_t encrypt;
3174
3175    ckseen(&val->seen);
3176
3177    get_conftoken(CONF_ANY);
3178    switch(tok) {
3179    case CONF_NONE:  
3180      encrypt = ENCRYPT_NONE; 
3181      break;
3182
3183    case CONF_CLIENT:  
3184      encrypt = ENCRYPT_CUST;
3185      break;
3186
3187    case CONF_SERVER: 
3188      encrypt = ENCRYPT_SERV_CUST;
3189      break;
3190
3191    default:
3192      conf_parserror(_("NONE, CLIENT or SERVER expected"));
3193      encrypt = ENCRYPT_NONE;
3194      break;
3195    }
3196
3197    val_t__encrypt(val) = (int)encrypt;
3198 }
3199
3200 static void
3201 read_holding(
3202     conf_var_t *np G_GNUC_UNUSED,
3203     val_t *val)
3204 {
3205    dump_holdingdisk_t holding;
3206
3207    ckseen(&val->seen);
3208
3209    get_conftoken(CONF_ANY);
3210    switch(tok) {
3211    case CONF_NEVER:  
3212      holding = HOLD_NEVER; 
3213      break;
3214
3215    case CONF_AUTO:  
3216      holding = HOLD_AUTO;
3217      break;
3218
3219    case CONF_REQUIRED: 
3220      holding = HOLD_REQUIRED;
3221      break;
3222
3223    default: /* can be a BOOLEAN */
3224      unget_conftoken();
3225      holding =  (dump_holdingdisk_t)get_bool();
3226      if (holding == 0)
3227         holding = HOLD_NEVER;
3228      else if (holding == 1 || holding == 2)
3229         holding = HOLD_AUTO;
3230      else
3231         conf_parserror(_("NEVER, AUTO or REQUIRED expected"));
3232      break;
3233    }
3234
3235    val_t__holding(val) = (int)holding;
3236 }
3237
3238 static void
3239 read_estimatelist(
3240     conf_var_t *np G_GNUC_UNUSED,
3241     val_t *val)
3242 {
3243     estimatelist_t estimates = NULL;
3244
3245     ckseen(&val->seen);
3246
3247     get_conftoken(CONF_ANY);
3248     do {
3249         switch(tok) {
3250         case CONF_CLIENT:
3251             estimates = g_slist_append(estimates, GINT_TO_POINTER(ES_CLIENT));
3252             break;
3253         case CONF_SERVER:
3254             estimates = g_slist_append(estimates, GINT_TO_POINTER(ES_SERVER));
3255             break;
3256         case CONF_CALCSIZE:
3257             estimates = g_slist_append(estimates, GINT_TO_POINTER(ES_CALCSIZE));
3258             break;
3259         default:
3260             conf_parserror(_("CLIENT, SERVER or CALCSIZE expected"));
3261         }
3262         get_conftoken(CONF_ANY);
3263         if (tok == CONF_NL)
3264             break;
3265     } while (1);
3266     val_t__estimatelist(val) = estimates;
3267 }
3268
3269 static void
3270 read_strategy(
3271     conf_var_t *np G_GNUC_UNUSED,
3272     val_t *val)
3273 {
3274     int strat;
3275
3276     ckseen(&val->seen);
3277
3278     get_conftoken(CONF_ANY);
3279     switch(tok) {
3280     case CONF_SKIP:
3281         strat = DS_SKIP;
3282         break;
3283     case CONF_STANDARD:
3284         strat = DS_STANDARD;
3285         break;
3286     case CONF_NOFULL:
3287         strat = DS_NOFULL;
3288         break;
3289     case CONF_NOINC:
3290         strat = DS_NOINC;
3291         break;
3292     case CONF_HANOI:
3293         strat = DS_HANOI;
3294         break;
3295     case CONF_INCRONLY:
3296         strat = DS_INCRONLY;
3297         break;
3298     default:
3299         conf_parserror(_("dump strategy expected"));
3300         strat = DS_STANDARD;
3301     }
3302     val_t__strategy(val) = strat;
3303 }
3304
3305 static void
3306 read_taperalgo(
3307     conf_var_t *np G_GNUC_UNUSED,
3308     val_t *val)
3309 {
3310     ckseen(&val->seen);
3311
3312     get_conftoken(CONF_ANY);
3313     switch(tok) {
3314     case CONF_FIRST:      val_t__taperalgo(val) = ALGO_FIRST;      break;
3315     case CONF_FIRSTFIT:   val_t__taperalgo(val) = ALGO_FIRSTFIT;   break;
3316     case CONF_LARGEST:    val_t__taperalgo(val) = ALGO_LARGEST;    break;
3317     case CONF_LARGESTFIT: val_t__taperalgo(val) = ALGO_LARGESTFIT; break;
3318     case CONF_SMALLEST:   val_t__taperalgo(val) = ALGO_SMALLEST;   break;
3319     case CONF_LAST:       val_t__taperalgo(val) = ALGO_LAST;       break;
3320     default:
3321         conf_parserror(_("FIRST, FIRSTFIT, LARGEST, LARGESTFIT, SMALLEST or LAST expected"));
3322     }
3323 }
3324
3325 static void
3326 read_send_amreport_on(
3327     conf_var_t *np G_GNUC_UNUSED,
3328     val_t *val)
3329 {
3330     ckseen(&val->seen);
3331
3332     get_conftoken(CONF_ANY);
3333     switch(tok) {
3334     case CONF_ALL:     val_t__send_amreport(val) = SEND_AMREPORT_ALL;     break;
3335     case CONF_STRANGE: val_t__send_amreport(val) = SEND_AMREPORT_STRANGE; break;
3336     case CONF_ERROR:   val_t__send_amreport(val) = SEND_AMREPORT_ERROR;   break;
3337     case CONF_NEVER:   val_t__send_amreport(val) = SEND_AMREPORT_NEVER;   break;
3338     default:
3339         conf_parserror(_("ALL, STRANGE, ERROR or NEVER expected"));
3340     }
3341 }
3342
3343 static void
3344 read_data_path(
3345     conf_var_t *np G_GNUC_UNUSED,
3346     val_t *val)
3347 {
3348     ckseen(&val->seen);
3349
3350     get_conftoken(CONF_ANY);
3351     switch(tok) {
3352     case CONF_AMANDA   : val_t__send_amreport(val) = DATA_PATH_AMANDA   ; break;
3353     case CONF_DIRECTTCP: val_t__send_amreport(val) = DATA_PATH_DIRECTTCP; break;
3354     default:
3355         conf_parserror(_("AMANDA or DIRECTTCP expected"));
3356     }
3357 }
3358
3359 static void
3360 read_priority(
3361     conf_var_t *np G_GNUC_UNUSED,
3362     val_t *val)
3363 {
3364     int pri;
3365
3366     ckseen(&val->seen);
3367
3368     get_conftoken(CONF_ANY);
3369     switch(tok) {
3370     case CONF_LOW: pri = 0; break;
3371     case CONF_MEDIUM: pri = 1; break;
3372     case CONF_HIGH: pri = 2; break;
3373     case CONF_INT: pri = tokenval.v.i; break;
3374     default:
3375         conf_parserror(_("LOW, MEDIUM, HIGH or integer expected"));
3376         pri = 0;
3377     }
3378     val_t__priority(val) = pri;
3379 }
3380
3381 static void
3382 read_rate(
3383     conf_var_t *np G_GNUC_UNUSED,
3384     val_t *val)
3385 {
3386     get_conftoken(CONF_REAL);
3387     val_t__rate(val)[0] = tokenval.v.r;
3388     val_t__rate(val)[1] = tokenval.v.r;
3389     val->seen = tokenval.seen;
3390     if(tokenval.v.r < 0) {
3391         conf_parserror(_("full compression rate must be >= 0"));
3392     }
3393
3394     get_conftoken(CONF_ANY);
3395     switch(tok) {
3396     case CONF_NL:
3397         return;
3398
3399     case CONF_END:
3400         return;
3401
3402     case CONF_COMMA:
3403         break;
3404
3405     default:
3406         unget_conftoken();
3407     }
3408
3409     get_conftoken(CONF_REAL);
3410     val_t__rate(val)[1] = tokenval.v.r;
3411     if(tokenval.v.r < 0) {
3412         conf_parserror(_("incremental compression rate must be >= 0"));
3413     }
3414 }
3415
3416 static void
3417 read_exinclude(
3418     conf_var_t *np G_GNUC_UNUSED,
3419     val_t *val)
3420 {
3421     int file, got_one = 0;
3422     sl_t *exclude;
3423     int optional = 0;
3424
3425     get_conftoken(CONF_ANY);
3426     if(tok == CONF_LIST) {
3427         file = 0;
3428         get_conftoken(CONF_ANY);
3429         exclude = val_t__exinclude(val).sl_list;
3430     }
3431     else {
3432         file = 1;
3433         if(tok == CONF_EFILE) get_conftoken(CONF_ANY);
3434         exclude = val_t__exinclude(val).sl_file;
3435     }
3436     ckseen(&val->seen);
3437
3438     if(tok == CONF_OPTIONAL) {
3439         get_conftoken(CONF_ANY);
3440         optional = 1;
3441     }
3442
3443     if(tok == CONF_APPEND) {
3444         get_conftoken(CONF_ANY);
3445     }
3446     else {
3447         free_sl(exclude);
3448         exclude = NULL;
3449     }
3450
3451     while(tok == CONF_STRING) {
3452         exclude = append_sl(exclude, tokenval.v.s);
3453         got_one = 1;
3454         get_conftoken(CONF_ANY);
3455     }
3456     unget_conftoken();
3457
3458     if(got_one == 0) { free_sl(exclude); exclude = NULL; }
3459
3460     if (file == 0)
3461         val_t__exinclude(val).sl_list = exclude;
3462     else
3463         val_t__exinclude(val).sl_file = exclude;
3464     val_t__exinclude(val).optional = optional;
3465 }
3466
3467 static void
3468 read_intrange(
3469     conf_var_t *np G_GNUC_UNUSED,
3470     val_t *val)
3471 {
3472     get_conftoken(CONF_INT);
3473     val_t__intrange(val)[0] = tokenval.v.i;
3474     val_t__intrange(val)[1] = tokenval.v.i;
3475     val->seen = tokenval.seen;
3476
3477     get_conftoken(CONF_ANY);
3478     switch(tok) {
3479     case CONF_NL:
3480         return;
3481
3482     case CONF_END:
3483         return;
3484
3485     case CONF_COMMA:
3486         break;
3487
3488     default:
3489         unget_conftoken();
3490     }
3491
3492     get_conftoken(CONF_INT);
3493     val_t__intrange(val)[1] = tokenval.v.i;
3494 }
3495
3496 static void
3497 read_property(
3498     conf_var_t *np G_GNUC_UNUSED,
3499     val_t      *val)
3500 {
3501     char *key;
3502     property_t *property = malloc(sizeof(property_t));
3503     property_t *old_property;
3504     property->append = 0; 
3505     property->priority = 0; 
3506     property->values = NULL;
3507
3508     get_conftoken(CONF_ANY);
3509     if (tok == CONF_PRIORITY) {
3510         property->priority = 1;
3511         get_conftoken(CONF_ANY);
3512     }
3513     if (tok == CONF_APPEND) {
3514         property->append = 1;
3515         get_conftoken(CONF_ANY);
3516     }
3517     if (tok != CONF_STRING) {
3518         conf_parserror(_("key expected"));
3519         return;
3520     }
3521     key = amandaify_property_name(tokenval.v.s);
3522
3523     get_conftoken(CONF_ANY);
3524     if (tok == CONF_NL ||  tok == CONF_END) {
3525         g_hash_table_remove(val->v.proplist, key);
3526         unget_conftoken();
3527         return;
3528     }
3529     if (tok != CONF_STRING) {
3530         conf_parserror(_("value expected"));
3531         return;
3532     }
3533
3534     if(val->seen.linenum == 0) {
3535         val->seen.filename = current_filename;
3536         val->seen.linenum = current_line_num;
3537     }
3538
3539     old_property = g_hash_table_lookup(val->v.proplist, key);
3540     if (property->append) {
3541         /* old_property will be freed by g_hash_table_insert, so
3542          * steal its values */
3543         if (old_property) {
3544             if (old_property->priority)
3545                 property->priority = 1;
3546             property->values = old_property->values;
3547             old_property->values = NULL;
3548         }
3549     }
3550     while(tok == CONF_STRING) {
3551         property->values = g_slist_append(property->values,
3552                                           strdup(tokenval.v.s));
3553         get_conftoken(CONF_ANY);
3554     }
3555     unget_conftoken();
3556     g_hash_table_insert(val->v.proplist, key, property);
3557 }
3558
3559
3560 static void
3561 read_dapplication(
3562     conf_var_t *np G_GNUC_UNUSED,
3563     val_t      *val)
3564 {
3565     application_t *application;
3566
3567     get_conftoken(CONF_ANY);
3568     if (tok == CONF_LBRACE) {
3569         current_line_num -= 1;
3570         application = read_application(vstralloc("custom(DUMPTYPE:",
3571                                                  dpcur.name, ")", ".",
3572                                                  anonymous_value(),NULL),
3573                                        NULL, NULL, NULL);
3574         current_line_num -= 1;
3575     } else if (tok == CONF_STRING) {
3576         application = lookup_application(tokenval.v.s);
3577         if (application == NULL) {
3578             conf_parserror(_("Unknown application named: %s"), tokenval.v.s);
3579             return;
3580         }
3581     } else {
3582         conf_parserror(_("application name expected: %d %d"), tok, CONF_STRING);
3583         return;
3584     }
3585     amfree(val->v.s);
3586     val->v.s = stralloc(application->name);
3587     ckseen(&val->seen);
3588 }
3589
3590 static void
3591 read_dpp_script(
3592     conf_var_t *np G_GNUC_UNUSED,
3593     val_t      *val)
3594 {
3595     pp_script_t *pp_script;
3596     get_conftoken(CONF_ANY);
3597     if (tok == CONF_LBRACE) {
3598         current_line_num -= 1;
3599         pp_script = read_pp_script(vstralloc("custom(DUMPTYPE:", dpcur.name,
3600                                              ")", ".", anonymous_value(),NULL),
3601                                    NULL, NULL, NULL);
3602         current_line_num -= 1;
3603         val->v.identlist = g_slist_insert_sorted(val->v.identlist,
3604                         stralloc(pp_script->name), &compare_pp_script_order);
3605     } else if (tok == CONF_STRING || tok == CONF_IDENT) {
3606         while (tok == CONF_STRING || tok == CONF_IDENT) {
3607             pp_script = lookup_pp_script(tokenval.v.s);
3608             if (pp_script == NULL) {
3609                 conf_parserror(_("Unknown pp_script named: %s"), tokenval.v.s);
3610                 return;
3611             }
3612             val->v.identlist = g_slist_insert_sorted(val->v.identlist,
3613                          stralloc(pp_script->name), &compare_pp_script_order);
3614             get_conftoken(CONF_ANY);
3615         }
3616         unget_conftoken();
3617     } else {
3618         conf_parserror(_("pp_script name expected: %d %d"), tok, CONF_STRING);
3619         return;
3620     }
3621     ckseen(&val->seen);
3622 }
3623 static void
3624 read_execute_on(
3625     conf_var_t *np G_GNUC_UNUSED,
3626     val_t *val)
3627 {
3628     ckseen(&val->seen);
3629
3630     get_conftoken(CONF_ANY);
3631     val->v.i = 0;
3632     do {
3633         switch(tok) {
3634         case CONF_PRE_DLE_AMCHECK:     val->v.i |= EXECUTE_ON_PRE_DLE_AMCHECK;     break;
3635         case CONF_PRE_HOST_AMCHECK:    val->v.i |= EXECUTE_ON_PRE_HOST_AMCHECK;    break;
3636         case CONF_POST_DLE_AMCHECK:    val->v.i |= EXECUTE_ON_POST_DLE_AMCHECK;    break;
3637         case CONF_POST_HOST_AMCHECK:   val->v.i |= EXECUTE_ON_POST_HOST_AMCHECK;   break;
3638         case CONF_PRE_DLE_ESTIMATE:    val->v.i |= EXECUTE_ON_PRE_DLE_ESTIMATE;    break;
3639         case CONF_PRE_HOST_ESTIMATE:   val->v.i |= EXECUTE_ON_PRE_HOST_ESTIMATE;   break;
3640         case CONF_POST_DLE_ESTIMATE:   val->v.i |= EXECUTE_ON_POST_DLE_ESTIMATE;   break;
3641         case CONF_POST_HOST_ESTIMATE:  val->v.i |= EXECUTE_ON_POST_HOST_ESTIMATE;  break;
3642         case CONF_PRE_DLE_BACKUP:      val->v.i |= EXECUTE_ON_PRE_DLE_BACKUP;      break;
3643         case CONF_PRE_HOST_BACKUP:     val->v.i |= EXECUTE_ON_PRE_HOST_BACKUP;     break;
3644         case CONF_POST_DLE_BACKUP:     val->v.i |= EXECUTE_ON_POST_DLE_BACKUP;     break;
3645         case CONF_POST_HOST_BACKUP:    val->v.i |= EXECUTE_ON_POST_HOST_BACKUP;    break;
3646         case CONF_PRE_RECOVER:         val->v.i |= EXECUTE_ON_PRE_RECOVER;         break;
3647         case CONF_POST_RECOVER:        val->v.i |= EXECUTE_ON_POST_RECOVER;        break;
3648         case CONF_PRE_LEVEL_RECOVER:   val->v.i |= EXECUTE_ON_PRE_LEVEL_RECOVER;   break;
3649         case CONF_POST_LEVEL_RECOVER:  val->v.i |= EXECUTE_ON_POST_LEVEL_RECOVER;  break;
3650         case CONF_INTER_LEVEL_RECOVER: val->v.i |= EXECUTE_ON_INTER_LEVEL_RECOVER; break;
3651         default:
3652         conf_parserror(_("Execute-on expected"));
3653         }
3654         get_conftoken(CONF_ANY);
3655         if (tok != CONF_COMMA) {
3656             unget_conftoken();
3657             break;
3658         }
3659         get_conftoken(CONF_ANY);
3660     } while (1);
3661 }
3662
3663 static void
3664 read_execute_where(
3665     conf_var_t *np G_GNUC_UNUSED,
3666     val_t *val)
3667 {
3668     ckseen(&val->seen);
3669
3670     get_conftoken(CONF_ANY);
3671     switch(tok) {
3672     case CONF_CLIENT:      val->v.i = ES_CLIENT;   break;
3673     case CONF_SERVER:      val->v.i = ES_SERVER;   break;
3674     default:
3675         conf_parserror(_("CLIENT or SERVER expected"));
3676     }
3677 }
3678
3679 static void
3680 read_int_or_str(
3681     conf_var_t *np G_GNUC_UNUSED,
3682     val_t *val)
3683 {
3684     ckseen(&val->seen);
3685
3686     get_conftoken(CONF_ANY);
3687     switch(tok) {
3688     case CONF_INT:
3689         amfree(val->v.s);
3690         val->v.s = g_strdup_printf("%d", tokenval.v.i);
3691         break;
3692
3693     case CONF_SIZE:
3694         amfree(val->v.s);
3695         val->v.s = g_strdup_printf("%zu", tokenval.v.size);
3696         break;
3697
3698     case CONF_INT64:
3699         amfree(val->v.s);
3700         val->v.s = g_strdup_printf("%jd", (intmax_t)tokenval.v.int64);
3701         break;
3702
3703     case CONF_STRING:
3704         val->v.s = newstralloc(val->v.s, tokenval.v.s);
3705         break;
3706     default:
3707         conf_parserror(_("CLIENT or SERVER expected"));
3708     }
3709 }
3710
3711 static void
3712 read_autolabel(
3713     conf_var_t *np G_GNUC_UNUSED,
3714     val_t *val)
3715 {
3716     int data = 0;
3717     ckseen(&val->seen);
3718
3719     get_conftoken(CONF_ANY);
3720     if (tok == CONF_STRING) {
3721         data++;
3722         val->v.autolabel.template = newstralloc(val->v.autolabel.template,
3723                                                 tokenval.v.s);
3724         get_conftoken(CONF_ANY);
3725     }
3726     val->v.autolabel.autolabel = 0;
3727     while (tok != CONF_NL && tok != CONF_END) {
3728         data++;
3729         if (tok == CONF_ANY_VOLUME)
3730             val->v.autolabel.autolabel |= AL_OTHER_CONFIG | AL_NON_AMANDA |
3731                                           AL_VOLUME_ERROR | AL_EMPTY;
3732         else if (tok == CONF_OTHER_CONFIG)
3733             val->v.autolabel.autolabel |= AL_OTHER_CONFIG;
3734         else if (tok == CONF_NON_AMANDA)
3735             val->v.autolabel.autolabel |= AL_NON_AMANDA;
3736         else if (tok == CONF_VOLUME_ERROR)
3737             val->v.autolabel.autolabel |= AL_VOLUME_ERROR;
3738         else if (tok == CONF_EMPTY)
3739             val->v.autolabel.autolabel |= AL_EMPTY;
3740         else {
3741             conf_parserror(_("ANY, NEW-VOLUME, OTHER-CONFIG, NON-AMANDA, VOLUME-ERROR or EMPTY is expected"));
3742         }
3743         get_conftoken(CONF_ANY);
3744     }
3745     if (data == 0) {
3746         amfree(val->v.autolabel.template);
3747         val->v.autolabel.autolabel = 0;
3748     } else if (val->v.autolabel.autolabel == 0) {
3749         val->v.autolabel.autolabel = AL_VOLUME_ERROR | AL_EMPTY;
3750     }
3751 }
3752
3753 static void
3754 read_part_cache_type(
3755     conf_var_t *np G_GNUC_UNUSED,
3756     val_t *val)
3757 {
3758    part_cache_type_t part_cache_type;
3759
3760    ckseen(&val->seen);
3761
3762    get_conftoken(CONF_ANY);
3763    switch(tok) {
3764    case CONF_NONE:
3765      part_cache_type = PART_CACHE_TYPE_NONE;
3766      break;
3767
3768    case CONF_DISK:
3769      part_cache_type = PART_CACHE_TYPE_DISK;
3770      break;
3771
3772    case CONF_MEMORY:
3773      part_cache_type = PART_CACHE_TYPE_MEMORY;
3774      break;
3775
3776    default:
3777      conf_parserror(_("NONE, DISK or MEMORY expected"));
3778      part_cache_type = PART_CACHE_TYPE_NONE;
3779      break;
3780    }
3781
3782    val_t__part_cache_type(val) = (int)part_cache_type;
3783 }
3784
3785 static void
3786 read_recovery_limit(
3787     conf_var_t *np G_GNUC_UNUSED,
3788     val_t *val)
3789 {
3790     recovery_limit_t *rl = &val_t__recovery_limit(val);
3791     ckseen(&val->seen);
3792
3793     while (1) {
3794         get_conftoken(CONF_ANY);
3795         switch(tok) {
3796         case CONF_STRING:
3797             rl->match_pats = g_slist_append(rl->match_pats, g_strdup(tokenval.v.s));
3798             break;
3799         case CONF_SAME_HOST:
3800             rl->same_host = TRUE;
3801             break;
3802
3803         case CONF_NL:
3804         case CONF_END:
3805             return;
3806
3807         default:
3808             conf_parserror("SAME-HOST or a string expected");
3809             break;
3810         }
3811     }
3812 }
3813
3814 /* get_* functions */
3815
3816 /* these functions use precompiler conditionals to skip useless size checks
3817  * when casting from one type to another.  SIZEOF_GINT64 is pretty simple to
3818  * calculate; the others are calculated by configure. */
3819
3820 #define SIZEOF_GINT64 8
3821
3822 static time_t
3823 get_time(void)
3824 {
3825     time_t hhmm;
3826
3827     get_conftoken(CONF_ANY);
3828     switch(tok) {
3829     case CONF_INT:
3830 #if SIZEOF_TIME_T < SIZEOF_INT
3831         if ((gint64)tokenval.v.i >= (gint64)TIME_MAX)
3832             conf_parserror(_("value too large"));
3833 #endif
3834         hhmm = (time_t)tokenval.v.i;
3835         break;
3836
3837     case CONF_SIZE:
3838 #if SIZEOF_TIME_T < SIZEOF_SSIZE_T
3839         if ((gint64)tokenval.v.size >= (gint64)TIME_MAX)
3840             conf_parserror(_("value too large"));
3841 #endif
3842         hhmm = (time_t)tokenval.v.size;
3843         break;
3844
3845     case CONF_INT64:
3846 #if SIZEOF_TIME_T < SIZEOF_GINT64
3847         if ((gint64)tokenval.v.int64 >= (gint64)TIME_MAX)
3848             conf_parserror(_("value too large"));
3849 #endif
3850         hhmm = (time_t)tokenval.v.int64;
3851         break;
3852
3853     case CONF_AMINFINITY:
3854         hhmm = TIME_MAX;
3855         break;
3856
3857     default:
3858         conf_parserror(_("a time is expected"));
3859         hhmm = 0;
3860         break;
3861     }
3862     return hhmm;
3863 }
3864
3865 static int
3866 get_int(void)
3867 {
3868     int val;
3869     keytab_t *save_kt;
3870
3871     save_kt = keytable;
3872     keytable = numb_keytable;
3873
3874     get_conftoken(CONF_ANY);
3875     switch(tok) {
3876     case CONF_INT:
3877         val = tokenval.v.i;
3878         break;
3879
3880     case CONF_SIZE:
3881 #if SIZEOF_INT < SIZEOF_SSIZE_T
3882         if ((gint64)tokenval.v.size > (gint64)INT_MAX)
3883             conf_parserror(_("value too large"));
3884         if ((gint64)tokenval.v.size < (gint64)INT_MIN)
3885             conf_parserror(_("value too small"));
3886 #endif
3887         val = (int)tokenval.v.size;
3888         break;
3889
3890     case CONF_INT64:
3891 #if SIZEOF_INT < SIZEOF_GINT64
3892         if (tokenval.v.int64 > (gint64)INT_MAX)
3893             conf_parserror(_("value too large"));
3894         if (tokenval.v.int64 < (gint64)INT_MIN)
3895             conf_parserror(_("value too small"));
3896 #endif
3897         val = (int)tokenval.v.int64;
3898         break;
3899
3900     case CONF_AMINFINITY:
3901         val = INT_MAX;
3902         break;
3903
3904     default:
3905         conf_parserror(_("an integer is expected"));
3906         val = 0;
3907         break;
3908     }
3909
3910     /* get multiplier, if any */
3911     get_conftoken(CONF_ANY);
3912     switch(tok) {
3913     case CONF_NL:                       /* multiply by one */
3914     case CONF_END:
3915     case CONF_MULT1:
3916     case CONF_MULT1K:
3917         break;
3918
3919     case CONF_MULT7:
3920         if (val > (INT_MAX / 7))
3921             conf_parserror(_("value too large"));
3922         if (val < (INT_MIN / 7))
3923             conf_parserror(_("value too small"));
3924         val *= 7;
3925         break;
3926
3927     case CONF_MULT1M:
3928         if (val > (INT_MAX / 1024))
3929             conf_parserror(_("value too large"));
3930         if (val < (INT_MIN / 1024))
3931             conf_parserror(_("value too small"));
3932         val *= 1024;
3933         break;
3934
3935     case CONF_MULT1G:
3936         if (val > (INT_MAX / (1024 * 1024)))
3937             conf_parserror(_("value too large"));
3938         if (val < (INT_MIN / (1024 * 1024)))
3939             conf_parserror(_("value too small"));
3940         val *= 1024 * 1024;
3941         break;
3942
3943     case CONF_MULT1T:
3944         if (val > (INT_MAX / (1024 * 1024 * 1024)))
3945             conf_parserror(_("value too large"));
3946         if (val < (INT_MIN / (1024 * 1024 * 1024)))
3947             conf_parserror(_("value too small"));
3948         val *= 1024 * 1024 * 1024;
3949         break;
3950
3951     default:    /* it was not a multiplier */
3952         unget_conftoken();
3953         break;
3954     }
3955
3956     keytable = save_kt;
3957     return val;
3958 }
3959
3960 static ssize_t
3961 get_size(void)
3962 {
3963     ssize_t val;
3964     keytab_t *save_kt;
3965
3966     save_kt = keytable;
3967     keytable = numb_keytable;
3968
3969     get_conftoken(CONF_ANY);
3970
3971     switch(tok) {
3972     case CONF_SIZE:
3973         val = tokenval.v.size;
3974         break;
3975
3976     case CONF_INT:
3977 #if SIZEOF_SIZE_T < SIZEOF_INT
3978         if ((gint64)tokenval.v.i > (gint64)SSIZE_MAX)
3979             conf_parserror(_("value too large"));
3980         if ((gint64)tokenval.v.i < (gint64)SSIZE_MIN)
3981             conf_parserror(_("value too small"));
3982 #endif
3983         val = (ssize_t)tokenval.v.i;
3984         break;
3985
3986     case CONF_INT64:
3987 #if SIZEOF_SIZE_T < SIZEOF_GINT64
3988         if (tokenval.v.int64 > (gint64)SSIZE_MAX)
3989             conf_parserror(_("value too large"));
3990         if (tokenval.v.int64 < (gint64)SSIZE_MIN)
3991             conf_parserror(_("value too small"));
3992 #endif
3993         val = (ssize_t)tokenval.v.int64;
3994         break;
3995
3996     case CONF_AMINFINITY:
3997         val = (ssize_t)SSIZE_MAX;
3998         break;
3999
4000     default:
4001         conf_parserror(_("an integer is expected"));
4002         val = 0;
4003         break;
4004     }
4005
4006     /* get multiplier, if any */
4007     get_conftoken(CONF_ANY);
4008
4009     switch(tok) {
4010     case CONF_NL:                       /* multiply by one */
4011     case CONF_MULT1:
4012     case CONF_MULT1K:
4013         break;
4014
4015     case CONF_MULT7:
4016         if (val > (ssize_t)(SSIZE_MAX / 7))
4017             conf_parserror(_("value too large"));
4018         if (val < (ssize_t)(SSIZE_MIN / 7))
4019             conf_parserror(_("value too small"));
4020         val *= (ssize_t)7;
4021         break;
4022
4023     case CONF_MULT1M:
4024         if (val > (ssize_t)(SSIZE_MAX / (ssize_t)1024))
4025             conf_parserror(_("value too large"));
4026         if (val < (ssize_t)(SSIZE_MIN / (ssize_t)1024))
4027             conf_parserror(_("value too small"));
4028         val *= (ssize_t)1024;
4029         break;
4030
4031     case CONF_MULT1G:
4032         if (val > (ssize_t)(SSIZE_MAX / (1024 * 1024)))
4033             conf_parserror(_("value too large"));
4034         if (val < (ssize_t)(SSIZE_MIN / (1024 * 1024)))
4035             conf_parserror(_("value too small"));
4036         val *= (ssize_t)(1024 * 1024);
4037         break;
4038
4039     case CONF_MULT1T:
4040         if (val > (INT_MAX / (1024 * 1024 * 1024)))
4041             conf_parserror(_("value too large"));
4042         if (val < (INT_MIN / (1024 * 1024 * 1024)))
4043             conf_parserror(_("value too small"));
4044         val *= 1024 * 1024 * 1024;
4045         break;
4046
4047     default:    /* it was not a multiplier */
4048         unget_conftoken();
4049         break;
4050     }
4051
4052     keytable = save_kt;
4053     return val;
4054 }
4055
4056 static ssize_t
4057 get_size_byte(void)
4058 {
4059     ssize_t val;
4060     keytab_t *save_kt;
4061
4062     save_kt = keytable;
4063     keytable = numb_keytable;
4064
4065     get_conftoken(CONF_ANY);
4066
4067     switch(tok) {
4068     case CONF_SIZE:
4069         val = tokenval.v.size;
4070         break;
4071
4072     case CONF_INT:
4073 #if SIZEOF_SIZE_T < SIZEOF_INT
4074         if ((gint64)tokenval.v.i > (gint64)SSIZE_MAX)
4075             conf_parserror(_("value too large"));
4076         if ((gint64)tokenval.v.i < (gint64)SSIZE_MIN)
4077             conf_parserror(_("value too small"));
4078 #endif
4079         val = (ssize_t)tokenval.v.i;
4080         break;
4081
4082     case CONF_INT64:
4083 #if SIZEOF_SIZE_T < SIZEOF_GINT64
4084         if (tokenval.v.int64 > (gint64)SSIZE_MAX)
4085             conf_parserror(_("value too large"));
4086         if (tokenval.v.int64 < (gint64)SSIZE_MIN)
4087             conf_parserror(_("value too small"));
4088 #endif
4089         val = (ssize_t)tokenval.v.int64;
4090         break;
4091
4092     case CONF_AMINFINITY:
4093         val = (ssize_t)SSIZE_MAX;
4094         break;
4095
4096     default:
4097         conf_parserror(_("an integer is expected"));
4098         val = 0;
4099         break;
4100     }
4101
4102     /* get multiplier, if any */
4103     get_conftoken(CONF_ANY);
4104
4105     switch(tok) {
4106     case CONF_NL:                       /* multiply by one */
4107     case CONF_MULT1:
4108         break;
4109     case CONF_MULT1K:
4110         if (val > (ssize_t)(SSIZE_MAX / (ssize_t)1024))
4111             conf_parserror(_("value too large"));
4112         if (val < (ssize_t)(SSIZE_MIN / (ssize_t)1024))
4113             conf_parserror(_("value too small"));
4114         val *= (ssize_t)1024;
4115
4116     case CONF_MULT7:
4117         if (val > (ssize_t)(SSIZE_MAX / 7))
4118             conf_parserror(_("value too large"));
4119         if (val < (ssize_t)(SSIZE_MIN / 7))
4120             conf_parserror(_("value too small"));
4121         val *= (ssize_t)7;
4122         break;
4123
4124     case CONF_MULT1M:
4125         if (val > (ssize_t)(SSIZE_MAX / (ssize_t)1024 * 1024))
4126             conf_parserror(_("value too large"));
4127         if (val < (ssize_t)(SSIZE_MIN / (ssize_t)1024 * 1024))
4128             conf_parserror(_("value too small"));
4129         val *= (ssize_t)(1024 * 1024);
4130         break;
4131
4132     case CONF_MULT1G:
4133         if (val > (ssize_t)(SSIZE_MAX / (1024 * 1024 * 1024)))
4134             conf_parserror(_("value too large"));
4135         if (val < (ssize_t)(SSIZE_MIN / (1024 * 1024 * 1024)))
4136             conf_parserror(_("value too small"));
4137         val *= (ssize_t)(1024 * 1024 * 1024);
4138         break;
4139
4140     case CONF_MULT1T:
4141         conf_parserror(_("value too large"));
4142         break;
4143
4144     default:    /* it was not a multiplier */
4145         unget_conftoken();
4146         break;
4147     }
4148
4149     keytable = save_kt;
4150     return val;
4151 }
4152
4153 static gint64
4154 get_int64(void)
4155 {
4156     gint64 val;
4157     keytab_t *save_kt;
4158
4159     save_kt = keytable;
4160     keytable = numb_keytable;
4161
4162     get_conftoken(CONF_ANY);
4163
4164     switch(tok) {
4165     case CONF_INT:
4166         val = (gint64)tokenval.v.i;
4167         break;
4168
4169     case CONF_SIZE:
4170         val = (gint64)tokenval.v.size;
4171         break;
4172
4173     case CONF_INT64:
4174         val = tokenval.v.int64;
4175         break;
4176
4177     case CONF_AMINFINITY:
4178         val = G_MAXINT64;
4179         break;
4180
4181     default:
4182         conf_parserror(_("an integer is expected"));
4183         val = 0;
4184         break;
4185     }
4186
4187     /* get multiplier, if any */
4188     get_conftoken(CONF_ANY);
4189
4190     switch(tok) {
4191     case CONF_NL:                       /* multiply by one */
4192     case CONF_MULT1:
4193     case CONF_MULT1K:
4194         break;
4195
4196     case CONF_MULT7:
4197         if (val > G_MAXINT64/7 || val < ((gint64)G_MININT64)/7)
4198             conf_parserror(_("value too large"));
4199         val *= 7;
4200         break;
4201
4202     case CONF_MULT1M:
4203         if (val > G_MAXINT64/1024 || val < ((gint64)G_MININT64)/1024)
4204             conf_parserror(_("value too large"));
4205         val *= 1024;
4206         break;
4207
4208     case CONF_MULT1G:
4209         if (val > G_MAXINT64/(1024*1024) || val < ((gint64)G_MININT64)/(1024*1024))
4210             conf_parserror(_("value too large"));
4211         val *= 1024*1024;
4212         break;
4213
4214     case CONF_MULT1T:
4215         if (val > G_MAXINT64/(1024*1024*1024) || val < ((gint64)G_MININT64)/(1024*1024*1024))
4216             conf_parserror(_("value too large"));
4217         val *= 1024*1024*1024;
4218         break;
4219
4220     default:    /* it was not a multiplier */
4221         unget_conftoken();
4222         break;
4223     }
4224
4225     keytable = save_kt;
4226
4227     return val;
4228 }
4229
4230 static int
4231 get_bool(void)
4232 {
4233     int val;
4234     keytab_t *save_kt;
4235
4236     save_kt = keytable;
4237     keytable = bool_keytable;
4238
4239     get_conftoken(CONF_ANY);
4240
4241     switch(tok) {
4242     case CONF_INT:
4243         if (tokenval.v.i != 0)
4244             val = 1;
4245         else
4246             val = 0;
4247         break;
4248
4249     case CONF_SIZE:
4250         if (tokenval.v.size != (size_t)0)
4251             val = 1;
4252         else
4253             val = 0;
4254         break;
4255
4256     case CONF_INT64:
4257         if (tokenval.v.int64 != (gint64)0)
4258             val = 1;
4259         else
4260             val = 0;
4261         break;
4262
4263     case CONF_ATRUE:
4264         val = 1;
4265         break;
4266
4267     case CONF_AFALSE:
4268         val = 0;
4269         break;
4270
4271     case CONF_NL:
4272         unget_conftoken();
4273         val = 2; /* no argument - most likely TRUE */
4274         break;
4275     default:
4276         unget_conftoken();
4277         val = 3; /* a bad argument - most likely TRUE */
4278         conf_parserror(_("YES, NO, TRUE, FALSE, ON, OFF, 0, 1 expected"));
4279         break;
4280     }
4281
4282     keytable = save_kt;
4283     return val;
4284 }
4285
4286 void
4287 ckseen(
4288     seen_t *seen)
4289 {
4290     if (seen->linenum && !allow_overwrites && current_line_num != -2) {
4291         conf_parserror(_("duplicate parameter; previous definition %s:%d"),
4292                 seen->filename, seen->linenum);
4293     }
4294     seen->filename = current_filename;
4295     seen->linenum = current_line_num;
4296 }
4297
4298 /* Validation functions */
4299
4300 static void
4301 validate_nonnegative(
4302     struct conf_var_s *np,
4303     val_t        *val)
4304 {
4305     switch(val->type) {
4306     case CONFTYPE_INT:
4307         if(val_t__int(val) < 0)
4308             conf_parserror(_("%s must be nonnegative"), get_token_name(np->token));
4309         break;
4310     case CONFTYPE_INT64:
4311         if(val_t__int64(val) < 0)
4312             conf_parserror(_("%s must be nonnegative"), get_token_name(np->token));
4313         break;
4314     case CONFTYPE_SIZE:
4315         if(val_t__size(val) < 0)
4316             conf_parserror(_("%s must be positive"), get_token_name(np->token));
4317         break;
4318     default:
4319         conf_parserror(_("validate_nonnegative invalid type %d\n"), val->type);
4320     }
4321 }
4322
4323 static void
4324 validate_non_zero(
4325     struct conf_var_s *np,
4326     val_t        *val)
4327 {
4328     switch(val->type) {
4329     case CONFTYPE_INT:
4330         if(val_t__int(val) == 0)
4331             conf_parserror(_("%s must not be 0"), get_token_name(np->token));
4332         break;
4333     case CONFTYPE_INT64:
4334         if(val_t__int64(val) == 0)
4335             conf_parserror(_("%s must not be 0"), get_token_name(np->token));
4336         break;
4337     case CONFTYPE_TIME:
4338         if(val_t__time(val) == 0)
4339             conf_parserror(_("%s must not be 0"), get_token_name(np->token));
4340         break;
4341     case CONFTYPE_SIZE:
4342         if(val_t__size(val) == 0)
4343             conf_parserror(_("%s must not be 0"), get_token_name(np->token));
4344         break;
4345     default:
4346         conf_parserror(_("validate_non_zero invalid type %d\n"), val->type);
4347     }
4348 }
4349
4350 static void
4351 validate_positive(
4352     struct conf_var_s *np,
4353     val_t        *val)
4354 {
4355     switch(val->type) {
4356     case CONFTYPE_INT:
4357         if(val_t__int(val) < 1)
4358             conf_parserror(_("%s must be positive"), get_token_name(np->token));
4359         break;
4360     case CONFTYPE_INT64:
4361         if(val_t__int64(val) < 1)
4362             conf_parserror(_("%s must be positive"), get_token_name(np->token));
4363         break;
4364     case CONFTYPE_TIME:
4365         if(val_t__time(val) < 1)
4366             conf_parserror(_("%s must be positive"), get_token_name(np->token));
4367         break;
4368     case CONFTYPE_SIZE:
4369         if(val_t__size(val) < 1)
4370             conf_parserror(_("%s must be positive"), get_token_name(np->token));
4371         break;
4372     default:
4373         conf_parserror(_("validate_positive invalid type %d\n"), val->type);
4374     }
4375 }
4376
4377 static void
4378 validate_runspercycle(
4379     struct conf_var_s *np G_GNUC_UNUSED,
4380     val_t        *val)
4381 {
4382     if(val_t__int(val) < -1)
4383         conf_parserror(_("runspercycle must be >= -1"));
4384 }
4385
4386 static void
4387 validate_bumppercent(
4388     struct conf_var_s *np G_GNUC_UNUSED,
4389     val_t        *val)
4390 {
4391     if(val_t__int(val) < 0 || val_t__int(val) > 100)
4392         conf_parserror(_("bumppercent must be between 0 and 100"));
4393 }
4394
4395 static void
4396 validate_inparallel(
4397     struct conf_var_s *np G_GNUC_UNUSED,
4398     val_t        *val)
4399 {
4400     if(val_t__int(val) < 1 || val_t__int(val) >MAX_DUMPERS)
4401         conf_parserror(_("inparallel must be between 1 and MAX_DUMPERS (%d)"),
4402                        MAX_DUMPERS);
4403 }
4404
4405 static void
4406 validate_bumpmult(
4407     struct conf_var_s *np G_GNUC_UNUSED,
4408     val_t        *val)
4409 {
4410     if(val_t__real(val) < 0.999) {
4411         conf_parserror(_("bumpmult must one or more"));
4412     }
4413 }
4414
4415 static void
4416 validate_displayunit(
4417     struct conf_var_s *np G_GNUC_UNUSED,
4418     val_t        *val G_GNUC_UNUSED)
4419 {
4420     char *s = val_t__str(val);
4421     if (strlen(s) == 1) {
4422         switch (s[0]) {
4423             case 'K':
4424             case 'M':
4425             case 'G':
4426             case 'T':
4427                 return; /* all good */
4428
4429             /* lower-case values should get folded to upper case */
4430             case 'k':
4431             case 'm':
4432             case 'g':
4433             case 't':
4434                 s[0] = toupper(s[0]);
4435                 return;
4436
4437             default:    /* bad */
4438                 break;
4439         }
4440     }
4441     conf_parserror(_("displayunit must be k,m,g or t."));
4442 }
4443
4444 static void
4445 validate_reserve(
4446     struct conf_var_s *np G_GNUC_UNUSED,
4447     val_t        *val)
4448 {
4449     if(val_t__int(val) < 0 || val_t__int(val) > 100)
4450         conf_parserror(_("reserve must be between 0 and 100"));
4451 }
4452
4453 static void
4454 validate_use(
4455     struct conf_var_s *np G_GNUC_UNUSED,
4456     val_t        *val)
4457 {
4458     val_t__int64(val) = am_floor(val_t__int64(val), DISK_BLOCK_KB);
4459 }
4460
4461 static void
4462 validate_chunksize(
4463     struct conf_var_s *np G_GNUC_UNUSED,
4464     val_t        *val)
4465 {
4466     /* NOTE: this function modifies the target value (rounding) */
4467     if(val_t__int64(val) == 0) {
4468         val_t__int64(val) = ((G_MAXINT64 / 1024) - (2 * DISK_BLOCK_KB));
4469     }
4470     else if(val_t__int64(val) < 0) {
4471         conf_parserror(_("Negative chunksize (%lld) is no longer supported"), (long long)val_t__int64(val));
4472     }
4473     val_t__int64(val) = am_floor(val_t__int64(val), (gint64)DISK_BLOCK_KB);
4474     if (val_t__int64(val) < 2*DISK_BLOCK_KB) {
4475         conf_parserror("chunksize must be at least %dkb", 2*DISK_BLOCK_KB);
4476     }
4477 }
4478
4479 static void
4480 validate_blocksize(
4481     struct conf_var_s *np G_GNUC_UNUSED,
4482     val_t        *val)
4483 {
4484     if(val_t__size(val) < DISK_BLOCK_KB) {
4485         conf_parserror(_("Tape blocksize must be at least %d KBytes"),
4486                   DISK_BLOCK_KB);
4487     }
4488 }
4489
4490 static void
4491 validate_debug(
4492     struct conf_var_s *np G_GNUC_UNUSED,
4493     val_t        *val)
4494 {
4495     if(val_t__int(val) < 0 || val_t__int(val) > 9) {
4496         conf_parserror(_("Debug must be between 0 and 9"));
4497     }
4498 }
4499
4500 static void
4501 validate_port_range(
4502     val_t        *val,
4503     int          smallest,
4504     int          largest)
4505 {
4506     int i;
4507     /* check both values are in range */
4508     for (i = 0; i < 2; i++) {
4509         if(val_t__intrange(val)[0] < smallest || val_t__intrange(val)[0] > largest) {
4510             conf_parserror(_("portrange must be in the range %d to %d, inclusive"), smallest, largest);
4511         }
4512      }
4513
4514     /* and check they're in the right order and not equal */
4515     if (val_t__intrange(val)[0] > val_t__intrange(val)[1]) {
4516         conf_parserror(_("portranges must be in order from low to high"));
4517     }
4518 }
4519
4520 static void
4521 validate_reserved_port_range(
4522     struct conf_var_s *np G_GNUC_UNUSED,
4523     val_t        *val)
4524 {
4525     validate_port_range(val, 1, IPPORT_RESERVED-1);
4526 }
4527
4528 static void
4529 validate_unreserved_port_range(
4530     struct conf_var_s *np G_GNUC_UNUSED,
4531     val_t        *val)
4532 {
4533     validate_port_range(val, IPPORT_RESERVED, 65535);
4534 }
4535
4536 /*
4537  * Initialization Implementation
4538  */
4539
4540 cfgerr_level_t
4541 config_init(
4542     config_init_flags flags,
4543     char *arg_config_name)
4544 {
4545     if (!(flags & CONFIG_INIT_OVERLAY)) {
4546         /* Clear out anything that's already in there */
4547         config_uninit();
4548
4549         /* and set everything to default values */
4550         init_defaults();
4551
4552         allow_overwrites = FALSE;
4553     } else {
4554         if (!config_initialized) {
4555             error(_("Attempt to overlay configuration with no existing configuration"));
4556             /* NOTREACHED */
4557         }
4558
4559         allow_overwrites = TRUE;
4560     }
4561
4562     /* store away our client-ness for later reference */
4563     config_client = flags & CONFIG_INIT_CLIENT;
4564
4565     /* if we're using an explicit name, but the name is '.', then we're using the
4566      * current directory */
4567     if ((flags & CONFIG_INIT_EXPLICIT_NAME) && arg_config_name) {
4568         if (0 == strcmp(arg_config_name, "."))
4569             flags = (flags & (~CONFIG_INIT_EXPLICIT_NAME)) | CONFIG_INIT_USE_CWD;
4570     }
4571
4572     if ((flags & CONFIG_INIT_EXPLICIT_NAME) && arg_config_name) {
4573         config_name = newstralloc(config_name, arg_config_name);
4574         config_dir = newvstralloc(config_dir, CONFIG_DIR, "/", arg_config_name, NULL);
4575     } else if (flags & CONFIG_INIT_USE_CWD) {
4576         char * cwd;
4577         
4578         cwd = get_original_cwd();
4579         if (!cwd) {
4580             /* (this isn't a config error, so it's always fatal) */
4581             error(_("Cannot determine current working directory"));
4582             /* NOTREACHED */
4583         }
4584
4585         config_dir = stralloc2(cwd, "/");
4586         if ((config_name = strrchr(cwd, '/')) != NULL) {
4587             config_name = stralloc(config_name + 1);
4588         }
4589
4590         amfree(cwd);
4591     } else if (flags & CONFIG_INIT_CLIENT) {
4592         amfree(config_name);
4593         config_dir = newstralloc(config_dir, CONFIG_DIR);
4594     } else {
4595         /* ok, then, we won't read anything (for e.g., amrestore) */
4596         amfree(config_name);
4597         amfree(config_dir);
4598     }
4599
4600     /* setup for apply_config_overrides */
4601     if (flags & CONFIG_INIT_CLIENT) {
4602         keytable = client_keytab;
4603         parsetable = client_var;
4604     } else {
4605         keytable = server_keytab;
4606         parsetable = server_var;
4607     }
4608
4609     if (config_overrides) {
4610         int i;
4611         for (i = 0; i < config_overrides->n_used; i++) {
4612             config_overrides->ovr[i].applied = FALSE;
4613         }
4614     }
4615
4616     /* apply config overrides to default setting */
4617     apply_config_overrides(config_overrides, NULL);
4618
4619     /* If we have a config_dir, we can try reading something */
4620     if (config_dir) {
4621         if (flags & CONFIG_INIT_CLIENT) {
4622             config_filename = newvstralloc(config_filename, config_dir, "/amanda-client.conf", NULL);
4623         } else {
4624             config_filename = newvstralloc(config_filename, config_dir, "/amanda.conf", NULL);
4625         }
4626
4627         read_conffile(config_filename,
4628                 flags & CONFIG_INIT_CLIENT,
4629                 flags & CONFIG_INIT_CLIENT);
4630     } else {
4631         amfree(config_filename);
4632     }
4633
4634     /* apply config overrides to default setting */
4635     apply_config_overrides(config_overrides, NULL);
4636
4637     if (config_overrides) {
4638         int i;
4639         for (i = 0; i < config_overrides->n_used; i++) {
4640             if (config_overrides->ovr[i].applied == FALSE) {
4641                 conf_parserror(_("unknown parameter '%s'"),
4642                                config_overrides->ovr[i].key);
4643             }
4644         }
4645     }
4646
4647     update_derived_values(flags & CONFIG_INIT_CLIENT);
4648
4649     return cfgerr_level;
4650 }
4651
4652 void
4653 config_uninit(void)
4654 {
4655     GSList           *hp;
4656     holdingdisk_t    *hd;
4657     dumptype_t       *dp, *dpnext;
4658     tapetype_t       *tp, *tpnext;
4659     interface_t      *ip, *ipnext;
4660     application_t *ap, *apnext;
4661     pp_script_t   *pp, *ppnext;
4662     device_config_t *dc, *dcnext;
4663     changer_config_t *cc, *ccnext;
4664     int               i;
4665
4666     if (!config_initialized) return;
4667
4668     for(hp=holdinglist; hp != NULL; hp = hp->next) {
4669         hd = hp->data;
4670         amfree(hd->name);
4671         for(i=0; i<HOLDING_HOLDING; i++) {
4672            free_val_t(&hd->value[i]);
4673         }
4674     }
4675     slist_free_full(holdinglist, g_free);
4676     holdinglist = NULL;
4677
4678     for(dp=dumplist; dp != NULL; dp = dpnext) {
4679         amfree(dp->name);
4680         for(i=0; i<DUMPTYPE_DUMPTYPE; i++) {
4681            free_val_t(&dp->value[i]);
4682         }
4683         dpnext = dp->next;
4684         amfree(dp);
4685     }
4686     dumplist = NULL;
4687
4688     for(tp=tapelist; tp != NULL; tp = tpnext) {
4689         amfree(tp->name);
4690         for(i=0; i<TAPETYPE_TAPETYPE; i++) {
4691            free_val_t(&tp->value[i]);
4692         }
4693         tpnext = tp->next;
4694         amfree(tp);
4695     }
4696     tapelist = NULL;
4697
4698     for(ip=interface_list; ip != NULL; ip = ipnext) {
4699         amfree(ip->name);
4700         for(i=0; i<INTER_INTER; i++) {
4701            free_val_t(&ip->value[i]);
4702         }
4703         ipnext = ip->next;
4704         amfree(ip);
4705     }
4706     interface_list = NULL;
4707
4708     for(ap=application_list; ap != NULL; ap = apnext) {
4709         amfree(ap->name);
4710         for(i=0; i<APPLICATION_APPLICATION; i++) {
4711            free_val_t(&ap->value[i]);
4712         }
4713         apnext = ap->next;
4714         amfree(ap);
4715     }
4716     application_list = NULL;
4717
4718     for(pp=pp_script_list; pp != NULL; pp = ppnext) {
4719         amfree(pp->name);
4720         for(i=0; i<PP_SCRIPT_PP_SCRIPT; i++) {
4721            free_val_t(&pp->value[i]);
4722         }
4723         ppnext = pp->next;
4724         amfree(pp);
4725     }
4726     pp_script_list = NULL;
4727
4728     for(dc=device_config_list; dc != NULL; dc = dcnext) {
4729         amfree(dc->name);
4730         for(i=0; i<DEVICE_CONFIG_DEVICE_CONFIG; i++) {
4731            free_val_t(&dc->value[i]);
4732         }
4733         dcnext = dc->next;
4734         amfree(dc);
4735     }
4736     device_config_list = NULL;
4737
4738     for(cc=changer_config_list; cc != NULL; cc = ccnext) {
4739         amfree(cc->name);
4740         for(i=0; i<CHANGER_CONFIG_CHANGER_CONFIG; i++) {
4741            free_val_t(&cc->value[i]);
4742         }
4743         ccnext = cc->next;
4744         amfree(cc);
4745     }
4746
4747     changer_config_list = NULL;
4748
4749     for(i=0; i<CNF_CNF; i++)
4750         free_val_t(&conf_data[i]);
4751
4752     if (config_overrides) {
4753         free_config_overrides(config_overrides);
4754         config_overrides = NULL;
4755     }
4756
4757     amfree(config_name);
4758     amfree(config_dir);
4759     amfree(config_filename);
4760
4761     slist_free_full(seen_filenames, g_free);
4762     seen_filenames = NULL;
4763
4764     config_client = FALSE;
4765
4766     config_clear_errors();
4767     config_initialized = FALSE;
4768 }
4769
4770 static void
4771 init_defaults(
4772     void)
4773 {
4774     assert(!config_initialized);
4775
4776     /* defaults for exported variables */
4777     conf_init_str(&conf_data[CNF_ORG], DEFAULT_CONFIG);
4778     conf_init_str(&conf_data[CNF_CONF], DEFAULT_CONFIG);
4779     conf_init_str(&conf_data[CNF_INDEX_SERVER], DEFAULT_SERVER);
4780     conf_init_str(&conf_data[CNF_TAPE_SERVER], DEFAULT_TAPE_SERVER);
4781     conf_init_str(&conf_data[CNF_AUTH], "bsd");
4782     conf_init_str(&conf_data[CNF_SSH_KEYS], "");
4783     conf_init_str(&conf_data[CNF_AMANDAD_PATH], "");
4784     conf_init_str(&conf_data[CNF_CLIENT_USERNAME], "");
4785     conf_init_str(&conf_data[CNF_CLIENT_PORT], "");
4786     conf_init_str(&conf_data[CNF_GNUTAR_LIST_DIR], GNUTAR_LISTED_INCREMENTAL_DIR);
4787     conf_init_str(&conf_data[CNF_AMANDATES], DEFAULT_AMANDATES_FILE);
4788     conf_init_str(&conf_data[CNF_MAILTO], "");
4789     conf_init_str(&conf_data[CNF_DUMPUSER], CLIENT_LOGIN);
4790     conf_init_str(&conf_data[CNF_TAPEDEV], DEFAULT_TAPE_DEVICE);
4791     conf_init_proplist(&conf_data[CNF_DEVICE_PROPERTY]);
4792     conf_init_proplist(&conf_data[CNF_PROPERTY]);
4793     conf_init_str(&conf_data[CNF_CHANGERDEV], NULL);
4794     conf_init_str(&conf_data[CNF_CHANGERFILE]             , "changer");
4795     conf_init_str   (&conf_data[CNF_LABELSTR]             , ".*");
4796     conf_init_str   (&conf_data[CNF_TAPELIST]             , "tapelist");
4797     conf_init_str   (&conf_data[CNF_DISKFILE]             , "disklist");
4798     conf_init_str   (&conf_data[CNF_INFOFILE]             , "/usr/adm/amanda/curinfo");
4799     conf_init_str   (&conf_data[CNF_LOGDIR]               , "/usr/adm/amanda");
4800     conf_init_str   (&conf_data[CNF_INDEXDIR]             , "/usr/adm/amanda/index");
4801     conf_init_ident    (&conf_data[CNF_TAPETYPE]             , "DEFAULT_TAPE");
4802     conf_init_identlist(&conf_data[CNF_HOLDINGDISK]          , NULL);
4803     conf_init_int      (&conf_data[CNF_DUMPCYCLE]            , 10);
4804     conf_init_int      (&conf_data[CNF_RUNSPERCYCLE]         , 0);
4805     conf_init_int      (&conf_data[CNF_TAPECYCLE]            , 15);
4806     conf_init_int      (&conf_data[CNF_NETUSAGE]             , 8000);
4807     conf_init_int      (&conf_data[CNF_INPARALLEL]           , 10);
4808     conf_init_str   (&conf_data[CNF_DUMPORDER]            , "ttt");
4809     conf_init_int      (&conf_data[CNF_BUMPPERCENT]          , 0);
4810     conf_init_int64    (&conf_data[CNF_BUMPSIZE]             , (gint64)10*1024);
4811     conf_init_real     (&conf_data[CNF_BUMPMULT]             , 1.5);
4812     conf_init_int      (&conf_data[CNF_BUMPDAYS]             , 2);
4813     conf_init_str   (&conf_data[CNF_TPCHANGER]            , "");
4814     conf_init_int      (&conf_data[CNF_RUNTAPES]             , 1);
4815     conf_init_int      (&conf_data[CNF_MAXDUMPS]             , 1);
4816     conf_init_int      (&conf_data[CNF_ETIMEOUT]             , 300);
4817     conf_init_int      (&conf_data[CNF_DTIMEOUT]             , 1800);
4818     conf_init_int      (&conf_data[CNF_CTIMEOUT]             , 30);
4819     conf_init_size     (&conf_data[CNF_DEVICE_OUTPUT_BUFFER_SIZE], 40*32768);
4820     conf_init_str   (&conf_data[CNF_PRINTER]              , "");
4821     conf_init_str   (&conf_data[CNF_MAILER]               , DEFAULT_MAILER);
4822     conf_init_bool     (&conf_data[CNF_AUTOFLUSH]            , 0);
4823     conf_init_int      (&conf_data[CNF_RESERVE]              , 100);
4824     conf_init_int64    (&conf_data[CNF_MAXDUMPSIZE]          , (gint64)-1);
4825     conf_init_str   (&conf_data[CNF_COLUMNSPEC]           , "");
4826     conf_init_bool     (&conf_data[CNF_AMRECOVER_DO_FSF]     , 1);
4827     conf_init_str   (&conf_data[CNF_AMRECOVER_CHANGER]    , "");
4828     conf_init_bool     (&conf_data[CNF_AMRECOVER_CHECK_LABEL], 1);
4829     conf_init_taperalgo(&conf_data[CNF_TAPERALGO]            , 0);
4830     conf_init_int      (&conf_data[CNF_TAPER_PARALLEL_WRITE]     , 1);
4831     conf_init_int      (&conf_data[CNF_FLUSH_THRESHOLD_DUMPED]   , 0);
4832     conf_init_int      (&conf_data[CNF_FLUSH_THRESHOLD_SCHEDULED], 0);
4833     conf_init_int      (&conf_data[CNF_TAPERFLUSH]               , 0);
4834     conf_init_str   (&conf_data[CNF_DISPLAYUNIT]          , "k");
4835     conf_init_str   (&conf_data[CNF_KRB5KEYTAB]           , "/.amanda-v5-keytab");
4836     conf_init_str   (&conf_data[CNF_KRB5PRINCIPAL]        , "service/amanda");
4837     conf_init_str   (&conf_data[CNF_LABEL_NEW_TAPES]      , "");
4838     conf_init_bool     (&conf_data[CNF_USETIMESTAMPS]        , 1);
4839     conf_init_int      (&conf_data[CNF_CONNECT_TRIES]        , 3);
4840     conf_init_int      (&conf_data[CNF_REP_TRIES]            , 5);
4841     conf_init_int      (&conf_data[CNF_REQ_TRIES]            , 3);
4842     conf_init_int      (&conf_data[CNF_DEBUG_DAYS]           , AMANDA_DEBUG_DAYS);
4843     conf_init_int      (&conf_data[CNF_DEBUG_AMANDAD]        , 0);
4844     conf_init_int      (&conf_data[CNF_DEBUG_RECOVERY]       , 1);
4845     conf_init_int      (&conf_data[CNF_DEBUG_AMIDXTAPED]     , 0);
4846     conf_init_int      (&conf_data[CNF_DEBUG_AMINDEXD]       , 0);
4847     conf_init_int      (&conf_data[CNF_DEBUG_AMRECOVER]      , 0);
4848     conf_init_int      (&conf_data[CNF_DEBUG_AUTH]           , 0);
4849     conf_init_int      (&conf_data[CNF_DEBUG_EVENT]          , 0);
4850     conf_init_int      (&conf_data[CNF_DEBUG_HOLDING]        , 0);
4851     conf_init_int      (&conf_data[CNF_DEBUG_PROTOCOL]       , 0);
4852     conf_init_int      (&conf_data[CNF_DEBUG_PLANNER]        , 0);
4853     conf_init_int      (&conf_data[CNF_DEBUG_DRIVER]         , 0);
4854     conf_init_int      (&conf_data[CNF_DEBUG_DUMPER]         , 0);
4855     conf_init_int      (&conf_data[CNF_DEBUG_CHUNKER]        , 0);
4856     conf_init_int      (&conf_data[CNF_DEBUG_TAPER]          , 0);
4857     conf_init_int      (&conf_data[CNF_DEBUG_SELFCHECK]      , 0);
4858     conf_init_int      (&conf_data[CNF_DEBUG_SENDSIZE]       , 0);
4859     conf_init_int      (&conf_data[CNF_DEBUG_SENDBACKUP]     , 0);
4860 #ifdef UDPPORTRANGE
4861     conf_init_intrange (&conf_data[CNF_RESERVED_UDP_PORT]    , UDPPORTRANGE);
4862 #else
4863     conf_init_intrange (&conf_data[CNF_RESERVED_UDP_PORT]    , 512, IPPORT_RESERVED-1);
4864 #endif
4865 #ifdef LOW_TCPPORTRANGE
4866     conf_init_intrange (&conf_data[CNF_RESERVED_TCP_PORT]    , LOW_TCPPORTRANGE);
4867 #else
4868     conf_init_intrange (&conf_data[CNF_RESERVED_TCP_PORT]    , 512, IPPORT_RESERVED-1);
4869 #endif
4870 #ifdef TCPPORTRANGE
4871     conf_init_intrange (&conf_data[CNF_UNRESERVED_TCP_PORT]  , TCPPORTRANGE);
4872 #else
4873     conf_init_intrange (&conf_data[CNF_UNRESERVED_TCP_PORT]  , IPPORT_RESERVED, 65535);
4874 #endif
4875     conf_init_send_amreport (&conf_data[CNF_SEND_AMREPORT_ON], SEND_AMREPORT_ALL);
4876     conf_init_autolabel(&conf_data[CNF_AUTOLABEL]);
4877     conf_init_recovery_limit(&conf_data[CNF_RECOVERY_LIMIT]);
4878
4879     /* reset internal variables */
4880     config_clear_errors();
4881     cfgerr_level = CFGERR_OK;
4882     allow_overwrites = 0;
4883     token_pushed = 0;
4884
4885     /* create some predefined dumptypes for backwards compatability */
4886     init_dumptype_defaults();
4887     dpcur.name = stralloc("NO-COMPRESS");
4888     dpcur.seen.linenum = -1;
4889     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
4890     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_NONE;
4891     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]).linenum = -1;
4892     save_dumptype();
4893
4894     init_dumptype_defaults();
4895     dpcur.name = stralloc("COMPRESS-FAST");
4896     dpcur.seen.linenum = -1;
4897     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
4898     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_FAST;
4899     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]).linenum = -1;
4900     save_dumptype();
4901
4902     init_dumptype_defaults();
4903     dpcur.name = stralloc("COMPRESS-BEST");
4904     dpcur.seen.linenum = -1;
4905     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
4906     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_BEST;
4907     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]).linenum = -1;
4908     save_dumptype();
4909
4910     init_dumptype_defaults();
4911     dpcur.name = stralloc("COMPRESS-CUST");
4912     dpcur.seen.linenum = -1;
4913     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
4914     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_CUST;
4915     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]).linenum = -1;
4916     save_dumptype();
4917
4918     init_dumptype_defaults();
4919     dpcur.name = stralloc("SRVCOMPRESS");
4920     dpcur.seen.linenum = -1;
4921     free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]);
4922     val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_SERVER_FAST;
4923     val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]).linenum = -1;
4924     save_dumptype();
4925
4926     init_dumptype_defaults();
4927     dpcur.name = stralloc("BSD-AUTH");
4928     dpcur.seen.linenum = -1;
4929     free_val_t(&dpcur.value[DUMPTYPE_AUTH]);
4930     val_t__str(&dpcur.value[DUMPTYPE_AUTH]) = stralloc("BSD");
4931     val_t__seen(&dpcur.value[DUMPTYPE_AUTH]).linenum = -1;
4932     save_dumptype();
4933
4934     init_dumptype_defaults();
4935     dpcur.name = stralloc("NO-RECORD");
4936     dpcur.seen.linenum = -1;
4937     free_val_t(&dpcur.value[DUMPTYPE_RECORD]);
4938     val_t__int(&dpcur.value[DUMPTYPE_RECORD]) = 0;
4939     val_t__seen(&dpcur.value[DUMPTYPE_RECORD]).linenum = -1;
4940     save_dumptype();
4941
4942     init_dumptype_defaults();
4943     dpcur.name = stralloc("NO-HOLD");
4944     dpcur.seen.linenum = -1;
4945     free_val_t(&dpcur.value[DUMPTYPE_HOLDINGDISK]);
4946     val_t__holding(&dpcur.value[DUMPTYPE_HOLDINGDISK]) = HOLD_NEVER;
4947     val_t__seen(&dpcur.value[DUMPTYPE_HOLDINGDISK]).linenum = -1;
4948     save_dumptype();
4949
4950     init_dumptype_defaults();
4951     dpcur.name = stralloc("NO-FULL");
4952     dpcur.seen.linenum = -1;
4953     free_val_t(&dpcur.value[DUMPTYPE_STRATEGY]);
4954     val_t__strategy(&dpcur.value[DUMPTYPE_STRATEGY]) = DS_NOFULL;
4955     val_t__seen(&dpcur.value[DUMPTYPE_STRATEGY]).linenum = -1;
4956     save_dumptype();
4957
4958     /* And we're initialized! */
4959     config_initialized = 1;
4960 }
4961
4962 char **
4963 get_config_options(
4964     int first)
4965 {
4966     char             **config_options;
4967     char             **config_option;
4968     int              n_config_overrides = 0;
4969     int              i;
4970
4971     if (config_overrides)
4972         n_config_overrides = config_overrides->n_used;
4973
4974     config_options = alloc((first+n_config_overrides+1)*SIZEOF(char *));
4975     config_option = config_options + first;
4976
4977     for (i = 0; i < n_config_overrides; i++) {
4978         char *key = config_overrides->ovr[i].key;
4979         char *value = config_overrides->ovr[i].value;
4980         *config_option = vstralloc("-o", key, "=", value, NULL);
4981         config_option++;
4982     }
4983
4984     *config_option = NULL; /* add terminating sentinel */
4985
4986     return config_options;
4987 }
4988
4989 static void
4990 update_derived_values(
4991     gboolean is_client)
4992 {
4993     interface_t   *ip;
4994     identlist_t    il;
4995     holdingdisk_t *hd;
4996
4997     if (!is_client) {
4998         /* Add a 'default' interface if one doesn't already exist */
4999         if (!(ip = lookup_interface("default"))) {
5000             init_interface_defaults();
5001             ifcur.name = stralloc("default");
5002             ifcur.seen = val_t__seen(getconf(CNF_NETUSAGE));
5003             save_interface();
5004
5005             ip = lookup_interface("default");
5006         }
5007
5008         /* .. and set its maxusage from 'netusage' */
5009         if (!interface_seen(ip, INTER_MAXUSAGE)) {
5010             val_t *v;
5011
5012             v = interface_getconf(ip, INTER_COMMENT);
5013             free_val_t(v);
5014             val_t__str(v) = stralloc(_("implicit from NETUSAGE"));
5015             val_t__seen(v) = val_t__seen(getconf(CNF_NETUSAGE));
5016
5017             v = interface_getconf(ip, INTER_MAXUSAGE);
5018             free_val_t(v);
5019             val_t__int(v) = getconf_int(CNF_NETUSAGE);
5020             val_t__seen(v) = val_t__seen(getconf(CNF_NETUSAGE));
5021         }
5022
5023         /* Check the tapetype is defined */
5024         if (lookup_tapetype(getconf_str(CNF_TAPETYPE)) == NULL) {
5025             /* Create a default tapetype so that other code has
5026              * something to refer to, but don't pretend it's real */
5027             if (!getconf_seen(CNF_TAPETYPE) &&
5028                 strcmp(getconf_str(CNF_TAPETYPE), "DEFAULT_TAPE") == 0 &&
5029                 !lookup_tapetype("DEFAULT_TAPE")) {
5030                 init_tapetype_defaults();
5031                 tpcur.name = stralloc("DEFAULT_TAPE");
5032                 tpcur.seen = val_t__seen(getconf(CNF_TAPETYPE));
5033                 save_tapetype();
5034             } else {
5035                 conf_parserror(_("tapetype %s is not defined"),
5036                                getconf_str(CNF_TAPETYPE));
5037             }
5038         }
5039
5040         /* Check the holdingdisk are defined */
5041         for (il = getconf_identlist(CNF_HOLDINGDISK);
5042                  il != NULL; il = il->next) {
5043             hd = lookup_holdingdisk(il->data);
5044             if (!hd) {
5045                 conf_parserror(_("holdingdisk %s is not defined"),
5046                                (char *)il->data);
5047             }
5048         }
5049
5050         if ((getconf_seen(CNF_LABEL_NEW_TAPES) > 0 &&
5051              getconf_seen(CNF_AUTOLABEL) > 0)  ||
5052             (getconf_seen(CNF_LABEL_NEW_TAPES) < 0 &&
5053              getconf_seen(CNF_AUTOLABEL) < 0)) {
5054                 conf_parserror(_("Can't specify both label-new-tapes and autolabel"));
5055         }
5056         if ((getconf_seen(CNF_LABEL_NEW_TAPES) != 0 &&
5057              getconf_seen(CNF_AUTOLABEL) == 0) ||
5058             (getconf_seen(CNF_LABEL_NEW_TAPES) < 0 &&
5059              getconf_seen(CNF_AUTOLABEL) >= 0)) {
5060             autolabel_t *autolabel = &(conf_data[CNF_AUTOLABEL].v.autolabel);
5061             autolabel->template = g_strdup(getconf_str(CNF_LABEL_NEW_TAPES));
5062             if (!autolabel->template || autolabel->template == '\0') {
5063                 autolabel->template = NULL;
5064                 autolabel->autolabel = 0;
5065             } else {
5066                 autolabel->autolabel = AL_VOLUME_ERROR | AL_EMPTY;
5067             }
5068         }
5069     }
5070
5071     /* fill in the debug_* values */
5072     debug_amandad    = getconf_int(CNF_DEBUG_AMANDAD);
5073     debug_recovery   = getconf_int(CNF_DEBUG_RECOVERY);
5074     debug_amidxtaped = getconf_int(CNF_DEBUG_AMIDXTAPED);
5075     debug_amindexd   = getconf_int(CNF_DEBUG_AMINDEXD);
5076     debug_amrecover  = getconf_int(CNF_DEBUG_AMRECOVER);
5077     debug_auth       = getconf_int(CNF_DEBUG_AUTH);
5078     debug_event      = getconf_int(CNF_DEBUG_EVENT);
5079     debug_holding    = getconf_int(CNF_DEBUG_HOLDING);
5080     debug_protocol   = getconf_int(CNF_DEBUG_PROTOCOL);
5081     debug_planner    = getconf_int(CNF_DEBUG_PLANNER);
5082     debug_driver     = getconf_int(CNF_DEBUG_DRIVER);
5083     debug_dumper     = getconf_int(CNF_DEBUG_DUMPER);
5084     debug_chunker    = getconf_int(CNF_DEBUG_CHUNKER);
5085     debug_taper      = getconf_int(CNF_DEBUG_TAPER);
5086     debug_selfcheck  = getconf_int(CNF_DEBUG_SELFCHECK);
5087     debug_sendsize   = getconf_int(CNF_DEBUG_SENDSIZE);
5088     debug_sendbackup = getconf_int(CNF_DEBUG_SENDBACKUP);
5089
5090     /* And finally, display unit */
5091     switch (getconf_str(CNF_DISPLAYUNIT)[0]) {
5092         case 'k':
5093         case 'K':
5094             unit_divisor = 1;
5095             break;
5096
5097         case 'm':
5098         case 'M':
5099             unit_divisor = 1024;
5100             break;
5101
5102         case 'g':
5103         case 'G':
5104             unit_divisor = 1024*1024;
5105             break;
5106
5107         case 't':
5108         case 'T':
5109             unit_divisor = 1024*1024*1024;
5110             break;
5111
5112         default:
5113             error(_("Invalid displayunit missed by validate_displayunit"));
5114             /* NOTREACHED */
5115     }
5116 }
5117
5118 static void
5119 conf_init_int(
5120     val_t *val,
5121     int    i)
5122 {
5123     val->seen.linenum = 0;
5124     val->seen.filename = NULL;
5125     val->type = CONFTYPE_INT;
5126     val_t__int(val) = i;
5127 }
5128
5129 static void
5130 conf_init_int64(
5131     val_t *val,
5132     gint64   l)
5133 {
5134     val->seen.linenum = 0;
5135     val->seen.filename = NULL;
5136     val->type = CONFTYPE_INT64;
5137     val_t__int64(val) = l;
5138 }
5139
5140 static void
5141 conf_init_real(
5142     val_t  *val,
5143     float r)
5144 {
5145     val->seen.linenum = 0;
5146     val->seen.filename = NULL;
5147     val->type = CONFTYPE_REAL;
5148     val_t__real(val) = r;
5149 }
5150
5151 static void
5152 conf_init_str(
5153     val_t *val,
5154     char  *s)
5155 {
5156     val->seen.linenum = 0;
5157     val->seen.filename = NULL;
5158     val->type = CONFTYPE_STR;
5159     if(s)
5160         val->v.s = stralloc(s);
5161     else
5162         val->v.s = NULL;
5163 }
5164
5165 static void
5166 conf_init_ident(
5167     val_t *val,
5168     char  *s)
5169 {
5170     val->seen.linenum = 0;
5171     val->seen.filename = NULL;
5172     val->type = CONFTYPE_IDENT;
5173     if(s)
5174         val->v.s = stralloc(s);
5175     else
5176         val->v.s = NULL;
5177 }
5178
5179 static void
5180 conf_init_identlist(
5181     val_t *val,
5182     char  *s)
5183 {
5184     val->seen.linenum = 0;
5185     val->seen.filename = NULL;
5186     val->type = CONFTYPE_IDENTLIST;
5187     val->v.identlist = NULL;
5188     if (s)
5189         val->v.identlist = g_slist_append(val->v.identlist, stralloc(s));
5190 }
5191
5192 static void
5193 conf_init_time(
5194     val_t *val,
5195     time_t   t)
5196 {
5197     val->seen.linenum = 0;
5198     val->seen.filename = NULL;
5199     val->type = CONFTYPE_TIME;
5200     val_t__time(val) = t;
5201 }
5202
5203 static void
5204 conf_init_size(
5205     val_t *val,
5206     ssize_t   sz)
5207 {
5208     val->seen.linenum = 0;
5209     val->seen.filename = NULL;
5210     val->type = CONFTYPE_SIZE;
5211     val_t__size(val) = sz;
5212 }
5213
5214 static void
5215 conf_init_bool(
5216     val_t *val,
5217     int    i)
5218 {
5219     val->seen.linenum = 0;
5220     val->seen.filename = NULL;
5221     val->type = CONFTYPE_BOOLEAN;
5222     val_t__boolean(val) = i;
5223 }
5224
5225 static void
5226 conf_init_compress(
5227     val_t *val,
5228     comp_t    i)
5229 {
5230     val->seen.linenum = 0;
5231     val->seen.filename = NULL;
5232     val->type = CONFTYPE_COMPRESS;
5233     val_t__compress(val) = (int)i;
5234 }
5235
5236 static void
5237 conf_init_encrypt(
5238     val_t *val,
5239     encrypt_t    i)
5240 {
5241     val->seen.linenum = 0;
5242     val->seen.filename = NULL;
5243     val->type = CONFTYPE_ENCRYPT;
5244     val_t__encrypt(val) = (int)i;
5245 }
5246
5247 static void
5248 conf_init_part_cache_type(
5249     val_t *val,
5250     part_cache_type_t    i)
5251 {
5252     val->seen.linenum = 0;
5253     val->seen.filename = NULL;
5254     val->type = CONFTYPE_PART_CACHE_TYPE;
5255     val_t__part_cache_type(val) = (int)i;
5256 }
5257
5258 static void
5259 conf_init_recovery_limit(
5260     val_t *val)
5261 {
5262     val->seen.linenum = 0;
5263     val->seen.filename = NULL;
5264     val->type = CONFTYPE_RECOVERY_LIMIT;
5265     val_t__recovery_limit(val).match_pats = NULL;
5266     val_t__recovery_limit(val).same_host = FALSE;
5267 }
5268
5269 static void
5270 conf_init_data_path(
5271     val_t *val,
5272     data_path_t    i)
5273 {
5274     val->seen.linenum = 0;
5275     val->seen.filename = NULL;
5276     val->type = CONFTYPE_DATA_PATH;
5277     val_t__data_path(val) = (int)i;
5278 }
5279
5280 static void
5281 conf_init_holding(
5282     val_t              *val,
5283     dump_holdingdisk_t  i)
5284 {
5285     val->seen.linenum = 0;
5286     val->seen.filename = NULL;
5287     val->type = CONFTYPE_HOLDING;
5288     val_t__holding(val) = (int)i;
5289 }
5290
5291 static void
5292 conf_init_estimatelist(
5293     val_t *val,
5294     estimate_t    i)
5295 {
5296     GSList *estimates = NULL;
5297     val->seen.linenum = 0;
5298     val->seen.filename = NULL;
5299     val->type = CONFTYPE_ESTIMATELIST;
5300     estimates = g_slist_append(estimates, GINT_TO_POINTER(i));
5301     val_t__estimatelist(val) = estimates;
5302 }
5303
5304 static void
5305 conf_init_strategy(
5306     val_t *val,
5307     strategy_t    i)
5308 {
5309     val->seen.linenum = 0;
5310     val->seen.filename = NULL;
5311     val->type = CONFTYPE_STRATEGY;
5312     val_t__strategy(val) = i;
5313 }
5314
5315 static void
5316 conf_init_taperalgo(
5317     val_t *val,
5318     taperalgo_t    i)
5319 {
5320     val->seen.linenum = 0;
5321     val->seen.filename = NULL;
5322     val->type = CONFTYPE_TAPERALGO;
5323     val_t__taperalgo(val) = i;
5324 }
5325
5326 static void
5327 conf_init_priority(
5328     val_t *val,
5329     int    i)
5330 {
5331     val->seen.linenum = 0;
5332     val->seen.filename = NULL;
5333     val->type = CONFTYPE_PRIORITY;
5334     val_t__priority(val) = i;
5335 }
5336
5337 static void
5338 conf_init_rate(
5339     val_t  *val,
5340     float r1,
5341     float r2)
5342 {
5343     val->seen.linenum = 0;
5344     val->seen.filename = NULL;
5345     val->type = CONFTYPE_RATE;
5346     val_t__rate(val)[0] = r1;
5347     val_t__rate(val)[1] = r2;
5348 }
5349
5350 static void
5351 conf_init_exinclude(
5352     val_t *val)
5353 {
5354     val->seen.linenum = 0;
5355     val->seen.filename = NULL;
5356     val->type = CONFTYPE_EXINCLUDE;
5357     val_t__exinclude(val).optional = 0;
5358     val_t__exinclude(val).sl_list = NULL;
5359     val_t__exinclude(val).sl_file = NULL;
5360 }
5361
5362 static void
5363 conf_init_intrange(
5364     val_t *val,
5365     int    i1,
5366     int    i2)
5367 {
5368     val->seen.linenum = 0;
5369     val->seen.filename = NULL;
5370     val->type = CONFTYPE_INTRANGE;
5371     val_t__intrange(val)[0] = i1;
5372     val_t__intrange(val)[1] = i2;
5373 }
5374
5375 static void
5376 conf_init_autolabel(
5377     val_t *val) {
5378     val->seen.linenum = 0;
5379     val->seen.filename = NULL;
5380     val->type = CONFTYPE_AUTOLABEL;
5381     val->v.autolabel.template = NULL;
5382     val->v.autolabel.autolabel = 0;
5383 }
5384
5385 void
5386 free_property_t(
5387     gpointer p)
5388 {
5389     property_t *propery = (property_t *)p;
5390     slist_free_full(propery->values, g_free);
5391     amfree(propery);
5392 }
5393
5394 static void
5395 conf_init_proplist(
5396     val_t *val)
5397 {
5398     val->seen.linenum = 0;
5399     val->seen.filename = NULL;
5400     val->type = CONFTYPE_PROPLIST;
5401     val_t__proplist(val) =
5402         g_hash_table_new_full(g_str_amanda_hash, g_str_amanda_equal,
5403                               &g_free, &free_property_t);
5404 }
5405
5406 static void
5407 conf_init_execute_on(
5408     val_t *val,
5409     int    i)
5410 {
5411     val->seen.linenum = 0;
5412     val->seen.filename = NULL;
5413     val->type = CONFTYPE_EXECUTE_ON;
5414     val->v.i = i;
5415 }
5416
5417 static void
5418 conf_init_execute_where(
5419     val_t *val,
5420     int    i)
5421 {
5422     val->seen.linenum = 0;
5423     val->seen.filename = NULL;
5424     val->type = CONFTYPE_EXECUTE_WHERE;
5425     val->v.i = i;
5426 }
5427
5428 static void
5429 conf_init_send_amreport(
5430     val_t *val,
5431     send_amreport_t i)
5432 {
5433     val->seen.linenum = 0;
5434     val->seen.filename = NULL;
5435     val->type = CONFTYPE_SEND_AMREPORT_ON;
5436     val->v.i = i;
5437 }
5438
5439 static void conf_init_application(val_t *val) {
5440     val->seen.linenum = 0;
5441     val->seen.filename = NULL;
5442     val->type = CONFTYPE_APPLICATION;
5443     val->v.s = NULL;
5444 }
5445
5446
5447 /*
5448  * Config access implementation
5449  */
5450
5451 val_t *
5452 getconf(confparm_key key)
5453 {
5454     assert(key < CNF_CNF);
5455     return &conf_data[key];
5456 }
5457
5458 GSList *
5459 getconf_list(
5460     char *listname)
5461 {
5462     tapetype_t *tp;
5463     dumptype_t *dp;
5464     interface_t *ip;
5465     holdingdisk_t *hd;
5466     GSList        *hp;
5467     application_t *ap;
5468     pp_script_t   *pp;
5469     device_config_t *dc;
5470     changer_config_t *cc;
5471     GSList *rv = NULL;
5472
5473     if (strcasecmp(listname,"tapetype") == 0) {
5474         for(tp = tapelist; tp != NULL; tp=tp->next) {
5475             rv = g_slist_append(rv, tp->name);
5476         }
5477     } else if (strcasecmp(listname,"dumptype") == 0) {
5478         for(dp = dumplist; dp != NULL; dp=dp->next) {
5479             rv = g_slist_append(rv, dp->name);
5480         }
5481     } else if (strcasecmp(listname,"holdingdisk") == 0) {
5482         for(hp = holdinglist; hp != NULL; hp=hp->next) {
5483             hd = hp->data;
5484             rv = g_slist_append(rv, hd->name);
5485         }
5486     } else if (strcasecmp(listname,"interface") == 0) {
5487         for(ip = interface_list; ip != NULL; ip=ip->next) {
5488             rv = g_slist_append(rv, ip->name);
5489         }
5490     } else if (strcasecmp(listname,"application_tool") == 0
5491             || strcasecmp(listname,"application-tool") == 0
5492             || strcasecmp(listname,"application") == 0) {
5493         for(ap = application_list; ap != NULL; ap=ap->next) {
5494             rv = g_slist_append(rv, ap->name);
5495         }
5496     } else if (strcasecmp(listname,"script_tool") == 0
5497             || strcasecmp(listname,"script-tool") == 0
5498             || strcasecmp(listname,"script") == 0) {
5499         for(pp = pp_script_list; pp != NULL; pp=pp->next) {
5500             rv = g_slist_append(rv, pp->name);
5501         }
5502     } else if (strcasecmp(listname,"device") == 0) {
5503         for(dc = device_config_list; dc != NULL; dc=dc->next) {
5504             rv = g_slist_append(rv, dc->name);
5505         }
5506     } else if (strcasecmp(listname,"changer") == 0) {
5507         for(cc = changer_config_list; cc != NULL; cc=cc->next) {
5508             rv = g_slist_append(rv, cc->name);
5509         }
5510     }
5511     return rv;
5512 }
5513
5514 val_t *
5515 getconf_byname(
5516     char *key)
5517 {
5518     val_t *rv = NULL;
5519
5520     if (!parm_key_info(key, NULL, &rv))
5521         return NULL;
5522
5523     return rv;
5524 }
5525
5526 tapetype_t *
5527 lookup_tapetype(
5528     char *str)
5529 {
5530     tapetype_t *p;
5531
5532     for(p = tapelist; p != NULL; p = p->next) {
5533         if(strcasecmp(p->name, str) == 0) return p;
5534     }
5535     return NULL;
5536 }
5537
5538 val_t *
5539 tapetype_getconf(
5540     tapetype_t *ttyp,
5541     tapetype_key key)
5542 {
5543     assert(ttyp != NULL);
5544     assert(key < TAPETYPE_TAPETYPE);
5545     return &ttyp->value[key];
5546 }
5547
5548 static void
5549 validate_program(
5550     conf_var_t *np G_GNUC_UNUSED,
5551     val_t        *val)
5552 {
5553     if (strcmp(val->v.s, "DUMP") != 0 &&
5554         strcmp(val->v.s, "GNUTAR") != 0 &&
5555         strcmp(val->v.s, "STAR") != 0 &&
5556         strcmp(val->v.s, "APPLICATION") != 0)
5557        conf_parserror("program must be \"DUMP\", \"GNUTAR\", \"STAR\" or \"APPLICATION\"");
5558 }
5559
5560 char *
5561 tapetype_name(
5562     tapetype_t *ttyp)
5563 {
5564     assert(ttyp != NULL);
5565     return ttyp->name;
5566 }
5567
5568 dumptype_t *
5569 lookup_dumptype(
5570     char *str)
5571 {
5572     dumptype_t *p;
5573
5574     for(p = dumplist; p != NULL; p = p->next) {
5575         if(strcasecmp(p->name, str) == 0) return p;
5576     }
5577     return NULL;
5578 }
5579
5580 val_t *
5581 dumptype_getconf(
5582     dumptype_t *dtyp,
5583     dumptype_key key)
5584 {
5585     assert(dtyp != NULL);
5586     assert(key < DUMPTYPE_DUMPTYPE);
5587     return &dtyp->value[key];
5588 }
5589
5590 char *
5591 dumptype_name(
5592     dumptype_t *dtyp)
5593 {
5594     assert(dtyp != NULL);
5595     return dtyp->name;
5596 }
5597
5598 interface_t *
5599 lookup_interface(
5600     char *str)
5601 {
5602     interface_t *p;
5603
5604     for(p = interface_list; p != NULL; p = p->next) {
5605         if(strcasecmp(p->name, str) == 0) return p;
5606     }
5607     return NULL;
5608 }
5609
5610 val_t *
5611 interface_getconf(
5612     interface_t *iface,
5613     interface_key key)
5614 {
5615     assert(iface != NULL);
5616     assert(key < INTER_INTER);
5617     return &iface->value[key];
5618 }
5619
5620 char *
5621 interface_name(
5622     interface_t *iface)
5623 {
5624     assert(iface != NULL);
5625     return iface->name;
5626 }
5627
5628 holdingdisk_t *
5629 lookup_holdingdisk(
5630     char *str)
5631 {
5632     GSList        *hp;
5633     holdingdisk_t *hd;
5634
5635     for (hp = holdinglist; hp != NULL; hp = hp->next) {
5636         hd = hp->data;
5637         if (strcasecmp(hd->name, str) == 0) return hd;
5638     }
5639     return NULL;
5640 }
5641
5642 GSList *
5643 getconf_holdingdisks(
5644     void)
5645 {
5646     return holdinglist;
5647 }
5648
5649 val_t *
5650 holdingdisk_getconf(
5651     holdingdisk_t *hdisk,
5652     holdingdisk_key key)
5653 {
5654     assert(hdisk != NULL);
5655     assert(key < HOLDING_HOLDING);
5656     return &hdisk->value[key];
5657 }
5658
5659 char *
5660 holdingdisk_name(
5661     holdingdisk_t *hdisk)
5662 {
5663     assert(hdisk != NULL);
5664     return hdisk->name;
5665 }
5666
5667 application_t *
5668 lookup_application(
5669     char *str)
5670 {
5671     application_t *p;
5672
5673     for(p = application_list; p != NULL; p = p->next) {
5674         if(strcasecmp(p->name, str) == 0) return p;
5675     }
5676     return NULL;
5677 }
5678
5679 val_t *
5680 application_getconf(
5681     application_t *ap,
5682     application_key key)
5683 {
5684     assert(ap != NULL);
5685     assert(key < APPLICATION_APPLICATION);
5686     return &ap->value[key];
5687 }
5688
5689 char *
5690 application_name(
5691     application_t *ap)
5692 {
5693     assert(ap != NULL);
5694     return ap->name;
5695 }
5696
5697 pp_script_t *
5698 lookup_pp_script(
5699     char *str)
5700 {
5701     pp_script_t *pps;
5702
5703     for(pps = pp_script_list; pps != NULL; pps = pps->next) {
5704         if(strcasecmp(pps->name, str) == 0) return pps;
5705     }
5706     return NULL;
5707 }
5708
5709 val_t *
5710 pp_script_getconf(
5711     pp_script_t *pps,
5712     pp_script_key key)
5713 {
5714     assert(pps != NULL);
5715     assert(key < PP_SCRIPT_PP_SCRIPT);
5716     return &pps->value[key];
5717 }
5718
5719 char *
5720 pp_script_name(
5721     pp_script_t *pps)
5722 {
5723     assert(pps != NULL);
5724     return pps->name;
5725 }
5726
5727 device_config_t *
5728 lookup_device_config(
5729     char *str)
5730 {
5731     device_config_t *devconf;
5732
5733     for(devconf = device_config_list; devconf != NULL; devconf = devconf->next) {
5734         if(strcasecmp(devconf->name, str) == 0) return devconf;
5735     }
5736     return NULL;
5737 }
5738
5739 val_t *
5740 device_config_getconf(
5741     device_config_t *devconf,
5742     device_config_key key)
5743 {
5744     assert(devconf != NULL);
5745     assert(key < DEVICE_CONFIG_DEVICE_CONFIG);
5746     return &devconf->value[key];
5747 }
5748
5749 char *
5750 device_config_name(
5751     device_config_t *devconf)
5752 {
5753     assert(devconf != NULL);
5754     return devconf->name;
5755 }
5756
5757 changer_config_t *
5758 lookup_changer_config(
5759     char *str)
5760 {
5761     changer_config_t *devconf;
5762
5763     for(devconf = changer_config_list; devconf != NULL; devconf = devconf->next) {
5764         if(strcasecmp(devconf->name, str) == 0) return devconf;
5765     }
5766     return NULL;
5767 }
5768
5769 val_t *
5770 changer_config_getconf(
5771     changer_config_t *devconf,
5772     changer_config_key key)
5773 {
5774     assert(devconf != NULL);
5775     assert(key < CHANGER_CONFIG_CHANGER_CONFIG);
5776     return &devconf->value[key];
5777 }
5778
5779 char *
5780 changer_config_name(
5781     changer_config_t *devconf)
5782 {
5783     assert(devconf != NULL);
5784     return devconf->name;
5785 }
5786
5787 long int
5788 getconf_unit_divisor(void)
5789 {
5790     return unit_divisor;
5791 }
5792
5793 /*
5794  * Command-line Handling Implementation
5795  */
5796
5797 config_overrides_t *
5798 new_config_overrides(
5799     int size_estimate)
5800 {
5801     config_overrides_t *co;
5802
5803     if (size_estimate <= 0)
5804         size_estimate = 10;
5805
5806     co = alloc(sizeof(*co));
5807     co->ovr = alloc(sizeof(*co->ovr) * size_estimate);
5808     co->n_allocated = size_estimate;
5809     co->n_used = 0;
5810
5811     return co;
5812 }
5813
5814 void
5815 free_config_overrides(
5816     config_overrides_t *co)
5817 {
5818     int i;
5819
5820     if (!co) return;
5821     for (i = 0; i < co->n_used; i++) {
5822         amfree(co->ovr[i].key);
5823         amfree(co->ovr[i].value);
5824     }
5825     amfree(co->ovr);
5826     amfree(co);
5827 }
5828
5829 void add_config_override(
5830     config_overrides_t *co,
5831     char *key,
5832     char *value)
5833 {
5834     /* reallocate if necessary */
5835     if (co->n_used == co->n_allocated) {
5836         co->n_allocated *= 2;
5837         co->ovr = realloc(co->ovr, co->n_allocated * sizeof(*co->ovr));
5838         if (!co->ovr) {
5839             error(_("Cannot realloc; out of memory"));
5840             /* NOTREACHED */
5841         }
5842     }
5843
5844     co->ovr[co->n_used].key = stralloc(key);
5845     co->ovr[co->n_used].value = stralloc(value);
5846     co->n_used++;
5847 }
5848
5849 void
5850 add_config_override_opt(
5851     config_overrides_t *co,
5852     char *optarg)
5853 {
5854     char *value;
5855     assert(optarg != NULL);
5856
5857     value = strchr(optarg, '=');
5858     if (value == NULL) {
5859         error(_("Must specify a value for %s."), optarg);
5860         /* NOTREACHED */
5861     }
5862
5863     *value = '\0';
5864     add_config_override(co, optarg, value+1);
5865     *value = '=';
5866 }
5867
5868 config_overrides_t *
5869 extract_commandline_config_overrides(
5870     int *argc,
5871     char ***argv)
5872 {
5873     int i, j, moveup;
5874     config_overrides_t *co = new_config_overrides(*argc/2);
5875
5876     i = 0;
5877     while (i<*argc) {
5878         if(strncmp((*argv)[i],"-o",2) == 0) {
5879             if(strlen((*argv)[i]) > 2) {
5880                 add_config_override_opt(co, (*argv)[i]+2);
5881                 moveup = 1;
5882             }
5883             else {
5884                 if (i+1 >= *argc) error(_("expect something after -o"));
5885                 add_config_override_opt(co, (*argv)[i+1]);
5886                 moveup = 2;
5887             }
5888
5889             /* move up remaining argment array */
5890             for (j = i; j+moveup<*argc; j++) {
5891                 (*argv)[j] = (*argv)[j+moveup];
5892             }
5893             *argc -= moveup;
5894         } else {
5895             i++;
5896         }
5897     }
5898
5899     return co;
5900 }
5901
5902 void
5903 set_config_overrides(
5904     config_overrides_t *co)
5905 {
5906     int i;
5907
5908     config_overrides = co;
5909
5910     for (i = 0; i < co->n_used; i++) {
5911         g_debug("config_overrides: %s %s", co->ovr[i].key, co->ovr[i].value);
5912     }
5913
5914     return;
5915 }
5916
5917 static cfgerr_level_t
5918 apply_config_overrides(
5919     config_overrides_t *co,
5920     char *key_ovr)
5921 {
5922     int i;
5923
5924     if(!co) return cfgerr_level;
5925     assert(keytable != NULL);
5926     assert(parsetable != NULL);
5927
5928     for (i = 0; i < co->n_used; i++) {
5929         char *key = co->ovr[i].key;
5930         char *value = co->ovr[i].value;
5931         val_t *key_val;
5932         conf_var_t *key_parm;
5933
5934         if (key_ovr && strncasecmp(key_ovr, key, strlen(key_ovr)) != 0) {
5935             continue;
5936         }
5937
5938         if (!parm_key_info(key, &key_parm, &key_val)) {
5939             /* not an error, only default config is loaded */
5940             continue;
5941         }
5942
5943         /* now set up a fake line and use the relevant read_function to
5944          * parse it.  This is sneaky! */
5945         if (key_parm->type == CONFTYPE_STR) {
5946             current_line = quote_string_always(value);
5947         } else {
5948             current_line = stralloc(value);
5949         }
5950
5951         current_char = current_line;
5952         token_pushed = 0;
5953         current_line_num = -2;
5954         allow_overwrites = 1;
5955         co->ovr[i].applied = TRUE;
5956
5957         key_parm->read_function(key_parm, key_val);
5958         if ((key_parm)->validate_function)
5959             key_parm->validate_function(key_parm, key_val);
5960
5961         amfree(current_line);
5962         current_char = NULL;
5963     }
5964
5965     return cfgerr_level;
5966 }
5967
5968 /*
5969  * val_t Management Implementation
5970  */
5971
5972 int
5973 val_t_to_int(
5974     val_t *val)
5975 {
5976     assert(config_initialized);
5977     if (val->type != CONFTYPE_INT) {
5978         error(_("val_t_to_int: val.type is not CONFTYPE_INT"));
5979         /*NOTREACHED*/
5980     }
5981     return val_t__int(val);
5982 }
5983
5984 gint64
5985 val_t_to_int64(
5986     val_t *val)
5987 {
5988     assert(config_initialized);
5989     if (val->type != CONFTYPE_INT64) {
5990         error(_("val_t_to_int64: val.type is not CONFTYPE_INT64"));
5991         /*NOTREACHED*/
5992     }
5993     return val_t__int64(val);
5994 }
5995
5996 float
5997 val_t_to_real(
5998     val_t *val)
5999 {
6000     assert(config_initialized);
6001     if (val->type != CONFTYPE_REAL) {
6002         error(_("val_t_to_real: val.type is not CONFTYPE_REAL"));
6003         /*NOTREACHED*/
6004     }
6005     return val_t__real(val);
6006 }
6007
6008 char *
6009 val_t_to_str(
6010     val_t *val)
6011 {
6012     assert(config_initialized);
6013     /* support CONFTYPE_IDENT, too */
6014     if (val->type != CONFTYPE_STR && val->type != CONFTYPE_IDENT) {
6015         error(_("val_t_to_str: val.type is not CONFTYPE_STR nor CONFTYPE_IDENT"));
6016         /*NOTREACHED*/
6017     }
6018     return val_t__str(val);
6019 }
6020
6021 char *
6022 val_t_to_ident(
6023     val_t *val)
6024 {
6025     assert(config_initialized);
6026     /* support CONFTYPE_STR, too */
6027     if (val->type != CONFTYPE_STR && val->type != CONFTYPE_IDENT) {
6028         error(_("val_t_to_ident: val.type is not CONFTYPE_IDENT nor CONFTYPE_STR"));
6029         /*NOTREACHED*/
6030     }
6031     return val_t__str(val);
6032 }
6033
6034 identlist_t
6035 val_t_to_identlist(
6036     val_t *val)
6037 {
6038     assert(config_initialized);
6039     if (val->type != CONFTYPE_IDENTLIST) {
6040         error(_("val_t_to_ident: val.type is not CONFTYPE_IDENTLIST"));
6041         /*NOTREACHED*/
6042     }
6043     return val_t__identlist(val);
6044 }
6045
6046 time_t
6047 val_t_to_time(
6048     val_t *val)
6049 {
6050     assert(config_initialized);
6051     if (val->type != CONFTYPE_TIME) {
6052         error(_("val_t_to_time: val.type is not CONFTYPE_TIME"));
6053         /*NOTREACHED*/
6054     }
6055     return val_t__time(val);
6056 }
6057
6058 ssize_t
6059 val_t_to_size(
6060     val_t *val)
6061 {
6062     assert(config_initialized);
6063     if (val->type != CONFTYPE_SIZE) {
6064         error(_("val_t_to_size: val.type is not CONFTYPE_SIZE"));
6065         /*NOTREACHED*/
6066     }
6067     return val_t__size(val);
6068 }
6069
6070 int
6071 val_t_to_boolean(
6072     val_t *val)
6073 {
6074     assert(config_initialized);
6075     if (val->type != CONFTYPE_BOOLEAN) {
6076         error(_("val_t_to_bool: val.type is not CONFTYPE_BOOLEAN"));
6077         /*NOTREACHED*/
6078     }
6079     return val_t__boolean(val);
6080 }
6081
6082 comp_t
6083 val_t_to_compress(
6084     val_t *val)
6085 {
6086     assert(config_initialized);
6087     if (val->type != CONFTYPE_COMPRESS) {
6088         error(_("val_t_to_compress: val.type is not CONFTYPE_COMPRESS"));
6089         /*NOTREACHED*/
6090     }
6091     return val_t__compress(val);
6092 }
6093
6094 encrypt_t
6095 val_t_to_encrypt(
6096     val_t *val)
6097 {
6098     assert(config_initialized);
6099     if (val->type != CONFTYPE_ENCRYPT) {
6100         error(_("val_t_to_encrypt: val.type is not CONFTYPE_ENCRYPT"));
6101         /*NOTREACHED*/
6102     }
6103     return val_t__encrypt(val);
6104 }
6105
6106 part_cache_type_t
6107 val_t_to_part_cache_type(
6108     val_t *val)
6109 {
6110     assert(config_initialized);
6111     if (val->type != CONFTYPE_PART_CACHE_TYPE) {
6112         error(_("val_t_to_part_cache_type: val.type is not CONFTYPE_PART_CACHE_TYPE"));
6113         /*NOTREACHED*/
6114     }
6115     return val_t__part_cache_type(val);
6116 }
6117
6118 recovery_limit_t *
6119 val_t_to_recovery_limit(
6120     val_t *val)
6121 {
6122     assert(config_initialized);
6123     if (val->type != CONFTYPE_RECOVERY_LIMIT) {
6124         error(_("val_t_to_recovery_limit: val.type is not CONFTYPE_RECOVERY_LIMIT"));
6125         /*NOTREACHED*/
6126     }
6127     return &val_t__recovery_limit(val);
6128 }
6129
6130 dump_holdingdisk_t
6131 val_t_to_holding(
6132     val_t *val)
6133 {
6134     assert(config_initialized);
6135     if (val->type != CONFTYPE_HOLDING) {
6136         error(_("val_t_to_hold: val.type is not CONFTYPE_HOLDING"));
6137         /*NOTREACHED*/
6138     }
6139     return val_t__holding(val);
6140 }
6141
6142 estimatelist_t
6143 val_t_to_estimatelist(
6144     val_t *val)
6145 {
6146     assert(config_initialized);
6147     if (val->type != CONFTYPE_ESTIMATELIST) {
6148         error(_("val_t_to_estimatelist: val.type is not CONFTYPE_ESTIMATELIST"));
6149         /*NOTREACHED*/
6150     }
6151     return val_t__estimatelist(val);
6152 }
6153
6154 strategy_t
6155 val_t_to_strategy(
6156     val_t *val)
6157 {
6158     assert(config_initialized);
6159     if (val->type != CONFTYPE_STRATEGY) {
6160         error(_("val_t_to_strategy: val.type is not CONFTYPE_STRATEGY"));
6161         /*NOTREACHED*/
6162     }
6163     return val_t__strategy(val);
6164 }
6165
6166 taperalgo_t
6167 val_t_to_taperalgo(
6168     val_t *val)
6169 {
6170     assert(config_initialized);
6171     if (val->type != CONFTYPE_TAPERALGO) {
6172         error(_("val_t_to_taperalgo: val.type is not CONFTYPE_TAPERALGO"));
6173         /*NOTREACHED*/
6174     }
6175     return val_t__taperalgo(val);
6176 }
6177
6178 send_amreport_t
6179 val_t_to_send_amreport(
6180     val_t *val)
6181 {
6182     assert(config_initialized);
6183     if (val->type != CONFTYPE_SEND_AMREPORT_ON) {
6184         error(_("val_t_to_send_amreport: val.type is not CONFTYPE_SEND_AMREPORT_ON"));
6185         /*NOTREACHED*/
6186     }
6187     return val_t__send_amreport(val);
6188 }
6189
6190 data_path_t
6191 val_t_to_data_path(
6192     val_t *val)
6193 {
6194     assert(config_initialized);
6195     if (val->type != CONFTYPE_DATA_PATH) {
6196         error(_("val_t_to_data_path: val.type is not CONFTYPE_DATA_PATH"));
6197         /*NOTREACHED*/
6198     }
6199     return val_t__data_path(val);
6200 }
6201
6202 int
6203 val_t_to_priority(
6204     val_t *val)
6205 {
6206     assert(config_initialized);
6207     if (val->type != CONFTYPE_PRIORITY) {
6208         error(_("val_t_to_priority: val.type is not CONFTYPE_PRIORITY"));
6209         /*NOTREACHED*/
6210     }
6211     return val_t__priority(val);
6212 }
6213
6214 float *
6215 val_t_to_rate(
6216     val_t *val)
6217 {
6218     assert(config_initialized);
6219     if (val->type != CONFTYPE_RATE) {
6220         error(_("val_t_to_rate: val.type is not CONFTYPE_RATE"));
6221         /*NOTREACHED*/
6222     }
6223     return val_t__rate(val);
6224 }
6225
6226 exinclude_t
6227 val_t_to_exinclude(
6228     val_t *val)
6229 {
6230     assert(config_initialized);
6231     if (val->type != CONFTYPE_EXINCLUDE) {
6232         error(_("val_t_to_exinclude: val.type is not CONFTYPE_EXINCLUDE"));
6233         /*NOTREACHED*/
6234     }
6235     return val_t__exinclude(val);
6236 }
6237
6238
6239 int *
6240 val_t_to_intrange(
6241     val_t *val)
6242 {
6243     assert(config_initialized);
6244     if (val->type != CONFTYPE_INTRANGE) {
6245         error(_("val_t_to_intrange: val.type is not CONFTYPE_INTRANGE"));
6246         /*NOTREACHED*/
6247     }
6248     return val_t__intrange(val);
6249 }
6250
6251 proplist_t
6252 val_t_to_proplist(
6253     val_t *val)
6254 {
6255     assert(config_initialized);
6256     if (val->type != CONFTYPE_PROPLIST) {
6257         error(_("val_t_to_proplist: val.type is not CONFTYPE_PROPLIST"));
6258         /*NOTREACHED*/
6259     }
6260     return val_t__proplist(val);
6261 }
6262
6263 autolabel_t
6264 val_t_to_autolabel(
6265     val_t *val)
6266 {
6267     assert(config_initialized);
6268     if (val->type != CONFTYPE_AUTOLABEL) {
6269         error(_("val_t_to_autolabel: val.type is not CONFTYPE_AUTOLABEL"));
6270         /*NOTREACHED*/
6271     }
6272     return val_t__autolabel(val);
6273 }
6274
6275 static void
6276 merge_val_t(
6277     val_t *valdst,
6278     val_t *valsrc)
6279 {
6280     if (valsrc->type == CONFTYPE_PROPLIST) {
6281         if (valsrc->v.proplist) {
6282             if (valdst->v.proplist == NULL) {
6283                 valdst->v.proplist = g_hash_table_new_full(g_str_amanda_hash,
6284                                                            g_str_amanda_equal,
6285                                                            &g_free,
6286                                                            &free_property_t);
6287                 g_hash_table_foreach(valsrc->v.proplist,
6288                                      &copy_proplist_foreach_fn,
6289                                      valdst->v.proplist);
6290             } else {
6291                 g_hash_table_foreach(valsrc->v.proplist,
6292                                      &merge_proplist_foreach_fn,
6293                                      valdst->v.proplist);
6294             }
6295         }
6296     } else if (valsrc->type == CONFTYPE_IDENTLIST) {
6297         if (valsrc->v.identlist) {
6298             identlist_t il;
6299             for (il = valsrc->v.identlist; il != NULL; il = il->next) {
6300                  valdst->v.identlist = g_slist_append(valdst->v.identlist,
6301                                                    stralloc((char *)il->data));
6302             }
6303         }
6304     } else {
6305         free_val_t(valdst);
6306         copy_val_t(valdst, valsrc);
6307     }
6308 }
6309
6310 static void
6311 copy_val_t(
6312     val_t *valdst,
6313     val_t *valsrc)
6314 {
6315     GSList *ia;
6316
6317     if(valsrc->seen.linenum) {
6318         valdst->type = valsrc->type;
6319         valdst->seen = valsrc->seen;
6320         switch(valsrc->type) {
6321         case CONFTYPE_INT:
6322         case CONFTYPE_BOOLEAN:
6323         case CONFTYPE_COMPRESS:
6324         case CONFTYPE_ENCRYPT:
6325         case CONFTYPE_HOLDING:
6326         case CONFTYPE_EXECUTE_ON:
6327         case CONFTYPE_EXECUTE_WHERE:
6328         case CONFTYPE_SEND_AMREPORT_ON:
6329         case CONFTYPE_DATA_PATH:
6330         case CONFTYPE_STRATEGY:
6331         case CONFTYPE_TAPERALGO:
6332         case CONFTYPE_PRIORITY:
6333         case CONFTYPE_PART_CACHE_TYPE:
6334             valdst->v.i = valsrc->v.i;
6335             break;
6336
6337         case CONFTYPE_SIZE:
6338             valdst->v.size = valsrc->v.size;
6339             break;
6340
6341         case CONFTYPE_INT64:
6342             valdst->v.int64 = valsrc->v.int64;
6343             break;
6344
6345         case CONFTYPE_REAL:
6346             valdst->v.r = valsrc->v.r;
6347             break;
6348
6349         case CONFTYPE_RATE:
6350             valdst->v.rate[0] = valsrc->v.rate[0];
6351             valdst->v.rate[1] = valsrc->v.rate[1];
6352             break;
6353
6354         case CONFTYPE_IDENT:
6355         case CONFTYPE_STR:
6356             valdst->v.s = stralloc(valsrc->v.s);
6357             break;
6358
6359         case CONFTYPE_IDENTLIST:
6360             valdst->v.identlist = NULL;
6361             for (ia = valsrc->v.identlist; ia != NULL; ia = ia->next) {
6362                 valdst->v.identlist = g_slist_append(valdst->v.identlist,
6363                                                      stralloc(ia->data));
6364             }
6365             break;
6366
6367         case CONFTYPE_RECOVERY_LIMIT:
6368             valdst->v.recovery_limit = valsrc->v.recovery_limit;
6369             valdst->v.recovery_limit.match_pats = NULL;
6370             for (ia = valsrc->v.recovery_limit.match_pats; ia != NULL; ia = ia->next) {
6371                 valdst->v.recovery_limit.match_pats =
6372                     g_slist_append(valdst->v.recovery_limit.match_pats, g_strdup(ia->data));
6373             }
6374             break;
6375
6376         case CONFTYPE_TIME:
6377             valdst->v.t = valsrc->v.t;
6378             break;
6379
6380         case CONFTYPE_ESTIMATELIST: {
6381             estimatelist_t estimates = valsrc->v.estimatelist;
6382             estimatelist_t dst_estimates = NULL;
6383             while (estimates != NULL) {
6384                 dst_estimates = g_slist_append(dst_estimates, estimates->data);
6385                 estimates = estimates->next;
6386             }
6387             valdst->v.estimatelist = dst_estimates;
6388             break;
6389         }
6390
6391         case CONFTYPE_EXINCLUDE:
6392             valdst->v.exinclude.optional = valsrc->v.exinclude.optional;
6393             valdst->v.exinclude.sl_list = duplicate_sl(valsrc->v.exinclude.sl_list);
6394             valdst->v.exinclude.sl_file = duplicate_sl(valsrc->v.exinclude.sl_file);
6395             break;
6396
6397         case CONFTYPE_INTRANGE:
6398             valdst->v.intrange[0] = valsrc->v.intrange[0];
6399             valdst->v.intrange[1] = valsrc->v.intrange[1];
6400             break;
6401
6402         case CONFTYPE_PROPLIST:
6403             if (valsrc->v.proplist) {
6404                 valdst->v.proplist = g_hash_table_new_full(g_str_amanda_hash,
6405                                                            g_str_amanda_equal,
6406                                                            &g_free,
6407                                                            &free_property_t);
6408
6409                 g_hash_table_foreach(valsrc->v.proplist,
6410                                      &copy_proplist_foreach_fn,
6411                                      valdst->v.proplist);
6412             } else {
6413                 valdst->v.proplist = NULL;
6414             }
6415             break;
6416
6417         case CONFTYPE_APPLICATION:
6418             valdst->v.s = stralloc(valsrc->v.s);
6419             break;
6420
6421         case CONFTYPE_AUTOLABEL:
6422             valdst->v.autolabel.template = stralloc(valsrc->v.autolabel.template);
6423             valdst->v.autolabel.autolabel = valsrc->v.autolabel.autolabel;
6424             break;
6425         }
6426     }
6427 }
6428
6429 static void
6430 merge_proplist_foreach_fn(
6431     gpointer key_p,
6432     gpointer value_p,
6433     gpointer user_data_p)
6434 {
6435     char *property_s = key_p;
6436     property_t *property = value_p;
6437     proplist_t proplist = user_data_p;
6438     GSList *elem = NULL;
6439     int new_prop = 0;
6440     property_t *new_property = g_hash_table_lookup(proplist, property_s);
6441     if (new_property && !property->append) {
6442         g_hash_table_remove(proplist, property_s);
6443         new_property = NULL;
6444     }
6445     if (!new_property) {
6446         new_property = malloc(sizeof(property_t));
6447         new_property->append = property->append;
6448         new_property->priority = property->priority;
6449         new_property->values = NULL;
6450         new_prop = 1;
6451     }
6452
6453     for(elem = property->values;elem != NULL; elem=elem->next) {
6454         new_property->values = g_slist_append(new_property->values,
6455                                               stralloc(elem->data));
6456     }
6457     if (new_prop)
6458         g_hash_table_insert(proplist, stralloc(property_s), new_property);
6459 }
6460
6461 static void
6462 copy_proplist_foreach_fn(
6463     gpointer key_p,
6464     gpointer value_p,
6465     gpointer user_data_p)
6466 {
6467     char *property_s = key_p;
6468     property_t *property = value_p;
6469     proplist_t proplist = user_data_p;
6470     GSList *elem = NULL;
6471     property_t *new_property = malloc(sizeof(property_t));
6472     new_property->append = property->append;
6473     new_property->priority = property->priority;
6474     new_property->values = NULL;
6475
6476     for(elem = property->values;elem != NULL; elem=elem->next) {
6477         new_property->values = g_slist_append(new_property->values,
6478                                               stralloc(elem->data));
6479     }
6480     g_hash_table_insert(proplist, stralloc(property_s), new_property);
6481 }
6482
6483 static void
6484 free_val_t(
6485     val_t *val)
6486 {
6487     switch(val->type) {
6488         case CONFTYPE_INT:
6489         case CONFTYPE_BOOLEAN:
6490         case CONFTYPE_COMPRESS:
6491         case CONFTYPE_ENCRYPT:
6492         case CONFTYPE_HOLDING:
6493         case CONFTYPE_EXECUTE_WHERE:
6494         case CONFTYPE_EXECUTE_ON:
6495         case CONFTYPE_SEND_AMREPORT_ON:
6496         case CONFTYPE_DATA_PATH:
6497         case CONFTYPE_STRATEGY:
6498         case CONFTYPE_SIZE:
6499         case CONFTYPE_TAPERALGO:
6500         case CONFTYPE_PRIORITY:
6501         case CONFTYPE_INT64:
6502         case CONFTYPE_REAL:
6503         case CONFTYPE_RATE:
6504         case CONFTYPE_INTRANGE:
6505         case CONFTYPE_PART_CACHE_TYPE:
6506             break;
6507
6508         case CONFTYPE_IDENT:
6509         case CONFTYPE_STR:
6510         case CONFTYPE_APPLICATION:
6511             amfree(val->v.s);
6512             break;
6513
6514         case CONFTYPE_IDENTLIST:
6515             slist_free_full(val->v.identlist, g_free);
6516             break;
6517
6518         case CONFTYPE_RECOVERY_LIMIT:
6519             slist_free_full(val->v.recovery_limit.match_pats, g_free);
6520             break;
6521
6522         case CONFTYPE_TIME:
6523             break;
6524
6525         case CONFTYPE_ESTIMATELIST:
6526             g_slist_free(val->v.estimatelist);
6527             break;
6528
6529         case CONFTYPE_EXINCLUDE:
6530             free_sl(val_t__exinclude(val).sl_list);
6531             free_sl(val_t__exinclude(val).sl_file);
6532             break;
6533
6534         case CONFTYPE_PROPLIST:
6535             g_hash_table_destroy(val_t__proplist(val));
6536             break;
6537
6538         case CONFTYPE_AUTOLABEL:
6539             amfree(val->v.autolabel.template);
6540             break;
6541     }
6542     val->seen.linenum = 0;
6543     val->seen.filename = NULL;
6544 }
6545
6546 /*
6547  * Utilities Implementation
6548  */
6549
6550 char *
6551 generic_get_security_conf(
6552         char *string,
6553         void *arg)
6554 {
6555         arg = arg;
6556         if(!string || !*string)
6557                 return(NULL);
6558
6559         if(strcmp(string, "krb5principal")==0) {
6560                 return(getconf_str(CNF_KRB5PRINCIPAL));
6561         } else if(strcmp(string, "krb5keytab")==0) {
6562                 return(getconf_str(CNF_KRB5KEYTAB));
6563         }
6564         return(NULL);
6565 }
6566
6567 char *
6568 generic_client_get_security_conf(
6569     char *      string,
6570     void *      arg)
6571 {
6572         (void)arg;      /* Quiet unused parameter warning */
6573
6574         if(!string || !*string)
6575                 return(NULL);
6576
6577         if(strcmp(string, "conf")==0) {
6578                 return(getconf_str(CNF_CONF));
6579         } else if(strcmp(string, "index_server")==0) {
6580                 return(getconf_str(CNF_INDEX_SERVER));
6581         } else if(strcmp(string, "tape_server")==0) {
6582                 return(getconf_str(CNF_TAPE_SERVER));
6583         } else if(strcmp(string, "tapedev")==0) {
6584                 return(getconf_str(CNF_TAPEDEV));
6585         } else if(strcmp(string, "auth")==0) {
6586                 return(getconf_str(CNF_AUTH));
6587         } else if(strcmp(string, "ssh_keys")==0) {
6588                 return(getconf_str(CNF_SSH_KEYS));
6589         } else if(strcmp(string, "amandad_path")==0) {
6590                 return(getconf_str(CNF_AMANDAD_PATH));
6591         } else if(strcmp(string, "client_username")==0) {
6592                 return(getconf_str(CNF_CLIENT_USERNAME));
6593         } else if(strcmp(string, "client_port")==0) {
6594                 return(getconf_str(CNF_CLIENT_PORT));
6595         } else if(strcmp(string, "gnutar_list_dir")==0) {
6596                 return(getconf_str(CNF_GNUTAR_LIST_DIR));
6597         } else if(strcmp(string, "amandates")==0) {
6598                 return(getconf_str(CNF_AMANDATES));
6599         } else if(strcmp(string, "krb5principal")==0) {
6600                 return(getconf_str(CNF_KRB5PRINCIPAL));
6601         } else if(strcmp(string, "krb5keytab")==0) {
6602                 return(getconf_str(CNF_KRB5KEYTAB));
6603         }
6604         return(NULL);
6605 }
6606
6607 void
6608 dump_configuration(void)
6609 {
6610     tapetype_t *tp;
6611     dumptype_t *dp;
6612     interface_t *ip;
6613     holdingdisk_t *hd;
6614     GSList        *hp;
6615     application_t *ap;
6616     pp_script_t *ps;
6617     device_config_t *dc;
6618     changer_config_t *cc;
6619     int i;
6620     conf_var_t *np;
6621     keytab_t *kt;
6622     char *prefix;
6623
6624     if (config_client) {
6625         error(_("Don't know how to dump client configurations."));
6626         /* NOTREACHED */
6627     }
6628
6629     g_printf(_("# AMANDA CONFIGURATION FROM FILE \"%s\":\n\n"), config_filename);
6630
6631     for(np=server_var; np->token != CONF_UNKNOWN; np++) {
6632         for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) 
6633             if (np->token == kt->token) break;
6634
6635         if(kt->token == CONF_UNKNOWN)
6636             error(_("server bad token"));
6637
6638         val_t_print_token(stdout, NULL, "%-21s ", kt, &conf_data[np->parm]);
6639     }
6640
6641     for(hp = holdinglist; hp != NULL; hp = hp->next) {
6642         hd = hp->data;
6643         g_printf("\nDEFINE HOLDINGDISK %s {\n", hd->name);
6644         for(i=0; i < HOLDING_HOLDING; i++) {
6645             for(np=holding_var; np->token != CONF_UNKNOWN; np++) {
6646                 if(np->parm == i)
6647                         break;
6648             }
6649             if(np->token == CONF_UNKNOWN)
6650                 error(_("holding bad value"));
6651
6652             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) {
6653                 if(kt->token == np->token)
6654                     break;
6655             }
6656             if(kt->token == CONF_UNKNOWN)
6657                 error(_("holding bad token"));
6658
6659             val_t_print_token(stdout, NULL, "      %-9s ", kt, &hd->value[i]);
6660         }
6661         g_printf("}\n");
6662     }
6663
6664     for(tp = tapelist; tp != NULL; tp = tp->next) {
6665         if(tp->seen.linenum == -1)
6666             prefix = "#";
6667         else
6668             prefix = "";
6669         g_printf("\n%sDEFINE TAPETYPE %s {\n", prefix, tp->name);
6670         for(i=0; i < TAPETYPE_TAPETYPE; i++) {
6671             for(np=tapetype_var; np->token != CONF_UNKNOWN; np++)
6672                 if(np->parm == i) break;
6673             if(np->token == CONF_UNKNOWN)
6674                 error(_("tapetype bad value"));
6675
6676             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
6677                 if(kt->token == np->token) break;
6678             if(kt->token == CONF_UNKNOWN)
6679                 error(_("tapetype bad token"));
6680
6681             val_t_print_token(stdout, prefix, "      %-9s ", kt, &tp->value[i]);
6682         }
6683         g_printf("%s}\n", prefix);
6684     }
6685
6686     for(dp = dumplist; dp != NULL; dp = dp->next) {
6687         if (strncmp_const(dp->name, "custom(") != 0) { /* don't dump disklist-derived dumptypes */
6688             if(dp->seen.linenum == -1)
6689                 prefix = "#";
6690             else
6691                 prefix = "";
6692             g_printf("\n%sDEFINE DUMPTYPE %s {\n", prefix, dp->name);
6693             for(i=0; i < DUMPTYPE_DUMPTYPE; i++) {
6694                 for(np=dumptype_var; np->token != CONF_UNKNOWN; np++)
6695                     if(np->parm == i) break;
6696                 if(np->token == CONF_UNKNOWN)
6697                     error(_("dumptype bad value"));
6698
6699                 for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
6700                     if(kt->token == np->token) break;
6701                 if(kt->token == CONF_UNKNOWN)
6702                     error(_("dumptype bad token"));
6703
6704                 val_t_print_token(stdout, prefix, "      %-19s ", kt, &dp->value[i]);
6705             }
6706             g_printf("%s}\n", prefix);
6707         }
6708     }
6709
6710     for(ip = interface_list; ip != NULL; ip = ip->next) {
6711         seen_t *netusage_seen = &val_t__seen(getconf(CNF_NETUSAGE));
6712         if (ip->seen.linenum == netusage_seen->linenum &&
6713             ip->seen.filename && netusage_seen->filename &&
6714             0 == strcmp(ip->seen.filename, netusage_seen->filename))
6715             prefix = "#";
6716         else
6717             prefix = "";
6718         g_printf("\n%sDEFINE INTERFACE %s {\n", prefix, ip->name);
6719         for(i=0; i < INTER_INTER; i++) {
6720             for(np=interface_var; np->token != CONF_UNKNOWN; np++)
6721                 if(np->parm == i) break;
6722             if(np->token == CONF_UNKNOWN)
6723                 error(_("interface bad value"));
6724
6725             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
6726                 if(kt->token == np->token) break;
6727             if(kt->token == CONF_UNKNOWN)
6728                 error(_("interface bad token"));
6729
6730             val_t_print_token(stdout, prefix, "      %-19s ", kt, &ip->value[i]);
6731         }
6732         g_printf("%s}\n",prefix);
6733     }
6734
6735     for(ap = application_list; ap != NULL; ap = ap->next) {
6736         if(strcmp(ap->name,"default") == 0)
6737             prefix = "#";
6738         else
6739             prefix = "";
6740         g_printf("\n%sDEFINE APPLICATION %s {\n", prefix, ap->name);
6741         for(i=0; i < APPLICATION_APPLICATION; i++) {
6742             for(np=application_var; np->token != CONF_UNKNOWN; np++)
6743                 if(np->parm == i) break;
6744             if(np->token == CONF_UNKNOWN)
6745                 error(_("application bad value"));
6746
6747             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
6748                 if(kt->token == np->token) break;
6749             if(kt->token == CONF_UNKNOWN)
6750                 error(_("application bad token"));
6751
6752             val_t_print_token(stdout, prefix, "      %-19s ", kt, &ap->value[i]);
6753         }
6754         g_printf("%s}\n",prefix);
6755     }
6756
6757     for(ps = pp_script_list; ps != NULL; ps = ps->next) {
6758         if(strcmp(ps->name,"default") == 0)
6759             prefix = "#";
6760         else
6761             prefix = "";
6762         g_printf("\n%sDEFINE SCRIPT %s {\n", prefix, ps->name);
6763         for(i=0; i < PP_SCRIPT_PP_SCRIPT; i++) {
6764             for(np=pp_script_var; np->token != CONF_UNKNOWN; np++)
6765                 if(np->parm == i) break;
6766             if(np->token == CONF_UNKNOWN)
6767                 error(_("script bad value"));
6768
6769             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
6770                 if(kt->token == np->token) break;
6771             if(kt->token == CONF_UNKNOWN)
6772                 error(_("script bad token"));
6773
6774             val_t_print_token(stdout, prefix, "      %-19s ", kt, &ps->value[i]);
6775         }
6776         g_printf("%s}\n",prefix);
6777     }
6778
6779     for(dc = device_config_list; dc != NULL; dc = dc->next) {
6780         prefix = "";
6781         g_printf("\n%sDEFINE DEVICE %s {\n", prefix, dc->name);
6782         for(i=0; i < DEVICE_CONFIG_DEVICE_CONFIG; i++) {
6783             for(np=device_config_var; np->token != CONF_UNKNOWN; np++)
6784                 if(np->parm == i) break;
6785             if(np->token == CONF_UNKNOWN)
6786                 error(_("device bad value"));
6787
6788             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
6789                 if(kt->token == np->token) break;
6790             if(kt->token == CONF_UNKNOWN)
6791                 error(_("device bad token"));
6792
6793             val_t_print_token(stdout, prefix, "      %-19s ", kt, &dc->value[i]);
6794         }
6795         g_printf("%s}\n",prefix);
6796     }
6797
6798     for(cc = changer_config_list; cc != NULL; cc = cc->next) {
6799         prefix = "";
6800         g_printf("\n%sDEFINE CHANGER %s {\n", prefix, cc->name);
6801         for(i=0; i < CHANGER_CONFIG_CHANGER_CONFIG; i++) {
6802             for(np=changer_config_var; np->token != CONF_UNKNOWN; np++)
6803                 if(np->parm == i) break;
6804             if(np->token == CONF_UNKNOWN)
6805                 error(_("changer bad value"));
6806
6807             for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++)
6808                 if(kt->token == np->token) break;
6809             if(kt->token == CONF_UNKNOWN)
6810                 error(_("changer bad token"));
6811
6812             val_t_print_token(stdout, prefix, "      %-19s ", kt, &cc->value[i]);
6813         }
6814         g_printf("%s}\n",prefix);
6815     }
6816 }
6817
6818 static void
6819 val_t_print_token(
6820     FILE     *output,
6821     char     *prefix,
6822     char     *format,
6823     keytab_t *kt,
6824     val_t    *val)
6825 {
6826     char       **dispstrs, **dispstr;
6827     dispstrs = val_t_display_strs(val, 1);
6828
6829     /* For most configuration types, this outputs
6830      *   PREFIX KEYWORD DISPSTR
6831      * for each of the display strings.  For identifiers, however, it
6832      * simply prints the first line of the display string.
6833      */
6834
6835     /* Print the keyword for anything that is not itself an identifier */
6836     if (kt->token != CONF_IDENT) {
6837         for(dispstr=dispstrs; *dispstr!=NULL; dispstr++) {
6838             if (prefix)
6839                 g_fprintf(output, "%s", prefix);
6840             g_fprintf(output, format, str_keyword(kt));
6841             g_fprintf(output, "%s\n", *dispstr);
6842         }
6843     } else {
6844         /* for identifiers, assume there's at most one display string */
6845         assert(g_strv_length(dispstrs) <= 1);
6846         if (*dispstrs) {
6847             g_fprintf(output, "%s\n", *dispstrs);
6848         }
6849     }
6850
6851     g_strfreev(dispstrs);
6852 }
6853
6854 char **
6855 val_t_display_strs(
6856     val_t *val,
6857     int    str_need_quote)
6858 {
6859     char **buf;
6860     buf = malloc(3*SIZEOF(char *));
6861     buf[0] = NULL;
6862     buf[1] = NULL;
6863     buf[2] = NULL;
6864
6865     switch(val->type) {
6866     case CONFTYPE_INT:
6867         buf[0] = vstrallocf("%d", val_t__int(val));
6868         break;
6869
6870     case CONFTYPE_SIZE:
6871         buf[0] = vstrallocf("%zd", (ssize_t)val_t__size(val));
6872         break;
6873
6874     case CONFTYPE_INT64:
6875         buf[0] = vstrallocf("%lld", (long long)val_t__int64(val));
6876         break;
6877
6878     case CONFTYPE_REAL:
6879         buf[0] = vstrallocf("%0.5f", val_t__real(val));
6880         break;
6881
6882     case CONFTYPE_RATE:
6883         buf[0] = vstrallocf("%0.5f %0.5f", val_t__rate(val)[0], val_t__rate(val)[1]);
6884         break;
6885
6886     case CONFTYPE_INTRANGE:
6887         buf[0] = vstrallocf("%d,%d", val_t__intrange(val)[0], val_t__intrange(val)[1]);
6888         break;
6889
6890     case CONFTYPE_IDENT:
6891         if(val->v.s) {
6892             buf[0] = stralloc(val->v.s);
6893         } else {
6894             buf[0] = stralloc("");
6895         }
6896         break;
6897
6898     case CONFTYPE_IDENTLIST:
6899         {
6900             GSList *ia;
6901             int     first = 1;
6902
6903             buf[0] = NULL;
6904             for (ia = val->v.identlist; ia != NULL; ia = ia->next) {
6905                 if (first) {
6906                     buf[0] = stralloc(ia->data);
6907                     first = 0;
6908                 } else {
6909                     strappend(buf[0], " ");
6910                     strappend(buf[0],  ia->data);
6911                 }
6912             }
6913         }
6914         break;
6915
6916     case CONFTYPE_STR:
6917         if(str_need_quote) {
6918             if(val->v.s) {
6919                 buf[0] = quote_string_always(val->v.s);
6920             } else {
6921                 buf[0] = stralloc("\"\"");
6922             }
6923         } else {
6924             if(val->v.s) {
6925                 buf[0] = stralloc(val->v.s);
6926             } else {
6927                 buf[0] = stralloc("");
6928             }
6929         }
6930         break;
6931
6932     case CONFTYPE_AUTOLABEL:
6933         {
6934             buf[0] = quote_string_always(val->v.autolabel.template);
6935             if (val->v.autolabel.autolabel & AL_OTHER_CONFIG) {
6936                 buf[0] = vstrextend(&buf[0], " OTHER-CONFIG", NULL);
6937             }
6938             if (val->v.autolabel.autolabel & AL_NON_AMANDA) {
6939                 buf[0] = vstrextend(&buf[0], " NON-AMANDA", NULL);
6940             }
6941             if (val->v.autolabel.autolabel & AL_VOLUME_ERROR) {
6942                 buf[0] = vstrextend(&buf[0], " VOLUME-ERROR", NULL);
6943             }
6944             if (val->v.autolabel.autolabel & AL_EMPTY) {
6945                 buf[0] = vstrextend(&buf[0], " EMPTY", NULL);
6946             }
6947         }
6948         break;
6949
6950     case CONFTYPE_TIME:
6951         buf[0] = vstrallocf("%2d%02d",
6952                          (int)val_t__time(val)/100, (int)val_t__time(val) % 100);
6953         break;
6954
6955     case CONFTYPE_EXINCLUDE: {
6956         buf[0] = exinclude_display_str(val, 0);
6957         buf[1] = exinclude_display_str(val, 1);
6958         break;
6959     }
6960
6961     case CONFTYPE_BOOLEAN:
6962         if(val_t__boolean(val))
6963             buf[0] = stralloc("yes");
6964         else
6965             buf[0] = stralloc("no");
6966         break;
6967
6968     case CONFTYPE_STRATEGY:
6969         switch(val_t__strategy(val)) {
6970         case DS_SKIP:
6971             buf[0] = vstrallocf("SKIP");
6972             break;
6973
6974         case DS_STANDARD:
6975             buf[0] = vstrallocf("STANDARD");
6976             break;
6977
6978         case DS_NOFULL:
6979             buf[0] = vstrallocf("NOFULL");
6980             break;
6981
6982         case DS_NOINC:
6983             buf[0] = vstrallocf("NOINC");
6984             break;
6985
6986         case DS_HANOI:
6987             buf[0] = vstrallocf("HANOI");
6988             break;
6989
6990         case DS_INCRONLY:
6991             buf[0] = vstrallocf("INCRONLY");
6992             break;
6993         }
6994         break;
6995
6996     case CONFTYPE_COMPRESS:
6997         switch(val_t__compress(val)) {
6998         case COMP_NONE:
6999             buf[0] = vstrallocf("NONE");
7000             break;
7001
7002         case COMP_FAST:
7003             buf[0] = vstrallocf("CLIENT FAST");
7004             break;
7005
7006         case COMP_BEST:
7007             buf[0] = vstrallocf("CLIENT BEST");
7008             break;
7009
7010         case COMP_CUST:
7011             buf[0] = vstrallocf("CLIENT CUSTOM");
7012             break;
7013
7014         case COMP_SERVER_FAST:
7015             buf[0] = vstrallocf("SERVER FAST");
7016             break;
7017
7018         case COMP_SERVER_BEST:
7019             buf[0] = vstrallocf("SERVER BEST");
7020             break;
7021
7022         case COMP_SERVER_CUST:
7023             buf[0] = vstrallocf("SERVER CUSTOM");
7024             break;
7025         }
7026         break;
7027
7028     case CONFTYPE_ESTIMATELIST: {
7029         estimatelist_t es = val_t__estimatelist(val);
7030         buf[0] = stralloc("");
7031         while (es) {
7032             switch((estimate_t)GPOINTER_TO_INT(es->data)) {
7033             case ES_CLIENT:
7034                 strappend(buf[0], "CLIENT");
7035                 break;
7036
7037             case ES_SERVER:
7038                 strappend(buf[0], "SERVER");
7039                 break;
7040
7041             case ES_CALCSIZE:
7042                 strappend(buf[0], "CALCSIZE");
7043                 break;
7044
7045             case ES_ES:
7046                 break;
7047             }
7048             es = es->next;
7049             if (es)
7050                 strappend(buf[0], " ");
7051         }
7052         break;
7053     }
7054
7055     case CONFTYPE_EXECUTE_WHERE:
7056         switch(val->v.i) {
7057         case ES_CLIENT:
7058             buf[0] = vstrallocf("CLIENT");
7059             break;
7060
7061         case ES_SERVER:
7062             buf[0] = vstrallocf("SERVER");
7063             break;
7064         }
7065         break;
7066
7067     case CONFTYPE_SEND_AMREPORT_ON:
7068         switch(val->v.i) {
7069         case SEND_AMREPORT_ALL:
7070             buf[0] = vstrallocf("ALL");
7071             break;
7072         case SEND_AMREPORT_STRANGE:
7073             buf[0] = vstrallocf("STRANGE");
7074             break;
7075         case SEND_AMREPORT_ERROR:
7076             buf[0] = vstrallocf("ERROR");
7077             break;
7078         case SEND_AMREPORT_NEVER:
7079             buf[0] = vstrallocf("NEVER");
7080             break;
7081         }
7082         break;
7083
7084     case CONFTYPE_DATA_PATH:
7085         buf[0] = g_strdup(data_path_to_string(val->v.i));
7086         break;
7087
7088      case CONFTYPE_ENCRYPT:
7089         switch(val_t__encrypt(val)) {
7090         case ENCRYPT_NONE:
7091             buf[0] = vstrallocf("NONE");
7092             break;
7093
7094         case ENCRYPT_CUST:
7095             buf[0] = vstrallocf("CLIENT");
7096             break;
7097
7098         case ENCRYPT_SERV_CUST:
7099             buf[0] = vstrallocf("SERVER");
7100             break;
7101         }
7102         break;
7103
7104      case CONFTYPE_PART_CACHE_TYPE:
7105         switch(val_t__part_cache_type(val)) {
7106         case PART_CACHE_TYPE_NONE:
7107             buf[0] = vstrallocf("NONE");
7108             break;
7109
7110         case PART_CACHE_TYPE_DISK:
7111             buf[0] = vstrallocf("DISK");
7112             break;
7113
7114         case PART_CACHE_TYPE_MEMORY:
7115             buf[0] = vstrallocf("MEMORY");
7116             break;
7117         }
7118         break;
7119
7120      case CONFTYPE_RECOVERY_LIMIT: {
7121         GSList *iter = val_t__recovery_limit(val).match_pats;
7122
7123         if(val_t__recovery_limit(val).same_host)
7124             buf[0] = stralloc("SAME-HOST ");
7125         else
7126             buf[0] = stralloc("");
7127
7128         while (iter) {
7129             strappend(buf[0], quote_string_always((char *)iter->data));
7130             strappend(buf[0], " ");
7131             iter = iter->next;
7132         }
7133         break;
7134      }
7135
7136      case CONFTYPE_HOLDING:
7137         switch(val_t__holding(val)) {
7138         case HOLD_NEVER:
7139             buf[0] = vstrallocf("NEVER");
7140             break;
7141
7142         case HOLD_AUTO:
7143             buf[0] = vstrallocf("AUTO");
7144             break;
7145
7146         case HOLD_REQUIRED:
7147             buf[0] = vstrallocf("REQUIRED");
7148             break;
7149         }
7150         break;
7151
7152      case CONFTYPE_TAPERALGO:
7153         buf[0] = vstrallocf("%s", taperalgo2str(val_t__taperalgo(val)));
7154         break;
7155
7156      case CONFTYPE_PRIORITY:
7157         switch(val_t__priority(val)) {
7158         case 0:
7159             buf[0] = vstrallocf("LOW");
7160             break;
7161
7162         case 1:
7163             buf[0] = vstrallocf("MEDIUM");
7164             break;
7165
7166         case 2:
7167             buf[0] = vstrallocf("HIGH");
7168             break;
7169         }
7170         break;
7171
7172     case CONFTYPE_PROPLIST: {
7173         int    nb_property;
7174         char **mybuf;
7175
7176         nb_property = g_hash_table_size(val_t__proplist(val));
7177         amfree(buf);
7178         buf = malloc((nb_property+1)*SIZEOF(char*));
7179         buf[nb_property] = NULL;
7180         mybuf = buf;
7181         g_hash_table_foreach(val_t__proplist(val),
7182                              proplist_display_str_foreach_fn,
7183                              &mybuf);
7184         break;
7185     }
7186
7187     case CONFTYPE_APPLICATION: {
7188         if (val->v.s) {
7189             buf[0] = quote_string_always(val->v.s);
7190         } else {
7191             buf[0] = stralloc("");
7192         }
7193         break;
7194     }
7195
7196     case CONFTYPE_EXECUTE_ON:
7197         buf[0] = stralloc("");
7198         if (val->v.i != 0) {
7199             char *sep = "";
7200             if (val->v.i & EXECUTE_ON_PRE_DLE_AMCHECK) {
7201                 buf[0] = vstrextend(&buf[0], sep, "PRE-DLE-AMCHECK", NULL);
7202                 sep = ", ";
7203             }
7204             if (val->v.i & EXECUTE_ON_PRE_HOST_AMCHECK) {
7205                 buf[0] = vstrextend(&buf[0], sep, "PRE-HOST-AMCHECK", NULL);
7206                 sep = ", ";
7207             }
7208             if (val->v.i & EXECUTE_ON_POST_DLE_AMCHECK) {
7209                 buf[0] = vstrextend(&buf[0], sep, "POST-DLE-AMCHECK", NULL);
7210                 sep = ", ";
7211             }
7212             if (val->v.i & EXECUTE_ON_POST_HOST_AMCHECK) {
7213                 buf[0] = vstrextend(&buf[0], sep, "POST-HOST-AMCHECK", NULL);
7214                 sep = ", ";
7215             }
7216             if (val->v.i & EXECUTE_ON_PRE_DLE_ESTIMATE) {
7217                 buf[0] = vstrextend(&buf[0], sep, "PRE-DLE-ESTIMATE", NULL);
7218                 sep = ", ";
7219             }
7220             if (val->v.i & EXECUTE_ON_PRE_HOST_ESTIMATE) {
7221                 buf[0] = vstrextend(&buf[0], sep, "PRE-HOST-ESTIMATE", NULL);
7222                 sep = ", ";
7223             }
7224             if (val->v.i & EXECUTE_ON_POST_DLE_ESTIMATE) {
7225                 buf[0] = vstrextend(&buf[0], sep, "POST-DLE-ESTIMATE", NULL);
7226                 sep = ", ";
7227             }
7228             if (val->v.i & EXECUTE_ON_POST_HOST_ESTIMATE) {
7229                 buf[0] = vstrextend(&buf[0], sep, "POST-HOST-ESTIMATE", NULL);
7230                 sep = ", ";
7231             }
7232             if (val->v.i & EXECUTE_ON_PRE_DLE_BACKUP) {
7233                 buf[0] = vstrextend(&buf[0], sep, "PRE-DLE-BACKUP", NULL);
7234                 sep = ", ";
7235             }
7236             if (val->v.i & EXECUTE_ON_PRE_HOST_BACKUP) {
7237                 buf[0] = vstrextend(&buf[0], sep, "PRE-HOST-BACKUP", NULL);
7238                 sep = ", ";
7239             }
7240             if (val->v.i & EXECUTE_ON_POST_DLE_BACKUP) {
7241                 buf[0] = vstrextend(&buf[0], sep, "POST-DLE-BACKUP", NULL);
7242                 sep = ", ";
7243             }
7244             if (val->v.i & EXECUTE_ON_POST_HOST_BACKUP) {
7245                 buf[0] = vstrextend(&buf[0], sep, "POST-HOST-BACKUP", NULL);
7246                 sep = ", ";
7247             }
7248             if (val->v.i & EXECUTE_ON_PRE_RECOVER) {
7249                 buf[0] = vstrextend(&buf[0], sep, "PRE-RECOVER", NULL);
7250                 sep = ", ";
7251             }
7252             if (val->v.i & EXECUTE_ON_POST_RECOVER) {
7253                 buf[0] = vstrextend(&buf[0], sep, "POST-RECOVER", NULL);
7254                 sep = ", ";
7255             }
7256             if (val->v.i & EXECUTE_ON_PRE_LEVEL_RECOVER) {
7257                 buf[0] = vstrextend(&buf[0], sep, "PRE-LEVEL-RECOVER", NULL);
7258                 sep = ", ";
7259             }
7260             if (val->v.i & EXECUTE_ON_POST_LEVEL_RECOVER) {
7261                 buf[0] = vstrextend(&buf[0], sep, "POST-LEVEL-RECOVER", NULL);
7262                 sep = ", ";
7263             }
7264             if (val->v.i & EXECUTE_ON_INTER_LEVEL_RECOVER) {
7265                 buf[0] = vstrextend(&buf[0], sep, "INTER-LEVEL-RECOVER", NULL);
7266                 sep = ", ";
7267             }
7268         }
7269         break;
7270
7271     }
7272     return buf;
7273 }
7274
7275 int
7276 val_t_to_execute_on(
7277     val_t *val)
7278 {
7279     if (val->type != CONFTYPE_EXECUTE_ON) {
7280         error(_("get_conftype_execute_on: val.type is not CONFTYPE_EXECUTE_ON"));
7281         /*NOTREACHED*/
7282     }
7283     return val_t__execute_on(val);
7284 }
7285
7286 int
7287 val_t_to_execute_where(
7288     val_t *val)
7289 {
7290     if (val->type != CONFTYPE_EXECUTE_WHERE) {
7291         error(_("get_conftype_execute_where: val.type is not CONFTYPE_EXECUTE_WHERE"));
7292         /*NOTREACHED*/
7293     }
7294     return val->v.i;
7295 }
7296
7297 char *
7298 val_t_to_application(
7299     val_t *val)
7300 {
7301     if (val->type != CONFTYPE_APPLICATION) {
7302         error(_("get_conftype_applicaiton: val.type is not CONFTYPE_APPLICATION"));
7303         /*NOTREACHED*/
7304     }
7305     return val->v.s;
7306 }
7307
7308
7309 static void
7310 proplist_display_str_foreach_fn(
7311     gpointer key_p,
7312     gpointer value_p,
7313     gpointer user_data_p)
7314 {
7315     char         *property_s = quote_string_always(key_p);
7316     property_t   *property   = value_p;
7317     GSList       *value;
7318     char       ***msg        = (char ***)user_data_p;
7319
7320     /* What to do with property->append? it should be printed only on client */
7321     if (property->priority) {
7322         **msg = vstralloc("priority ", property_s, NULL);
7323         amfree(property_s);
7324     } else {
7325         **msg = property_s;
7326         property_s = NULL;
7327     }
7328     for(value=property->values; value != NULL; value = value->next) {
7329         char *qstr = quote_string_always((char *)value->data);
7330         **msg = vstrextend(*msg, " ", qstr, NULL);
7331         amfree(qstr);
7332     }
7333     (*msg)++;
7334 }
7335
7336 static char *
7337 exinclude_display_str(
7338     val_t *val,
7339     int    file)
7340 {
7341     sl_t  *sl;
7342     sle_t *excl;
7343     char *rval;
7344
7345     assert(val->type == CONFTYPE_EXINCLUDE);
7346
7347     rval = stralloc("");
7348
7349     if (file == 0) {
7350         sl = val_t__exinclude(val).sl_list;
7351         strappend(rval, "LIST");
7352     } else {
7353         sl = val_t__exinclude(val).sl_file;
7354         strappend(rval, "FILE");
7355     }
7356
7357     if (val_t__exinclude(val).optional == 1) {
7358         strappend(rval, " OPTIONAL");
7359     }
7360
7361     if (sl != NULL) {
7362         for(excl = sl->first; excl != NULL; excl = excl->next) {
7363             char *qstr = quote_string_always(excl->name);
7364             vstrextend(&rval, " ", qstr, NULL);
7365             amfree(qstr);
7366         }
7367     }
7368
7369     return rval;
7370 }
7371
7372 char *
7373 taperalgo2str(
7374     taperalgo_t taperalgo)
7375 {
7376     if(taperalgo == ALGO_FIRST) return "FIRST";
7377     if(taperalgo == ALGO_FIRSTFIT) return "FIRSTFIT";
7378     if(taperalgo == ALGO_LARGEST) return "LARGEST";
7379     if(taperalgo == ALGO_LARGESTFIT) return "LARGESTFIT";
7380     if(taperalgo == ALGO_SMALLEST) return "SMALLEST";
7381     if(taperalgo == ALGO_LAST) return "LAST";
7382     return "UNKNOWN";
7383 }
7384
7385 char *
7386 config_dir_relative(
7387     char *filename)
7388 {
7389     if (*filename == '/' || config_dir == NULL) {
7390         return stralloc(filename);
7391     } else {
7392         if (config_dir[strlen(config_dir)-1] == '/') {
7393             return vstralloc(config_dir, filename, NULL);
7394         } else {
7395             return vstralloc(config_dir, "/", filename, NULL);
7396         }
7397     }
7398 }
7399
7400 static int
7401 parm_key_info(
7402     char *key,
7403     conf_var_t **parm,
7404     val_t **val)
7405 {
7406     conf_var_t *np;
7407     keytab_t *kt;
7408     char *s;
7409     char ch;
7410     char *subsec_type;
7411     char *subsec_name;
7412     char *subsec_key;
7413     tapetype_t *tp;
7414     dumptype_t *dp;
7415     interface_t *ip;
7416     holdingdisk_t *hp;
7417     application_t *ap;
7418     pp_script_t   *pp;
7419     device_config_t   *dc;
7420     changer_config_t   *cc;
7421     int success = FALSE;
7422
7423     /* WARNING: assumes globals keytable and parsetable are set correctly. */
7424     assert(keytable != NULL);
7425     assert(parsetable != NULL);
7426
7427     /* make a copy we can stomp on */
7428     key = stralloc(key);
7429
7430     /* uppercase the key */
7431     for (s = key; (ch = *s) != 0; s++) {
7432         if (islower((int)ch))
7433             *s = (char)toupper(ch);
7434     }
7435
7436     subsec_name = strchr(key, ':');
7437     if (subsec_name) {
7438         subsec_type = key;
7439
7440         *subsec_name = '\0';
7441         subsec_name++;
7442
7443         /* convert subsec_type '-' to '_' */
7444         for (s = subsec_type; (ch = *s) != 0; s++) {
7445             if (*s == '-') *s = '_';
7446         }
7447
7448         subsec_key = strchr(subsec_name,':');
7449         if(!subsec_key) goto out; /* failure */
7450
7451         *subsec_key = '\0';
7452         subsec_key++;
7453
7454         /* convert subsec_key '-' to '_' */
7455         for (s = subsec_key; (ch = *s) != 0; s++) {
7456             if (*s == '-') *s = '_';
7457         }
7458
7459         /* If the keyword doesn't exist, there's no need to look up the
7460          * subsection -- we know it's invalid */
7461         for(kt = keytable; kt->token != CONF_UNKNOWN; kt++) {
7462             if(kt->keyword && strcmp(kt->keyword, subsec_key) == 0)
7463                 break;
7464         }
7465         if(kt->token == CONF_UNKNOWN) goto out;
7466
7467         /* Otherwise, figure out which kind of subsection we're dealing with,
7468          * and parse against that. */
7469         if (strcmp(subsec_type, "TAPETYPE") == 0) {
7470             tp = lookup_tapetype(subsec_name);
7471             if (!tp) goto out;
7472             for(np = tapetype_var; np->token != CONF_UNKNOWN; np++) {
7473                 if(np->token == kt->token)
7474                    break;
7475             }
7476             if (np->token == CONF_UNKNOWN) goto out;
7477
7478             if (val) *val = &tp->value[np->parm];
7479             if (parm) *parm = np;
7480             success = TRUE;
7481         } else if (strcmp(subsec_type, "DUMPTYPE") == 0) {
7482             dp = lookup_dumptype(subsec_name);
7483             if (!dp) goto out;
7484             for(np = dumptype_var; np->token != CONF_UNKNOWN; np++) {
7485                 if(np->token == kt->token)
7486                    break;
7487             }
7488             if (np->token == CONF_UNKNOWN) goto out;
7489
7490             if (val) *val = &dp->value[np->parm];
7491             if (parm) *parm = np;
7492             success = TRUE;
7493         } else if (strcmp(subsec_type, "HOLDINGDISK") == 0) {
7494             hp = lookup_holdingdisk(subsec_name);
7495             if (!hp) goto out;
7496             for(np = holding_var; np->token != CONF_UNKNOWN; np++) {
7497                 if(np->token == kt->token)
7498                    break;
7499             }
7500             if (np->token == CONF_UNKNOWN) goto out;
7501
7502             if (val) *val = &hp->value[np->parm];
7503             if (parm) *parm = np;
7504             success = TRUE;
7505         } else if (strcmp(subsec_type, "INTERFACE") == 0) {
7506             ip = lookup_interface(subsec_name);
7507             if (!ip) goto out;
7508             for(np = interface_var; np->token != CONF_UNKNOWN; np++) {
7509                 if(np->token == kt->token)
7510                    break;
7511             }
7512             if (np->token == CONF_UNKNOWN) goto out;
7513
7514             if (val) *val = &ip->value[np->parm];
7515             if (parm) *parm = np;
7516             success = TRUE;
7517         /* accept the old name here, too */
7518         } else if (strcmp(subsec_type, "APPLICATION_TOOL") == 0
7519                 || strcmp(subsec_type, "APPLICATION") == 0) {
7520             ap = lookup_application(subsec_name);
7521             if (!ap) goto out;
7522             for(np = application_var; np->token != CONF_UNKNOWN; np++) {
7523                 if(np->token == kt->token)
7524                    break;
7525             }
7526             if (np->token == CONF_UNKNOWN) goto out;
7527
7528             if (val) *val = &ap->value[np->parm];
7529             if (parm) *parm = np;
7530             success = TRUE;
7531         /* accept the old name here, too */
7532         } else if (strcmp(subsec_type, "SCRIPT_TOOL") == 0
7533                 || strcmp(subsec_type, "SCRIPT") == 0) {
7534             pp = lookup_pp_script(subsec_name);
7535             if (!pp) goto out;
7536             for(np = pp_script_var; np->token != CONF_UNKNOWN; np++) {
7537                 if(np->token == kt->token)
7538                    break;
7539             }
7540             if (np->token == CONF_UNKNOWN) goto out;
7541
7542             if (val) *val = &pp->value[np->parm];
7543             if (parm) *parm = np;
7544             success = TRUE;
7545         } else if (strcmp(subsec_type, "DEVICE") == 0) {
7546             dc = lookup_device_config(subsec_name);
7547             if (!dc) goto out;
7548             for(np = device_config_var; np->token != CONF_UNKNOWN; np++) {
7549                 if(np->token == kt->token)
7550                    break;
7551             }
7552             if (np->token == CONF_UNKNOWN) goto out;
7553
7554             if (val) *val = &dc->value[np->parm];
7555             if (parm) *parm = np;
7556             success = TRUE;
7557         } else if (strcmp(subsec_type, "CHANGER") == 0) {
7558             cc = lookup_changer_config(subsec_name);
7559             if (!cc) goto out;
7560             for(np = changer_config_var; np->token != CONF_UNKNOWN; np++) {
7561                 if(np->token == kt->token)
7562                    break;
7563             }
7564             if (np->token == CONF_UNKNOWN) goto out;
7565
7566             if (val) *val = &cc->value[np->parm];
7567             if (parm) *parm = np;
7568             success = TRUE;
7569         }
7570
7571     /* No delimiters -- we're referencing a global config parameter */
7572     } else {
7573         /* convert key '-' to '_' */
7574         for (s = key; (ch = *s) != 0; s++) {
7575             if (*s == '-') *s = '_';
7576         }
7577
7578         /* look up the keyword */
7579         for(kt = keytable; kt->token != CONF_UNKNOWN; kt++) {
7580             if(kt->keyword && strcmp(kt->keyword, key) == 0)
7581                 break;
7582         }
7583         if(kt->token == CONF_UNKNOWN) goto out;
7584
7585         /* and then look that up in the parse table */
7586         for(np = parsetable; np->token != CONF_UNKNOWN; np++) {
7587             if(np->token == kt->token)
7588                 break;
7589         }
7590         if(np->token == CONF_UNKNOWN) goto out;
7591
7592         if (val) *val = &conf_data[np->parm];
7593         if (parm) *parm = np;
7594         success = TRUE;
7595     }
7596
7597 out:
7598     amfree(key);
7599     return success;
7600 }
7601
7602 gint64 
7603 find_multiplier(
7604     char * str)
7605 {
7606     keytab_t * table_entry;
7607
7608     str = g_strdup(str);
7609     g_strstrip(str);
7610
7611     if (*str == '\0') {
7612         g_free(str);
7613         return 1;
7614     }
7615
7616     for (table_entry = numb_keytable; table_entry->keyword != NULL;
7617          table_entry ++) {
7618         if (strcasecmp(str, table_entry->keyword) == 0) {
7619             g_free(str);
7620             switch (table_entry->token) {
7621             case CONF_MULT1K:
7622                 return 1024;
7623             case CONF_MULT1M:
7624                 return 1024*1024;
7625             case CONF_MULT1G:
7626                 return 1024*1024*1024;
7627             case CONF_MULT1T:
7628                 return (gint64)1024*1024*1024*1024;
7629             case CONF_MULT7:
7630                 return 7;
7631             case CONF_AMINFINITY:
7632                 return G_MAXINT64;
7633             case CONF_MULT1:
7634             case CONF_IDENT:
7635                 return 1;
7636             default:
7637                 /* Should not happen. */
7638                 return 0;
7639             }
7640         }
7641     }
7642
7643     /* None found; this is an error. */
7644     g_free(str);
7645     return 0;
7646 }
7647
7648 int
7649 string_to_boolean(
7650     const char *str)
7651 {
7652     keytab_t * table_entry;
7653
7654     if (str == NULL || *str == '\0') {
7655         return -1;
7656     }
7657
7658     /* 0 and 1 are not in the table, as they are parsed as ints */
7659     if (0 == strcmp(str, "0"))
7660         return 0;
7661     if (0 == strcmp(str, "1"))
7662         return 1;
7663
7664     for (table_entry = bool_keytable; table_entry->keyword != NULL;
7665          table_entry ++) {
7666         if (strcasecmp(str, table_entry->keyword) == 0) {
7667             switch (table_entry->token) {
7668             case CONF_ATRUE:
7669                 return 1;
7670             case CONF_AFALSE:
7671                 return 0;
7672             default:
7673                 return -1;
7674             }
7675         }
7676     }
7677
7678     return -1;
7679 }
7680
7681 /*
7682  * Error Handling Implementaiton
7683  */
7684
7685 void config_add_error(
7686     cfgerr_level_t level,
7687     char * errmsg)
7688 {
7689     cfgerr_level = max(cfgerr_level, level);
7690
7691     g_debug("%s", errmsg);
7692     cfgerr_errors = g_slist_append(cfgerr_errors, errmsg);
7693 }
7694
7695 static void conf_error_common(
7696     cfgerr_level_t level,
7697     const char * format,
7698     va_list argp)
7699 {
7700     char *msg = g_strdup_vprintf(format, argp);
7701     char *errstr = NULL;
7702
7703     if(current_line)
7704         errstr = g_strdup_printf(_("argument \"%s\": %s"),
7705                     current_line, msg);
7706     else if (current_filename && current_line_num > 0)
7707         errstr = g_strdup_printf(_("\"%s\", line %d: %s"),
7708                     current_filename, current_line_num, msg);
7709     else
7710         errstr = g_strdup_printf(_("parse error: %s"), msg);
7711     amfree(msg);
7712
7713     config_add_error(level, errstr);
7714 }
7715
7716 printf_arglist_function(void conf_parserror, const char *, format)
7717 {
7718     va_list argp;
7719     
7720     arglist_start(argp, format);
7721     conf_error_common(CFGERR_ERRORS, format, argp);
7722     arglist_end(argp);
7723 }
7724
7725 printf_arglist_function(void conf_parswarn, const char *, format) {
7726     va_list argp;
7727     
7728     arglist_start(argp, format);
7729     conf_error_common(CFGERR_WARNINGS, format, argp);
7730     arglist_end(argp);
7731 }
7732
7733 cfgerr_level_t
7734 config_errors(GSList **errstr)
7735 {
7736     if (errstr)
7737         *errstr = cfgerr_errors;
7738     return cfgerr_level;
7739 }
7740
7741 void
7742 config_clear_errors(void)
7743 {
7744     slist_free_full(cfgerr_errors, g_free);
7745
7746     cfgerr_errors = NULL;
7747     cfgerr_level = CFGERR_OK;
7748 }
7749
7750 void
7751 config_print_errors(void)
7752 {
7753     GSList *iter;
7754
7755     for (iter = cfgerr_errors; iter; iter = g_slist_next(iter)) {
7756         g_fprintf(stderr, "%s\n", (char *)iter->data);
7757     }
7758 }
7759
7760 /* Get the config name */
7761 char *get_config_name(void)
7762 {
7763     return config_name;
7764 }
7765
7766 /* Get the config directory */
7767 char *get_config_dir(void)
7768 {
7769     return config_dir;
7770 }
7771
7772 /* Get the config filename */
7773 char *get_config_filename(void)
7774 {
7775     return config_filename;
7776 }
7777
7778 char *
7779 anonymous_value(void)
7780 {
7781     static char number[NUM_STR_SIZE];
7782     static int value=1;
7783
7784     g_snprintf(number, sizeof(number), "%d", value);
7785
7786     value++;
7787     return number;
7788 }
7789
7790 gint compare_pp_script_order(
7791     gconstpointer a,
7792     gconstpointer b)
7793 {
7794     return pp_script_get_order(lookup_pp_script((char *)a)) > pp_script_get_order(lookup_pp_script((char *)b));
7795 }
7796
7797 char *
7798 data_path_to_string(
7799     data_path_t data_path)
7800 {
7801     switch (data_path) {
7802         case DATA_PATH_AMANDA   : return "AMANDA";
7803         case DATA_PATH_DIRECTTCP: return "DIRECTTCP";
7804     }
7805     error(_("datapath is not DATA_PATH_AMANDA or DATA_PATH_DIRECTTCP"));
7806     /* NOTREACHED */
7807 }
7808
7809 data_path_t
7810 data_path_from_string(
7811     char *data)
7812 {
7813     if (strcmp(data, "AMANDA") == 0)
7814         return DATA_PATH_AMANDA;
7815     if (strcmp(data, "DIRECTTCP") == 0)
7816         return DATA_PATH_DIRECTTCP;
7817     error(_("datapath is not AMANDA or DIRECTTCP :%s:"), data);
7818     /* NOTREACHED */
7819 }
7820
7821 gchar *
7822 amandaify_property_name(
7823     const gchar *name)
7824 {
7825     gchar *ret, *cur_r;
7826     const gchar *cur_o;
7827     if (!name) return NULL;
7828
7829     ret = g_malloc0(strlen(name)+1);
7830     cur_r = ret;
7831     for (cur_o = name; *cur_o; cur_o++) {
7832         if ('_' == *cur_o)
7833             *cur_r = '-';
7834         else
7835             *cur_r = g_ascii_tolower(*cur_o);
7836
7837         cur_r++;
7838     }
7839
7840     return ret;
7841 }
7842
7843 static char keyword_str[1024];
7844
7845 static char *
7846 str_keyword(
7847     keytab_t *kt)
7848 {
7849     char *p = kt->keyword;
7850     char *s = keyword_str;
7851
7852     while(*p != '\0') {
7853         if (*p == '_') {
7854             *s = '-';
7855         } else {
7856             *s = *p;
7857         }
7858         p++;
7859         s++;
7860     }
7861     *s = '\0';
7862
7863     return keyword_str;
7864 }