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