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