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