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