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