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