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