X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=common-src%2Fconffile.c;h=ae50db9c80fea4f97ccba858ee55eee91874abbe;hb=HEAD;hp=986d9b46bbdbdf43b7a4b50d1abb64b80bfe0ace;hpb=d3b2175e084f88c8736ad7073eacbf4670147aec;p=debian%2Famanda diff --git a/common-src/conffile.c b/common-src/conffile.c index 986d9b4..ae50db9 100644 --- a/common-src/conffile.c +++ b/common-src/conffile.c @@ -1,6 +1,7 @@ /* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-2000 University of Maryland at College Park + * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved. * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its @@ -35,228 +36,782 @@ #include "util.h" #include "conffile.h" #include "clock.h" +#include -#ifdef HAVE_LIMITS_H -#include -#endif +/* + * Lexical analysis + */ -#ifndef AMANDATES_FILE -#define AMANDATES_FILE "/etc/amandates" -#endif +/* This module implements its own quixotic lexer and parser, present for historical + * reasons. If this were written from scratch, it would use flex/bison. */ -#ifndef INT_MAX -#define INT_MAX 2147483647 -#endif +/* An enumeration of the various tokens that might appear in a configuration file. + * + * - CONF_UNKNOWN has special meaning as an unrecognized token. + * - CONF_ANY can be used to request any token, rather than requiring a specific + * token. + */ +typedef enum { + CONF_UNKNOWN, CONF_ANY, CONF_COMMA, + CONF_LBRACE, CONF_RBRACE, CONF_NL, + CONF_END, CONF_IDENT, CONF_INT, + CONF_INT64, CONF_BOOL, CONF_REAL, + CONF_STRING, CONF_TIME, CONF_SIZE, + + /* config parameters */ + CONF_INCLUDEFILE, CONF_ORG, CONF_MAILTO, + CONF_DUMPUSER, CONF_TAPECYCLE, CONF_TAPEDEV, + CONF_CHANGERDEV, CONF_CHANGERFILE, CONF_LABELSTR, + CONF_BUMPPERCENT, CONF_BUMPSIZE, CONF_BUMPDAYS, + CONF_BUMPMULT, CONF_ETIMEOUT, CONF_DTIMEOUT, + CONF_CTIMEOUT, CONF_TAPELIST, + CONF_DEVICE_OUTPUT_BUFFER_SIZE, + CONF_DISKFILE, CONF_INFOFILE, CONF_LOGDIR, + CONF_LOGFILE, CONF_DISKDIR, CONF_DISKSIZE, + CONF_INDEXDIR, CONF_NETUSAGE, CONF_INPARALLEL, + CONF_DUMPORDER, CONF_TIMEOUT, CONF_TPCHANGER, + CONF_RUNTAPES, CONF_DEFINE, CONF_DUMPTYPE, + CONF_TAPETYPE, CONF_INTERFACE, CONF_PRINTER, + CONF_MAILER, + CONF_AUTOFLUSH, CONF_RESERVE, CONF_MAXDUMPSIZE, + CONF_COLUMNSPEC, CONF_AMRECOVER_DO_FSF, CONF_AMRECOVER_CHECK_LABEL, + CONF_AMRECOVER_CHANGER, CONF_LABEL_NEW_TAPES, CONF_USETIMESTAMPS, + CONF_CHANGER, + + CONF_TAPERALGO, CONF_FIRST, CONF_FIRSTFIT, + CONF_LARGEST, CONF_LARGESTFIT, CONF_SMALLEST, + CONF_LAST, CONF_DISPLAYUNIT, CONF_RESERVED_UDP_PORT, + CONF_RESERVED_TCP_PORT, CONF_UNRESERVED_TCP_PORT, + CONF_TAPERFLUSH, + CONF_FLUSH_THRESHOLD_DUMPED, + CONF_FLUSH_THRESHOLD_SCHEDULED, + CONF_DEVICE_PROPERTY, CONF_PROPERTY, CONF_PLUGIN, + CONF_APPLICATION, CONF_APPLICATION_TOOL, + CONF_SCRIPT, CONF_SCRIPT_TOOL, + CONF_EXECUTE_ON, CONF_EXECUTE_WHERE, CONF_SEND_AMREPORT_ON, + CONF_DEVICE, CONF_ORDER, CONF_SINGLE_EXECUTION, + CONF_DATA_PATH, CONF_AMANDA, CONF_DIRECTTCP, + CONF_TAPER_PARALLEL_WRITE, CONF_INTERACTIVITY, CONF_TAPERSCAN, + CONF_MAX_DLE_BY_VOLUME, CONF_EJECT_VOLUME, CONF_TMPDIR, + CONF_REPORT_USE_MEDIA, CONF_REPORT_NEXT_MEDIA, + + /* execute on */ + CONF_PRE_AMCHECK, CONF_POST_AMCHECK, + CONF_PRE_DLE_AMCHECK, CONF_PRE_HOST_AMCHECK, + CONF_POST_DLE_AMCHECK, CONF_POST_HOST_AMCHECK, + CONF_PRE_ESTIMATE, CONF_POST_ESTIMATE, + CONF_PRE_DLE_ESTIMATE, CONF_PRE_HOST_ESTIMATE, + CONF_POST_DLE_ESTIMATE, CONF_POST_HOST_ESTIMATE, + CONF_PRE_BACKUP, CONF_POST_BACKUP, + CONF_PRE_DLE_BACKUP, CONF_PRE_HOST_BACKUP, + CONF_POST_DLE_BACKUP, CONF_POST_HOST_BACKUP, + CONF_PRE_RECOVER, CONF_POST_RECOVER, + CONF_PRE_LEVEL_RECOVER, CONF_POST_LEVEL_RECOVER, + CONF_INTER_LEVEL_RECOVER, + + /* kerberos 5 */ + CONF_KRB5KEYTAB, CONF_KRB5PRINCIPAL, + + /* holding disk */ + CONF_COMMENT, CONF_DIRECTORY, CONF_USE, + CONF_CHUNKSIZE, + + /* dump type */ + /*COMMENT,*/ CONF_PROGRAM, CONF_DUMPCYCLE, + CONF_RUNSPERCYCLE, CONF_MAXCYCLE, CONF_MAXDUMPS, + CONF_OPTIONS, CONF_PRIORITY, CONF_FREQUENCY, + CONF_INDEX, CONF_MAXPROMOTEDAY, CONF_STARTTIME, + CONF_COMPRESS, CONF_ENCRYPT, CONF_AUTH, + CONF_STRATEGY, CONF_ESTIMATE, CONF_SKIP_INCR, + CONF_SKIP_FULL, CONF_RECORD, CONF_HOLDING, + CONF_EXCLUDE, CONF_INCLUDE, CONF_KENCRYPT, + CONF_IGNORE, CONF_COMPRATE, CONF_TAPE_SPLITSIZE, + CONF_SPLIT_DISKBUFFER, CONF_FALLBACK_SPLITSIZE,CONF_SRVCOMPPROG, + CONF_CLNTCOMPPROG, CONF_SRV_ENCRYPT, CONF_CLNT_ENCRYPT, + CONF_SRV_DECRYPT_OPT, CONF_CLNT_DECRYPT_OPT, CONF_AMANDAD_PATH, + CONF_CLIENT_USERNAME, CONF_CLIENT_PORT, CONF_ALLOW_SPLIT, + CONF_MAX_WARNINGS, + + /* tape type */ + /*COMMENT,*/ CONF_BLOCKSIZE, + CONF_LBL_TEMPL, CONF_FILEMARK, CONF_LENGTH, + CONF_SPEED, CONF_READBLOCKSIZE, + + /* client conf */ + CONF_CONF, CONF_INDEX_SERVER, CONF_TAPE_SERVER, + CONF_SSH_KEYS, CONF_GNUTAR_LIST_DIR, CONF_AMANDATES, + CONF_AMDUMP_SERVER, + + /* protocol config */ + CONF_REP_TRIES, CONF_CONNECT_TRIES, CONF_REQ_TRIES, + + /* debug config */ + CONF_DEBUG_DAYS, + CONF_DEBUG_AMANDAD, CONF_DEBUG_AMIDXTAPED, CONF_DEBUG_AMINDEXD, + CONF_DEBUG_AMRECOVER, CONF_DEBUG_AUTH, CONF_DEBUG_EVENT, + CONF_DEBUG_HOLDING, CONF_DEBUG_PROTOCOL, CONF_DEBUG_PLANNER, + CONF_DEBUG_DRIVER, CONF_DEBUG_DUMPER, CONF_DEBUG_CHUNKER, + CONF_DEBUG_TAPER, CONF_DEBUG_SELFCHECK, CONF_DEBUG_SENDSIZE, + CONF_DEBUG_SENDBACKUP, CONF_DEBUG_RECOVERY, + + /* network interface */ + /* COMMENT, */ /* USE, */ + + /* dump options (obsolete) */ + CONF_EXCLUDE_FILE, CONF_EXCLUDE_LIST, + + /* compress, estimate, encryption */ + CONF_NONE, CONF_FAST, CONF_BEST, + CONF_SERVER, CONF_CLIENT, CONF_CALCSIZE, + CONF_CUSTOM, + + /* autolabel */ + CONF_AUTOLABEL, CONF_ANY_VOLUME, CONF_OTHER_CONFIG, + CONF_NON_AMANDA, CONF_VOLUME_ERROR, CONF_EMPTY, + CONF_META_AUTOLABEL, + + /* part_cache_type */ + CONF_PART_SIZE, CONF_PART_CACHE_TYPE, CONF_PART_CACHE_DIR, + CONF_PART_CACHE_MAX_SIZE, CONF_DISK, CONF_MEMORY, + + /* host-limit */ + CONF_RECOVERY_LIMIT, CONF_SAME_HOST, CONF_DUMP_LIMIT, + + /* holdingdisk */ + CONF_NEVER, CONF_AUTO, CONF_REQUIRED, + + /* send_amreport */ + CONF_ALL, CONF_STRANGE, CONF_ERROR, + + /* priority */ + CONF_LOW, CONF_MEDIUM, CONF_HIGH, + + /* dump strategy */ + CONF_SKIP, CONF_STANDARD, CONF_NOFULL, + CONF_NOINC, CONF_HANOI, CONF_INCRONLY, + + /* exclude list */ + CONF_LIST, CONF_EFILE, CONF_APPEND, + CONF_OPTIONAL, + + /* numbers */ + CONF_AMINFINITY, CONF_MULT1, CONF_MULT7, + CONF_MULT1K, CONF_MULT1M, CONF_MULT1G, + CONF_MULT1T, + + /* boolean */ + CONF_ATRUE, CONF_AFALSE, + + CONF_CLIENT_NAME, +} tok_t; + +/* A keyword table entry, mapping the given keyword to the given token. + * Note that punctuation, integers, and quoted strings are handled + * internally to the lexer, so they do not appear here. */ +typedef struct { + char *keyword; + tok_t token; +} keytab_t; + +/* The current keyword table, used by all token-related functions */ +static keytab_t *keytable = NULL; + +/* Has a token been "ungotten", and if so, what was it? */ +static int token_pushed; +static tok_t pushed_tok; + +/* The current token and its value. Note that, unlike most other val_t*, + * tokenval's v.s points to statically allocated memory which cannot be + * free()'d. */ +static tok_t tok; +static val_t tokenval; + +/* The current input information: file, filename, line, and character + * (which points somewhere within current_line) */ +static FILE *current_file = NULL; +static char *current_filename = NULL; +static char *current_line = NULL; +static char *current_char = NULL; +static char *current_block = NULL; +static int current_line_num = 0; /* (technically, managed by the parser) */ + +/* A static buffer for storing tokens while they are being scanned. */ +static char tkbuf[4096]; + +/* Return a token formated for output */ +static char *str_keyword(keytab_t *kt); + +static char *str_keyword(keytab_t *kt); +/* Look up the name of the given token in the current keytable */ +static char *get_token_name(tok_t); + +/* Look up a token in keytable, given a string, returning CONF_UNKNOWN + * for unrecognized strings. Search is case-insensitive. */ +static tok_t lookup_keyword(char *str); + +/* Get the next token. If exp is anything but CONF_ANY, and the next token + * does not match, then a parse error is flagged. This function reads from the + * current_* static variables, recognizes keywords against the keytable static + * variable, and places its result in tok and tokenval. */ +static void get_conftoken(tok_t exp); + +/* "Unget" the current token; this supports a 1-token lookahead. */ +static void unget_conftoken(void); -/* this corresponds to the normal output of amanda, but may - * be adapted to any spacing as you like. +/* Tokenizer character-by-character access. */ +static int conftoken_getc(void); +static int conftoken_ungetc(int c); + +static void merge_proplist_foreach_fn(gpointer key_p, + gpointer value_p, + gpointer user_data_p); +static void copy_proplist_foreach_fn(gpointer key_p, + gpointer value_p, + gpointer user_data_p); + +/* + * Parser + */ + +/* A parser table entry. Read as " introduces parameter , + * the data for which will be read by and validated by + * (if not NULL). is only used in formatting + * config overwrites. */ +typedef struct conf_var_s { + tok_t token; + conftype_t type; + void (*read_function) (struct conf_var_s *, val_t*); + int parm; + void (*validate_function) (struct conf_var_s *, val_t *); +} conf_var_t; + +/* This is a list of filenames that are used in 'seen_t' structs. */ +static GSList *seen_filenames = NULL; + +/* get a copy of filename that's stored in seen_filenames so that it won't go + * away until config_uninit. */ +static char *get_seen_filename(char *filename); + +/* If allow_overwrites is true, the a parameter which has already been + * seen will simply overwrite the old value, rather than triggering an + * error. Note that this does not apply to all parameters, e.g., + * device_property */ +static int allow_overwrites; + +/* subsection structs + * + * The 'seen' fields in these structs are useless outside this module; + * they are only used to generate error messages for multiply defined + * subsections. */ -ColumnInfo ColumnData[] = { - { "HostName", 0, 12, 12, 0, "%-*.*s", "HOSTNAME" }, - { "Disk", 1, 11, 11, 0, "%-*.*s", "DISK" }, - { "Level", 1, 1, 1, 0, "%*.*d", "L" }, - { "OrigKB", 1, 7, 0, 0, "%*.*lf", "ORIG-KB" }, - { "OutKB", 1, 7, 0, 0, "%*.*lf", "OUT-KB" }, - { "Compress", 1, 6, 1, 0, "%*.*lf", "COMP%" }, - { "DumpTime", 1, 7, 7, 0, "%*.*s", "MMM:SS" }, - { "DumpRate", 1, 6, 1, 0, "%*.*lf", "KB/s" }, - { "TapeTime", 1, 6, 6, 0, "%*.*s", "MMM:SS" }, - { "TapeRate", 1, 6, 1, 0, "%*.*lf", "KB/s" }, - { NULL, 0, 0, 0, 0, NULL, NULL } +struct tapetype_s { + struct tapetype_s *next; + seen_t seen; + char *name; + + val_t value[TAPETYPE_TAPETYPE]; }; -char *config_name = NULL; -char *config_dir = NULL; +struct dumptype_s { + struct dumptype_s *next; + seen_t seen; + char *name; -int debug_amandad = 0; -int debug_amidxtaped = 0; -int debug_amindexd = 0; -int debug_amrecover = 0; -int debug_auth = 0; -int debug_event = 0; -int debug_holding = 0; -int debug_protocol = 0; -int debug_planner = 0; -int debug_driver = 0; -int debug_dumper = 0; -int debug_chunker = 0; -int debug_taper = 0; -int debug_selfcheck = 0; -int debug_sendsize = 0; -int debug_sendbackup = 0; + val_t value[DUMPTYPE_DUMPTYPE]; +}; -/* visible holding disk variables */ +struct interface_s { + struct interface_s *next; + seen_t seen; + char *name; -holdingdisk_t *holdingdisks; -int num_holdingdisks; + val_t value[INTER_INTER]; +}; -long int unit_divisor = 1; +struct holdingdisk_s { + seen_t seen; + char *name; -/* configuration parameters */ + val_t value[HOLDING_HOLDING]; +}; -val_t conf_data[CNF_CNF]; -int conffile_init = 0; +struct application_s { + struct application_s *next; + seen_t seen; + char *name; -command_option_t *program_options = NULL; -int program_options_size = 0; + val_t value[APPLICATION_APPLICATION]; +}; -/* other internal variables */ -static holdingdisk_t hdcur; +struct pp_script_s { + struct pp_script_s *next; + seen_t seen; + char *name; -static tapetype_t tpcur; + val_t value[PP_SCRIPT_PP_SCRIPT]; +}; -static dumptype_t dpcur; +struct device_config_s { + struct device_config_s *next; + seen_t seen; + char *name; -static interface_t ifcur; + val_t value[DEVICE_CONFIG_DEVICE_CONFIG]; +}; -static dumptype_t *dumplist = NULL; -static tapetype_t *tapelist = NULL; -static interface_t *interface_list = NULL; +struct changer_config_s { + struct changer_config_s *next; + seen_t seen; + char *name; -static int allow_overwrites; -static int token_pushed; -static tok_t tok, pushed_tok; -static val_t tokenval; + val_t value[CHANGER_CONFIG_CHANGER_CONFIG]; +}; -static int conf_line_num; -static int got_parserror; -static FILE *conf_conf = (FILE *)NULL; -static char *conf_confname = NULL; -static char *conf_line = NULL; -static char *conf_char = NULL; -static keytab_t *keytable = NULL; +struct interactivity_s { + struct interactivity_s *next; + seen_t seen; + char *name; -/* predeclare local functions */ - -char *get_token_name(tok_t); - - -static void validate_positive0 (t_conf_var *, val_t *); -static void validate_positive1 (t_conf_var *, val_t *); -static void validate_runspercycle (t_conf_var *, val_t *); -static void validate_bumppercent (t_conf_var *, val_t *); -static void validate_bumpmult (t_conf_var *, val_t *); -static void validate_inparallel (t_conf_var *, val_t *); -static void validate_displayunit (t_conf_var *, val_t *); -static void validate_reserve (t_conf_var *, val_t *); -static void validate_use (t_conf_var *, val_t *); -static void validate_chunksize (t_conf_var *, val_t *); -static void validate_blocksize (t_conf_var *, val_t *); -static void validate_debug (t_conf_var *, val_t *); -static void validate_reserved_port_range (t_conf_var *, val_t *); -static void validate_unreserved_port_range(t_conf_var *, val_t *); - -/*static t_conf_var *get_np(t_conf_var *get_var, int parm);*/ -static int get_int(void); -/*static long get_long(void);*/ -static time_t get_time(void); -static ssize_t get_size(void); -static off_t get_am64_t(void); -static int get_bool(void); -static void ckseen(int *seen); -static void conf_parserror(const char *format, ...) - __attribute__ ((format (printf, 1, 2))); -static tok_t lookup_keyword(char *str); - -static void read_string(t_conf_var *, val_t *); -static void read_ident(t_conf_var *, val_t *); -static void read_int(t_conf_var *, val_t *); -/*static void read_long(t_conf_var *, val_t *);*/ -static void read_size(t_conf_var *, val_t *); -static void read_am64(t_conf_var *, val_t *); -static void read_bool(t_conf_var *, val_t *); -static void read_real(t_conf_var *, val_t *); -static void read_time(t_conf_var *, val_t *); -static void read_intrange(t_conf_var *, val_t *); -static void conf_init_string(val_t *, char *); -static void conf_init_ident(val_t *, char *); -static void conf_init_int(val_t *, int); -static void conf_init_bool(val_t *, int); -static void conf_init_strategy(val_t *, int); -static void conf_init_estimate(val_t *, int); -static void conf_init_taperalgo(val_t *, int); -static void conf_init_priority(val_t *, int); -static void conf_init_strategy(val_t *, int); -static void conf_init_compress(val_t *, comp_t); -static void conf_init_encrypt(val_t *, encrypt_t); -static void conf_init_holding(val_t *, dump_holdingdisk_t); -/*static void conf_init_long(val_t *, long);*/ -static void conf_init_size(val_t *, ssize_t); -static void conf_init_am64(val_t *, off_t); -static void conf_init_real(val_t *, double); -static void conf_init_rate(val_t *, double, double); -static void conf_init_intrange(val_t *, int, int); -static void conf_init_time(val_t *, time_t); -/*static void conf_init_sl(val_t *, sl_t *);*/ -static void conf_init_exinclude(val_t *); -static void conf_set_string(val_t *, char *); -/*static void conf_set_int(val_t *, int);*/ -static void conf_set_bool(val_t *, int); -static void conf_set_compress(val_t *, comp_t); -/*static void conf_set_encrypt(val_t *, encrypt_t);*/ -static void conf_set_holding(val_t *, dump_holdingdisk_t); -static void conf_set_strategy(val_t *, int); + val_t value[INTERACTIVITY_INTERACTIVITY]; +}; -static void init_defaults(void); -static void read_conffile_recursively(char *filename); -static void read_client_conffile_recursively(char *filename); +struct taperscan_s { + struct taperscan_s *next; + seen_t seen; + char *name; -static int read_confline(void); -static int read_client_confline(void); + val_t value[TAPERSCAN_TAPERSCAN]; +}; -static void read_block(command_option_t *command_options, t_conf_var *read_var, - keytab_t *keytab, val_t *valarray, char *prefix, - char *errormsg, int read_brace, - void (*copy_function)(void)); +/* The current parser table */ +static conf_var_t *parsetable = NULL; -static void copy_val_t(val_t *, val_t *); -static void free_val_t(val_t *); -static char *conf_print(val_t *, int, char *); -static void conf_print_exinclude(val_t *, int, int, char *prefix, char **buf, int *free_space); +/* Read and parse a configuration file, recursively reading any included + * files. This function sets the keytable and parsetable appropriately + * according to is_client. + * + * @param filename: configuration file to read + * @param is_client: true if this is a client + * @param missing_ok: is it OK if the file is missing? + */ +static void read_conffile(char *filename, + gboolean is_client, + gboolean missing_ok); + +/* Read and process a line of input from the current file, using the + * current keytable and parsetable. For blocks, this recursively + * reads the entire block. + * + * @param is_client: true if this is a client + * @returns: true on success, false on EOF + */ +static gboolean read_confline(gboolean is_client); + +/* Handle an invalid token, recognizing deprecated tokens as such, + * and producing an appropriate error message. + * + * @param token: the identifier + */ +static void handle_invalid_keyword(const char * token); + +/* Check whether token is deprecated, and issue a warning if it + * is. This consults the global variables 'tok' and 'tokenval' + */ +static void handle_deprecated_keyword(void); -static void get_holdingdisk(void); +/* Read a brace-delimited block using the given parse table. This + * function is used to read brace-delimited subsections in the config + * files and also (via read_dumptype) to read dumptypes from + * the disklist. + * + * This function implements "inheritance" as follows: if a bare + * identifier occurs within the braces, it calls copy_function (if + * not NULL), which looks up an existing subsection using the + * identifier from tokenval and copies any values not already seen + * into valarray. + * + * @param read_var: the parse table to use + * @param valarray: the (pre-initialized) val_t array to fill in + * @param errormsg: error message to display for unrecognized keywords + * @param read_brace: if true, read the opening brace + * @param copy_function: function to copy configuration from + * another subsection into this one. + */ +static void read_block(conf_var_t *read_var, val_t *valarray, + char *errormsg, int read_brace, + void (*copy_function)(void), + char *type, char *name); + +/* For each subsection type, we have a global and four functions: + * - foocur is a temporary struct used to assemble new subsections + * - get_foo is called after reading "DEFINE FOO", and + * is responsible for reading the entire block, using + * read_block() + * - init_foo_defaults initializes a new subsection struct + * to its default values + * - save_foo copies foocur to a newly allocated struct and + * inserts that into the relevant list. + * - copy_foo implements inheritance as described in read_block() + */ +static holdingdisk_t hdcur; +static void get_holdingdisk(int is_define); static void init_holdingdisk_defaults(void); static void save_holdingdisk(void); +static void copy_holdingdisk(void); + +static dumptype_t dpcur; static void get_dumptype(void); static void init_dumptype_defaults(void); static void save_dumptype(void); static void copy_dumptype(void); + +static tapetype_t tpcur; static void get_tapetype(void); static void init_tapetype_defaults(void); static void save_tapetype(void); static void copy_tapetype(void); + +static interface_t ifcur; static void get_interface(void); static void init_interface_defaults(void); static void save_interface(void); static void copy_interface(void); -static void get_comprate(t_conf_var *, val_t *); -static void get_compress(t_conf_var *, val_t *); -static void get_encrypt (t_conf_var *, val_t *); -static void get_holding (t_conf_var *, val_t *); -static void get_priority(t_conf_var *, val_t *); -static void get_strategy(t_conf_var *, val_t *); -static void get_estimate(t_conf_var *, val_t *); -static void get_exclude (t_conf_var *, val_t *); -/*static void get_include(t_conf_var *, val_t *);*/ -static void get_taperalgo(t_conf_var *, val_t *); -static int conftoken_getc(void); -static int conftoken_ungetc(int c); -static void unget_conftoken(void); -static void get_conftoken(tok_t exp); +static application_t apcur; +static void get_application(void); +static void init_application_defaults(void); +static void save_application(void); +static void copy_application(void); + +static pp_script_t pscur; +static void get_pp_script(void); +static void init_pp_script_defaults(void); +static void save_pp_script(void); +static void copy_pp_script(void); + +static device_config_t dccur; +static void get_device_config(void); +static void init_device_config_defaults(void); +static void save_device_config(void); +static void copy_device_config(void); + +static changer_config_t cccur; +static void get_changer_config(void); +static void init_changer_config_defaults(void); +static void save_changer_config(void); +static void copy_changer_config(void); + +static interactivity_t ivcur; +static void get_interactivity(void); +static void init_interactivity_defaults(void); +static void save_interactivity(void); +static void copy_interactivity(void); + +static taperscan_t tscur; +static void get_taperscan(void); +static void init_taperscan_defaults(void); +static void save_taperscan(void); +static void copy_taperscan(void); + +/* read_functions -- these fit into the read_function slot in a parser + * table entry, and are responsible for calling getconf_token as necessary + * to consume their arguments, and setting their second argument with the + * result. The first argument is a copy of the parser table entry, if + * needed. */ +static void read_int(conf_var_t *, val_t *); +static void read_int64(conf_var_t *, val_t *); +static void read_real(conf_var_t *, val_t *); +static void read_str(conf_var_t *, val_t *); +static void read_ident(conf_var_t *, val_t *); +static void read_time(conf_var_t *, val_t *); +static void read_size(conf_var_t *, val_t *); +static void read_bool(conf_var_t *, val_t *); +static void read_no_yes_all(conf_var_t *, val_t *); +static void read_compress(conf_var_t *, val_t *); +static void read_encrypt(conf_var_t *, val_t *); +static void read_holding(conf_var_t *, val_t *); +static void read_estimatelist(conf_var_t *, val_t *); +static void read_strategy(conf_var_t *, val_t *); +static void read_taperalgo(conf_var_t *, val_t *); +static void read_send_amreport_on(conf_var_t *, val_t *); +static void read_data_path(conf_var_t *, val_t *); +static void read_priority(conf_var_t *, val_t *); +static void read_rate(conf_var_t *, val_t *); +static void read_exinclude(conf_var_t *, val_t *); +static void read_intrange(conf_var_t *, val_t *); +static void read_dapplication(conf_var_t *, val_t *); +static void read_dinteractivity(conf_var_t *, val_t *); +static void read_dtaperscan(conf_var_t *, val_t *); +static void read_dpp_script(conf_var_t *, val_t *); +static void read_property(conf_var_t *, val_t *); +static void read_execute_on(conf_var_t *, val_t *); +static void read_execute_where(conf_var_t *, val_t *); +static void read_holdingdisk(conf_var_t *, val_t *); +static void read_int_or_str(conf_var_t *, val_t *); +static void read_autolabel(conf_var_t *, val_t *); +static void read_part_cache_type(conf_var_t *, val_t *); +static void read_host_limit(conf_var_t *, val_t *); + +static application_t *read_application(char *name, FILE *from, char *fname, + int *linenum); +static pp_script_t *read_pp_script(char *name, FILE *from, char *fname, + int *linenum); +static device_config_t *read_device_config(char *name, FILE *from, char *fname, + int *linenum); +static changer_config_t *read_changer_config(char *name, FILE *from, + char *fname, int *linenum); +static interactivity_t *read_interactivity(char *name, FILE *from, + char *fname, int *linenum); +static taperscan_t *read_taperscan(char *name, FILE *from, char *fname, + int *linenum); +/* Functions to get various types of values. These are called by + * read_functions to take care of any variations in the way that these + * values can be written: integers can have units, boolean values can be + * specified with a number of names, etc. They form utility functions + * for the read_functions, below. */ +static gint64 get_multiplier(gint64 val, confunit_t unit); +static time_t get_time(void); +static int get_int(confunit_t unit); +static ssize_t get_size(confunit_t unit); +static gint64 get_int64(confunit_t unit); +static int get_bool(void); +static int get_no_yes_all(void); + +/* Check the given 'seen', flagging an error if this value has already + * been seen and allow_overwrites is false. Also marks the value as + * seen on the current line. + * + * @param seen: (in/out) seen value to adjust + */ +static void ckseen(seen_t *seen); + +/* validate_functions -- these fit into the validate_function solt in + * a parser table entry. They call conf_parserror if the value in their + * second argument is invalid. */ +static void validate_nonnegative(conf_var_t *, val_t *); +static void validate_non_zero(conf_var_t *, val_t *); +static void validate_positive(conf_var_t *, val_t *); +static void validate_runspercycle(conf_var_t *, val_t *); +static void validate_bumppercent(conf_var_t *, val_t *); +static void validate_bumpmult(conf_var_t *, val_t *); +static void validate_inparallel(conf_var_t *, val_t *); +static void validate_displayunit(conf_var_t *, val_t *); +static void validate_reserve(conf_var_t *, val_t *); +static void validate_use(conf_var_t *, val_t *); +static void validate_chunksize(conf_var_t *, val_t *); +static void validate_blocksize(conf_var_t *, val_t *); +static void validate_debug(conf_var_t *, val_t *); +static void validate_port_range(val_t *, int, int); +static void validate_reserved_port_range(conf_var_t *, val_t *); +static void validate_unreserved_port_range(conf_var_t *, val_t *); +static void validate_program(conf_var_t *, val_t *); +static void validate_dump_limit(conf_var_t *, val_t *); +static void validate_tmpdir(conf_var_t *, val_t *); + +gint compare_pp_script_order(gconstpointer a, gconstpointer b); + +/* + * Initialization + */ + +/* The name of the configuration under which this application is running. + * This variable is initialized by config_init. + */ +static char *config_name = NULL; + +/* The directory containing the configuration for this application. This + * variable is initialized by config_init + */ +static char *config_dir = NULL; + +/* The most recently read top-level configuration file. This variable is + * initialized by config_init + */ +static char *config_filename = NULL; + +/* Has the config been initialized? */ +static gboolean config_initialized = FALSE; + +/* Are we running a client? (true if last init was + * with CONFIG_INIT_CLIENT) */ +static gboolean config_client = FALSE; + +/* What config overwrites to use? */ +static config_overrides_t *config_overrides = NULL; + +/* All global parameters */ +static val_t conf_data[CNF_CNF]; + +/* Linked list of holding disks */ +static GSList *holdinglist = NULL; +static dumptype_t *dumplist = NULL; +static tapetype_t *tapelist = NULL; +static interface_t *interface_list = NULL; +static application_t *application_list = NULL; +static pp_script_t *pp_script_list = NULL; +static device_config_t *device_config_list = NULL; +static changer_config_t *changer_config_list = NULL; +static interactivity_t *interactivity_list = NULL; +static taperscan_t *taperscan_list = NULL; + +/* storage for derived values */ +static long int unit_divisor = 1; + +int debug_amandad = 0; +int debug_recovery = 0; +int debug_amidxtaped = 0; +int debug_amindexd = 0; +int debug_amrecover = 0; +int debug_auth = 0; +int debug_event = 0; +int debug_holding = 0; +int debug_protocol = 0; +int debug_planner = 0; +int debug_driver = 0; +int debug_dumper = 0; +int debug_chunker = 0; +int debug_taper = 0; +int debug_selfcheck = 0; +int debug_sendsize = 0; +int debug_sendbackup = 0; + +/* Reset all configuration values to their defaults (which, in many + * cases, come from --with-foo options at build time) */ +static void init_defaults(void); + +/* Update all dervied values based on the current configuration. This + * function can be called multiple times, once after each adjustment + * to the current configuration. + * + * @param is_client: are we running a client? + */ +static void update_derived_values(gboolean is_client); + +static cfgerr_level_t apply_config_overrides(config_overrides_t *co, + char *key_ovr); + +/* per-type conf_init functions, used as utilities for init_defaults + * and for each subsection's init_foo_defaults. + * + * These set the value's type and seen flags, as well as copying + * the relevant value into the 'v' field. + */ +static void conf_init_int(val_t *val, confunit_t unit, int i); +static void conf_init_int64(val_t *val, confunit_t unit, gint64 l); +static void conf_init_real(val_t *val, float r); +static void conf_init_str(val_t *val, char *s); +static void conf_init_ident(val_t *val, char *s); +static void conf_init_identlist(val_t *val, char *s); +static void conf_init_time(val_t *val, time_t t); +static void conf_init_size(val_t *val, confunit_t unit, ssize_t sz); +static void conf_init_bool(val_t *val, int i); +static void conf_init_no_yes_all(val_t *val, int i); +static void conf_init_compress(val_t *val, comp_t i); +static void conf_init_encrypt(val_t *val, encrypt_t i); +static void conf_init_data_path(val_t *val, data_path_t i); +static void conf_init_holding(val_t *val, dump_holdingdisk_t i); +static void conf_init_estimatelist(val_t *val, estimate_t i); +static void conf_init_execute_on(val_t *, int); +static void conf_init_execute_where(val_t *, int); +static void conf_init_send_amreport(val_t *val, send_amreport_t i); +static void conf_init_strategy(val_t *val, strategy_t); +static void conf_init_taperalgo(val_t *val, taperalgo_t i); +static void conf_init_priority(val_t *val, int i); +static void conf_init_rate(val_t *val, float r1, float r2); +static void conf_init_exinclude(val_t *val); /* to empty list */ +static void conf_init_intrange(val_t *val, int i1, int i2); +static void conf_init_proplist(val_t *val); /* to empty list */ +static void conf_init_application(val_t *val); +static void conf_init_autolabel(val_t *val); +static void conf_init_part_cache_type(val_t *val, part_cache_type_t i); +static void conf_init_host_limit(val_t *val); +static void conf_init_host_limit_server(val_t *val); + +/* + * Command-line Handling + */ + +typedef struct config_override_s { + char *key; + char *value; + gboolean applied; +} config_override_t; + +struct config_overrides_s { + int n_allocated; + int n_used; + config_override_t *ovr; +}; + +/* + * val_t Management + */ + +static void merge_val_t(val_t *, val_t *); +static void copy_val_t(val_t *, val_t *); +static void free_val_t(val_t *); + +/* + * Utilities + */ + +/* memory handling */ +void free_property_t(gpointer p); + +/* Utility functions/structs for val_t_display_strs */ +static char *exinclude_display_str(val_t *val, int file); +static void proplist_display_str_foreach_fn(gpointer key_p, gpointer value_p, gpointer user_data_p); +static void val_t_print_token(gboolean print_default, gboolean print_source, FILE *output, char *prefix, char *format, keytab_t *kt, val_t *val); + +/* Given a key name as used in config overwrites, return a pointer to the corresponding + * conf_var_t in the current parsetable, and the val_t representing that value. This + * function will access subsections if key has the form TYPE:SUBSEC:KEYWORD. Returns + * false if the value does not exist. + * + * Assumes keytable and parsetable are set correctly, which is generally OK after + * config_init has been called. + * + * @param key: the key to look up + * @param parm: (result) the parse table entry + * @param val: (result) the parameter value + * @returns: true on success + */ +static int parm_key_info(char *key, conf_var_t **parm, val_t **val); + +/* + * Error handling + */ + +/* Have we seen a parse error yet? Parsing continues after an error, so this + * flag is checked after the parse is complete. + */ +static cfgerr_level_t cfgerr_level; +static GSList *cfgerr_errors = NULL; + +static void conf_error_common(cfgerr_level_t level, const char * format, va_list argp); +static void conf_parserror(const char *format, ...) + __attribute__ ((format (printf, 1, 2))); + +static void conf_parswarn(const char *format, ...) + __attribute__ ((format (printf, 1, 2))); -keytab_t *my_keytab = NULL; -t_conf_var *my_var = NULL; +/* + * Tables + */ +/* First, the keyword tables for client and server */ keytab_t client_keytab[] = { { "CONF", CONF_CONF }, + { "AMDUMP_SERVER", CONF_AMDUMP_SERVER }, { "INDEX_SERVER", CONF_INDEX_SERVER }, { "TAPE_SERVER", CONF_TAPE_SERVER }, { "TAPEDEV", CONF_TAPEDEV }, { "AUTH", CONF_AUTH }, { "SSH_KEYS", CONF_SSH_KEYS }, { "AMANDAD_PATH", CONF_AMANDAD_PATH }, + { "CLIENT_NAME", CONF_CLIENT_NAME }, { "CLIENT_USERNAME", CONF_CLIENT_USERNAME }, + { "CLIENT_PORT", CONF_CLIENT_PORT }, { "GNUTAR_LIST_DIR", CONF_GNUTAR_LIST_DIR }, { "AMANDATES", CONF_AMANDATES }, { "KRB5KEYTAB", CONF_KRB5KEYTAB }, @@ -265,7 +820,10 @@ keytab_t client_keytab[] = { { "CONNECT_TRIES", CONF_CONNECT_TRIES }, { "REP_TRIES", CONF_REP_TRIES }, { "REQ_TRIES", CONF_REQ_TRIES }, + { "CLIENT", CONF_CLIENT }, + { "DEBUG_DAYS", CONF_DEBUG_DAYS }, { "DEBUG_AMANDAD", CONF_DEBUG_AMANDAD }, + { "DEBUG_RECOVERY", CONF_DEBUG_RECOVERY }, { "DEBUG_AMIDXTAPED", CONF_DEBUG_AMIDXTAPED }, { "DEBUG_AMINDEXD", CONF_DEBUG_AMINDEXD }, { "DEBUG_AMRECOVER", CONF_DEBUG_AMRECOVER }, @@ -281,55 +839,67 @@ keytab_t client_keytab[] = { { "DEBUG_SELFCHECK", CONF_DEBUG_SELFCHECK }, { "DEBUG_SENDSIZE", CONF_DEBUG_SENDSIZE }, { "DEBUG_SENDBACKUP", CONF_DEBUG_SENDBACKUP }, - { "UNRESERVED-TCP-PORT", CONF_UNRESERVED_TCP_PORT }, - { NULL, CONF_UNKNOWN }, -}; - -t_conf_var client_var [] = { - { CONF_CONF , CONFTYPE_STRING , read_string , CNF_CONF , NULL }, - { CONF_INDEX_SERVER , CONFTYPE_STRING , read_string , CNF_INDEX_SERVER , NULL }, - { CONF_TAPE_SERVER , CONFTYPE_STRING , read_string , CNF_TAPE_SERVER , NULL }, - { CONF_TAPEDEV , CONFTYPE_STRING , read_string , CNF_TAPEDEV , NULL }, - { CONF_AUTH , CONFTYPE_STRING , read_string , CNF_AUTH , NULL }, - { CONF_SSH_KEYS , CONFTYPE_STRING , read_string , CNF_SSH_KEYS , NULL }, - { CONF_AMANDAD_PATH , CONFTYPE_STRING , read_string , CNF_AMANDAD_PATH , NULL }, - { CONF_CLIENT_USERNAME , CONFTYPE_STRING , read_string , CNF_CLIENT_USERNAME , NULL }, - { CONF_GNUTAR_LIST_DIR , CONFTYPE_STRING , read_string , CNF_GNUTAR_LIST_DIR , NULL }, - { CONF_AMANDATES , CONFTYPE_STRING , read_string , CNF_AMANDATES , NULL }, - { CONF_KRB5KEYTAB , CONFTYPE_STRING , read_string , CNF_KRB5KEYTAB , NULL }, - { CONF_KRB5PRINCIPAL , CONFTYPE_STRING , read_string , CNF_KRB5PRINCIPAL , NULL }, - { CONF_CONNECT_TRIES , CONFTYPE_INT , read_int , CNF_CONNECT_TRIES , validate_positive1 }, - { CONF_REP_TRIES , CONFTYPE_INT , read_int , CNF_REP_TRIES , validate_positive1 }, - { CONF_REQ_TRIES , CONFTYPE_INT , read_int , CNF_REQ_TRIES , validate_positive1 }, - { CONF_DEBUG_AMANDAD , CONFTYPE_INT , read_int , CNF_DEBUG_AMANDAD , validate_debug }, - { CONF_DEBUG_AMIDXTAPED , CONFTYPE_INT , read_int , CNF_DEBUG_AMIDXTAPED , validate_debug }, - { CONF_DEBUG_AMINDEXD , CONFTYPE_INT , read_int , CNF_DEBUG_AMINDEXD , validate_debug }, - { CONF_DEBUG_AMRECOVER , CONFTYPE_INT , read_int , CNF_DEBUG_AMRECOVER , validate_debug }, - { CONF_DEBUG_AUTH , CONFTYPE_INT , read_int , CNF_DEBUG_AUTH , validate_debug }, - { CONF_DEBUG_EVENT , CONFTYPE_INT , read_int , CNF_DEBUG_EVENT , validate_debug }, - { CONF_DEBUG_HOLDING , CONFTYPE_INT , read_int , CNF_DEBUG_HOLDING , validate_debug }, - { CONF_DEBUG_PROTOCOL , CONFTYPE_INT , read_int , CNF_DEBUG_PROTOCOL , validate_debug }, - { CONF_DEBUG_PLANNER , CONFTYPE_INT , read_int , CNF_DEBUG_PLANNER , validate_debug }, - { CONF_DEBUG_DRIVER , CONFTYPE_INT , read_int , CNF_DEBUG_DRIVER , validate_debug }, - { CONF_DEBUG_DUMPER , CONFTYPE_INT , read_int , CNF_DEBUG_DUMPER , validate_debug }, - { CONF_DEBUG_CHUNKER , CONFTYPE_INT , read_int , CNF_DEBUG_CHUNKER , validate_debug }, - { CONF_DEBUG_TAPER , CONFTYPE_INT , read_int , CNF_DEBUG_TAPER , validate_debug }, - { CONF_DEBUG_SELFCHECK , CONFTYPE_INT , read_int , CNF_DEBUG_SELFCHECK , validate_debug }, - { CONF_DEBUG_SENDSIZE , CONFTYPE_INT , read_int , CNF_DEBUG_SENDSIZE , validate_debug }, - { CONF_DEBUG_SENDBACKUP , CONFTYPE_INT , read_int , CNF_DEBUG_SENDBACKUP , validate_debug }, - { CONF_UNRESERVED_TCP_PORT, CONFTYPE_INTRANGE, read_intrange, CNF_UNRESERVED_TCP_PORT, validate_unreserved_port_range }, - { CONF_UNKNOWN , CONFTYPE_INT , NULL , CNF_CNF , NULL } + { "EXECUTE_ON", CONF_EXECUTE_ON }, + { "EXECUTE_WHERE", CONF_EXECUTE_WHERE }, + { "RESERVED_UDP_PORT", CONF_RESERVED_UDP_PORT }, + { "RESERVED_TCP_PORT", CONF_RESERVED_TCP_PORT }, + { "UNRESERVED_TCP_PORT", CONF_UNRESERVED_TCP_PORT }, + { "DEFINE", CONF_DEFINE }, + { "COMMENT", CONF_COMMENT }, + { "MAILER", CONF_MAILER }, + { "ORDER", CONF_ORDER }, + { "SCRIPT", CONF_SCRIPT }, + { "SCRIPT_TOOL", CONF_SCRIPT_TOOL }, + { "PLUGIN", CONF_PLUGIN }, + { "PRE_AMCHECK", CONF_PRE_AMCHECK }, + { "PRE_DLE_AMCHECK", CONF_PRE_DLE_AMCHECK }, + { "PRE_HOST_AMCHECK", CONF_PRE_HOST_AMCHECK }, + { "POST_AMCHECK", CONF_POST_AMCHECK }, + { "POST_DLE_AMCHECK", CONF_POST_DLE_AMCHECK }, + { "POST_HOST_AMCHECK", CONF_POST_HOST_AMCHECK }, + { "PRE_ESTIMATE", CONF_PRE_ESTIMATE }, + { "PRE_DLE_ESTIMATE", CONF_PRE_DLE_ESTIMATE }, + { "PRE_HOST_ESTIMATE", CONF_PRE_HOST_ESTIMATE }, + { "POST_ESTIMATE", CONF_POST_ESTIMATE }, + { "POST_DLE_ESTIMATE", CONF_POST_DLE_ESTIMATE }, + { "POST_HOST_ESTIMATE", CONF_POST_HOST_ESTIMATE }, + { "POST_BACKUP", CONF_POST_BACKUP }, + { "POST_DLE_BACKUP", CONF_POST_DLE_BACKUP }, + { "POST_HOST_BACKUP", CONF_POST_HOST_BACKUP }, + { "PRE_BACKUP", CONF_PRE_BACKUP }, + { "PRE_DLE_BACKUP", CONF_PRE_DLE_BACKUP }, + { "PRE_HOST_BACKUP", CONF_PRE_HOST_BACKUP }, + { "PRE_RECOVER", CONF_PRE_RECOVER }, + { "POST_RECOVER", CONF_POST_RECOVER }, + { "PRE_LEVEL_RECOVER", CONF_PRE_LEVEL_RECOVER }, + { "POST_LEVEL_RECOVER", CONF_POST_LEVEL_RECOVER }, + { "INTER_LEVEL_RECOVER", CONF_INTER_LEVEL_RECOVER }, + { "PRIORITY", CONF_PRIORITY }, + { "PROPERTY", CONF_PROPERTY }, + { "APPLICATION", CONF_APPLICATION }, + { "APPLICATION_TOOL", CONF_APPLICATION_TOOL }, + { "SERVER", CONF_SERVER }, + { "APPEND", CONF_APPEND }, + { NULL, CONF_IDENT }, + { NULL, CONF_UNKNOWN } }; keytab_t server_keytab[] = { + { "ALL", CONF_ALL }, + { "ALLOW_SPLIT", CONF_ALLOW_SPLIT }, + { "AMANDA", CONF_AMANDA }, { "AMANDAD_PATH", CONF_AMANDAD_PATH }, { "AMRECOVER_CHANGER", CONF_AMRECOVER_CHANGER }, { "AMRECOVER_CHECK_LABEL", CONF_AMRECOVER_CHECK_LABEL }, { "AMRECOVER_DO_FSF", CONF_AMRECOVER_DO_FSF }, + { "ANY", CONF_ANY_VOLUME }, { "APPEND", CONF_APPEND }, { "AUTH", CONF_AUTH }, { "AUTO", CONF_AUTO }, { "AUTOFLUSH", CONF_AUTOFLUSH }, + { "AUTOLABEL", CONF_AUTOLABEL }, + { "APPLICATION", CONF_APPLICATION }, + { "APPLICATION_TOOL", CONF_APPLICATION_TOOL }, { "BEST", CONF_BEST }, { "BLOCKSIZE", CONF_BLOCKSIZE }, { "BUMPDAYS", CONF_BUMPDAYS }, @@ -337,13 +907,15 @@ keytab_t server_keytab[] = { { "BUMPPERCENT", CONF_BUMPPERCENT }, { "BUMPSIZE", CONF_BUMPSIZE }, { "CALCSIZE", CONF_CALCSIZE }, - { "CHANGERDEV", CONF_CHNGRDEV }, - { "CHANGERFILE", CONF_CHNGRFILE }, + { "CHANGER", CONF_CHANGER }, + { "CHANGERDEV", CONF_CHANGERDEV }, + { "CHANGERFILE", CONF_CHANGERFILE }, { "CHUNKSIZE", CONF_CHUNKSIZE }, { "CLIENT", CONF_CLIENT }, { "CLIENT_CUSTOM_COMPRESS", CONF_CLNTCOMPPROG }, { "CLIENT_DECRYPT_OPTION", CONF_CLNT_DECRYPT_OPT }, { "CLIENT_ENCRYPT", CONF_CLNT_ENCRYPT }, + { "CLIENT_NAME", CONF_CLIENT_NAME }, { "CLIENT_USERNAME", CONF_CLIENT_USERNAME }, { "COLUMNSPEC", CONF_COLUMNSPEC }, { "COMMENT", CONF_COMMENT }, @@ -352,7 +924,10 @@ keytab_t server_keytab[] = { { "CONNECT_TRIES", CONF_CONNECT_TRIES }, { "CTIMEOUT", CONF_CTIMEOUT }, { "CUSTOM", CONF_CUSTOM }, + { "DATA_PATH", CONF_DATA_PATH }, + { "DEBUG_DAYS" , CONF_DEBUG_DAYS }, { "DEBUG_AMANDAD" , CONF_DEBUG_AMANDAD }, + { "DEBUG_RECOVERY" , CONF_DEBUG_RECOVERY }, { "DEBUG_AMIDXTAPED" , CONF_DEBUG_AMIDXTAPED }, { "DEBUG_AMINDEXD" , CONF_DEBUG_AMINDEXD }, { "DEBUG_AMRECOVER" , CONF_DEBUG_AMRECOVER }, @@ -369,7 +944,11 @@ keytab_t server_keytab[] = { { "DEBUG_SENDSIZE" , CONF_DEBUG_SENDSIZE }, { "DEBUG_SENDBACKUP" , CONF_DEBUG_SENDBACKUP }, { "DEFINE", CONF_DEFINE }, + { "DEVICE", CONF_DEVICE }, + { "DEVICE_PROPERTY", CONF_DEVICE_PROPERTY }, { "DIRECTORY", CONF_DIRECTORY }, + { "DIRECTTCP", CONF_DIRECTTCP }, + { "DISK", CONF_DISK }, { "DISKFILE", CONF_DISKFILE }, { "DISPLAYUNIT", CONF_DISPLAYUNIT }, { "DTIMEOUT", CONF_DTIMEOUT }, @@ -377,16 +956,21 @@ keytab_t server_keytab[] = { { "DUMPORDER", CONF_DUMPORDER }, { "DUMPTYPE", CONF_DUMPTYPE }, { "DUMPUSER", CONF_DUMPUSER }, + { "DUMP_LIMIT", CONF_DUMP_LIMIT }, + { "EJECT_VOLUME", CONF_EJECT_VOLUME }, + { "EMPTY", CONF_EMPTY }, { "ENCRYPT", CONF_ENCRYPT }, + { "ERROR", CONF_ERROR }, { "ESTIMATE", CONF_ESTIMATE }, { "ETIMEOUT", CONF_ETIMEOUT }, { "EXCLUDE", CONF_EXCLUDE }, - { "EXCLUDE-FILE", CONF_EXCLUDE_FILE }, - { "EXCLUDE-LIST", CONF_EXCLUDE_LIST }, + { "EXCLUDE_FILE", CONF_EXCLUDE_FILE }, + { "EXCLUDE_LIST", CONF_EXCLUDE_LIST }, + { "EXECUTE_ON", CONF_EXECUTE_ON }, + { "EXECUTE_WHERE", CONF_EXECUTE_WHERE }, { "FALLBACK_SPLITSIZE", CONF_FALLBACK_SPLITSIZE }, { "FAST", CONF_FAST }, { "FILE", CONF_EFILE }, - { "FILE-PAD", CONF_FILE_PAD }, { "FILEMARK", CONF_FILEMARK }, { "FIRST", CONF_FIRST }, { "FIRSTFIT", CONF_FIRSTFIT }, @@ -401,6 +985,7 @@ keytab_t server_keytab[] = { { "INDEXDIR", CONF_INDEXDIR }, { "INFOFILE", CONF_INFOFILE }, { "INPARALLEL", CONF_INPARALLEL }, + { "INTERACTIVITY", CONF_INTERACTIVITY }, { "INTERFACE", CONF_INTERFACE }, { "KENCRYPT", CONF_KENCRYPT }, { "KRB5KEYTAB", CONF_KRB5KEYTAB }, @@ -410,4759 +995,7725 @@ keytab_t server_keytab[] = { { "LARGEST", CONF_LARGEST }, { "LARGESTFIT", CONF_LARGESTFIT }, { "LAST", CONF_LAST }, - { "LBL-TEMPL", CONF_LBL_TEMPL }, + { "LBL_TEMPL", CONF_LBL_TEMPL }, { "LENGTH", CONF_LENGTH }, { "LIST", CONF_LIST }, { "LOGDIR", CONF_LOGDIR }, { "LOW", CONF_LOW }, + { "MAILER", CONF_MAILER }, { "MAILTO", CONF_MAILTO }, { "READBLOCKSIZE", CONF_READBLOCKSIZE }, + { "MAX_DLE_BY_VOLUME", CONF_MAX_DLE_BY_VOLUME }, { "MAXDUMPS", CONF_MAXDUMPS }, { "MAXDUMPSIZE", CONF_MAXDUMPSIZE }, { "MAXPROMOTEDAY", CONF_MAXPROMOTEDAY }, + { "MAX_WARNINGS", CONF_MAX_WARNINGS }, + { "MEMORY", CONF_MEMORY }, { "MEDIUM", CONF_MEDIUM }, - { "NETUSAGE", CONF_NETUSAGE }, /* XXX - historical */ + { "META_AUTOLABEL", CONF_META_AUTOLABEL }, + { "NETUSAGE", CONF_NETUSAGE }, { "NEVER", CONF_NEVER }, { "NOFULL", CONF_NOFULL }, { "NOINC", CONF_NOINC }, { "NONE", CONF_NONE }, + { "NON_AMANDA", CONF_NON_AMANDA }, { "OPTIONAL", CONF_OPTIONAL }, + { "ORDER", CONF_ORDER }, { "ORG", CONF_ORG }, + { "OTHER_CONFIG", CONF_OTHER_CONFIG }, + { "PART_CACHE_DIR", CONF_PART_CACHE_DIR }, + { "PART_CACHE_MAX_SIZE", CONF_PART_CACHE_MAX_SIZE }, + { "PART_CACHE_TYPE", CONF_PART_CACHE_TYPE }, + { "PART_SIZE", CONF_PART_SIZE }, + { "PLUGIN", CONF_PLUGIN }, + { "PRE_AMCHECK", CONF_PRE_AMCHECK }, + { "PRE_DLE_AMCHECK", CONF_PRE_DLE_AMCHECK }, + { "PRE_HOST_AMCHECK", CONF_PRE_HOST_AMCHECK }, + { "POST_AMCHECK", CONF_POST_AMCHECK }, + { "POST_DLE_AMCHECK", CONF_POST_DLE_AMCHECK }, + { "POST_HOST_AMCHECK", CONF_POST_HOST_AMCHECK }, + { "PRE_ESTIMATE", CONF_PRE_ESTIMATE }, + { "PRE_DLE_ESTIMATE", CONF_PRE_DLE_ESTIMATE }, + { "PRE_HOST_ESTIMATE", CONF_PRE_HOST_ESTIMATE }, + { "POST_ESTIMATE", CONF_POST_ESTIMATE }, + { "POST_DLE_ESTIMATE", CONF_POST_DLE_ESTIMATE }, + { "POST_HOST_ESTIMATE", CONF_POST_HOST_ESTIMATE }, + { "POST_BACKUP", CONF_POST_BACKUP }, + { "POST_DLE_BACKUP", CONF_POST_DLE_BACKUP }, + { "POST_HOST_BACKUP", CONF_POST_HOST_BACKUP }, + { "PRE_BACKUP", CONF_PRE_BACKUP }, + { "PRE_DLE_BACKUP", CONF_PRE_DLE_BACKUP }, + { "PRE_HOST_BACKUP", CONF_PRE_HOST_BACKUP }, + { "PRE_RECOVER", CONF_PRE_RECOVER }, + { "POST_RECOVER", CONF_POST_RECOVER }, + { "PRE_LEVEL_RECOVER", CONF_PRE_LEVEL_RECOVER }, + { "POST_LEVEL_RECOVER", CONF_POST_LEVEL_RECOVER }, + { "INTER_LEVEL_RECOVER", CONF_INTER_LEVEL_RECOVER }, { "PRINTER", CONF_PRINTER }, { "PRIORITY", CONF_PRIORITY }, { "PROGRAM", CONF_PROGRAM }, - { "RAWTAPEDEV", CONF_RAWTAPEDEV }, + { "PROPERTY", CONF_PROPERTY }, { "RECORD", CONF_RECORD }, + { "RECOVERY_LIMIT", CONF_RECOVERY_LIMIT }, { "REP_TRIES", CONF_REP_TRIES }, + { "REPORT_USE_MEDIA", CONF_REPORT_USE_MEDIA }, + { "REPORT_NEXT_MEDIA", CONF_REPORT_NEXT_MEDIA }, { "REQ_TRIES", CONF_REQ_TRIES }, { "REQUIRED", CONF_REQUIRED }, { "RESERVE", CONF_RESERVE }, - { "RESERVED-UDP-PORT", CONF_RESERVED_UDP_PORT }, - { "RESERVED-TCP-PORT", CONF_RESERVED_TCP_PORT }, + { "RESERVED_UDP_PORT", CONF_RESERVED_UDP_PORT }, + { "RESERVED_TCP_PORT", CONF_RESERVED_TCP_PORT }, { "RUNSPERCYCLE", CONF_RUNSPERCYCLE }, { "RUNTAPES", CONF_RUNTAPES }, + { "SAME_HOST", CONF_SAME_HOST }, + { "SCRIPT", CONF_SCRIPT }, + { "SCRIPT_TOOL", CONF_SCRIPT_TOOL }, + { "SEND_AMREPORT_ON", CONF_SEND_AMREPORT_ON }, + { "CLIENT_PORT", CONF_CLIENT_PORT }, { "SERVER", CONF_SERVER }, { "SERVER_CUSTOM_COMPRESS", CONF_SRVCOMPPROG }, { "SERVER_DECRYPT_OPTION", CONF_SRV_DECRYPT_OPT }, { "SERVER_ENCRYPT", CONF_SRV_ENCRYPT }, { "SKIP", CONF_SKIP }, - { "SKIP-FULL", CONF_SKIP_FULL }, - { "SKIP-INCR", CONF_SKIP_INCR }, + { "SKIP_FULL", CONF_SKIP_FULL }, + { "SKIP_INCR", CONF_SKIP_INCR }, + { "SINGLE_EXECUTION", CONF_SINGLE_EXECUTION }, { "SMALLEST", CONF_SMALLEST }, { "SPEED", CONF_SPEED }, { "SPLIT_DISKBUFFER", CONF_SPLIT_DISKBUFFER }, { "SSH_KEYS", CONF_SSH_KEYS }, { "STANDARD", CONF_STANDARD }, { "STARTTIME", CONF_STARTTIME }, + { "STRANGE", CONF_STRANGE }, { "STRATEGY", CONF_STRATEGY }, - { "TAPEBUFS", CONF_TAPEBUFS }, + { "DEVICE_OUTPUT_BUFFER_SIZE", CONF_DEVICE_OUTPUT_BUFFER_SIZE }, { "TAPECYCLE", CONF_TAPECYCLE }, { "TAPEDEV", CONF_TAPEDEV }, { "TAPELIST", CONF_TAPELIST }, { "TAPERALGO", CONF_TAPERALGO }, + { "TAPERSCAN", CONF_TAPERSCAN }, + { "TAPER_PARALLEL_WRITE", CONF_TAPER_PARALLEL_WRITE }, + { "FLUSH_THRESHOLD_DUMPED", CONF_FLUSH_THRESHOLD_DUMPED }, + { "FLUSH_THRESHOLD_SCHEDULED", CONF_FLUSH_THRESHOLD_SCHEDULED }, + { "TAPERFLUSH", CONF_TAPERFLUSH }, { "TAPETYPE", CONF_TAPETYPE }, { "TAPE_SPLITSIZE", CONF_TAPE_SPLITSIZE }, + { "TMPDIR", CONF_TMPDIR }, { "TPCHANGER", CONF_TPCHANGER }, - { "UNRESERVED-TCP-PORT", CONF_UNRESERVED_TCP_PORT }, + { "UNRESERVED_TCP_PORT", CONF_UNRESERVED_TCP_PORT }, { "USE", CONF_USE }, { "USETIMESTAMPS", CONF_USETIMESTAMPS }, + { "VOLUME_ERROR", CONF_VOLUME_ERROR }, { NULL, CONF_IDENT }, { NULL, CONF_UNKNOWN } }; -t_conf_var server_var [] = { - { CONF_ORG , CONFTYPE_STRING , read_string , CNF_ORG , NULL }, - { CONF_MAILTO , CONFTYPE_STRING , read_string , CNF_MAILTO , NULL }, - { CONF_DUMPUSER , CONFTYPE_STRING , read_string , CNF_DUMPUSER , NULL }, - { CONF_PRINTER , CONFTYPE_STRING , read_string , CNF_PRINTER , NULL }, - { CONF_TAPEDEV , CONFTYPE_STRING , read_string , CNF_TAPEDEV , NULL }, - { CONF_TPCHANGER , CONFTYPE_STRING , read_string , CNF_TPCHANGER , NULL }, - { CONF_CHNGRDEV , CONFTYPE_STRING , read_string , CNF_CHNGRDEV , NULL }, - { CONF_CHNGRFILE , CONFTYPE_STRING , read_string , CNF_CHNGRFILE , NULL }, - { CONF_LABELSTR , CONFTYPE_STRING , read_string , CNF_LABELSTR , NULL }, - { CONF_TAPELIST , CONFTYPE_STRING , read_string , CNF_TAPELIST , NULL }, - { CONF_DISKFILE , CONFTYPE_STRING , read_string , CNF_DISKFILE , NULL }, - { CONF_INFOFILE , CONFTYPE_STRING , read_string , CNF_INFOFILE , NULL }, - { CONF_LOGDIR , CONFTYPE_STRING , read_string , CNF_LOGDIR , NULL }, - { CONF_INDEXDIR , CONFTYPE_STRING , read_string , CNF_INDEXDIR , NULL }, - { CONF_TAPETYPE , CONFTYPE_IDENT , read_ident , CNF_TAPETYPE , NULL }, - { CONF_DUMPCYCLE , CONFTYPE_INT , read_int , CNF_DUMPCYCLE , validate_positive0 }, - { CONF_RUNSPERCYCLE , CONFTYPE_INT , read_int , CNF_RUNSPERCYCLE , validate_runspercycle }, - { CONF_RUNTAPES , CONFTYPE_INT , read_int , CNF_RUNTAPES , validate_positive0 }, - { CONF_TAPECYCLE , CONFTYPE_INT , read_int , CNF_TAPECYCLE , validate_positive1 }, - { CONF_BUMPDAYS , CONFTYPE_INT , read_int , CNF_BUMPDAYS , validate_positive1 }, - { CONF_BUMPSIZE , CONFTYPE_AM64 , read_am64 , CNF_BUMPSIZE , validate_positive1 }, - { CONF_BUMPPERCENT , CONFTYPE_INT , read_int , CNF_BUMPPERCENT , validate_bumppercent }, - { CONF_BUMPMULT , CONFTYPE_REAL , read_real , CNF_BUMPMULT , validate_bumpmult }, - { CONF_NETUSAGE , CONFTYPE_INT , read_int , CNF_NETUSAGE , validate_positive1 }, - { CONF_INPARALLEL , CONFTYPE_INT , read_int , CNF_INPARALLEL , validate_inparallel }, - { CONF_DUMPORDER , CONFTYPE_STRING , read_string , CNF_DUMPORDER , NULL }, - { CONF_MAXDUMPS , CONFTYPE_INT , read_int , CNF_MAXDUMPS , validate_positive1 }, - { CONF_ETIMEOUT , CONFTYPE_INT , read_int , CNF_ETIMEOUT , NULL }, - { CONF_DTIMEOUT , CONFTYPE_INT , read_int , CNF_DTIMEOUT , validate_positive1 }, - { CONF_CTIMEOUT , CONFTYPE_INT , read_int , CNF_CTIMEOUT , validate_positive1 }, - { CONF_TAPEBUFS , CONFTYPE_INT , read_int , CNF_TAPEBUFS , validate_positive1 }, - { CONF_RAWTAPEDEV , CONFTYPE_STRING , read_string , CNF_RAWTAPEDEV , NULL }, - { CONF_COLUMNSPEC , CONFTYPE_STRING , read_string , CNF_COLUMNSPEC , NULL }, - { CONF_TAPERALGO , CONFTYPE_TAPERALGO, get_taperalgo, CNF_TAPERALGO , NULL }, - { CONF_DISPLAYUNIT , CONFTYPE_STRING , read_string , CNF_DISPLAYUNIT , validate_displayunit }, - { CONF_AUTOFLUSH , CONFTYPE_BOOL , read_bool , CNF_AUTOFLUSH , NULL }, - { CONF_RESERVE , CONFTYPE_INT , read_int , CNF_RESERVE , validate_reserve }, - { CONF_MAXDUMPSIZE , CONFTYPE_AM64 , read_am64 , CNF_MAXDUMPSIZE , NULL }, - { CONF_KRB5KEYTAB , CONFTYPE_STRING , read_string , CNF_KRB5KEYTAB , NULL }, - { CONF_KRB5PRINCIPAL , CONFTYPE_STRING , read_string , CNF_KRB5PRINCIPAL , NULL }, - { CONF_LABEL_NEW_TAPES , CONFTYPE_STRING , read_string , CNF_LABEL_NEW_TAPES , NULL }, - { CONF_USETIMESTAMPS , CONFTYPE_BOOL , read_bool , CNF_USETIMESTAMPS , NULL }, - { CONF_AMRECOVER_DO_FSF , CONFTYPE_BOOL , read_bool , CNF_AMRECOVER_DO_FSF , NULL }, - { CONF_AMRECOVER_CHANGER , CONFTYPE_STRING , read_string , CNF_AMRECOVER_CHANGER , NULL }, - { CONF_AMRECOVER_CHECK_LABEL, CONFTYPE_BOOL , read_bool , CNF_AMRECOVER_CHECK_LABEL, NULL }, - { CONF_CONNECT_TRIES , CONFTYPE_INT , read_int , CNF_CONNECT_TRIES , validate_positive1 }, - { CONF_REP_TRIES , CONFTYPE_INT , read_int , CNF_REP_TRIES , validate_positive1 }, - { CONF_REQ_TRIES , CONFTYPE_INT , read_int , CNF_REQ_TRIES , validate_positive1 }, - { CONF_DEBUG_AMANDAD , CONFTYPE_INT , read_int , CNF_DEBUG_AMANDAD , validate_debug }, - { CONF_DEBUG_AMIDXTAPED , CONFTYPE_INT , read_int , CNF_DEBUG_AMIDXTAPED , validate_debug }, - { CONF_DEBUG_AMINDEXD , CONFTYPE_INT , read_int , CNF_DEBUG_AMINDEXD , validate_debug }, - { CONF_DEBUG_AMRECOVER , CONFTYPE_INT , read_int , CNF_DEBUG_AMRECOVER , validate_debug }, - { CONF_DEBUG_AUTH , CONFTYPE_INT , read_int , CNF_DEBUG_AUTH , validate_debug }, - { CONF_DEBUG_EVENT , CONFTYPE_INT , read_int , CNF_DEBUG_EVENT , validate_debug }, - { CONF_DEBUG_HOLDING , CONFTYPE_INT , read_int , CNF_DEBUG_HOLDING , validate_debug }, - { CONF_DEBUG_PROTOCOL , CONFTYPE_INT , read_int , CNF_DEBUG_PROTOCOL , validate_debug }, - { CONF_DEBUG_PLANNER , CONFTYPE_INT , read_int , CNF_DEBUG_PLANNER , validate_debug }, - { CONF_DEBUG_DRIVER , CONFTYPE_INT , read_int , CNF_DEBUG_DRIVER , validate_debug }, - { CONF_DEBUG_DUMPER , CONFTYPE_INT , read_int , CNF_DEBUG_DUMPER , validate_debug }, - { CONF_DEBUG_CHUNKER , CONFTYPE_INT , read_int , CNF_DEBUG_CHUNKER , validate_debug }, - { CONF_DEBUG_TAPER , CONFTYPE_INT , read_int , CNF_DEBUG_TAPER , validate_debug }, - { CONF_DEBUG_SELFCHECK , CONFTYPE_INT , read_int , CNF_DEBUG_SELFCHECK , validate_debug }, - { CONF_DEBUG_SENDSIZE , CONFTYPE_INT , read_int , CNF_DEBUG_SENDSIZE , validate_debug }, - { CONF_DEBUG_SENDBACKUP , CONFTYPE_INT , read_int , CNF_DEBUG_SENDBACKUP , validate_debug }, - { CONF_RESERVED_UDP_PORT , CONFTYPE_INTRANGE , read_intrange, CNF_RESERVED_UDP_PORT , validate_reserved_port_range }, - { CONF_RESERVED_TCP_PORT , CONFTYPE_INTRANGE , read_intrange, CNF_RESERVED_TCP_PORT , validate_reserved_port_range }, - { CONF_UNRESERVED_TCP_PORT , CONFTYPE_INTRANGE , read_intrange, CNF_UNRESERVED_TCP_PORT , validate_unreserved_port_range }, - { CONF_UNKNOWN , CONFTYPE_INT , NULL , CNF_CNF , NULL } -}; - -t_conf_var tapetype_var [] = { - { CONF_COMMENT , CONFTYPE_STRING, read_string, TAPETYPE_COMMENT , NULL }, - { CONF_LBL_TEMPL , CONFTYPE_STRING, read_string, TAPETYPE_LBL_TEMPL , NULL }, - { CONF_BLOCKSIZE , CONFTYPE_SIZE , read_size , TAPETYPE_BLOCKSIZE , validate_blocksize }, - { CONF_READBLOCKSIZE, CONFTYPE_SIZE , read_size , TAPETYPE_READBLOCKSIZE, validate_blocksize }, - { CONF_LENGTH , CONFTYPE_AM64 , read_am64 , TAPETYPE_LENGTH , validate_positive0 }, - { CONF_FILEMARK , CONFTYPE_AM64 , read_am64 , TAPETYPE_FILEMARK , NULL }, - { CONF_SPEED , CONFTYPE_INT , read_int , TAPETYPE_SPEED , validate_positive0 }, - { CONF_FILE_PAD , CONFTYPE_BOOL , read_bool , TAPETYPE_FILE_PAD , NULL }, - { CONF_UNKNOWN , CONFTYPE_INT , NULL , TAPETYPE_TAPETYPE , NULL } -}; - -t_conf_var dumptype_var [] = { - { CONF_COMMENT , CONFTYPE_STRING , read_string , DUMPTYPE_COMMENT , NULL }, - { CONF_AUTH , CONFTYPE_STRING , read_string , DUMPTYPE_SECURITY_DRIVER , NULL }, - { CONF_BUMPDAYS , CONFTYPE_INT , read_int , DUMPTYPE_BUMPDAYS , NULL }, - { CONF_BUMPMULT , CONFTYPE_REAL , read_real , DUMPTYPE_BUMPMULT , NULL }, - { CONF_BUMPSIZE , CONFTYPE_AM64 , read_am64 , DUMPTYPE_BUMPSIZE , NULL }, - { CONF_BUMPPERCENT , CONFTYPE_INT , read_int , DUMPTYPE_BUMPPERCENT , NULL }, - { CONF_COMPRATE , CONFTYPE_REAL , get_comprate, DUMPTYPE_COMPRATE , NULL }, - { CONF_COMPRESS , CONFTYPE_INT , get_compress, DUMPTYPE_COMPRESS , NULL }, - { CONF_ENCRYPT , CONFTYPE_INT , get_encrypt , DUMPTYPE_ENCRYPT , NULL }, - { CONF_DUMPCYCLE , CONFTYPE_INT , read_int , DUMPTYPE_DUMPCYCLE , validate_positive0 }, - { CONF_EXCLUDE , CONFTYPE_EXINCLUDE, get_exclude , DUMPTYPE_EXCLUDE , NULL }, - { CONF_INCLUDE , CONFTYPE_EXINCLUDE, get_exclude , DUMPTYPE_INCLUDE , NULL }, - { CONF_IGNORE , CONFTYPE_BOOL , read_bool , DUMPTYPE_IGNORE , NULL }, - { CONF_HOLDING , CONFTYPE_HOLDING , get_holding , DUMPTYPE_HOLDINGDISK , NULL }, - { CONF_INDEX , CONFTYPE_BOOL , read_bool , DUMPTYPE_INDEX , NULL }, - { CONF_KENCRYPT , CONFTYPE_BOOL , read_bool , DUMPTYPE_KENCRYPT , NULL }, - { CONF_MAXDUMPS , CONFTYPE_INT , read_int , DUMPTYPE_MAXDUMPS , validate_positive1 }, - { CONF_MAXPROMOTEDAY , CONFTYPE_INT , read_int , DUMPTYPE_MAXPROMOTEDAY , validate_positive0 }, - { CONF_PRIORITY , CONFTYPE_PRIORITY , get_priority, DUMPTYPE_PRIORITY , NULL }, - { CONF_PROGRAM , CONFTYPE_STRING , read_string , DUMPTYPE_PROGRAM , NULL }, - { CONF_RECORD , CONFTYPE_BOOL , read_bool , DUMPTYPE_RECORD , NULL }, - { CONF_SKIP_FULL , CONFTYPE_BOOL , read_bool , DUMPTYPE_SKIP_FULL , NULL }, - { CONF_SKIP_INCR , CONFTYPE_BOOL , read_bool , DUMPTYPE_SKIP_INCR , NULL }, - { CONF_STARTTIME , CONFTYPE_TIME , read_time , DUMPTYPE_STARTTIME , NULL }, - { CONF_STRATEGY , CONFTYPE_INT , get_strategy, DUMPTYPE_STRATEGY , NULL }, - { CONF_TAPE_SPLITSIZE , CONFTYPE_AM64 , read_am64 , DUMPTYPE_TAPE_SPLITSIZE , validate_positive0 }, - { CONF_SPLIT_DISKBUFFER , CONFTYPE_STRING , read_string , DUMPTYPE_SPLIT_DISKBUFFER , NULL }, - { CONF_ESTIMATE , CONFTYPE_INT , get_estimate, DUMPTYPE_ESTIMATE , NULL }, - { CONF_SRV_ENCRYPT , CONFTYPE_STRING , read_string , DUMPTYPE_SRV_ENCRYPT , NULL }, - { CONF_CLNT_ENCRYPT , CONFTYPE_STRING , read_string , DUMPTYPE_CLNT_ENCRYPT , NULL }, - { CONF_AMANDAD_PATH , CONFTYPE_STRING , read_string , DUMPTYPE_AMANDAD_PATH , NULL }, - { CONF_CLIENT_USERNAME , CONFTYPE_STRING , read_string , DUMPTYPE_CLIENT_USERNAME , NULL }, - { CONF_SSH_KEYS , CONFTYPE_STRING , read_string , DUMPTYPE_SSH_KEYS , NULL }, - { CONF_SRVCOMPPROG , CONFTYPE_STRING , read_string , DUMPTYPE_SRVCOMPPROG , NULL }, - { CONF_CLNTCOMPPROG , CONFTYPE_STRING , read_string , DUMPTYPE_CLNTCOMPPROG , NULL }, - { CONF_FALLBACK_SPLITSIZE, CONFTYPE_AM64 , read_am64 , DUMPTYPE_FALLBACK_SPLITSIZE, NULL }, - { CONF_SRV_DECRYPT_OPT , CONFTYPE_STRING , read_string , DUMPTYPE_SRV_DECRYPT_OPT , NULL }, - { CONF_CLNT_DECRYPT_OPT , CONFTYPE_STRING , read_string , DUMPTYPE_CLNT_DECRYPT_OPT , NULL }, - { CONF_UNKNOWN , CONFTYPE_INT , NULL , DUMPTYPE_DUMPTYPE , NULL } -}; - -t_conf_var holding_var [] = { - { CONF_DIRECTORY, CONFTYPE_STRING, read_string, HOLDING_DISKDIR , NULL }, - { CONF_COMMENT , CONFTYPE_STRING, read_string, HOLDING_COMMENT , NULL }, - { CONF_USE , CONFTYPE_AM64 , read_am64 , HOLDING_DISKSIZE , validate_use }, - { CONF_CHUNKSIZE, CONFTYPE_AM64 , read_am64 , HOLDING_CHUNKSIZE, validate_chunksize }, - { CONF_UNKNOWN , CONFTYPE_INT , NULL , HOLDING_HOLDING , NULL } +/* A keyword table for recognizing unit suffixes. No distinction is made for kinds + * of suffixes: 1024 weeks = 7 k. */ +keytab_t numb_keytable[] = { + { "B", CONF_MULT1 }, + { "BPS", CONF_MULT1 }, + { "BYTE", CONF_MULT1 }, + { "BYTES", CONF_MULT1 }, + { "DAY", CONF_MULT1 }, + { "DAYS", CONF_MULT1 }, + { "INF", CONF_AMINFINITY }, + { "K", CONF_MULT1K }, + { "KB", CONF_MULT1K }, + { "KBPS", CONF_MULT1K }, + { "KBYTE", CONF_MULT1K }, + { "KBYTES", CONF_MULT1K }, + { "KILOBYTE", CONF_MULT1K }, + { "KILOBYTES", CONF_MULT1K }, + { "KPS", CONF_MULT1K }, + { "M", CONF_MULT1M }, + { "MB", CONF_MULT1M }, + { "MBPS", CONF_MULT1M }, + { "MBYTE", CONF_MULT1M }, + { "MBYTES", CONF_MULT1M }, + { "MEG", CONF_MULT1M }, + { "MEGABYTE", CONF_MULT1M }, + { "MEGABYTES", CONF_MULT1M }, + { "G", CONF_MULT1G }, + { "GB", CONF_MULT1G }, + { "GBPS", CONF_MULT1G }, + { "GBYTE", CONF_MULT1G }, + { "GBYTES", CONF_MULT1G }, + { "GIG", CONF_MULT1G }, + { "GIGABYTE", CONF_MULT1G }, + { "GIGABYTES", CONF_MULT1G }, + { "T", CONF_MULT1T }, + { "TB", CONF_MULT1T }, + { "TBPS", CONF_MULT1T }, + { "TBYTE", CONF_MULT1T }, + { "TBYTES", CONF_MULT1T }, + { "TERA", CONF_MULT1T }, + { "TERABYTE", CONF_MULT1T }, + { "TERABYTES", CONF_MULT1T }, + { "MPS", CONF_MULT1M }, + { "TAPE", CONF_MULT1 }, + { "TAPES", CONF_MULT1 }, + { "WEEK", CONF_MULT7 }, + { "WEEKS", CONF_MULT7 }, + { NULL, CONF_IDENT } }; -/* -** ------------------------ -** External entry points -** ------------------------ -*/ - -int -read_conffile( - char *filename) -{ - interface_t *ip; +/* Boolean keywords -- all the ways to say "true" and "false" in amanda.conf */ +keytab_t bool_keytable[] = { + { "Y", CONF_ATRUE }, + { "YES", CONF_ATRUE }, + { "T", CONF_ATRUE }, + { "TRUE", CONF_ATRUE }, + { "ON", CONF_ATRUE }, + { "N", CONF_AFALSE }, + { "NO", CONF_AFALSE }, + { "F", CONF_AFALSE }, + { "FALSE", CONF_AFALSE }, + { "OFF", CONF_AFALSE }, + { NULL, CONF_IDENT } +}; - my_keytab = server_keytab; - my_var = server_var; - init_defaults(); +/* no_yes_all keywords -- all the ways to say "true" and "false" in amanda.conf */ +keytab_t no_yes_all_keytable[] = { + { "Y", CONF_ATRUE }, + { "YES", CONF_ATRUE }, + { "T", CONF_ATRUE }, + { "TRUE", CONF_ATRUE }, + { "ON", CONF_ATRUE }, + { "N", CONF_AFALSE }, + { "NO", CONF_AFALSE }, + { "F", CONF_AFALSE }, + { "FALSE", CONF_AFALSE }, + { "OFF", CONF_AFALSE }, + { "ALL", CONF_ALL }, + { NULL, CONF_IDENT } +}; - /* We assume that conf_confname & conf are initialized to NULL above */ - read_conffile_recursively(filename); +/* Now, the parser tables for client and server global parameters, and for + * each of the server subsections */ +conf_var_t client_var [] = { + { CONF_CONF , CONFTYPE_STR , read_str , CNF_CONF , NULL }, + { CONF_AMDUMP_SERVER , CONFTYPE_STR , read_str , CNF_AMDUMP_SERVER , NULL }, + { CONF_INDEX_SERVER , CONFTYPE_STR , read_str , CNF_INDEX_SERVER , NULL }, + { CONF_TAPE_SERVER , CONFTYPE_STR , read_str , CNF_TAPE_SERVER , NULL }, + { CONF_TAPEDEV , CONFTYPE_STR , read_str , CNF_TAPEDEV , NULL }, + { CONF_AUTH , CONFTYPE_STR , read_str , CNF_AUTH , NULL }, + { CONF_SSH_KEYS , CONFTYPE_STR , read_str , CNF_SSH_KEYS , NULL }, + { CONF_AMANDAD_PATH , CONFTYPE_STR , read_str , CNF_AMANDAD_PATH , NULL }, + { CONF_CLIENT_USERNAME , CONFTYPE_STR , read_str , CNF_CLIENT_USERNAME , NULL }, + { CONF_CLIENT_PORT , CONFTYPE_STR , read_int_or_str, CNF_CLIENT_PORT , NULL }, + { CONF_GNUTAR_LIST_DIR , CONFTYPE_STR , read_str , CNF_GNUTAR_LIST_DIR , NULL }, + { CONF_AMANDATES , CONFTYPE_STR , read_str , CNF_AMANDATES , NULL }, + { CONF_MAILER , CONFTYPE_STR , read_str , CNF_MAILER , NULL }, + { CONF_KRB5KEYTAB , CONFTYPE_STR , read_str , CNF_KRB5KEYTAB , NULL }, + { CONF_KRB5PRINCIPAL , CONFTYPE_STR , read_str , CNF_KRB5PRINCIPAL , NULL }, + { CONF_CONNECT_TRIES , CONFTYPE_INT , read_int , CNF_CONNECT_TRIES , validate_positive }, + { CONF_REP_TRIES , CONFTYPE_INT , read_int , CNF_REP_TRIES , validate_positive }, + { CONF_REQ_TRIES , CONFTYPE_INT , read_int , CNF_REQ_TRIES , validate_positive }, + { CONF_DEBUG_DAYS , CONFTYPE_INT , read_int , CNF_DEBUG_DAYS , NULL }, + { CONF_DEBUG_AMANDAD , CONFTYPE_INT , read_int , CNF_DEBUG_AMANDAD , validate_debug }, + { CONF_DEBUG_RECOVERY , CONFTYPE_INT , read_int , CNF_DEBUG_RECOVERY , validate_debug }, + { CONF_DEBUG_AMIDXTAPED , CONFTYPE_INT , read_int , CNF_DEBUG_AMIDXTAPED , validate_debug }, + { CONF_DEBUG_AMINDEXD , CONFTYPE_INT , read_int , CNF_DEBUG_AMINDEXD , validate_debug }, + { CONF_DEBUG_AMRECOVER , CONFTYPE_INT , read_int , CNF_DEBUG_AMRECOVER , validate_debug }, + { CONF_DEBUG_AUTH , CONFTYPE_INT , read_int , CNF_DEBUG_AUTH , validate_debug }, + { CONF_DEBUG_EVENT , CONFTYPE_INT , read_int , CNF_DEBUG_EVENT , validate_debug }, + { CONF_DEBUG_HOLDING , CONFTYPE_INT , read_int , CNF_DEBUG_HOLDING , validate_debug }, + { CONF_DEBUG_PROTOCOL , CONFTYPE_INT , read_int , CNF_DEBUG_PROTOCOL , validate_debug }, + { CONF_DEBUG_PLANNER , CONFTYPE_INT , read_int , CNF_DEBUG_PLANNER , validate_debug }, + { CONF_DEBUG_DRIVER , CONFTYPE_INT , read_int , CNF_DEBUG_DRIVER , validate_debug }, + { CONF_DEBUG_DUMPER , CONFTYPE_INT , read_int , CNF_DEBUG_DUMPER , validate_debug }, + { CONF_DEBUG_CHUNKER , CONFTYPE_INT , read_int , CNF_DEBUG_CHUNKER , validate_debug }, + { CONF_DEBUG_TAPER , CONFTYPE_INT , read_int , CNF_DEBUG_TAPER , validate_debug }, + { CONF_DEBUG_SELFCHECK , CONFTYPE_INT , read_int , CNF_DEBUG_SELFCHECK , validate_debug }, + { CONF_DEBUG_SENDSIZE , CONFTYPE_INT , read_int , CNF_DEBUG_SENDSIZE , validate_debug }, + { CONF_DEBUG_SENDBACKUP , CONFTYPE_INT , read_int , CNF_DEBUG_SENDBACKUP , validate_debug }, + { CONF_RESERVED_UDP_PORT , CONFTYPE_INTRANGE, read_intrange, CNF_RESERVED_UDP_PORT , validate_reserved_port_range }, + { CONF_RESERVED_TCP_PORT , CONFTYPE_INTRANGE, read_intrange, CNF_RESERVED_TCP_PORT , validate_reserved_port_range }, + { CONF_UNRESERVED_TCP_PORT, CONFTYPE_INTRANGE, read_intrange, CNF_UNRESERVED_TCP_PORT, validate_unreserved_port_range }, + { CONF_PROPERTY , CONFTYPE_PROPLIST, read_property, CNF_PROPERTY , NULL }, + { CONF_APPLICATION , CONFTYPE_STR , read_dapplication, DUMPTYPE_APPLICATION, NULL }, + { CONF_SCRIPT , CONFTYPE_STR , read_dpp_script, DUMPTYPE_SCRIPTLIST, NULL }, + { CONF_UNKNOWN , CONFTYPE_INT , NULL , CNF_CNF , NULL } +}; - /* overwrite with command line option */ - command_overwrite(program_options, my_var, my_keytab, conf_data, - ""); +conf_var_t server_var [] = { + { CONF_ORG , CONFTYPE_STR , read_str , CNF_ORG , NULL }, + { CONF_MAILTO , CONFTYPE_STR , read_str , CNF_MAILTO , NULL }, + { CONF_DUMPUSER , CONFTYPE_STR , read_str , CNF_DUMPUSER , NULL }, + { CONF_PRINTER , CONFTYPE_STR , read_str , CNF_PRINTER , NULL }, + { CONF_MAILER , CONFTYPE_STR , read_str , CNF_MAILER , NULL }, + { CONF_TAPEDEV , CONFTYPE_STR , read_str , CNF_TAPEDEV , NULL }, + { CONF_DEVICE_PROPERTY , CONFTYPE_PROPLIST , read_property , CNF_DEVICE_PROPERTY , NULL }, + { CONF_PROPERTY , CONFTYPE_PROPLIST , read_property , CNF_PROPERTY , NULL }, + { CONF_TPCHANGER , CONFTYPE_STR , read_str , CNF_TPCHANGER , NULL }, + { CONF_CHANGERDEV , CONFTYPE_STR , read_str , CNF_CHANGERDEV , NULL }, + { CONF_CHANGERFILE , CONFTYPE_STR , read_str , CNF_CHANGERFILE , NULL }, + { CONF_LABELSTR , CONFTYPE_STR , read_str , CNF_LABELSTR , NULL }, + { CONF_TAPELIST , CONFTYPE_STR , read_str , CNF_TAPELIST , NULL }, + { CONF_DISKFILE , CONFTYPE_STR , read_str , CNF_DISKFILE , NULL }, + { CONF_INFOFILE , CONFTYPE_STR , read_str , CNF_INFOFILE , NULL }, + { CONF_LOGDIR , CONFTYPE_STR , read_str , CNF_LOGDIR , NULL }, + { CONF_INDEXDIR , CONFTYPE_STR , read_str , CNF_INDEXDIR , NULL }, + { CONF_TAPETYPE , CONFTYPE_IDENT , read_ident , CNF_TAPETYPE , NULL }, + { CONF_HOLDING , CONFTYPE_IDENTLIST, read_holdingdisk , CNF_HOLDINGDISK , NULL }, + { CONF_DUMPCYCLE , CONFTYPE_INT , read_int , CNF_DUMPCYCLE , validate_nonnegative }, + { CONF_RUNSPERCYCLE , CONFTYPE_INT , read_int , CNF_RUNSPERCYCLE , validate_runspercycle }, + { CONF_RUNTAPES , CONFTYPE_INT , read_int , CNF_RUNTAPES , validate_nonnegative }, + { CONF_TAPECYCLE , CONFTYPE_INT , read_int , CNF_TAPECYCLE , validate_positive }, + { CONF_BUMPDAYS , CONFTYPE_INT , read_int , CNF_BUMPDAYS , validate_positive }, + { CONF_BUMPSIZE , CONFTYPE_INT64 , read_int64 , CNF_BUMPSIZE , validate_positive }, + { CONF_BUMPPERCENT , CONFTYPE_INT , read_int , CNF_BUMPPERCENT , validate_bumppercent }, + { CONF_BUMPMULT , CONFTYPE_REAL , read_real , CNF_BUMPMULT , validate_bumpmult }, + { CONF_NETUSAGE , CONFTYPE_INT , read_int , CNF_NETUSAGE , validate_positive }, + { CONF_INPARALLEL , CONFTYPE_INT , read_int , CNF_INPARALLEL , validate_inparallel }, + { CONF_DUMPORDER , CONFTYPE_STR , read_str , CNF_DUMPORDER , NULL }, + { CONF_MAXDUMPS , CONFTYPE_INT , read_int , CNF_MAXDUMPS , validate_positive }, + { CONF_MAX_DLE_BY_VOLUME , CONFTYPE_INT , read_int , CNF_MAX_DLE_BY_VOLUME , validate_positive }, + { CONF_ETIMEOUT , CONFTYPE_INT , read_int , CNF_ETIMEOUT , validate_non_zero }, + { CONF_DTIMEOUT , CONFTYPE_INT , read_int , CNF_DTIMEOUT , validate_positive }, + { CONF_CTIMEOUT , CONFTYPE_INT , read_int , CNF_CTIMEOUT , validate_positive }, + { CONF_DEVICE_OUTPUT_BUFFER_SIZE, CONFTYPE_SIZE , read_size , CNF_DEVICE_OUTPUT_BUFFER_SIZE, validate_positive }, + { CONF_COLUMNSPEC , CONFTYPE_STR , read_str , CNF_COLUMNSPEC , NULL }, + { CONF_TAPERALGO , CONFTYPE_TAPERALGO, read_taperalgo , CNF_TAPERALGO , NULL }, + { CONF_TAPER_PARALLEL_WRITE , CONFTYPE_INT , read_int , CNF_TAPER_PARALLEL_WRITE , NULL }, + { CONF_SEND_AMREPORT_ON , CONFTYPE_SEND_AMREPORT_ON, read_send_amreport_on, CNF_SEND_AMREPORT_ON , NULL }, + { CONF_FLUSH_THRESHOLD_DUMPED, CONFTYPE_INT , read_int , CNF_FLUSH_THRESHOLD_DUMPED, validate_nonnegative }, + { CONF_FLUSH_THRESHOLD_SCHEDULED, CONFTYPE_INT , read_int , CNF_FLUSH_THRESHOLD_SCHEDULED, validate_nonnegative }, + { CONF_TAPERFLUSH , CONFTYPE_INT , read_int , CNF_TAPERFLUSH , validate_nonnegative }, + { CONF_DISPLAYUNIT , CONFTYPE_STR , read_str , CNF_DISPLAYUNIT , validate_displayunit }, + { CONF_AUTOFLUSH , CONFTYPE_NO_YES_ALL,read_no_yes_all , CNF_AUTOFLUSH , NULL }, + { CONF_RESERVE , CONFTYPE_INT , read_int , CNF_RESERVE , validate_reserve }, + { CONF_MAXDUMPSIZE , CONFTYPE_INT64 , read_int64 , CNF_MAXDUMPSIZE , NULL }, + { CONF_KRB5KEYTAB , CONFTYPE_STR , read_str , CNF_KRB5KEYTAB , NULL }, + { CONF_KRB5PRINCIPAL , CONFTYPE_STR , read_str , CNF_KRB5PRINCIPAL , NULL }, + { CONF_LABEL_NEW_TAPES , CONFTYPE_STR , read_str , CNF_LABEL_NEW_TAPES , NULL }, + { CONF_AUTOLABEL , CONFTYPE_AUTOLABEL, read_autolabel , CNF_AUTOLABEL , NULL }, + { CONF_META_AUTOLABEL , CONFTYPE_STR , read_str , CNF_META_AUTOLABEL , NULL }, + { CONF_EJECT_VOLUME , CONFTYPE_BOOLEAN , read_bool , CNF_EJECT_VOLUME , NULL }, + { CONF_TMPDIR , CONFTYPE_STR , read_str , CNF_TMPDIR , validate_tmpdir }, + { CONF_USETIMESTAMPS , CONFTYPE_BOOLEAN , read_bool , CNF_USETIMESTAMPS , NULL }, + { CONF_AMRECOVER_DO_FSF , CONFTYPE_BOOLEAN , read_bool , CNF_AMRECOVER_DO_FSF , NULL }, + { CONF_AMRECOVER_CHANGER , CONFTYPE_STR , read_str , CNF_AMRECOVER_CHANGER , NULL }, + { CONF_AMRECOVER_CHECK_LABEL, CONFTYPE_BOOLEAN , read_bool , CNF_AMRECOVER_CHECK_LABEL, NULL }, + { CONF_CONNECT_TRIES , CONFTYPE_INT , read_int , CNF_CONNECT_TRIES , validate_positive }, + { CONF_REP_TRIES , CONFTYPE_INT , read_int , CNF_REP_TRIES , validate_positive }, + { CONF_REQ_TRIES , CONFTYPE_INT , read_int , CNF_REQ_TRIES , validate_positive }, + { CONF_DEBUG_DAYS , CONFTYPE_INT , read_int , CNF_DEBUG_DAYS , NULL }, + { CONF_DEBUG_AMANDAD , CONFTYPE_INT , read_int , CNF_DEBUG_AMANDAD , validate_debug }, + { CONF_DEBUG_RECOVERY , CONFTYPE_INT , read_int , CNF_DEBUG_RECOVERY , validate_debug }, + { CONF_DEBUG_AMIDXTAPED , CONFTYPE_INT , read_int , CNF_DEBUG_AMIDXTAPED , validate_debug }, + { CONF_DEBUG_AMINDEXD , CONFTYPE_INT , read_int , CNF_DEBUG_AMINDEXD , validate_debug }, + { CONF_DEBUG_AMRECOVER , CONFTYPE_INT , read_int , CNF_DEBUG_AMRECOVER , validate_debug }, + { CONF_DEBUG_AUTH , CONFTYPE_INT , read_int , CNF_DEBUG_AUTH , validate_debug }, + { CONF_DEBUG_EVENT , CONFTYPE_INT , read_int , CNF_DEBUG_EVENT , validate_debug }, + { CONF_DEBUG_HOLDING , CONFTYPE_INT , read_int , CNF_DEBUG_HOLDING , validate_debug }, + { CONF_DEBUG_PROTOCOL , CONFTYPE_INT , read_int , CNF_DEBUG_PROTOCOL , validate_debug }, + { CONF_DEBUG_PLANNER , CONFTYPE_INT , read_int , CNF_DEBUG_PLANNER , validate_debug }, + { CONF_DEBUG_DRIVER , CONFTYPE_INT , read_int , CNF_DEBUG_DRIVER , validate_debug }, + { CONF_DEBUG_DUMPER , CONFTYPE_INT , read_int , CNF_DEBUG_DUMPER , validate_debug }, + { CONF_DEBUG_CHUNKER , CONFTYPE_INT , read_int , CNF_DEBUG_CHUNKER , validate_debug }, + { CONF_DEBUG_TAPER , CONFTYPE_INT , read_int , CNF_DEBUG_TAPER , validate_debug }, + { CONF_DEBUG_SELFCHECK , CONFTYPE_INT , read_int , CNF_DEBUG_SELFCHECK , validate_debug }, + { CONF_DEBUG_SENDSIZE , CONFTYPE_INT , read_int , CNF_DEBUG_SENDSIZE , validate_debug }, + { CONF_DEBUG_SENDBACKUP , CONFTYPE_INT , read_int , CNF_DEBUG_SENDBACKUP , validate_debug }, + { CONF_RESERVED_UDP_PORT , CONFTYPE_INTRANGE , read_intrange , CNF_RESERVED_UDP_PORT , validate_reserved_port_range }, + { CONF_RESERVED_TCP_PORT , CONFTYPE_INTRANGE , read_intrange , CNF_RESERVED_TCP_PORT , validate_reserved_port_range }, + { CONF_UNRESERVED_TCP_PORT , CONFTYPE_INTRANGE , read_intrange , CNF_UNRESERVED_TCP_PORT , validate_unreserved_port_range }, + { CONF_RECOVERY_LIMIT , CONFTYPE_HOST_LIMIT, read_host_limit , CNF_RECOVERY_LIMIT , NULL }, + { CONF_INTERACTIVITY , CONFTYPE_STR , read_dinteractivity, CNF_INTERACTIVITY , NULL }, + { CONF_TAPERSCAN , CONFTYPE_STR , read_dtaperscan , CNF_TAPERSCAN , NULL }, + { CONF_REPORT_USE_MEDIA , CONFTYPE_BOOLEAN , read_bool , CNF_REPORT_USE_MEDIA , NULL }, + { CONF_REPORT_NEXT_MEDIA , CONFTYPE_BOOLEAN , read_bool , CNF_REPORT_NEXT_MEDIA , NULL }, + { CONF_UNKNOWN , CONFTYPE_INT , NULL , CNF_CNF , NULL } +}; - if(got_parserror != -1 ) { - if(lookup_tapetype(conf_data[CNF_TAPETYPE].v.s) == NULL) { - char *save_confname = conf_confname; +conf_var_t tapetype_var [] = { + { CONF_COMMENT , CONFTYPE_STR , read_str , TAPETYPE_COMMENT , NULL }, + { CONF_LBL_TEMPL , CONFTYPE_STR , read_str , TAPETYPE_LBL_TEMPL , NULL }, + { CONF_BLOCKSIZE , CONFTYPE_SIZE , read_size , TAPETYPE_BLOCKSIZE , validate_blocksize }, + { CONF_READBLOCKSIZE , CONFTYPE_SIZE , read_size , TAPETYPE_READBLOCKSIZE , validate_blocksize }, + { CONF_LENGTH , CONFTYPE_INT64 , read_int64 , TAPETYPE_LENGTH , validate_nonnegative }, + { CONF_FILEMARK , CONFTYPE_INT64 , read_int64 , TAPETYPE_FILEMARK , NULL }, + { CONF_SPEED , CONFTYPE_INT , read_int , TAPETYPE_SPEED , validate_nonnegative }, + { CONF_PART_SIZE , CONFTYPE_INT64 , read_int64 , TAPETYPE_PART_SIZE , validate_nonnegative }, + { CONF_PART_CACHE_TYPE , CONFTYPE_PART_CACHE_TYPE, read_part_cache_type, TAPETYPE_PART_CACHE_TYPE, NULL }, + { CONF_PART_CACHE_DIR , CONFTYPE_STR , read_str , TAPETYPE_PART_CACHE_DIR , NULL }, + { CONF_PART_CACHE_MAX_SIZE , CONFTYPE_INT64 , read_int64 , TAPETYPE_PART_CACHE_MAX_SIZE, validate_nonnegative }, + { CONF_UNKNOWN , CONFTYPE_INT , NULL , TAPETYPE_TAPETYPE , NULL } +}; - conf_confname = filename; - if(!conf_data[CNF_TAPETYPE].seen) - conf_parserror("default tapetype %s not defined", conf_data[CNF_TAPETYPE].v.s); - else { - conf_line_num = conf_data[CNF_TAPETYPE].seen; - conf_parserror("tapetype %s not defined", conf_data[CNF_TAPETYPE].v.s); - } - conf_confname = save_confname; - } - } +conf_var_t dumptype_var [] = { + { CONF_COMMENT , CONFTYPE_STR , read_str , DUMPTYPE_COMMENT , NULL }, + { CONF_AUTH , CONFTYPE_STR , read_str , DUMPTYPE_AUTH , NULL }, + { CONF_BUMPDAYS , CONFTYPE_INT , read_int , DUMPTYPE_BUMPDAYS , NULL }, + { CONF_BUMPMULT , CONFTYPE_REAL , read_real , DUMPTYPE_BUMPMULT , NULL }, + { CONF_BUMPSIZE , CONFTYPE_INT64 , read_int64 , DUMPTYPE_BUMPSIZE , NULL }, + { CONF_BUMPPERCENT , CONFTYPE_INT , read_int , DUMPTYPE_BUMPPERCENT , NULL }, + { CONF_COMPRATE , CONFTYPE_REAL , read_rate , DUMPTYPE_COMPRATE , NULL }, + { CONF_COMPRESS , CONFTYPE_INT , read_compress , DUMPTYPE_COMPRESS , NULL }, + { CONF_ENCRYPT , CONFTYPE_INT , read_encrypt , DUMPTYPE_ENCRYPT , NULL }, + { CONF_DUMPCYCLE , CONFTYPE_INT , read_int , DUMPTYPE_DUMPCYCLE , validate_nonnegative }, + { CONF_EXCLUDE , CONFTYPE_EXINCLUDE, read_exinclude, DUMPTYPE_EXCLUDE , NULL }, + { CONF_INCLUDE , CONFTYPE_EXINCLUDE, read_exinclude, DUMPTYPE_INCLUDE , NULL }, + { CONF_IGNORE , CONFTYPE_BOOLEAN , read_bool , DUMPTYPE_IGNORE , NULL }, + { CONF_HOLDING , CONFTYPE_HOLDING , read_holding , DUMPTYPE_HOLDINGDISK , NULL }, + { CONF_INDEX , CONFTYPE_BOOLEAN , read_bool , DUMPTYPE_INDEX , NULL }, + { CONF_KENCRYPT , CONFTYPE_BOOLEAN , read_bool , DUMPTYPE_KENCRYPT , NULL }, + { CONF_MAXDUMPS , CONFTYPE_INT , read_int , DUMPTYPE_MAXDUMPS , validate_positive }, + { CONF_MAXPROMOTEDAY , CONFTYPE_INT , read_int , DUMPTYPE_MAXPROMOTEDAY , validate_nonnegative }, + { CONF_PRIORITY , CONFTYPE_PRIORITY , read_priority , DUMPTYPE_PRIORITY , NULL }, + { CONF_PROGRAM , CONFTYPE_STR , read_str , DUMPTYPE_PROGRAM , validate_program }, + { CONF_PROPERTY , CONFTYPE_PROPLIST , read_property , DUMPTYPE_PROPERTY , NULL }, + { CONF_RECORD , CONFTYPE_BOOLEAN , read_bool , DUMPTYPE_RECORD , NULL }, + { CONF_SKIP_FULL , CONFTYPE_BOOLEAN , read_bool , DUMPTYPE_SKIP_FULL , NULL }, + { CONF_SKIP_INCR , CONFTYPE_BOOLEAN , read_bool , DUMPTYPE_SKIP_INCR , NULL }, + { CONF_STARTTIME , CONFTYPE_TIME , read_time , DUMPTYPE_STARTTIME , NULL }, + { CONF_STRATEGY , CONFTYPE_INT , read_strategy , DUMPTYPE_STRATEGY , NULL }, + { CONF_TAPE_SPLITSIZE , CONFTYPE_INT64 , read_int64 , DUMPTYPE_TAPE_SPLITSIZE , validate_nonnegative }, + { CONF_SPLIT_DISKBUFFER , CONFTYPE_STR , read_str , DUMPTYPE_SPLIT_DISKBUFFER , NULL }, + { CONF_ESTIMATE , CONFTYPE_ESTIMATELIST, read_estimatelist , DUMPTYPE_ESTIMATELIST , NULL }, + { CONF_SRV_ENCRYPT , CONFTYPE_STR , read_str , DUMPTYPE_SRV_ENCRYPT , NULL }, + { CONF_CLNT_ENCRYPT , CONFTYPE_STR , read_str , DUMPTYPE_CLNT_ENCRYPT , NULL }, + { CONF_AMANDAD_PATH , CONFTYPE_STR , read_str , DUMPTYPE_AMANDAD_PATH , NULL }, + { CONF_CLIENT_USERNAME , CONFTYPE_STR , read_str , DUMPTYPE_CLIENT_USERNAME , NULL }, + { CONF_CLIENT_PORT , CONFTYPE_STR , read_int_or_str, DUMPTYPE_CLIENT_PORT , NULL }, + { CONF_SSH_KEYS , CONFTYPE_STR , read_str , DUMPTYPE_SSH_KEYS , NULL }, + { CONF_SRVCOMPPROG , CONFTYPE_STR , read_str , DUMPTYPE_SRVCOMPPROG , NULL }, + { CONF_CLNTCOMPPROG , CONFTYPE_STR , read_str , DUMPTYPE_CLNTCOMPPROG , NULL }, + { CONF_FALLBACK_SPLITSIZE, CONFTYPE_INT64 , read_int64 , DUMPTYPE_FALLBACK_SPLITSIZE, NULL }, + { CONF_SRV_DECRYPT_OPT , CONFTYPE_STR , read_str , DUMPTYPE_SRV_DECRYPT_OPT , NULL }, + { CONF_CLNT_DECRYPT_OPT , CONFTYPE_STR , read_str , DUMPTYPE_CLNT_DECRYPT_OPT , NULL }, + { CONF_APPLICATION , CONFTYPE_STR , read_dapplication, DUMPTYPE_APPLICATION , NULL }, + { CONF_SCRIPT , CONFTYPE_STR , read_dpp_script, DUMPTYPE_SCRIPTLIST , NULL }, + { CONF_DATA_PATH , CONFTYPE_DATA_PATH, read_data_path, DUMPTYPE_DATA_PATH , NULL }, + { CONF_ALLOW_SPLIT , CONFTYPE_BOOLEAN , read_bool , DUMPTYPE_ALLOW_SPLIT , NULL }, + { CONF_MAX_WARNINGS , CONFTYPE_INT , read_int , DUMPTYPE_MAX_WARNINGS , validate_nonnegative }, + { CONF_RECOVERY_LIMIT , CONFTYPE_HOST_LIMIT, read_host_limit, DUMPTYPE_RECOVERY_LIMIT , NULL }, + { CONF_DUMP_LIMIT , CONFTYPE_HOST_LIMIT, read_host_limit, DUMPTYPE_DUMP_LIMIT , validate_dump_limit }, + { CONF_UNKNOWN , CONFTYPE_INT , NULL , DUMPTYPE_DUMPTYPE , NULL } +}; - ip = alloc(SIZEOF(interface_t)); - ip->name = stralloc("default"); - ip->seen = conf_data[CNF_NETUSAGE].seen; - conf_init_string(&ip->value[INTER_COMMENT], "implicit from NETUSAGE"); - conf_init_int(&ip->value[INTER_MAXUSAGE], conf_data[CNF_NETUSAGE].v.i); - ip->curusage = 0; - ip->next = interface_list; - interface_list = ip; +conf_var_t holding_var [] = { + { CONF_DIRECTORY, CONFTYPE_STR , read_str , HOLDING_DISKDIR , NULL }, + { CONF_COMMENT , CONFTYPE_STR , read_str , HOLDING_COMMENT , NULL }, + { CONF_USE , CONFTYPE_INT64 , read_int64 , HOLDING_DISKSIZE , validate_use }, + { CONF_CHUNKSIZE, CONFTYPE_INT64 , read_int64 , HOLDING_CHUNKSIZE, validate_chunksize }, + { CONF_UNKNOWN , CONFTYPE_INT , NULL , HOLDING_HOLDING , NULL } +}; - debug_amandad = getconf_int(CNF_DEBUG_AMANDAD); - debug_amidxtaped = getconf_int(CNF_DEBUG_AMIDXTAPED); - debug_amindexd = getconf_int(CNF_DEBUG_AMINDEXD); - debug_amrecover = getconf_int(CNF_DEBUG_AMRECOVER); - debug_auth = getconf_int(CNF_DEBUG_AUTH); - debug_event = getconf_int(CNF_DEBUG_EVENT); - debug_holding = getconf_int(CNF_DEBUG_HOLDING); - debug_protocol = getconf_int(CNF_DEBUG_PROTOCOL); - debug_planner = getconf_int(CNF_DEBUG_PLANNER); - debug_driver = getconf_int(CNF_DEBUG_DRIVER); - debug_dumper = getconf_int(CNF_DEBUG_DUMPER); - debug_chunker = getconf_int(CNF_DEBUG_CHUNKER); - debug_taper = getconf_int(CNF_DEBUG_TAPER); - debug_selfcheck = getconf_int(CNF_DEBUG_SELFCHECK); - debug_sendsize = getconf_int(CNF_DEBUG_SENDSIZE); - debug_sendbackup = getconf_int(CNF_DEBUG_SENDBACKUP); +conf_var_t interface_var [] = { + { CONF_COMMENT, CONFTYPE_STR , read_str , INTER_COMMENT , NULL }, + { CONF_USE , CONFTYPE_INT , read_int , INTER_MAXUSAGE, validate_positive }, + { CONF_UNKNOWN, CONFTYPE_INT , NULL , INTER_INTER , NULL } +}; - return got_parserror; -} -static void -validate_positive0( - struct s_conf_var *np, - val_t *val) -{ - switch(val->type) { - case CONFTYPE_INT: - if(val->v.i < 0) - conf_parserror("%s must be positive", get_token_name(np->token)); - break; - case CONFTYPE_LONG: - if(val->v.l < 0) - conf_parserror("%s must be positive", get_token_name(np->token)); - break; - case CONFTYPE_AM64: - if(val->v.am64 < 0) - conf_parserror("%s must be positive", get_token_name(np->token)); - break; - default: - conf_parserror("validate_positive0 invalid type %d\n", val->type); - } -} +conf_var_t application_var [] = { + { CONF_COMMENT , CONFTYPE_STR , read_str , APPLICATION_COMMENT , NULL }, + { CONF_PLUGIN , CONFTYPE_STR , read_str , APPLICATION_PLUGIN , NULL }, + { CONF_PROPERTY , CONFTYPE_PROPLIST, read_property, APPLICATION_PROPERTY , NULL }, + { CONF_CLIENT_NAME, CONFTYPE_STR , read_str , APPLICATION_CLIENT_NAME, NULL }, + { CONF_UNKNOWN , CONFTYPE_INT , NULL , APPLICATION_APPLICATION, NULL } +}; -static void -validate_positive1( - struct s_conf_var *np, - val_t *val) -{ - switch(val->type) { - case CONFTYPE_INT: - if(val->v.i < 1) - conf_parserror("%s must be positive", get_token_name(np->token)); - break; - case CONFTYPE_LONG: - if(val->v.l < 1) - conf_parserror("%s must be positive", get_token_name(np->token)); - break; - case CONFTYPE_AM64: - if(val->v.am64 < 1) - conf_parserror("%s must be positive", get_token_name(np->token)); - break; - case CONFTYPE_TIME: - if(val->v.t < 1) - conf_parserror("%s must be positive", get_token_name(np->token)); - break; - default: - conf_parserror("validate_positive1 invalid type %d\n", val->type); - } -} +conf_var_t pp_script_var [] = { + { CONF_COMMENT , CONFTYPE_STR , read_str , PP_SCRIPT_COMMENT , NULL }, + { CONF_PLUGIN , CONFTYPE_STR , read_str , PP_SCRIPT_PLUGIN , NULL }, + { CONF_PROPERTY , CONFTYPE_PROPLIST, read_property, PP_SCRIPT_PROPERTY , NULL }, + { CONF_EXECUTE_ON , CONFTYPE_EXECUTE_ON , read_execute_on , PP_SCRIPT_EXECUTE_ON , NULL }, + { CONF_EXECUTE_WHERE, CONFTYPE_EXECUTE_WHERE , read_execute_where , PP_SCRIPT_EXECUTE_WHERE, NULL }, + { CONF_ORDER , CONFTYPE_INT , read_int , PP_SCRIPT_ORDER , NULL }, + { CONF_SINGLE_EXECUTION, CONFTYPE_BOOLEAN, read_bool , PP_SCRIPT_SINGLE_EXECUTION, NULL }, + { CONF_CLIENT_NAME , CONFTYPE_STR , read_str , PP_SCRIPT_CLIENT_NAME , NULL }, + { CONF_UNKNOWN , CONFTYPE_INT , NULL , PP_SCRIPT_PP_SCRIPT , NULL } +}; -static void -validate_runspercycle( - struct s_conf_var *np, - val_t *val) -{ - np = np; - if(val->v.i < -1) - conf_parserror("runspercycle must be >= -1"); -} +conf_var_t device_config_var [] = { + { CONF_COMMENT , CONFTYPE_STR , read_str , DEVICE_CONFIG_COMMENT , NULL }, + { CONF_DEVICE_PROPERTY , CONFTYPE_PROPLIST , read_property , DEVICE_CONFIG_DEVICE_PROPERTY, NULL }, + { CONF_TAPEDEV , CONFTYPE_STR , read_str , DEVICE_CONFIG_TAPEDEV , NULL }, + { CONF_UNKNOWN , CONFTYPE_INT , NULL , DEVICE_CONFIG_DEVICE_CONFIG , NULL } +}; -static void -validate_bumppercent( - struct s_conf_var *np, - val_t *val) -{ - np = np; - if(val->v.i < 0 || val->v.i > 100) - conf_parserror("bumppercent must be between 0 and 100"); -} +conf_var_t changer_config_var [] = { + { CONF_COMMENT , CONFTYPE_STR , read_str , CHANGER_CONFIG_COMMENT , NULL }, + { CONF_TAPEDEV , CONFTYPE_STR , read_str , CHANGER_CONFIG_TAPEDEV , NULL }, + { CONF_TPCHANGER , CONFTYPE_STR , read_str , CHANGER_CONFIG_TPCHANGER , NULL }, + { CONF_CHANGERDEV , CONFTYPE_STR , read_str , CHANGER_CONFIG_CHANGERDEV , NULL }, + { CONF_CHANGERFILE , CONFTYPE_STR , read_str , CHANGER_CONFIG_CHANGERFILE , NULL }, + { CONF_PROPERTY , CONFTYPE_PROPLIST , read_property , CHANGER_CONFIG_PROPERTY , NULL }, + { CONF_DEVICE_PROPERTY , CONFTYPE_PROPLIST , read_property , CHANGER_CONFIG_DEVICE_PROPERTY, NULL }, + { CONF_UNKNOWN , CONFTYPE_INT , NULL , CHANGER_CONFIG_CHANGER_CONFIG , NULL } +}; -static void -validate_inparallel( - struct s_conf_var *np, - val_t *val) -{ - np = np; - if(val->v.i < 1 || val->v.i >MAX_DUMPERS) - conf_parserror("inparallel must be between 1 and MAX_DUMPERS (%d)", - MAX_DUMPERS); -} +conf_var_t interactivity_var [] = { + { CONF_COMMENT , CONFTYPE_STR , read_str , INTERACTIVITY_COMMENT , NULL }, + { CONF_PLUGIN , CONFTYPE_STR , read_str , INTERACTIVITY_PLUGIN , NULL }, + { CONF_PROPERTY , CONFTYPE_PROPLIST , read_property , INTERACTIVITY_PROPERTY , NULL }, + { CONF_UNKNOWN , CONFTYPE_INT , NULL , INTERACTIVITY_INTERACTIVITY , NULL } +}; -static void -validate_bumpmult( - struct s_conf_var *np, - val_t *val) -{ - np = np; - if(val->v.r < 0.999) { - conf_parserror("bumpmult must be positive"); - } -} +conf_var_t taperscan_var [] = { + { CONF_COMMENT , CONFTYPE_STR , read_str , TAPERSCAN_COMMENT , NULL }, + { CONF_PLUGIN , CONFTYPE_STR , read_str , TAPERSCAN_PLUGIN , NULL }, + { CONF_PROPERTY , CONFTYPE_PROPLIST , read_property , TAPERSCAN_PROPERTY , NULL }, + { CONF_UNKNOWN , CONFTYPE_INT , NULL , TAPERSCAN_TAPERSCAN , NULL } +}; -static void -validate_displayunit( - struct s_conf_var *np, - val_t *val) +/* + * Lexical Analysis Implementation + */ + +static char * +get_token_name( + tok_t token) { - np = np; - if(strcmp(val->v.s, "k") == 0 || - strcmp(val->v.s, "K") == 0) { - val->v.s[0] = (char)toupper(val->v.s[0]); - unit_divisor=1; - } - else if(strcmp(val->v.s, "m") == 0 || - strcmp(val->v.s, "M") == 0) { - val->v.s[0] = (char)toupper(val->v.s[0]); - unit_divisor=1024; - } - else if(strcmp(val->v.s, "g") == 0 || - strcmp(val->v.s, "G") == 0) { - val->v.s[0] = (char)toupper(val->v.s[0]); - unit_divisor=1024*1024; - } - else if(strcmp(val->v.s, "t") == 0 || - strcmp(val->v.s, "T") == 0) { - val->v.s[0] = (char)toupper(val->v.s[0]); - unit_divisor=1024*1024*1024; - } - else { - conf_parserror("displayunit must be k,m,g or t."); + keytab_t *kt; + + if (keytable == NULL) { + error(_("keytable == NULL")); + /*NOTREACHED*/ } -} -static void -validate_reserve( - struct s_conf_var *np, - val_t *val) -{ - np = np; - if(val->v.i < 0 || val->v.i > 100) - conf_parserror("reserve must be between 0 and 100"); -} + for(kt = keytable; kt->token != CONF_UNKNOWN; kt++) + if(kt->token == token) break; -static void -validate_use( - struct s_conf_var *np, - val_t *val) -{ - np = np; - val->v.am64 = am_floor(val->v.am64, DISK_BLOCK_KB); + if(kt->token == CONF_UNKNOWN) + return(""); + return(kt->keyword); } -static void -validate_chunksize( - struct s_conf_var *np, - val_t *val) +static tok_t +lookup_keyword( + char * str) { - np = np; - if(val->v.am64 == 0) { - val->v.am64 = ((AM64_MAX / 1024) - (2 * DISK_BLOCK_KB)); - } - else if(val->v.am64 < 0) { - conf_parserror("Negative chunksize (" OFF_T_FMT - ") is no longer supported", val->v.am64); - } - val->v.am64 = am_floor(val->v.am64, (off_t)DISK_BLOCK_KB); - if (val->v.am64 < 2*DISK_BLOCK_KB) { - conf_parserror("chunksize must be at least %dkb", 2*DISK_BLOCK_KB); - } -} + keytab_t *kwp; + char *str1 = stralloc(str); + char *p = str1; -static void -validate_blocksize( - struct s_conf_var *np, - val_t *val) -{ - np = np; - if(val->v.l < DISK_BLOCK_KB) { - conf_parserror("Tape blocksize must be at least %d KBytes", - DISK_BLOCK_KB); - } else if(val->v.l > MAX_TAPE_BLOCK_KB) { - conf_parserror("Tape blocksize must not be larger than %d KBytes", - MAX_TAPE_BLOCK_KB); + /* Fold '-' to '_' in the token. Note that this modifies str1 + * in place. */ + while (*p) { + if (*p == '-') *p = '_'; + p++; } -} -static void -validate_debug( - struct s_conf_var *np, - val_t *val) -{ - np = np; - if(val->v.i < 0 || val->v.i > 9) { - conf_parserror("Debug must be between 0 and 9"); + for(kwp = keytable; kwp->keyword != NULL; kwp++) { + if (strcasecmp(kwp->keyword, str1) == 0) break; } -} -static void -validate_reserved_port_range( - struct s_conf_var *np, - val_t *val) -{ - np = np; - if(val->v.intrange[0] < 1 || val->v.intrange[0] > IPPORT_RESERVED-1) { - conf_parserror("portrange must be between 1 and %d", IPPORT_RESERVED-1); - } else if(val->v.intrange[1] < 1 || val->v.intrange[1] > IPPORT_RESERVED-1) { - conf_parserror("portrange must be between 1 and IPPORT_RESERVED-1"); - } + amfree(str1); + return kwp->token; } static void -validate_unreserved_port_range( - struct s_conf_var *np, - val_t *val) +get_conftoken( + tok_t exp) { - np = np; - if(val->v.intrange[0] < IPPORT_RESERVED+1 || val->v.intrange[0] > 65536) { - conf_parserror("portrange must be between %d and 65536", IPPORT_RESERVED+1); - } else if(val->v.intrange[1] < IPPORT_RESERVED+1 || val->v.intrange[1] > 65536) { - conf_parserror("portrange must be between %d and 65536", IPPORT_RESERVED+1); - } -} + int ch, d; + gint64 int64; + char *buf; + char *tmps; + int token_overflow; + int inquote = 0; + int escape = 0; + int sign; -char * -getconf_byname( - char *str) -{ - static char *tmpstr; - t_conf_var *np; - keytab_t *kt; - char *s; - char ch; - char *first_delim; - char *second_delim; - tapetype_t *tp; - dumptype_t *dp; - interface_t *ip; - holdingdisk_t *hp; + if (token_pushed) { + token_pushed = 0; + tok = pushed_tok; - tmpstr = stralloc(str); - s = tmpstr; - while((ch = *s++) != '\0') { - if(islower((int)ch)) - s[-1] = (char)toupper(ch); - } + /* + ** If it looked like a keyword before then look it + ** up again in the current keyword table. + */ + switch(tok) { + case CONF_INT64: case CONF_SIZE: + case CONF_INT: case CONF_REAL: case CONF_STRING: + case CONF_LBRACE: case CONF_RBRACE: case CONF_COMMA: + case CONF_NL: case CONF_END: case CONF_UNKNOWN: + case CONF_TIME: + break; /* not a keyword */ - first_delim = strchr(tmpstr, ':'); - if (first_delim) { - *first_delim = '\0'; - first_delim++; - second_delim = strchr(first_delim,':'); - if(!second_delim) { - amfree(tmpstr); - return(NULL); + default: + if (exp == CONF_IDENT) + tok = CONF_IDENT; + else + tok = lookup_keyword(tokenval.v.s); + break; } - *second_delim = '\0'; - second_delim++; + } + else { + ch = conftoken_getc(); - for(kt = my_keytab; kt->token != CONF_UNKNOWN; kt++) { - if(kt->keyword && strcmp(kt->keyword, second_delim) == 0) - break; + /* note that we're explicitly assuming this file is ASCII. Someday + * maybe we'll support UTF-8? */ + while(ch != EOF && ch != '\n' && g_ascii_isspace(ch)) + ch = conftoken_getc(); + if (ch == '#') { /* comment - eat everything but eol/eof */ + while((ch = conftoken_getc()) != EOF && ch != '\n') { + (void)ch; /* Quiet empty loop complaints */ + } } - if(kt->token == CONF_UNKNOWN) - return NULL; + if (isalpha(ch)) { /* identifier */ + buf = tkbuf; + token_overflow = 0; + do { + if (buf < tkbuf+sizeof(tkbuf)-1) { + *buf++ = (char)ch; + } else { + *buf = '\0'; + if (!token_overflow) { + conf_parserror(_("token too long: %.20s..."), tkbuf); + } + token_overflow = 1; + } + ch = conftoken_getc(); + } while(isalnum(ch) || ch == '_' || ch == '-'); - if (strcmp(tmpstr, "TAPETYPE") == 0) { - tp = lookup_tapetype(first_delim); - if (!tp) { - amfree(tmpstr); - return(NULL); - } - for(np = tapetype_var; np->token != CONF_UNKNOWN; np++) { - if(np->token == kt->token) - break; + if (ch != EOF && conftoken_ungetc(ch) == EOF) { + if (ferror(current_file)) { + conf_parserror(_("Pushback of '%c' failed: %s"), + ch, strerror(ferror(current_file))); + } else { + conf_parserror(_("Pushback of '%c' failed: EOF"), ch); + } } - if (np->token == CONF_UNKNOWN) return NULL; - tmpstr = stralloc(conf_print(&tp->value[np->parm], 0, "")); - } else if (strcmp(tmpstr, "DUMPTYPE") == 0) { - dp = lookup_dumptype(first_delim); - if (!dp) { - amfree(tmpstr); - return(NULL); + *buf = '\0'; + + tokenval.v.s = tkbuf; + + if (token_overflow) tok = CONF_UNKNOWN; + else if (exp == CONF_IDENT) tok = CONF_IDENT; + else tok = lookup_keyword(tokenval.v.s); + } + else if (isdigit(ch)) { /* integer */ + sign = 1; + +negative_number: /* look for goto negative_number below sign is set there */ + int64 = 0; + do { + int64 = int64 * 10 + (ch - '0'); + ch = conftoken_getc(); + } while (isdigit(ch)); + + if (ch != '.') { + if (exp == CONF_INT) { + tok = CONF_INT; + tokenval.v.i = sign * (int)int64; + } else if (exp != CONF_REAL) { + tok = CONF_INT64; + tokenval.v.int64 = (gint64)sign * int64; + } else { + /* automatically convert to real when expected */ + tokenval.v.r = (double)sign * (double)int64; + tok = CONF_REAL; + } + } else { + /* got a real number, not an int */ + tokenval.v.r = sign * (double) int64; + int64 = 0; + d = 1; + ch = conftoken_getc(); + while (isdigit(ch)) { + int64 = int64 * 10 + (ch - '0'); + d = d * 10; + ch = conftoken_getc(); + } + tokenval.v.r += sign * ((double)int64) / d; + tok = CONF_REAL; } - for(np = dumptype_var; np->token != CONF_UNKNOWN; np++) { - if(np->token == kt->token) - break; + + if (ch != EOF && conftoken_ungetc(ch) == EOF) { + if (ferror(current_file)) { + conf_parserror(_("Pushback of '%c' failed: %s"), + ch, strerror(ferror(current_file))); + } else { + conf_parserror(_("Pushback of '%c' failed: EOF"), ch); + } } - if (np->token == CONF_UNKNOWN) return NULL; - tmpstr = stralloc(conf_print(&dp->value[np->parm], 0, "")); - } else if (strcmp(tmpstr, "HOLDINGDISK") == 0) { - hp = lookup_holdingdisk(first_delim); - if (!hp) { - amfree(tmpstr); - return(NULL); + } else switch(ch) { + case '"': /* string */ + buf = tkbuf; + token_overflow = 0; + inquote = 1; + *buf++ = (char)ch; + while (inquote && ((ch = conftoken_getc()) != EOF)) { + if (ch == '\n') { + if (!escape) { + conf_parserror(_("string not terminated")); + conftoken_ungetc(ch); + break; + } + escape = 0; + buf--; /* Consume escape in buffer */ + } else if (ch == '\\' && !escape) { + escape = 1; + } else { + if (ch == '"') { + if (!escape) + inquote = 0; + } + escape = 0; + } + + if(buf >= &tkbuf[sizeof(tkbuf) - 1]) { + if (!token_overflow) { + conf_parserror(_("string too long: %.20s..."), tkbuf); + } + token_overflow = 1; + break; + } + *buf++ = (char)ch; } - for(np = holding_var; np->token != CONF_UNKNOWN; np++) { - if(np->token == kt->token) - break; + *buf = '\0'; + + /* + * A little manuver to leave a fully unquoted, unallocated string + * in tokenval.v.s + */ + tmps = unquote_string(tkbuf); + strncpy(tkbuf, tmps, sizeof(tkbuf)); + amfree(tmps); + tokenval.v.s = tkbuf; + + tok = (token_overflow) ? CONF_UNKNOWN : + (exp == CONF_IDENT) ? CONF_IDENT : CONF_STRING; + break; + + case '-': + ch = conftoken_getc(); + if (isdigit(ch)) { + sign = -1; + goto negative_number; } - if (np->token == CONF_UNKNOWN) return NULL; - tmpstr = stralloc(conf_print(&hp->value[np->parm], 0, "")); - } else if (strcmp(tmpstr, "INTERFACE") == 0) { - ip = lookup_interface(first_delim); - if (!ip) { - amfree(tmpstr); - return(NULL); + else { + if (ch != EOF && conftoken_ungetc(ch) == EOF) { + if (ferror(current_file)) { + conf_parserror(_("Pushback of '%c' failed: %s"), + ch, strerror(ferror(current_file))); + } else { + conf_parserror(_("Pushback of '%c' failed: EOF"), ch); + } + } + tok = CONF_UNKNOWN; } - for(np = holding_var; np->token != CONF_UNKNOWN; np++) { - if(np->token == kt->token) - break; + break; + + case ',': + tok = CONF_COMMA; + break; + + case '{': + tok = CONF_LBRACE; + break; + + case '}': + tok = CONF_RBRACE; + break; + + case '\n': + tok = CONF_NL; + break; + + case EOF: + tok = CONF_END; + break; + + default: + tok = CONF_UNKNOWN; + break; + } + } + + if (exp != CONF_ANY && tok != exp) { + char *str; + keytab_t *kwp; + + switch(exp) { + case CONF_LBRACE: + str = "\"{\""; + break; + + case CONF_RBRACE: + str = "\"}\""; + break; + + case CONF_COMMA: + str = "\",\""; + break; + + case CONF_NL: + str = _("end of line"); + break; + + case CONF_END: + str = _("end of file"); + break; + + case CONF_INT: + str = _("an integer"); + break; + + case CONF_REAL: + str = _("a real number"); + break; + + case CONF_STRING: + str = _("a quoted string"); + break; + + case CONF_IDENT: + str = _("an identifier"); + break; + + default: + for(kwp = keytable; kwp->keyword != NULL; kwp++) { + if (exp == kwp->token) + break; } - if (np->token == CONF_UNKNOWN) return NULL; - tmpstr = stralloc(conf_print(&ip->value[np->parm], 0, "")); - } else { - amfree(tmpstr); - return(NULL); + if (kwp->keyword == NULL) + str = _("token not"); + else + str = str_keyword(kwp); + break; + } + conf_parserror(_("%s is expected"), str); + tok = exp; + if (tok == CONF_INT) + tokenval.v.i = 0; + else + tokenval.v.s = ""; + } +} + +static void +unget_conftoken(void) +{ + assert(!token_pushed); + token_pushed = 1; + pushed_tok = tok; + tok = CONF_UNKNOWN; +} + +static int +conftoken_getc(void) +{ + if(current_line == NULL) + return getc(current_file); + if(*current_char == '\0') + return -1; + return(*current_char++); +} + +static int +conftoken_ungetc( + int c) +{ + if(current_line == NULL) + return ungetc(c, current_file); + else if(current_char > current_line) { + if(c == -1) + return c; + current_char--; + if(*current_char != c) { + error(_("*current_char != c : %c %c"), *current_char, c); + /* NOTREACHED */ } } else { - for(kt = my_keytab; kt->token != CONF_UNKNOWN; kt++) { - if(kt->keyword && strcmp(kt->keyword, tmpstr) == 0) - break; + error(_("current_char == current_line")); + /* NOTREACHED */ + } + return c; +} + +/* + * Parser Implementation + */ + +static void +read_conffile( + char *filename, + gboolean is_client, + gboolean missing_ok) +{ + /* Save global locations. */ + FILE *save_file = current_file; + char *save_filename = current_filename; + int save_line_num = current_line_num; + int rc; + + if (is_client) { + keytable = client_keytab; + parsetable = client_var; + } else { + keytable = server_keytab; + parsetable = server_var; + } + filename = config_dir_relative(filename); + current_filename = get_seen_filename(filename); + amfree(filename); + + if ((current_file = fopen(current_filename, "r")) == NULL) { + if (!missing_ok) + conf_parserror(_("could not open conf file \"%s\": %s"), + current_filename, strerror(errno)); + goto finish; + } + + current_line_num = 0; + + do { + /* read_confline() can invoke us recursively via "includefile" */ + rc = read_confline(is_client); + } while (rc != 0); + + afclose(current_file); + +finish: + + /* Restore servers */ + current_line_num = save_line_num; + current_file = save_file; + current_filename = save_filename; +} + +static gboolean +read_confline( + gboolean is_client) +{ + conf_var_t *np; + + current_line_num += 1; + get_conftoken(CONF_ANY); + handle_deprecated_keyword(); + + switch(tok) { + case CONF_INCLUDEFILE: + get_conftoken(CONF_STRING); + read_conffile(tokenval.v.s, is_client, FALSE); + break; + + case CONF_DEFINE: + if (is_client) { + get_conftoken(CONF_ANY); + /* accept application-tool here, too, for backward compatibility */ + if(tok == CONF_APPLICATION_TOOL || tok == CONF_APPLICATION) get_application(); + else if(tok == CONF_SCRIPT_TOOL || tok == CONF_SCRIPT) get_pp_script(); + else conf_parserror(_("APPLICATION-TOOL or SCRIPT-TOOL expected")); + } else { + get_conftoken(CONF_ANY); + if(tok == CONF_DUMPTYPE) get_dumptype(); + else if(tok == CONF_TAPETYPE) get_tapetype(); + else if(tok == CONF_INTERFACE) get_interface(); + else if(tok == CONF_APPLICATION_TOOL || tok == CONF_APPLICATION) get_application(); + else if(tok == CONF_SCRIPT_TOOL || tok == CONF_SCRIPT) get_pp_script(); + else if(tok == CONF_DEVICE) get_device_config(); + else if(tok == CONF_CHANGER) get_changer_config(); + else if(tok == CONF_HOLDING) get_holdingdisk(1); + else if(tok == CONF_INTERACTIVITY) get_interactivity(); + else if(tok == CONF_TAPERSCAN) get_taperscan(); + else conf_parserror(_("DUMPTYPE, INTERFACE, TAPETYPE, HOLDINGDISK, APPLICATION, SCRIPT, DEVICE, CHANGER, INTERACTIVITY or TAPERSCAN expected")); + current_block = NULL; } + break; - if(kt->token == CONF_UNKNOWN) - return NULL; + case CONF_NL: /* empty line */ + break; + + case CONF_END: /* end of file */ + return 0; + + /* These should never be at the begining of a line */ + case CONF_LBRACE: + case CONF_RBRACE: + case CONF_IDENT: + case CONF_INT: + case CONF_INT64: + case CONF_BOOL: + case CONF_REAL: + case CONF_STRING: + case CONF_TIME: + case CONF_SIZE: + conf_parserror("error: not a keyword."); + break; + + /* if it's not a known punctuation mark, then check the parse table and use the + * read_function we find there. */ + default: + { + for(np = parsetable; np->token != CONF_UNKNOWN; np++) + if(np->token == tok) break; + + if(np->token == CONF_UNKNOWN) { + handle_invalid_keyword(tokenval.v.s); + } else { + np->read_function(np, &conf_data[np->parm]); + if(np->validate_function) + np->validate_function(np, &conf_data[np->parm]); + } + } + } + if(tok != CONF_NL) + get_conftoken(CONF_NL); + return 1; +} + +static void +handle_deprecated_keyword(void) +{ + /* Procedure for deprecated keywords: + * + * 1) At time of deprecation, add to warning_deprecated below. Note the + * version in which deprecation will expire. The keyword will still be + * parsed, and can still be used from other parts of Amanda, during this + * time. + * 2) After it has expired, move the keyword (as a string) to + * error_deprecated below. Remove the token (CONF_XXX) and + * config parameter (CNF_XXX) from the rest of the module. + * Note the date of the move. + */ + + static struct { tok_t tok; gboolean warned; } + warning_deprecated[] = { + { CONF_LABEL_NEW_TAPES, 0 }, /* exp in Amanda-3.2 */ + { CONF_AMRECOVER_DO_FSF, 0 }, /* exp in Amanda-3.3 */ + { CONF_AMRECOVER_CHECK_LABEL, 0 }, /* exp in Amanda-3.3 */ + { CONF_TAPE_SPLITSIZE, 0 }, /* exp. in Amanda-3.3 */ + { CONF_SPLIT_DISKBUFFER, 0 }, /* exp. in Amanda-3.3 */ + { CONF_FALLBACK_SPLITSIZE, 0 }, /* exp. in Amanda-3.3 */ + { 0, 0 }, + }, *dep; + + for (dep = warning_deprecated; dep->tok; dep++) { + if (tok == dep->tok) { + if (!dep->warned) + conf_parswarn(_("warning: Keyword %s is deprecated."), + tokenval.v.s); + dep->warned = 1; + break; + } + } +} + +static void +handle_invalid_keyword( + const char * token) +{ + static const char * error_deprecated[] = { + "rawtapedev", + "tapebufs", /* deprecated: 2007-10-15; invalid: 2010-04-14 */ + "file-pad", /* deprecated: 2008-07-01; invalid: 2010-04-14 */ + NULL + }; + const char ** s; + char *folded_token, *p; + + /* convert '_' to '-' in TOKEN */ + folded_token = g_strdup(token); + for (p = folded_token; *p; p++) { + if (*p == '_') *p = '-'; + } + + for (s = error_deprecated; *s != NULL; s ++) { + if (g_ascii_strcasecmp(*s, folded_token) == 0) { + conf_parserror(_("error: Keyword %s is deprecated."), + token); + g_free(folded_token); + return; + } + } + g_free(folded_token); + + if (*s == NULL) { + conf_parserror(_("configuration keyword expected")); + } + + for (;;) { + char c = conftoken_getc(); + if (c == '\n' || c == -1) { + conftoken_ungetc(c); + return; + } + } + + g_assert_not_reached(); +} + +static char * +get_seen_filename( + char *filename) +{ + GSList *iter; + char *istr; + + for (iter = seen_filenames; iter; iter = iter->next) { + istr = iter->data; + if (istr == filename || 0 == strcmp(istr, filename)) + return istr; + } + + istr = stralloc(filename); + seen_filenames = g_slist_prepend(seen_filenames, istr); + return istr; +} + +static void +read_block( + conf_var_t *read_var, + val_t *valarray, + char *errormsg, + int read_brace, + void (*copy_function)(void), + char *type, + char *name) +{ + conf_var_t *np; + int done; + char *key_ovr; + int i; + + if(read_brace) { + get_conftoken(CONF_LBRACE); + get_conftoken(CONF_NL); + } + + done = 0; + do { + current_line_num += 1; + get_conftoken(CONF_ANY); + handle_deprecated_keyword(); + + switch(tok) { + case CONF_RBRACE: + done = 1; + break; + case CONF_NL: /* empty line */ + break; + case CONF_END: /* end of file */ + done = 1; + break; + + /* inherit from a "parent" */ + case CONF_IDENT: + case CONF_STRING: + if(copy_function) + copy_function(); + else + conf_parserror(_("ident not expected")); + break; + default: + { + for(np = read_var; np->token != CONF_UNKNOWN; np++) + if(np->token == tok) break; + + if(np->token == CONF_UNKNOWN) + conf_parserror("%s", errormsg); + else { + np->read_function(np, &valarray[np->parm]); + if(np->validate_function) + np->validate_function(np, &valarray[np->parm]); + } + } + } + if(tok != CONF_NL && tok != CONF_END && tok != CONF_RBRACE) + get_conftoken(CONF_NL); + } while(!done); + + if (!config_overrides) + return; + + key_ovr = vstralloc(type, ":", name, NULL); + for (i = 0; i < config_overrides->n_used; i++) { + config_override_t *co = &config_overrides->ovr[i]; + char *key = co->key; + char *keyword; + char *value; + keytab_t *kt; + + if (key_ovr && strncasecmp(key_ovr, key, strlen(key_ovr)) != 0) + continue; + + if (strlen(key) <= strlen(key_ovr) + 1) + continue; + + keyword = key + strlen(key_ovr) + 1; + value = co->value; + + /* find the token in keytable */ + for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) { + if (kt->keyword && strcasecmp(kt->keyword, keyword) == 0) + break; + } + if (kt->token == CONF_UNKNOWN) + continue; + + /* find the var in read_var */ + for (np = read_var; np->token != CONF_UNKNOWN; np++) + if (np->token == kt->token) break; + if (np->token == CONF_UNKNOWN) + continue; + + /* now set up a fake line and use the relevant read_function to + * parse it. This is sneaky! */ + if (np->type == CONFTYPE_STR) { + current_line = quote_string_always(value); + } else { + current_line = stralloc(value); + } + + current_char = current_line; + token_pushed = 0; + current_line_num = -2; + allow_overwrites = 1; + co->applied = TRUE; + + np->read_function(np, &valarray[np->parm]); + if (np->validate_function) + np->validate_function(np, &valarray[np->parm]); + + amfree(current_line); + current_char = NULL; + } + amfree(key_ovr); + +} + +static void +read_holdingdisk( + conf_var_t *np G_GNUC_UNUSED, + val_t *val G_GNUC_UNUSED) +{ + assert (val == &conf_data[CNF_HOLDINGDISK]); + get_holdingdisk(0); +} + +static void +get_holdingdisk( + int is_define) +{ + int save_overwrites; + + save_overwrites = allow_overwrites; + allow_overwrites = 1; + + init_holdingdisk_defaults(); + + get_conftoken(CONF_IDENT); + hdcur.name = stralloc(tokenval.v.s); + current_block = g_strconcat("holdingdisk ", hdcur.name, NULL); + hdcur.seen.block = current_block; + hdcur.seen.filename = current_filename; + hdcur.seen.linenum = current_line_num; + + get_conftoken(CONF_ANY); + if (tok == CONF_LBRACE) { + holdingdisk_t *hd; + hd = lookup_holdingdisk(hdcur.name); + if (hd) { + conf_parserror(_("holding disk '%s' already defined"), + hdcur.name); + } else { + unget_conftoken(); + read_block(holding_var, hdcur.value, + _("holding disk parameter expected"), 1, copy_holdingdisk, + "HOLDINGDISK", hdcur.name); + get_conftoken(CONF_NL); + save_holdingdisk(); + if (!is_define) { + conf_data[CNF_HOLDINGDISK].v.identlist = g_slist_append( + conf_data[CNF_HOLDINGDISK].v.identlist, + stralloc(hdcur.name)); + } + } + } else { /* use the already defined holding disk */ + unget_conftoken(); + if (is_define) { + conf_parserror(_("holdingdisk definition must specify holdingdisk parameters")); + } + do { + identlist_t il; + + for (il = conf_data[CNF_HOLDINGDISK].v.identlist; il != NULL; + il = il->next) { + if (strcmp((char *)il->data, hdcur.name) == 0) { + break; + } + } + if (il) { + conf_parserror(_("holding disk '%s' already in use"), + hdcur.name); + } else { + conf_data[CNF_HOLDINGDISK].v.identlist = g_slist_append( + conf_data[CNF_HOLDINGDISK].v.identlist, + stralloc(hdcur.name)); + } + amfree(hdcur.name); + get_conftoken(CONF_ANY); + if (tok == CONF_IDENT || tok == CONF_STRING) { + hdcur.name = stralloc(tokenval.v.s); + } else if (tok != CONF_NL) { + conf_parserror(_("IDENT or NL expected")); + } + } while (tok == CONF_IDENT || tok == CONF_STRING); + } + + allow_overwrites = save_overwrites; +} + +static void +init_holdingdisk_defaults( + void) +{ + conf_init_str(&hdcur.value[HOLDING_COMMENT] , ""); + conf_init_str(&hdcur.value[HOLDING_DISKDIR] , ""); + conf_init_int64(&hdcur.value[HOLDING_DISKSIZE] , CONF_UNIT_K, (gint64)0); + /* 1 Gb = 1M counted in 1Kb blocks */ + conf_init_int64(&hdcur.value[HOLDING_CHUNKSIZE], CONF_UNIT_K, (gint64)1024*1024); +} + +static void +save_holdingdisk( + void) +{ + holdingdisk_t *hp; + + hp = alloc(sizeof(holdingdisk_t)); + *hp = hdcur; + holdinglist = g_slist_append(holdinglist, hp); +} + +static void +copy_holdingdisk( + void) +{ + holdingdisk_t *hp; + int i; + + hp = lookup_holdingdisk(tokenval.v.s); + + if (hp == NULL) { + conf_parserror(_("holdingdisk parameter expected")); + return; + } + + for(i=0; i < HOLDING_HOLDING; i++) { + if(hp->value[i].seen.linenum) { + merge_val_t(&hdcur.value[i], &hp->value[i]); + } + } + +} + + +/* WARNING: + * This function is called both from this module and from diskfile.c. Modify + * with caution. */ +dumptype_t * +read_dumptype( + char *name, + FILE *from, + char *fname, + int *linenum) +{ + int save_overwrites; + FILE *saved_conf = NULL; + char *saved_fname = NULL; + + if (from) { + saved_conf = current_file; + current_file = from; + } + + if (fname) { + saved_fname = current_filename; + current_filename = get_seen_filename(fname); + } + + if (linenum) + current_line_num = *linenum; + + save_overwrites = allow_overwrites; + allow_overwrites = 1; + + init_dumptype_defaults(); + if (name) { + dpcur.name = name; + } else { + get_conftoken(CONF_IDENT); + dpcur.name = stralloc(tokenval.v.s); + } + current_block = g_strconcat("dumptype ", dpcur.name, NULL); + dpcur.seen.block = current_block; + dpcur.seen.filename = current_filename; + dpcur.seen.linenum = current_line_num; + + read_block(dumptype_var, dpcur.value, + _("dumptype parameter expected"), + (name == NULL), copy_dumptype, + "DUMPTYPE", dpcur.name); + + if(!name) /* !name => reading disklist, not conffile */ + get_conftoken(CONF_NL); + + /* XXX - there was a stupidity check in here for skip-incr and + ** skip-full. This check should probably be somewhere else. */ + + save_dumptype(); + + allow_overwrites = save_overwrites; + + if (linenum) + *linenum = current_line_num; + + if (fname) + current_filename = saved_fname; + + if (from) + current_file = saved_conf; + + return lookup_dumptype(dpcur.name); +} + +static void +get_dumptype(void) +{ + read_dumptype(NULL, NULL, NULL, NULL); +} + +static void +init_dumptype_defaults(void) +{ + dpcur.name = NULL; + conf_init_str (&dpcur.value[DUMPTYPE_COMMENT] , ""); + conf_init_str (&dpcur.value[DUMPTYPE_PROGRAM] , "DUMP"); + conf_init_str (&dpcur.value[DUMPTYPE_SRVCOMPPROG] , ""); + conf_init_str (&dpcur.value[DUMPTYPE_CLNTCOMPPROG] , ""); + conf_init_str (&dpcur.value[DUMPTYPE_SRV_ENCRYPT] , ""); + conf_init_str (&dpcur.value[DUMPTYPE_CLNT_ENCRYPT] , ""); + conf_init_str (&dpcur.value[DUMPTYPE_AMANDAD_PATH] , ""); + conf_init_str (&dpcur.value[DUMPTYPE_CLIENT_USERNAME] , ""); + conf_init_str (&dpcur.value[DUMPTYPE_CLIENT_PORT] , ""); + conf_init_str (&dpcur.value[DUMPTYPE_SSH_KEYS] , ""); + conf_init_str (&dpcur.value[DUMPTYPE_AUTH] , "BSDTCP"); + conf_init_exinclude(&dpcur.value[DUMPTYPE_EXCLUDE]); + conf_init_exinclude(&dpcur.value[DUMPTYPE_INCLUDE]); + conf_init_priority (&dpcur.value[DUMPTYPE_PRIORITY] , 1); + conf_init_int (&dpcur.value[DUMPTYPE_DUMPCYCLE] , CONF_UNIT_NONE, conf_data[CNF_DUMPCYCLE].v.i); + conf_init_int (&dpcur.value[DUMPTYPE_MAXDUMPS] , CONF_UNIT_NONE, conf_data[CNF_MAXDUMPS].v.i); + conf_init_int (&dpcur.value[DUMPTYPE_MAXPROMOTEDAY] , CONF_UNIT_NONE, 10000); + conf_init_int (&dpcur.value[DUMPTYPE_BUMPPERCENT] , CONF_UNIT_NONE, conf_data[CNF_BUMPPERCENT].v.i); + conf_init_int64 (&dpcur.value[DUMPTYPE_BUMPSIZE] , CONF_UNIT_K , conf_data[CNF_BUMPSIZE].v.int64); + conf_init_int (&dpcur.value[DUMPTYPE_BUMPDAYS] , CONF_UNIT_NONE, conf_data[CNF_BUMPDAYS].v.i); + conf_init_real (&dpcur.value[DUMPTYPE_BUMPMULT] , conf_data[CNF_BUMPMULT].v.r); + conf_init_time (&dpcur.value[DUMPTYPE_STARTTIME] , (time_t)0); + conf_init_strategy (&dpcur.value[DUMPTYPE_STRATEGY] , DS_STANDARD); + conf_init_estimatelist(&dpcur.value[DUMPTYPE_ESTIMATELIST] , ES_CLIENT); + conf_init_compress (&dpcur.value[DUMPTYPE_COMPRESS] , COMP_FAST); + conf_init_encrypt (&dpcur.value[DUMPTYPE_ENCRYPT] , ENCRYPT_NONE); + conf_init_data_path(&dpcur.value[DUMPTYPE_DATA_PATH] , DATA_PATH_AMANDA); + conf_init_str (&dpcur.value[DUMPTYPE_SRV_DECRYPT_OPT] , "-d"); + conf_init_str (&dpcur.value[DUMPTYPE_CLNT_DECRYPT_OPT] , "-d"); + conf_init_rate (&dpcur.value[DUMPTYPE_COMPRATE] , 0.50, 0.50); + conf_init_int64 (&dpcur.value[DUMPTYPE_TAPE_SPLITSIZE] , CONF_UNIT_K, (gint64)0); + conf_init_int64 (&dpcur.value[DUMPTYPE_FALLBACK_SPLITSIZE], CONF_UNIT_K, (gint64)10 * 1024); + conf_init_str (&dpcur.value[DUMPTYPE_SPLIT_DISKBUFFER] , NULL); + conf_init_bool (&dpcur.value[DUMPTYPE_RECORD] , 1); + conf_init_bool (&dpcur.value[DUMPTYPE_SKIP_INCR] , 0); + conf_init_bool (&dpcur.value[DUMPTYPE_SKIP_FULL] , 0); + conf_init_holding (&dpcur.value[DUMPTYPE_HOLDINGDISK] , HOLD_AUTO); + conf_init_bool (&dpcur.value[DUMPTYPE_KENCRYPT] , 0); + conf_init_bool (&dpcur.value[DUMPTYPE_IGNORE] , 0); + conf_init_bool (&dpcur.value[DUMPTYPE_INDEX] , 1); + conf_init_application(&dpcur.value[DUMPTYPE_APPLICATION]); + conf_init_identlist(&dpcur.value[DUMPTYPE_SCRIPTLIST], NULL); + conf_init_proplist(&dpcur.value[DUMPTYPE_PROPERTY]); + conf_init_bool (&dpcur.value[DUMPTYPE_ALLOW_SPLIT] , 1); + conf_init_int (&dpcur.value[DUMPTYPE_MAX_WARNINGS] , CONF_UNIT_NONE, 20); + conf_init_host_limit(&dpcur.value[DUMPTYPE_RECOVERY_LIMIT]); + conf_init_host_limit_server(&dpcur.value[DUMPTYPE_DUMP_LIMIT]); +} + +static void +save_dumptype(void) +{ + dumptype_t *dp, *dp1;; + + dp = lookup_dumptype(dpcur.name); + + if(dp != (dumptype_t *)0) { + if (dp->seen.linenum == -1) { + conf_parserror(_("dumptype %s is defined by default and cannot be redefined"), dp->name); + } else { + conf_parserror(_("dumptype %s already defined at %s:%d"), dp->name, + dp->seen.filename, dp->seen.linenum); + } + return; + } + + dp = alloc(sizeof(dumptype_t)); + *dp = dpcur; + dp->next = NULL; + /* add at end of list */ + if(!dumplist) + dumplist = dp; + else { + dp1 = dumplist; + while (dp1->next != NULL) { + dp1 = dp1->next; + } + dp1->next = dp; + } +} + +static void +copy_dumptype(void) +{ + dumptype_t *dt; + int i; + + dt = lookup_dumptype(tokenval.v.s); + + if(dt == NULL) { + conf_parserror(_("dumptype parameter expected")); + return; + } + + for(i=0; i < DUMPTYPE_DUMPTYPE; i++) { + if(dt->value[i].seen.linenum) { + merge_val_t(&dpcur.value[i], &dt->value[i]); + if (i == DUMPTYPE_SCRIPTLIST) { + /* sort in 'order' */ + dpcur.value[i].v.identlist = g_slist_sort(dpcur.value[i].v.identlist, &compare_pp_script_order); + } + } + } +} + +static void +get_tapetype(void) +{ + int save_overwrites; + + save_overwrites = allow_overwrites; + allow_overwrites = 1; + + init_tapetype_defaults(); + + get_conftoken(CONF_IDENT); + tpcur.name = stralloc(tokenval.v.s); + current_block = g_strconcat("tapetype ", tpcur.name, NULL); + tpcur.seen.block = current_block; + tpcur.seen.filename = current_filename; + tpcur.seen.linenum = current_line_num; + + read_block(tapetype_var, tpcur.value, + _("tapetype parameter expected"), 1, copy_tapetype, + "TAPETYPE", tpcur.name); + get_conftoken(CONF_NL); + + if (tapetype_get_readblocksize(&tpcur) < + tapetype_get_blocksize(&tpcur)) { + conf_init_size(&tpcur.value[TAPETYPE_READBLOCKSIZE], CONF_UNIT_K, + tapetype_get_blocksize(&tpcur)); + } + save_tapetype(); + + allow_overwrites = save_overwrites; +} + +static void +init_tapetype_defaults(void) +{ + conf_init_str(&tpcur.value[TAPETYPE_COMMENT] , ""); + conf_init_str(&tpcur.value[TAPETYPE_LBL_TEMPL] , ""); + conf_init_size (&tpcur.value[TAPETYPE_BLOCKSIZE] , CONF_UNIT_K, DISK_BLOCK_KB); + conf_init_size (&tpcur.value[TAPETYPE_READBLOCKSIZE], CONF_UNIT_K, DISK_BLOCK_KB); + conf_init_int64 (&tpcur.value[TAPETYPE_LENGTH] , CONF_UNIT_K, ((gint64)2000)); + conf_init_int64 (&tpcur.value[TAPETYPE_FILEMARK] , CONF_UNIT_K, (gint64)1); + conf_init_int (&tpcur.value[TAPETYPE_SPEED] , CONF_UNIT_NONE, 200); + conf_init_int64(&tpcur.value[TAPETYPE_PART_SIZE], CONF_UNIT_K, 0); + conf_init_part_cache_type(&tpcur.value[TAPETYPE_PART_CACHE_TYPE], PART_CACHE_TYPE_NONE); + conf_init_str(&tpcur.value[TAPETYPE_PART_CACHE_DIR], ""); + conf_init_int64(&tpcur.value[TAPETYPE_PART_CACHE_MAX_SIZE], CONF_UNIT_K, 0); +} + +static void +save_tapetype(void) +{ + tapetype_t *tp, *tp1; + + tp = lookup_tapetype(tpcur.name); + + if(tp != (tapetype_t *)0) { + amfree(tpcur.name); + conf_parserror(_("tapetype %s already defined at %s:%d"), + tp->name, tp->seen.filename, tp->seen.linenum); + return; + } + + tp = alloc(sizeof(tapetype_t)); + *tp = tpcur; + + /* add at end of list */ + if(!tapelist) + tapelist = tp; + else { + tp1 = tapelist; + while (tp1->next != NULL) { + tp1 = tp1->next; + } + tp1->next = tp; + } +} + +static void +copy_tapetype(void) +{ + tapetype_t *tp; + int i; + + tp = lookup_tapetype(tokenval.v.s); + + if(tp == NULL) { + conf_parserror(_("tape type parameter expected")); + return; + } + + for(i=0; i < TAPETYPE_TAPETYPE; i++) { + if(tp->value[i].seen.linenum) { + merge_val_t(&tpcur.value[i], &tp->value[i]); + } + } +} + +static void +get_interface(void) +{ + int save_overwrites; + + save_overwrites = allow_overwrites; + allow_overwrites = 1; + + init_interface_defaults(); + + get_conftoken(CONF_IDENT); + ifcur.name = stralloc(tokenval.v.s); + current_block = g_strconcat("interface ", ifcur.name, NULL); + ifcur.seen.block = current_block; + ifcur.seen.filename = current_filename; + ifcur.seen.linenum = current_line_num; + + read_block(interface_var, ifcur.value, + _("interface parameter expected"), 1, copy_interface, + "INTERFACE", ifcur.name); + get_conftoken(CONF_NL); + + save_interface(); + + allow_overwrites = save_overwrites; + + return; +} + +static void +init_interface_defaults(void) +{ + conf_init_str(&ifcur.value[INTER_COMMENT] , ""); + conf_init_int (&ifcur.value[INTER_MAXUSAGE], CONF_UNIT_K, 80000); +} + +static void +save_interface(void) +{ + interface_t *ip, *ip1; + + ip = lookup_interface(ifcur.name); + + if(ip != (interface_t *)0) { + conf_parserror(_("interface %s already defined at %s:%d"), + ip->name, ip->seen.filename, ip->seen.linenum); + return; + } + + ip = alloc(sizeof(interface_t)); + *ip = ifcur; + /* add at end of list */ + if(!interface_list) { + interface_list = ip; + } else { + ip1 = interface_list; + while (ip1->next != NULL) { + ip1 = ip1->next; + } + ip1->next = ip; + } +} + +static void +copy_interface(void) +{ + interface_t *ip; + int i; + + ip = lookup_interface(tokenval.v.s); + + if(ip == NULL) { + conf_parserror(_("interface parameter expected")); + return; + } + + for(i=0; i < INTER_INTER; i++) { + if(ip->value[i].seen.linenum) { + merge_val_t(&ifcur.value[i], &ip->value[i]); + } + } +} + + +static application_t * +read_application( + char *name, + FILE *from, + char *fname, + int *linenum) +{ + int save_overwrites; + FILE *saved_conf = NULL; + char *saved_fname = NULL; + + if (from) { + saved_conf = current_file; + current_file = from; + } + + if (fname) { + saved_fname = current_filename; + current_filename = get_seen_filename(fname); + } + + if (linenum) + current_line_num = *linenum; + + save_overwrites = allow_overwrites; + allow_overwrites = 1; + + init_application_defaults(); + if (name) { + apcur.name = name; + } else { + get_conftoken(CONF_IDENT); + apcur.name = stralloc(tokenval.v.s); + } + current_block = g_strconcat("application ", apcur.name, NULL); + apcur.seen.block = current_block; + apcur.seen.filename = current_filename; + apcur.seen.linenum = current_line_num; + + read_block(application_var, apcur.value, + _("application parameter expected"), + (name == NULL), *copy_application, + "APPLICATION", apcur.name); + if(!name) + get_conftoken(CONF_NL); + + save_application(); + + allow_overwrites = save_overwrites; + + if (linenum) + *linenum = current_line_num; + + if (fname) + current_filename = saved_fname; + + if (from) + current_file = saved_conf; + + return lookup_application(apcur.name); +} + +static void +get_application( + void) +{ + read_application(NULL, NULL, NULL, NULL); +} + +static void +init_application_defaults( + void) +{ + apcur.name = NULL; + conf_init_str(&apcur.value[APPLICATION_COMMENT] , ""); + conf_init_str(&apcur.value[APPLICATION_PLUGIN] , ""); + conf_init_proplist(&apcur.value[APPLICATION_PROPERTY]); + conf_init_str(&apcur.value[APPLICATION_CLIENT_NAME] , ""); +} + +static void +save_application( + void) +{ + application_t *ap, *ap1; + + ap = lookup_application(apcur.name); + + if(ap != (application_t *)0) { + conf_parserror(_("application %s already defined at %s:%d"), + ap->name, ap->seen.filename, ap->seen.linenum); + return; + } + + ap = alloc(sizeof(application_t)); + *ap = apcur; + ap->next = NULL; + /* add at end of list */ + if (!application_list) + application_list = ap; + else { + ap1 = application_list; + while (ap1->next != NULL) { + ap1 = ap1->next; + } + ap1->next = ap; + } +} + +static void +copy_application(void) +{ + application_t *ap; + int i; + + ap = lookup_application(tokenval.v.s); + + if(ap == NULL) { + conf_parserror(_("application parameter expected")); + return; + } + + for(i=0; i < APPLICATION_APPLICATION; i++) { + if(ap->value[i].seen.linenum) { + merge_val_t(&apcur.value[i], &ap->value[i]); + } + } +} + +static interactivity_t * +read_interactivity( + char *name, + FILE *from, + char *fname, + int *linenum) +{ + int save_overwrites; + FILE *saved_conf = NULL; + char *saved_fname = NULL; + + if (from) { + saved_conf = current_file; + current_file = from; + } + + if (fname) { + saved_fname = current_filename; + current_filename = get_seen_filename(fname); + } + + if (linenum) + current_line_num = *linenum; + + save_overwrites = allow_overwrites; + allow_overwrites = 1; + + init_interactivity_defaults(); + if (name) { + ivcur.name = name; + } else { + get_conftoken(CONF_IDENT); + ivcur.name = stralloc(tokenval.v.s); + } + current_block = g_strconcat("interactivity ", ivcur.name, NULL); + ivcur.seen.block = current_block; + ivcur.seen.filename = current_filename; + ivcur.seen.linenum = current_line_num; + + read_block(interactivity_var, ivcur.value, + _("interactivity parameter expected"), + (name == NULL), *copy_interactivity, + "INTERACTIVITY", ivcur.name); + if(!name) + get_conftoken(CONF_NL); + + save_interactivity(); + + allow_overwrites = save_overwrites; + + if (linenum) + *linenum = current_line_num; + + if (fname) + current_filename = saved_fname; + + if (from) + current_file = saved_conf; + + return lookup_interactivity(ivcur.name); +} + +static void +get_interactivity( + void) +{ + read_interactivity(NULL, NULL, NULL, NULL); +} + +static void +init_interactivity_defaults( + void) +{ + ivcur.name = NULL; + conf_init_str(&ivcur.value[INTERACTIVITY_COMMENT] , ""); + conf_init_str(&ivcur.value[INTERACTIVITY_PLUGIN] , ""); + conf_init_proplist(&ivcur.value[INTERACTIVITY_PROPERTY]); +} + +static void +save_interactivity( + void) +{ + interactivity_t *iv, *iv1; + + iv = lookup_interactivity(ivcur.name); + + if (iv != (interactivity_t *)0) { + conf_parserror(_("interactivity %s already defined at %s:%d"), + iv->name, iv->seen.filename, iv->seen.linenum); + return; + } + + iv = alloc(sizeof(interactivity_t)); + *iv = ivcur; + iv->next = NULL; + /* add at end of list */ + if (!interactivity_list) + interactivity_list = iv; + else { + iv1 = interactivity_list; + while (iv1->next != NULL) { + iv1 = iv1->next; + } + iv1->next = iv; + } +} + +static void +copy_interactivity(void) +{ + interactivity_t *iv; + int i; + + iv = lookup_interactivity(tokenval.v.s); + + if (iv == NULL) { + conf_parserror(_("interactivity parameter expected")); + return; + } + + for (i=0; i < INTERACTIVITY_INTERACTIVITY; i++) { + if(iv->value[i].seen.linenum) { + merge_val_t(&ivcur.value[i], &iv->value[i]); + } + } +} + +static taperscan_t * +read_taperscan( + char *name, + FILE *from, + char *fname, + int *linenum) +{ + int save_overwrites; + FILE *saved_conf = NULL; + char *saved_fname = NULL; + + if (from) { + saved_conf = current_file; + current_file = from; + } + + if (fname) { + saved_fname = current_filename; + current_filename = get_seen_filename(fname); + } + + if (linenum) + current_line_num = *linenum; + + save_overwrites = allow_overwrites; + allow_overwrites = 1; + + init_taperscan_defaults(); + if (name) { + tscur.name = name; + } else { + get_conftoken(CONF_IDENT); + tscur.name = stralloc(tokenval.v.s); + } + current_block = g_strconcat("taperscan ", tscur.name, NULL); + tscur.seen.block = current_block; + tscur.seen.filename = current_filename; + tscur.seen.linenum = current_line_num; + + read_block(taperscan_var, tscur.value, + _("taperscan parameter expected"), + (name == NULL), *copy_taperscan, + "TAPERSCAN", tscur.name); + if(!name) + get_conftoken(CONF_NL); + + save_taperscan(); + + allow_overwrites = save_overwrites; + + if (linenum) + *linenum = current_line_num; + + if (fname) + current_filename = saved_fname; + + if (from) + current_file = saved_conf; + + return lookup_taperscan(tscur.name); +} + +static void +get_taperscan( + void) +{ + read_taperscan(NULL, NULL, NULL, NULL); +} + +static void +init_taperscan_defaults( + void) +{ + tscur.name = NULL; + conf_init_str(&tscur.value[TAPERSCAN_COMMENT] , ""); + conf_init_str(&tscur.value[TAPERSCAN_PLUGIN] , ""); + conf_init_proplist(&tscur.value[TAPERSCAN_PROPERTY]); +} + +static void +save_taperscan( + void) +{ + taperscan_t *ts, *ts1; + + ts = lookup_taperscan(tscur.name); + + if (ts != (taperscan_t *)0) { + conf_parserror(_("taperscan %s already defined at %s:%d"), + ts->name, ts->seen.filename, ts->seen.linenum); + return; + } + + ts = alloc(sizeof(taperscan_t)); + *ts = tscur; + ts->next = NULL; + /* add at end of list */ + if (!taperscan_list) + taperscan_list = ts; + else { + ts1 = taperscan_list; + while (ts1->next != NULL) { + ts1 = ts1->next; + } + ts1->next = ts; + } +} + +static void +copy_taperscan(void) +{ + taperscan_t *ts; + int i; + + ts = lookup_taperscan(tokenval.v.s); + + if (ts == NULL) { + conf_parserror(_("taperscan parameter expected")); + return; + } + + for (i=0; i < TAPERSCAN_TAPERSCAN; i++) { + if(ts->value[i].seen.linenum) { + merge_val_t(&tscur.value[i], &ts->value[i]); + } + } +} + +static pp_script_t * +read_pp_script( + char *name, + FILE *from, + char *fname, + int *linenum) +{ + int save_overwrites; + FILE *saved_conf = NULL; + char *saved_fname = NULL; + + if (from) { + saved_conf = current_file; + current_file = from; + } + + if (fname) { + saved_fname = current_filename; + current_filename = get_seen_filename(fname); + } + + if (linenum) + current_line_num = *linenum; + + save_overwrites = allow_overwrites; + allow_overwrites = 1; + + init_pp_script_defaults(); + if (name) { + pscur.name = name; + } else { + get_conftoken(CONF_IDENT); + pscur.name = stralloc(tokenval.v.s); + } + current_block = g_strconcat("script ", pscur.name, NULL); + pscur.seen.block = current_block; + pscur.seen.filename = current_filename; + pscur.seen.linenum = current_line_num; + + read_block(pp_script_var, pscur.value, + _("script parameter expected"), + (name == NULL), *copy_pp_script, + "SCRIPT", pscur.name); + if(!name) + get_conftoken(CONF_NL); + + save_pp_script(); + + allow_overwrites = save_overwrites; + + if (linenum) + *linenum = current_line_num; + + if (fname) + current_filename = saved_fname; + + if (from) + current_file = saved_conf; + + return lookup_pp_script(pscur.name); +} + +static void +get_pp_script( + void) +{ + read_pp_script(NULL, NULL, NULL, NULL); +} + +static void +init_pp_script_defaults( + void) +{ + pscur.name = NULL; + conf_init_str(&pscur.value[PP_SCRIPT_COMMENT] , ""); + conf_init_str(&pscur.value[PP_SCRIPT_PLUGIN] , ""); + conf_init_proplist(&pscur.value[PP_SCRIPT_PROPERTY]); + conf_init_execute_on(&pscur.value[PP_SCRIPT_EXECUTE_ON], 0); + conf_init_execute_where(&pscur.value[PP_SCRIPT_EXECUTE_WHERE], ES_CLIENT); + conf_init_int(&pscur.value[PP_SCRIPT_ORDER], CONF_UNIT_NONE, 5000); + conf_init_bool(&pscur.value[PP_SCRIPT_SINGLE_EXECUTION], 0); + conf_init_str(&pscur.value[PP_SCRIPT_CLIENT_NAME], ""); +} + +static void +save_pp_script( + void) +{ + pp_script_t *ps, *ps1; + + ps = lookup_pp_script(pscur.name); + + if(ps != (pp_script_t *)0) { + conf_parserror(_("script %s already defined at %s:%d"), + ps->name, ps->seen.filename, ps->seen.linenum); + return; + } + + ps = alloc(sizeof(pp_script_t)); + *ps = pscur; + ps->next = NULL; + /* add at end of list */ + if (!pp_script_list) + pp_script_list = ps; + else { + ps1 = pp_script_list; + while (ps1->next != NULL) { + ps1 = ps1->next; + } + ps1->next = ps; + } +} + +static void +copy_pp_script(void) +{ + pp_script_t *ps; + int i; + + ps = lookup_pp_script(tokenval.v.s); + + if(ps == NULL) { + conf_parserror(_("script parameter expected")); + return; + } + + for(i=0; i < PP_SCRIPT_PP_SCRIPT; i++) { + if(ps->value[i].seen.linenum) { + merge_val_t(&pscur.value[i], &ps->value[i]); + } + } +} + +static device_config_t * +read_device_config( + char *name, + FILE *from, + char *fname, + int *linenum) +{ + int save_overwrites; + FILE *saved_conf = NULL; + char *saved_fname = NULL; + + if (from) { + saved_conf = current_file; + current_file = from; + } + + if (fname) { + saved_fname = current_filename; + current_filename = get_seen_filename(fname); + } + + if (linenum) + current_line_num = *linenum; + + save_overwrites = allow_overwrites; + allow_overwrites = 1; + + init_device_config_defaults(); + if (name) { + dccur.name = name; + } else { + get_conftoken(CONF_IDENT); + dccur.name = stralloc(tokenval.v.s); + } + current_block = g_strconcat("device ", dccur.name, NULL); + dccur.seen.block = current_block; + dccur.seen.filename = current_filename; + dccur.seen.linenum = current_line_num; + + read_block(device_config_var, dccur.value, + _("device parameter expected"), + (name == NULL), *copy_device_config, + "DEVICE", dccur.name); + if(!name) + get_conftoken(CONF_NL); + + save_device_config(); + + allow_overwrites = save_overwrites; + + if (linenum) + *linenum = current_line_num; + + if (fname) + current_filename = saved_fname; + + if (from) + current_file = saved_conf; + + return lookup_device_config(dccur.name); +} + +static void +get_device_config( + void) +{ + read_device_config(NULL, NULL, NULL, NULL); +} + +static void +init_device_config_defaults( + void) +{ + dccur.name = NULL; + conf_init_str(&dccur.value[DEVICE_CONFIG_COMMENT] , ""); + conf_init_str(&dccur.value[DEVICE_CONFIG_TAPEDEV] , ""); + conf_init_proplist(&dccur.value[DEVICE_CONFIG_DEVICE_PROPERTY]); +} + +static void +save_device_config( + void) +{ + device_config_t *dc, *dc1; + + dc = lookup_device_config(dccur.name); + + if(dc != (device_config_t *)0) { + conf_parserror(_("device %s already defined at %s:%d"), + dc->name, dc->seen.filename, dc->seen.linenum); + return; + } + + dc = alloc(sizeof(device_config_t)); + *dc = dccur; + dc->next = NULL; + /* add at end of list */ + if (!device_config_list) + device_config_list = dc; + else { + dc1 = device_config_list; + while (dc1->next != NULL) { + dc1 = dc1->next; + } + dc1->next = dc; + } +} + +static void +copy_device_config(void) +{ + device_config_t *dc; + int i; + + dc = lookup_device_config(tokenval.v.s); + + if(dc == NULL) { + conf_parserror(_("device parameter expected")); + return; + } + + for(i=0; i < DEVICE_CONFIG_DEVICE_CONFIG; i++) { + if(dc->value[i].seen.linenum) { + merge_val_t(&dccur.value[i], &dc->value[i]); + } + } +} + +static changer_config_t * +read_changer_config( + char *name, + FILE *from, + char *fname, + int *linenum) +{ + int save_overwrites; + FILE *saved_conf = NULL; + char *saved_fname = NULL; + + if (from) { + saved_conf = current_file; + current_file = from; + } + + if (fname) { + saved_fname = current_filename; + current_filename = fname; + } + + if (linenum) + current_line_num = *linenum; + + save_overwrites = allow_overwrites; + allow_overwrites = 1; + + init_changer_config_defaults(); + if (name) { + cccur.name = name; + } else { + get_conftoken(CONF_IDENT); + cccur.name = stralloc(tokenval.v.s); + } + current_block = g_strconcat("changer ", cccur.name, NULL); + cccur.seen.block = current_block; + cccur.seen.filename = current_filename; + cccur.seen.linenum = current_line_num; + + read_block(changer_config_var, cccur.value, + _("changer parameter expected"), + (name == NULL), *copy_changer_config, + "CHANGER", cccur.name); + if(!name) + get_conftoken(CONF_NL); + + save_changer_config(); + + allow_overwrites = save_overwrites; + + if (linenum) + *linenum = current_line_num; - for(np = my_var; np->token != CONF_UNKNOWN; np++) { - if(np->token == kt->token) - break; - } + if (fname) + current_filename = saved_fname; - if(np->token == CONF_UNKNOWN) return NULL; + if (from) + current_file = saved_conf; - tmpstr = stralloc(conf_print(&conf_data[np->parm], 0, "")); - } + return lookup_changer_config(cccur.name); +} - return tmpstr; +static void +get_changer_config( + void) +{ + read_changer_config(NULL, NULL, NULL, NULL); } +static void +init_changer_config_defaults( + void) +{ + cccur.name = NULL; + conf_init_str(&cccur.value[CHANGER_CONFIG_COMMENT] , ""); + conf_init_str(&cccur.value[CHANGER_CONFIG_TAPEDEV] , ""); + conf_init_str(&cccur.value[CHANGER_CONFIG_TPCHANGER] , ""); + conf_init_str(&cccur.value[CHANGER_CONFIG_CHANGERDEV] , ""); + conf_init_str(&cccur.value[CHANGER_CONFIG_CHANGERFILE] , ""); + conf_init_proplist(&cccur.value[CHANGER_CONFIG_PROPERTY]); + conf_init_proplist(&cccur.value[CHANGER_CONFIG_DEVICE_PROPERTY]); +} -char * -getconf_list( - char *listname) +static void +save_changer_config( + void) { - char *result = NULL; - tapetype_t *tp; - dumptype_t *dp; - interface_t *ip; - holdingdisk_t *hp; + changer_config_t *dc, *dc1; - if (strcasecmp(listname,"tapetype") == 0) { - result = stralloc(""); - for(tp = tapelist; tp != NULL; tp=tp->next) { - result = vstrextend(&result, tp->name, "\n", NULL); - } - } else if (strcasecmp(listname,"dumptype") == 0) { - result = stralloc(""); - for(dp = dumplist; dp != NULL; dp=dp->next) { - result = vstrextend(&result, dp->name, "\n", NULL); - } - } else if (strcasecmp(listname,"holdingdisk") == 0) { - result = stralloc(""); - for(hp = holdingdisks; hp != NULL; hp=hp->next) { - result = vstrextend(&result, hp->name, "\n", NULL); + dc = lookup_changer_config(cccur.name); + + if(dc != (changer_config_t *)0) { + conf_parserror(_("changer %s already defined at %s:%d"), + dc->name, dc->seen.filename, dc->seen.linenum); + return; + } + + dc = alloc(sizeof(changer_config_t)); + *dc = cccur; + dc->next = NULL; + /* add at end of list */ + if (!changer_config_list) + changer_config_list = dc; + else { + dc1 = changer_config_list; + while (dc1->next != NULL) { + dc1 = dc1->next; } - } else if (strcasecmp(listname,"interface") == 0) { - result = stralloc(""); - for(ip = interface_list; ip != NULL; ip=ip->next) { - result = vstrextend(&result, ip->name, "\n", NULL); + dc1->next = dc; + } +} + +static void +copy_changer_config(void) +{ + changer_config_t *dc; + int i; + + dc = lookup_changer_config(tokenval.v.s); + + if(dc == NULL) { + conf_parserror(_("changer parameter expected")); + return; + } + + for(i=0; i < CHANGER_CONFIG_CHANGER_CONFIG; i++) { + if(dc->value[i].seen.linenum) { + merge_val_t(&cccur.value[i], &dc->value[i]); } } - return result; } +/* Read functions */ -int -getconf_seen( - confparm_t parm) +static void +read_int( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - return(conf_data[parm].seen); + ckseen(&val->seen); + val_t__int(val) = get_int(val->unit); } -int -getconf_boolean( - confparm_t parm) +static void +read_int64( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - if (conf_data[parm].type != CONFTYPE_BOOL) { - error("getconf_boolean: parm is not a CONFTYPE_BOOL"); - /*NOTREACHED*/ - } - return(conf_data[parm].v.i != 0); + ckseen(&val->seen); + val_t__int64(val) = get_int64(val->unit); } -int -getconf_int( - confparm_t parm) +static void +read_real( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - if (conf_data[parm].type != CONFTYPE_INT) { - error("getconf_int: parm is not a CONFTYPE_INT"); - /*NOTREACHED*/ - } - return(conf_data[parm].v.i); + ckseen(&val->seen); + get_conftoken(CONF_REAL); + val_t__real(val) = tokenval.v.r; } -long -getconf_long( - confparm_t parm) +static void +read_str( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - if (conf_data[parm].type != CONFTYPE_LONG) { - error("getconf_long: parm is not a CONFTYPE_LONG"); - /*NOTREACHED*/ - } - return(conf_data[parm].v.l); + ckseen(&val->seen); + get_conftoken(CONF_STRING); + val->v.s = newstralloc(val->v.s, tokenval.v.s); } -time_t -getconf_time( - confparm_t parm) +static void +read_ident( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - if (conf_data[parm].type != CONFTYPE_TIME) { - error("getconf_time: parm is not a CONFTYPE_TIME"); - /*NOTREACHED*/ - } - return(conf_data[parm].v.t); + ckseen(&val->seen); + get_conftoken(CONF_IDENT); + val->v.s = newstralloc(val->v.s, tokenval.v.s); } -ssize_t -getconf_size( - confparm_t parm) +static void +read_time( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - if (conf_data[parm].type != CONFTYPE_SIZE) { - error("getconf_size: parm is not a CONFTYPE_SIZE"); - /*NOTREACHED*/ - } - return(conf_data[parm].v.size); + ckseen(&val->seen); + val_t__time(val) = get_time(); } -off_t -getconf_am64( - confparm_t parm) +static void +read_size( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - if (conf_data[parm].type != CONFTYPE_AM64) { - error("getconf_am64: parm is not a CONFTYPE_AM64"); - /*NOTREACHED*/ - } - return(conf_data[parm].v.am64); + ckseen(&val->seen); + val_t__size(val) = get_size(val->unit); } -double -getconf_real( - confparm_t parm) +static void +read_bool( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - if (conf_data[parm].type != CONFTYPE_REAL) { - error("getconf_real: parm is not a CONFTYPE_REAL"); - /*NOTREACHED*/ - } - return(conf_data[parm].v.r); + ckseen(&val->seen); + val_t__boolean(val) = get_bool(); } -char * -getconf_str( - confparm_t parm) +static void +read_no_yes_all( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - if (conf_data[parm].type != CONFTYPE_STRING && - conf_data[parm].type != CONFTYPE_IDENT) { - error("getconf_str: parm is not a CONFTYPE_STRING|CONFTYPE_IDENT: %d", parm); - /*NOTREACHED*/ - } - return(conf_data[parm].v.s); + ckseen(&val->seen); + val_t__int(val) = get_no_yes_all(); } -int -getconf_taperalgo( - confparm_t parm) +static void +read_compress( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - if (conf_data[parm].type != CONFTYPE_TAPERALGO) { - error("getconf_taperalgo: parm is not a CONFTYPE_TAPERALGO"); - /*NOTREACHED*/ + int serv, clie, none, fast, best, custom; + int done; + comp_t comp; + + ckseen(&val->seen); + + serv = clie = none = fast = best = custom = 0; + + done = 0; + do { + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_NONE: none = 1; break; + case CONF_FAST: fast = 1; break; + case CONF_BEST: best = 1; break; + case CONF_CLIENT: clie = 1; break; + case CONF_SERVER: serv = 1; break; + case CONF_CUSTOM: custom=1; break; + case CONF_NL: done = 1; break; + case CONF_END: done = 1; break; + default: + done = 1; + serv = clie = 1; /* force an error */ + } + } while(!done); + + if(serv + clie == 0) clie = 1; /* default to client */ + if(none + fast + best + custom == 0) fast = 1; /* default to fast */ + + comp = -1; + + if(!serv && clie) { + if(none && !fast && !best && !custom) comp = COMP_NONE; + if(!none && fast && !best && !custom) comp = COMP_FAST; + if(!none && !fast && best && !custom) comp = COMP_BEST; + if(!none && !fast && !best && custom) comp = COMP_CUST; + } + + if(serv && !clie) { + if(none && !fast && !best && !custom) comp = COMP_NONE; + if(!none && fast && !best && !custom) comp = COMP_SERVER_FAST; + if(!none && !fast && best && !custom) comp = COMP_SERVER_BEST; + if(!none && !fast && !best && custom) comp = COMP_SERVER_CUST; + } + + if((int)comp == -1) { + conf_parserror(_("NONE, CLIENT FAST, CLIENT BEST, CLIENT CUSTOM, SERVER FAST, SERVER BEST or SERVER CUSTOM expected")); + comp = COMP_NONE; } - return(conf_data[parm].v.i); + + val_t__compress(val) = (int)comp; } -int* -getconf_intrange( - confparm_t parm) +static void +read_encrypt( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - if (conf_data[parm].type != CONFTYPE_INTRANGE) { - error("getconf_intrange: parm is not a CONFTYPE_INTRANGE"); - /*NOTREACHED*/ + encrypt_t encrypt; + + ckseen(&val->seen); + + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_NONE: + encrypt = ENCRYPT_NONE; + break; + + case CONF_CLIENT: + encrypt = ENCRYPT_CUST; + break; + + case CONF_SERVER: + encrypt = ENCRYPT_SERV_CUST; + break; + + default: + conf_parserror(_("NONE, CLIENT or SERVER expected")); + encrypt = ENCRYPT_NONE; + break; + } + + val_t__encrypt(val) = (int)encrypt; +} + +static void +read_holding( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) +{ + dump_holdingdisk_t holding; + + ckseen(&val->seen); + + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_NEVER: + holding = HOLD_NEVER; + break; + + case CONF_AUTO: + holding = HOLD_AUTO; + break; + + case CONF_REQUIRED: + holding = HOLD_REQUIRED; + break; + + default: /* can be a BOOLEAN */ + unget_conftoken(); + holding = (dump_holdingdisk_t)get_bool(); + if (holding == 0) + holding = HOLD_NEVER; + else if (holding == 1 || holding == 2) + holding = HOLD_AUTO; + else + conf_parserror(_("NEVER, AUTO or REQUIRED expected")); + break; + } + + val_t__holding(val) = (int)holding; +} + +static void +read_estimatelist( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) +{ + estimatelist_t estimates = NULL; + + ckseen(&val->seen); + + get_conftoken(CONF_ANY); + do { + switch(tok) { + case CONF_CLIENT: + estimates = g_slist_append(estimates, GINT_TO_POINTER(ES_CLIENT)); + break; + case CONF_SERVER: + estimates = g_slist_append(estimates, GINT_TO_POINTER(ES_SERVER)); + break; + case CONF_CALCSIZE: + estimates = g_slist_append(estimates, GINT_TO_POINTER(ES_CALCSIZE)); + break; + default: + conf_parserror(_("CLIENT, SERVER or CALCSIZE expected")); + } + get_conftoken(CONF_ANY); + if (tok == CONF_NL) + break; + } while (1); + val_t__estimatelist(val) = estimates; +} + +static void +read_strategy( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) +{ + int strat; + + ckseen(&val->seen); + + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_SKIP: + strat = DS_SKIP; + break; + case CONF_STANDARD: + strat = DS_STANDARD; + break; + case CONF_NOFULL: + strat = DS_NOFULL; + break; + case CONF_NOINC: + strat = DS_NOINC; + break; + case CONF_HANOI: + strat = DS_HANOI; + break; + case CONF_INCRONLY: + strat = DS_INCRONLY; + break; + default: + conf_parserror(_("dump strategy expected")); + strat = DS_STANDARD; } - return(conf_data[parm].v.intrange); -} - -holdingdisk_t * -getconf_holdingdisks( - void) -{ - return holdingdisks; + val_t__strategy(val) = strat; } -dumptype_t * -lookup_dumptype( - char *str) +static void +read_taperalgo( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - dumptype_t *p; + ckseen(&val->seen); - for(p = dumplist; p != NULL; p = p->next) { - if(strcasecmp(p->name, str) == 0) return p; + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_FIRST: val_t__taperalgo(val) = ALGO_FIRST; break; + case CONF_FIRSTFIT: val_t__taperalgo(val) = ALGO_FIRSTFIT; break; + case CONF_LARGEST: val_t__taperalgo(val) = ALGO_LARGEST; break; + case CONF_LARGESTFIT: val_t__taperalgo(val) = ALGO_LARGESTFIT; break; + case CONF_SMALLEST: val_t__taperalgo(val) = ALGO_SMALLEST; break; + case CONF_LAST: val_t__taperalgo(val) = ALGO_LAST; break; + default: + conf_parserror(_("FIRST, FIRSTFIT, LARGEST, LARGESTFIT, SMALLEST or LAST expected")); } - return NULL; } -tapetype_t * -lookup_tapetype( - char *str) +static void +read_send_amreport_on( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - tapetype_t *p; + ckseen(&val->seen); - for(p = tapelist; p != NULL; p = p->next) { - if(strcasecmp(p->name, str) == 0) return p; + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_ALL: val_t__send_amreport(val) = SEND_AMREPORT_ALL; break; + case CONF_STRANGE: val_t__send_amreport(val) = SEND_AMREPORT_STRANGE; break; + case CONF_ERROR: val_t__send_amreport(val) = SEND_AMREPORT_ERROR; break; + case CONF_NEVER: val_t__send_amreport(val) = SEND_AMREPORT_NEVER; break; + default: + conf_parserror(_("ALL, STRANGE, ERROR or NEVER expected")); } - return NULL; } -holdingdisk_t * -lookup_holdingdisk( - char *str) +static void +read_data_path( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - holdingdisk_t *p; + ckseen(&val->seen); - for(p = holdingdisks; p != NULL; p = p->next) { - if(strcasecmp(p->name, str) == 0) return p; + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_AMANDA : val_t__data_path(val) = DATA_PATH_AMANDA ; break; + case CONF_DIRECTTCP: val_t__data_path(val) = DATA_PATH_DIRECTTCP; break; + default: + conf_parserror(_("AMANDA or DIRECTTCP expected")); } - return NULL; } -interface_t * -lookup_interface( - char *str) +static void +read_priority( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { -#ifndef __lint - interface_t *p; -#endif + int pri; - if (str == NULL) - return interface_list; + ckseen(&val->seen); -#ifndef __lint - for (p = interface_list; p != NULL; p = p->next) { - if (strcasecmp(p->name, str) == 0) - return p; + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_LOW: pri = 0; break; + case CONF_MEDIUM: pri = 1; break; + case CONF_HIGH: pri = 2; break; + case CONF_INT: pri = tokenval.v.i; break; + default: + conf_parserror(_("LOW, MEDIUM, HIGH or integer expected")); + pri = 0; } -#endif - return NULL; + val_t__priority(val) = pri; } - -/* -** ------------------------ -** Internal routines -** ------------------------ -*/ - - static void -init_defaults( - void) +read_rate( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - char *s; - - /* defaults for exported variables */ - -#ifdef DEFAULT_CONFIG - s = DEFAULT_CONFIG; -#else - s = "YOUR ORG"; -#endif -#ifdef DEFAULT_CONFIG - s = DEFAULT_CONFIG; -#else - s = ""; -#endif - conf_init_string(&conf_data[CNF_CONF], s); -#ifdef DEFAULT_SERVER - s = DEFAULT_SERVER; -#else - s = ""; -#endif - conf_init_string(&conf_data[CNF_INDEX_SERVER], s); - - -#ifdef DEFAULT_TAPE_SERVER - s = DEFAULT_TAPE_SERVER; -#else -#ifdef DEFAULT_SERVER - s = DEFAULT_SERVER; -#else - s = ""; -#endif -#endif - conf_init_string(&conf_data[CNF_TAPE_SERVER], s); - conf_init_string(&conf_data[CNF_AUTH], "bsd"); - conf_init_string(&conf_data[CNF_SSH_KEYS], ""); - conf_init_string(&conf_data[CNF_AMANDAD_PATH], ""); - conf_init_string(&conf_data[CNF_CLIENT_USERNAME], ""); -#ifdef GNUTAR_LISTED_INCREMENTAL_DIR - conf_init_string(&conf_data[CNF_GNUTAR_LIST_DIR], - GNUTAR_LISTED_INCREMENTAL_DIR); -#else - conf_init_string(&conf_data[CNF_GNUTAR_LIST_DIR], NULL); -#endif - conf_init_string(&conf_data[CNF_AMANDATES], AMANDATES_FILE); - conf_init_string(&conf_data[CNF_KRB5KEYTAB], "/.amanda-v5-keytab"); - conf_init_string(&conf_data[CNF_KRB5PRINCIPAL], "service/amanda"); - - conf_init_string(&conf_data[CNF_ORG], s); - conf_init_string(&conf_data[CNF_MAILTO], "operators"); - conf_init_string(&conf_data[CNF_DUMPUSER], CLIENT_LOGIN); -#ifdef DEFAULT_TAPE_DEVICE - s = DEFAULT_TAPE_DEVICE; -#else - s = NULL; -#endif - conf_init_string(&conf_data[CNF_TAPEDEV], s); -#ifdef DEFAULT_CHANGER_DEVICE - s = DEFAULT_CHANGER_DEVICE; -#else - s = "/dev/null"; -#endif - conf_init_string(&conf_data[CNF_CHNGRDEV], s); - conf_init_string(&conf_data[CNF_CHNGRFILE], "/usr/adm/amanda/changer-status"); -#ifdef DEFAULT_RAW_TAPE_DEVICE - s = DEFAULT_RAW_TAPE_DEVICE; -#else - s = "/dev/rawft0"; -#endif - conf_init_string (&conf_data[CNF_LABELSTR] , ".*"); - conf_init_string (&conf_data[CNF_TAPELIST] , "tapelist"); - conf_init_string (&conf_data[CNF_DISKFILE] , "disklist"); - conf_init_string (&conf_data[CNF_INFOFILE] , "/usr/adm/amanda/curinfo"); - conf_init_string (&conf_data[CNF_LOGDIR] , "/usr/adm/amanda"); - conf_init_string (&conf_data[CNF_INDEXDIR] , "/usr/adm/amanda/index"); - conf_init_ident (&conf_data[CNF_TAPETYPE] , "EXABYTE"); - conf_init_int (&conf_data[CNF_DUMPCYCLE] , 10); - conf_init_int (&conf_data[CNF_RUNSPERCYCLE] , 0); - conf_init_int (&conf_data[CNF_TAPECYCLE] , 15); - conf_init_int (&conf_data[CNF_NETUSAGE] , 300); - conf_init_int (&conf_data[CNF_INPARALLEL] , 10); - conf_init_string (&conf_data[CNF_DUMPORDER] , "ttt"); - conf_init_int (&conf_data[CNF_BUMPPERCENT] , 0); - conf_init_am64 (&conf_data[CNF_BUMPSIZE] , (off_t)10*1024); - conf_init_real (&conf_data[CNF_BUMPMULT] , 1.5); - conf_init_int (&conf_data[CNF_BUMPDAYS] , 2); - conf_init_string (&conf_data[CNF_TPCHANGER] , ""); - conf_init_int (&conf_data[CNF_RUNTAPES] , 1); - conf_init_int (&conf_data[CNF_MAXDUMPS] , 1); - conf_init_int (&conf_data[CNF_ETIMEOUT] , 300); - conf_init_int (&conf_data[CNF_DTIMEOUT] , 1800); - conf_init_int (&conf_data[CNF_CTIMEOUT] , 30); - conf_init_int (&conf_data[CNF_TAPEBUFS] , 20); - conf_init_string (&conf_data[CNF_RAWTAPEDEV] , s); - conf_init_string (&conf_data[CNF_PRINTER] , ""); - conf_init_bool (&conf_data[CNF_AUTOFLUSH] , 0); - conf_init_int (&conf_data[CNF_RESERVE] , 100); - conf_init_am64 (&conf_data[CNF_MAXDUMPSIZE] , (off_t)-1); - conf_init_string (&conf_data[CNF_COLUMNSPEC] , ""); - conf_init_bool (&conf_data[CNF_AMRECOVER_DO_FSF] , 1); - conf_init_string (&conf_data[CNF_AMRECOVER_CHANGER] , ""); - conf_init_bool (&conf_data[CNF_AMRECOVER_CHECK_LABEL], 1); - conf_init_taperalgo(&conf_data[CNF_TAPERALGO] , 0); - conf_init_string (&conf_data[CNF_DISPLAYUNIT] , "k"); - conf_init_string (&conf_data[CNF_KRB5KEYTAB] , "/.amanda-v5-keytab"); - conf_init_string (&conf_data[CNF_KRB5PRINCIPAL] , "service/amanda"); - conf_init_string (&conf_data[CNF_LABEL_NEW_TAPES] , ""); - conf_init_bool (&conf_data[CNF_USETIMESTAMPS] , 0); - conf_init_int (&conf_data[CNF_CONNECT_TRIES] , 3); - conf_init_int (&conf_data[CNF_REP_TRIES] , 5); - conf_init_int (&conf_data[CNF_REQ_TRIES] , 3); - conf_init_int (&conf_data[CNF_DEBUG_AMANDAD] , 0); - conf_init_int (&conf_data[CNF_DEBUG_AMIDXTAPED] , 0); - conf_init_int (&conf_data[CNF_DEBUG_AMINDEXD] , 0); - conf_init_int (&conf_data[CNF_DEBUG_AMRECOVER] , 0); - conf_init_int (&conf_data[CNF_DEBUG_AUTH] , 0); - conf_init_int (&conf_data[CNF_DEBUG_EVENT] , 0); - conf_init_int (&conf_data[CNF_DEBUG_HOLDING] , 0); - conf_init_int (&conf_data[CNF_DEBUG_PROTOCOL] , 0); - conf_init_int (&conf_data[CNF_DEBUG_PLANNER] , 0); - conf_init_int (&conf_data[CNF_DEBUG_DRIVER] , 0); - conf_init_int (&conf_data[CNF_DEBUG_DUMPER] , 0); - conf_init_int (&conf_data[CNF_DEBUG_CHUNKER] , 0); - conf_init_int (&conf_data[CNF_DEBUG_TAPER] , 0); - conf_init_int (&conf_data[CNF_DEBUG_SELFCHECK] , 0); - conf_init_int (&conf_data[CNF_DEBUG_SENDSIZE] , 0); - conf_init_int (&conf_data[CNF_DEBUG_SENDBACKUP] , 0); -#ifdef UDPPORTRANGE - conf_init_intrange (&conf_data[CNF_RESERVED_UDP_PORT] , UDPPORTRANGE); -#else - conf_init_intrange (&conf_data[CNF_RESERVED_UDP_PORT] , 512, 1023); -#endif -#ifdef LOW_TCPPORTRANGE - conf_init_intrange (&conf_data[CNF_RESERVED_TCP_PORT] , LOW_TCPPORTRANGE); -#else - conf_init_intrange (&conf_data[CNF_RESERVED_TCP_PORT] , 512, 1023); -#endif -#ifdef TCPPORTRANGE - conf_init_intrange (&conf_data[CNF_UNRESERVED_TCP_PORT] , TCPPORTRANGE); -#else - conf_init_intrange (&conf_data[CNF_UNRESERVED_TCP_PORT] , 0, 0); -#endif - - /* defaults for internal variables */ - - conf_line_num = got_parserror = 0; - allow_overwrites = 0; - token_pushed = 0; - - while(holdingdisks != NULL) { - holdingdisk_t *hp; - - hp = holdingdisks; - holdingdisks = holdingdisks->next; - amfree(hp); + get_conftoken(CONF_REAL); + val_t__rate(val)[0] = tokenval.v.r; + val_t__rate(val)[1] = tokenval.v.r; + val->seen = tokenval.seen; + if(tokenval.v.r < 0) { + conf_parserror(_("full compression rate must be >= 0")); } - num_holdingdisks = 0; - /* free any previously declared dump, tape and interface types */ + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_NL: + return; - while(dumplist != NULL) { - dumptype_t *dp; + case CONF_END: + return; - dp = dumplist; - dumplist = dumplist->next; - amfree(dp); - } - while(tapelist != NULL) { - tapetype_t *tp; + case CONF_COMMA: + break; - tp = tapelist; - tapelist = tapelist->next; - amfree(tp); + default: + unget_conftoken(); } - while(interface_list != NULL) { - interface_t *ip; - ip = interface_list; - interface_list = interface_list->next; - amfree(ip); + get_conftoken(CONF_REAL); + val_t__rate(val)[1] = tokenval.v.r; + if(tokenval.v.r < 0) { + conf_parserror(_("incremental compression rate must be >= 0")); } - - /* create some predefined dumptypes for backwards compatability */ - init_dumptype_defaults(); - dpcur.name = stralloc("NO-COMPRESS"); - dpcur.seen = -1; - conf_set_compress(&dpcur.value[DUMPTYPE_COMPRESS], COMP_NONE); - save_dumptype(); - - init_dumptype_defaults(); - dpcur.name = stralloc("COMPRESS-FAST"); - dpcur.seen = -1; - conf_set_compress(&dpcur.value[DUMPTYPE_COMPRESS], COMP_FAST); - save_dumptype(); - - init_dumptype_defaults(); - dpcur.name = stralloc("COMPRESS-BEST"); - dpcur.seen = -1; - conf_set_compress(&dpcur.value[DUMPTYPE_COMPRESS], COMP_BEST); - save_dumptype(); - - init_dumptype_defaults(); - dpcur.name = stralloc("COMPRESS-CUST"); - dpcur.seen = -1; - conf_set_compress(&dpcur.value[DUMPTYPE_COMPRESS], COMP_CUST); - save_dumptype(); - - init_dumptype_defaults(); - dpcur.name = stralloc("SRVCOMPRESS"); - dpcur.seen = -1; - conf_set_compress(&dpcur.value[DUMPTYPE_COMPRESS], COMP_SERVER_FAST); - save_dumptype(); - - init_dumptype_defaults(); - dpcur.name = stralloc("BSD-AUTH"); - dpcur.seen = -1; - conf_set_string(&dpcur.value[DUMPTYPE_SECURITY_DRIVER], "BSD"); - save_dumptype(); - - init_dumptype_defaults(); - dpcur.name = stralloc("KRB4-AUTH"); - dpcur.seen = -1; - conf_set_string(&dpcur.value[DUMPTYPE_SECURITY_DRIVER], "KRB4"); - save_dumptype(); - - init_dumptype_defaults(); - dpcur.name = stralloc("NO-RECORD"); - dpcur.seen = -1; - conf_set_bool(&dpcur.value[DUMPTYPE_RECORD], 0); - save_dumptype(); - - init_dumptype_defaults(); - dpcur.name = stralloc("NO-HOLD"); - dpcur.seen = -1; - conf_set_holding(&dpcur.value[DUMPTYPE_HOLDINGDISK], HOLD_NEVER); - save_dumptype(); - - init_dumptype_defaults(); - dpcur.name = stralloc("NO-FULL"); - dpcur.seen = -1; - conf_set_strategy(&dpcur.value[DUMPTYPE_STRATEGY], DS_NOFULL); - save_dumptype(); - conffile_init = 1; } static void -read_conffile_recursively( - char *filename) +read_exinclude( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - /* Save globals used in read_confline(), elsewhere. */ - int save_line_num = conf_line_num; - FILE *save_conf = conf_conf; - char *save_confname = conf_confname; - int rc; + int file, got_one = 0; + am_sl_t *exclude; + int optional = 0; - if (*filename == '/' || config_dir == NULL) { - conf_confname = stralloc(filename); - } else { - conf_confname = stralloc2(config_dir, filename); + get_conftoken(CONF_ANY); + if(tok == CONF_LIST) { + file = 0; + get_conftoken(CONF_ANY); + exclude = val_t__exinclude(val).sl_list; } + else { + file = 1; + if(tok == CONF_EFILE) get_conftoken(CONF_ANY); + exclude = val_t__exinclude(val).sl_file; + } + ckseen(&val->seen); - if((conf_conf = fopen(conf_confname, "r")) == NULL) { - fprintf(stderr, "could not open conf file \"%s\": %s\n", conf_confname, - strerror(errno)); - amfree(conf_confname); - got_parserror = -1; - return; + if(tok == CONF_OPTIONAL) { + get_conftoken(CONF_ANY); + optional = 1; } - conf_line_num = 0; + if(tok == CONF_APPEND) { + get_conftoken(CONF_ANY); + } + else { + free_sl(exclude); + exclude = NULL; + } - /* read_confline() can invoke us recursively via "includefile" */ - do { - rc = read_confline(); - } while (rc != 0); - afclose(conf_conf); + while(tok == CONF_STRING) { + exclude = append_sl(exclude, tokenval.v.s); + got_one = 1; + get_conftoken(CONF_ANY); + } + unget_conftoken(); - amfree(conf_confname); + if(got_one == 0) { free_sl(exclude); exclude = NULL; } - /* Restore servers */ - conf_line_num = save_line_num; - conf_conf = save_conf; - conf_confname = save_confname; + if (file == 0) + val_t__exinclude(val).sl_list = exclude; + else + val_t__exinclude(val).sl_file = exclude; + val_t__exinclude(val).optional = optional; } - -/* ------------------------ */ - - -static int -read_confline( - void) +static void +read_intrange( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - t_conf_var *np; - - keytable = server_keytab; + get_conftoken(CONF_INT); + val_t__intrange(val)[0] = tokenval.v.i; + val_t__intrange(val)[1] = tokenval.v.i; + val->seen = tokenval.seen; - conf_line_num += 1; get_conftoken(CONF_ANY); switch(tok) { - case CONF_INCLUDEFILE: - { - char *fn; - char *cname; - - get_conftoken(CONF_STRING); - fn = tokenval.v.s; - if (*fn == '/' || config_dir == NULL) { - cname = stralloc(fn); - } else { - cname = stralloc2(config_dir, fn); - } - if ( cname != NULL && (access(cname, R_OK) == 0)) { - read_conffile_recursively(cname); - amfree(cname); - } else { - conf_parserror("cannot open %s: %s\n", fn, strerror(errno)); - } - amfree(cname); - - } - break; - - case CONF_HOLDING: - get_holdingdisk(); - break; - - case CONF_DEFINE: - get_conftoken(CONF_ANY); - if(tok == CONF_DUMPTYPE) get_dumptype(); - else if(tok == CONF_TAPETYPE) get_tapetype(); - else if(tok == CONF_INTERFACE) get_interface(); - else conf_parserror("DUMPTYPE, INTERFACE or TAPETYPE expected"); - break; + case CONF_NL: + return; - case CONF_NL: /* empty line */ - break; + case CONF_END: + return; - case CONF_END: /* end of file */ - return 0; + case CONF_COMMA: + break; default: - { - for(np = server_var; np->token != CONF_UNKNOWN; np++) - if(np->token == tok) break; - - if(np->token == CONF_UNKNOWN) { - conf_parserror("configuration keyword expected"); - } else { - np->read_function(np, &conf_data[np->parm]); - if(np->validate) - np->validate(np, &conf_data[np->parm]); - } - } + unget_conftoken(); } - if(tok != CONF_NL) - get_conftoken(CONF_NL); - return 1; + + get_conftoken(CONF_INT); + val_t__intrange(val)[1] = tokenval.v.i; } static void -get_holdingdisk( - void) -{ - char *prefix; - int save_overwrites; - - save_overwrites = allow_overwrites; - allow_overwrites = 1; - - init_holdingdisk_defaults(); +read_property( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) +{ + char *key; + gboolean set_seen = TRUE; + property_t *property = malloc(sizeof(property_t)); + property_t *old_property; + property->append = 0; + property->priority = 0; + property->values = NULL; - get_conftoken(CONF_IDENT); - hdcur.name = stralloc(tokenval.v.s); - hdcur.seen = conf_line_num; + get_conftoken(CONF_ANY); + if (tok == CONF_PRIORITY) { + property->priority = 1; + get_conftoken(CONF_ANY); + } + if (tok == CONF_APPEND) { + property->append = 1; + get_conftoken(CONF_ANY); + } + if (tok != CONF_STRING) { + conf_parserror(_("key expected")); + return; + } + key = amandaify_property_name(tokenval.v.s); - prefix = vstralloc( "HOLDINGDISK:", hdcur.name, ":", NULL); - read_block(program_options, holding_var, server_keytab, hdcur.value, prefix, - "holding disk parameter expected", 1, NULL); - amfree(prefix); - get_conftoken(CONF_NL); + get_conftoken(CONF_ANY); + if (tok == CONF_NL || tok == CONF_END) { + g_hash_table_remove(val->v.proplist, key); + unget_conftoken(); + return; + } + if (tok != CONF_STRING) { + conf_parserror(_("value expected")); + return; + } - hdcur.disksize = holdingdisk_get_disksize(&hdcur); - save_holdingdisk(); + if(val->seen.linenum == 0) { + ckseen(&val->seen); // first property + } - allow_overwrites = save_overwrites; + old_property = g_hash_table_lookup(val->v.proplist, key); + if (property->append) { + /* old_property will be freed by g_hash_table_insert, so + * steal its values */ + if (old_property) { + if (old_property->priority) + property->priority = 1; + property->values = old_property->values; + old_property->values = NULL; + set_seen = FALSE; + } + } + while(tok == CONF_STRING) { + property->values = g_slist_append(property->values, + strdup(tokenval.v.s)); + get_conftoken(CONF_ANY); + } + unget_conftoken(); + g_hash_table_insert(val->v.proplist, key, property); + if (set_seen) { + property->seen.linenum = 0; + property->seen.filename = NULL; + property->seen.block = NULL; + ckseen(&property->seen); + } } + static void -init_holdingdisk_defaults( - void) +read_dapplication( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - conf_init_string(&hdcur.value[HOLDING_COMMENT] , ""); - conf_init_string(&hdcur.value[HOLDING_DISKDIR] , ""); - conf_init_am64(&hdcur.value[HOLDING_DISKSIZE] , (off_t)0); - /* 1 Gb = 1M counted in 1Kb blocks */ - conf_init_am64(&hdcur.value[HOLDING_CHUNKSIZE], (off_t)1024*1024); + application_t *application; - hdcur.up = (void *)0; - hdcur.disksize = 0LL; + get_conftoken(CONF_ANY); + if (tok == CONF_LBRACE) { + current_line_num -= 1; + application = read_application(vstralloc("custom(DUMPTYPE:", + dpcur.name, ")", ".", + anonymous_value(),NULL), + NULL, NULL, NULL); + current_line_num -= 1; + } else if (tok == CONF_STRING) { + application = lookup_application(tokenval.v.s); + if (application == NULL) { + conf_parserror(_("Unknown application named: %s"), tokenval.v.s); + return; + } + } else { + conf_parserror(_("application name expected: %d %d"), tok, CONF_STRING); + return; + } + amfree(val->v.s); + val->v.s = stralloc(application->name); + ckseen(&val->seen); } static void -save_holdingdisk( - void) +read_dinteractivity( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - holdingdisk_t *hp; + interactivity_t *interactivity; - hp = alloc(sizeof(holdingdisk_t)); - *hp = hdcur; - hp->next = holdingdisks; - holdingdisks = hp; - - num_holdingdisks++; + get_conftoken(CONF_ANY); + if (tok == CONF_LBRACE) { + current_line_num -= 1; + interactivity = read_interactivity(vstralloc("custom(iv)", ".", + anonymous_value(),NULL), + NULL, NULL, NULL); + current_line_num -= 1; + } else if (tok == CONF_STRING) { + interactivity = lookup_interactivity(tokenval.v.s); + if (interactivity == NULL) { + conf_parserror(_("Unknown interactivity named: %s"), tokenval.v.s); + return; + } + } else { + conf_parserror(_("interactivity name expected: %d %d"), tok, CONF_STRING); + return; + } + amfree(val->v.s); + val->v.s = stralloc(interactivity->name); + ckseen(&val->seen); } - -dumptype_t * -read_dumptype( - char *name, - FILE *from, - char *fname, - int *linenum) +static void +read_dtaperscan( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - int save_overwrites; - FILE *saved_conf = NULL; - char *saved_fname = NULL; - char *prefix; - - if (from) { - saved_conf = conf_conf; - conf_conf = from; - } + taperscan_t *taperscan; - if (fname) { - saved_fname = conf_confname; - conf_confname = fname; + get_conftoken(CONF_ANY); + if (tok == CONF_LBRACE) { + current_line_num -= 1; + taperscan = read_taperscan(vstralloc("custom(ts)", ".", + anonymous_value(),NULL), + NULL, NULL, NULL); + current_line_num -= 1; + } else if (tok == CONF_STRING) { + taperscan = lookup_taperscan(tokenval.v.s); + if (taperscan == NULL) { + conf_parserror(_("Unknown taperscan named: %s"), tokenval.v.s); + return; + } + } else { + conf_parserror(_("taperscan name expected: %d %d"), tok, CONF_STRING); + return; } + amfree(val->v.s); + val->v.s = stralloc(taperscan->name); + ckseen(&val->seen); +} - if (linenum) - conf_line_num = *linenum; - - save_overwrites = allow_overwrites; - allow_overwrites = 1; - - init_dumptype_defaults(); - if (name) { - dpcur.name = name; +static void +read_dpp_script( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) +{ + pp_script_t *pp_script; + get_conftoken(CONF_ANY); + if (tok == CONF_LBRACE) { + current_line_num -= 1; + pp_script = read_pp_script(vstralloc("custom(DUMPTYPE:", dpcur.name, + ")", ".", anonymous_value(),NULL), + NULL, NULL, NULL); + current_line_num -= 1; + val->v.identlist = g_slist_insert_sorted(val->v.identlist, + stralloc(pp_script->name), &compare_pp_script_order); + } else if (tok == CONF_STRING || tok == CONF_IDENT) { + while (tok == CONF_STRING || tok == CONF_IDENT) { + pp_script = lookup_pp_script(tokenval.v.s); + if (pp_script == NULL) { + conf_parserror(_("Unknown pp_script named: %s"), tokenval.v.s); + return; + } + val->v.identlist = g_slist_insert_sorted(val->v.identlist, + stralloc(pp_script->name), &compare_pp_script_order); + get_conftoken(CONF_ANY); + } + unget_conftoken(); } else { - get_conftoken(CONF_IDENT); - dpcur.name = stralloc(tokenval.v.s); + conf_parserror(_("pp_script name expected: %d %d"), tok, CONF_STRING); + return; } - dpcur.seen = conf_line_num; + ckseen(&val->seen); +} +static void +read_execute_on( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) +{ + ckseen(&val->seen); - prefix = vstralloc( "DUMPTYPE:", dpcur.name, ":", NULL); - read_block(program_options, dumptype_var, server_keytab, dpcur.value, - prefix, "dumptype parameter expected", - (name == NULL), *copy_dumptype); - amfree(prefix); - if(!name) - get_conftoken(CONF_NL); + get_conftoken(CONF_ANY); + val->v.i = 0; + do { + switch(tok) { + case CONF_PRE_AMCHECK: val->v.i |= EXECUTE_ON_PRE_AMCHECK; break; + case CONF_PRE_DLE_AMCHECK: val->v.i |= EXECUTE_ON_PRE_DLE_AMCHECK; break; + case CONF_PRE_HOST_AMCHECK: val->v.i |= EXECUTE_ON_PRE_HOST_AMCHECK; break; + case CONF_POST_DLE_AMCHECK: val->v.i |= EXECUTE_ON_POST_DLE_AMCHECK; break; + case CONF_POST_HOST_AMCHECK: val->v.i |= EXECUTE_ON_POST_HOST_AMCHECK; break; + case CONF_POST_AMCHECK: val->v.i |= EXECUTE_ON_POST_AMCHECK; break; + case CONF_PRE_ESTIMATE: val->v.i |= EXECUTE_ON_PRE_ESTIMATE; break; + case CONF_PRE_DLE_ESTIMATE: val->v.i |= EXECUTE_ON_PRE_DLE_ESTIMATE; break; + case CONF_PRE_HOST_ESTIMATE: val->v.i |= EXECUTE_ON_PRE_HOST_ESTIMATE; break; + case CONF_POST_DLE_ESTIMATE: val->v.i |= EXECUTE_ON_POST_DLE_ESTIMATE; break; + case CONF_POST_HOST_ESTIMATE: val->v.i |= EXECUTE_ON_POST_HOST_ESTIMATE; break; + case CONF_POST_ESTIMATE: val->v.i |= EXECUTE_ON_POST_ESTIMATE; break; + case CONF_PRE_BACKUP: val->v.i |= EXECUTE_ON_PRE_BACKUP; break; + case CONF_PRE_DLE_BACKUP: val->v.i |= EXECUTE_ON_PRE_DLE_BACKUP; break; + case CONF_PRE_HOST_BACKUP: val->v.i |= EXECUTE_ON_PRE_HOST_BACKUP; break; + case CONF_POST_BACKUP: val->v.i |= EXECUTE_ON_POST_BACKUP; break; + case CONF_POST_DLE_BACKUP: val->v.i |= EXECUTE_ON_POST_DLE_BACKUP; break; + case CONF_POST_HOST_BACKUP: val->v.i |= EXECUTE_ON_POST_HOST_BACKUP; break; + case CONF_PRE_RECOVER: val->v.i |= EXECUTE_ON_PRE_RECOVER; break; + case CONF_POST_RECOVER: val->v.i |= EXECUTE_ON_POST_RECOVER; break; + case CONF_PRE_LEVEL_RECOVER: val->v.i |= EXECUTE_ON_PRE_LEVEL_RECOVER; break; + case CONF_POST_LEVEL_RECOVER: val->v.i |= EXECUTE_ON_POST_LEVEL_RECOVER; break; + case CONF_INTER_LEVEL_RECOVER: val->v.i |= EXECUTE_ON_INTER_LEVEL_RECOVER; break; + default: + conf_parserror(_("Execute-on expected")); + } + get_conftoken(CONF_ANY); + if (tok != CONF_COMMA) { + unget_conftoken(); + break; + } + get_conftoken(CONF_ANY); + } while (1); +} - /* XXX - there was a stupidity check in here for skip-incr and - ** skip-full. This check should probably be somewhere else. */ +static void +read_execute_where( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) +{ + ckseen(&val->seen); - save_dumptype(); + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_CLIENT: val->v.i = ES_CLIENT; break; + case CONF_SERVER: val->v.i = ES_SERVER; break; + default: + conf_parserror(_("CLIENT or SERVER expected")); + } +} - allow_overwrites = save_overwrites; +static void +read_int_or_str( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) +{ + ckseen(&val->seen); - if (linenum) - *linenum = conf_line_num; + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_INT: + amfree(val->v.s); + val->v.s = g_strdup_printf("%d", tokenval.v.i); + break; - if (fname) - conf_confname = saved_fname; + case CONF_SIZE: + amfree(val->v.s); + val->v.s = g_strdup_printf("%zu", tokenval.v.size); + break; - if (from) - conf_conf = saved_conf; + case CONF_INT64: + amfree(val->v.s); + val->v.s = g_strdup_printf("%jd", (intmax_t)tokenval.v.int64); + break; - return lookup_dumptype(dpcur.name); + case CONF_STRING: + val->v.s = newstralloc(val->v.s, tokenval.v.s); + break; + default: + conf_parserror(_("an integer or a quoted string is expected")); + } } static void -get_dumptype(void) +read_autolabel( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - read_dumptype(NULL, NULL, NULL, NULL); -} + int data = 0; + ckseen(&val->seen); -static void -init_dumptype_defaults(void) -{ - dpcur.name = NULL; - conf_init_string (&dpcur.value[DUMPTYPE_COMMENT] , ""); - conf_init_string (&dpcur.value[DUMPTYPE_PROGRAM] , "DUMP"); - conf_init_string (&dpcur.value[DUMPTYPE_SRVCOMPPROG] , ""); - conf_init_string (&dpcur.value[DUMPTYPE_CLNTCOMPPROG] , ""); - conf_init_string (&dpcur.value[DUMPTYPE_SRV_ENCRYPT] , ""); - conf_init_string (&dpcur.value[DUMPTYPE_CLNT_ENCRYPT] , ""); - conf_init_string (&dpcur.value[DUMPTYPE_AMANDAD_PATH] , "X"); - conf_init_string (&dpcur.value[DUMPTYPE_CLIENT_USERNAME] , "X"); - conf_init_string (&dpcur.value[DUMPTYPE_SSH_KEYS] , "X"); - conf_init_string (&dpcur.value[DUMPTYPE_SECURITY_DRIVER] , "BSD"); - conf_init_exinclude(&dpcur.value[DUMPTYPE_EXCLUDE]); - conf_init_exinclude(&dpcur.value[DUMPTYPE_INCLUDE]); - conf_init_priority (&dpcur.value[DUMPTYPE_PRIORITY] , 1); - conf_init_int (&dpcur.value[DUMPTYPE_DUMPCYCLE] , conf_data[CNF_DUMPCYCLE].v.i); - conf_init_int (&dpcur.value[DUMPTYPE_MAXDUMPS] , conf_data[CNF_MAXDUMPS].v.i); - conf_init_int (&dpcur.value[DUMPTYPE_MAXPROMOTEDAY] , 10000); - conf_init_int (&dpcur.value[DUMPTYPE_BUMPPERCENT] , conf_data[CNF_BUMPPERCENT].v.i); - conf_init_am64 (&dpcur.value[DUMPTYPE_BUMPSIZE] , conf_data[CNF_BUMPSIZE].v.am64); - conf_init_int (&dpcur.value[DUMPTYPE_BUMPDAYS] , conf_data[CNF_BUMPDAYS].v.i); - conf_init_real (&dpcur.value[DUMPTYPE_BUMPMULT] , conf_data[CNF_BUMPMULT].v.r); - conf_init_time (&dpcur.value[DUMPTYPE_STARTTIME] , (time_t)0); - conf_init_strategy (&dpcur.value[DUMPTYPE_STRATEGY] , DS_STANDARD); - conf_init_estimate (&dpcur.value[DUMPTYPE_ESTIMATE] , ES_CLIENT); - conf_init_compress (&dpcur.value[DUMPTYPE_COMPRESS] , COMP_FAST); - conf_init_encrypt (&dpcur.value[DUMPTYPE_ENCRYPT] , ENCRYPT_NONE); - conf_init_string (&dpcur.value[DUMPTYPE_SRV_DECRYPT_OPT] , "-d"); - conf_init_string (&dpcur.value[DUMPTYPE_CLNT_DECRYPT_OPT] , "-d"); - conf_init_rate (&dpcur.value[DUMPTYPE_COMPRATE] , 0.50, 0.50); - conf_init_am64 (&dpcur.value[DUMPTYPE_TAPE_SPLITSIZE] , (off_t)0); - conf_init_am64 (&dpcur.value[DUMPTYPE_FALLBACK_SPLITSIZE], (off_t)10 * 1024); - conf_init_string (&dpcur.value[DUMPTYPE_SPLIT_DISKBUFFER] , NULL); - conf_init_bool (&dpcur.value[DUMPTYPE_RECORD] , 1); - conf_init_bool (&dpcur.value[DUMPTYPE_SKIP_INCR] , 0); - conf_init_bool (&dpcur.value[DUMPTYPE_SKIP_FULL] , 0); - conf_init_holding (&dpcur.value[DUMPTYPE_HOLDINGDISK] , HOLD_AUTO); - conf_init_bool (&dpcur.value[DUMPTYPE_KENCRYPT] , 0); - conf_init_bool (&dpcur.value[DUMPTYPE_IGNORE] , 0); - conf_init_bool (&dpcur.value[DUMPTYPE_INDEX] , 1); + get_conftoken(CONF_ANY); + if (tok == CONF_STRING) { + data++; + val->v.autolabel.template = newstralloc(val->v.autolabel.template, + tokenval.v.s); + get_conftoken(CONF_ANY); + } + val->v.autolabel.autolabel = 0; + while (tok != CONF_NL && tok != CONF_END) { + data++; + if (tok == CONF_ANY_VOLUME) + val->v.autolabel.autolabel |= AL_OTHER_CONFIG | AL_NON_AMANDA | + AL_VOLUME_ERROR | AL_EMPTY; + else if (tok == CONF_OTHER_CONFIG) + val->v.autolabel.autolabel |= AL_OTHER_CONFIG; + else if (tok == CONF_NON_AMANDA) + val->v.autolabel.autolabel |= AL_NON_AMANDA; + else if (tok == CONF_VOLUME_ERROR) + val->v.autolabel.autolabel |= AL_VOLUME_ERROR; + else if (tok == CONF_EMPTY) + val->v.autolabel.autolabel |= AL_EMPTY; + else { + conf_parserror(_("ANY, NEW-VOLUME, OTHER-CONFIG, NON-AMANDA, VOLUME-ERROR or EMPTY is expected")); + } + get_conftoken(CONF_ANY); + } + if (data == 0) { + amfree(val->v.autolabel.template); + val->v.autolabel.autolabel = 0; + } else if (val->v.autolabel.autolabel == 0) { + val->v.autolabel.autolabel = AL_VOLUME_ERROR | AL_EMPTY; + } } static void -save_dumptype(void) +read_part_cache_type( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - dumptype_t *dp, *dp1;; + part_cache_type_t part_cache_type; - dp = lookup_dumptype(dpcur.name); + ckseen(&val->seen); - if(dp != (dumptype_t *)0) { - conf_parserror("dumptype %s already defined on line %d", dp->name, dp->seen); - return; - } + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_NONE: + part_cache_type = PART_CACHE_TYPE_NONE; + break; - dp = alloc(sizeof(dumptype_t)); - *dp = dpcur; - dp->next = NULL; - /* add at end of list */ - if(!dumplist) - dumplist = dp; - else { - dp1 = dumplist; - while (dp1->next != NULL) { - dp1 = dp1->next; - } - dp1->next = dp; - } + case CONF_DISK: + part_cache_type = PART_CACHE_TYPE_DISK; + break; + + case CONF_MEMORY: + part_cache_type = PART_CACHE_TYPE_MEMORY; + break; + + default: + conf_parserror(_("NONE, DISK or MEMORY expected")); + part_cache_type = PART_CACHE_TYPE_NONE; + break; + } + + val_t__part_cache_type(val) = (int)part_cache_type; } static void -copy_dumptype(void) +read_host_limit( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) { - dumptype_t *dt; - int i; + host_limit_t *rl = &val_t__host_limit(val); + ckseen(&val->seen); - dt = lookup_dumptype(tokenval.v.s); + rl->match_pats = NULL; + rl->same_host = FALSE; + rl->server = FALSE; - if(dt == NULL) { - conf_parserror("dumptype parameter expected"); - return; - } + while (1) { + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_STRING: + rl->match_pats = g_slist_append(rl->match_pats, g_strdup(tokenval.v.s)); + break; + case CONF_SAME_HOST: + rl->same_host = TRUE; + break; - for(i=0; i < DUMPTYPE_DUMPTYPE; i++) { - if(dt->value[i].seen) { - free_val_t(&dpcur.value[i]); - copy_val_t(&dpcur.value[i], &dt->value[i]); + case CONF_SERVER: + rl->server = TRUE; + break; + + case CONF_NL: + case CONF_END: + return; + + default: + conf_parserror("SAME-HOST or a string expected"); + break; } } } -static void -get_tapetype(void) -{ - int save_overwrites; - char *prefix; +/* get_* functions */ - save_overwrites = allow_overwrites; - allow_overwrites = 1; +/* these functions use precompiler conditionals to skip useless size checks + * when casting from one type to another. SIZEOF_GINT64 is pretty simple to + * calculate; the others are calculated by configure. */ - init_tapetype_defaults(); +#define SIZEOF_GINT64 8 - get_conftoken(CONF_IDENT); - tpcur.name = stralloc(tokenval.v.s); - tpcur.seen = conf_line_num; +static time_t +get_time(void) +{ + time_t hhmm; - prefix = vstralloc( "TAPETYPE:", tpcur.name, ":", NULL); - read_block(program_options, tapetype_var, server_keytab, tpcur.value, - prefix, "tapetype parameter expected", 1, ©_tapetype); - amfree(prefix); - get_conftoken(CONF_NL); + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_INT: +#if SIZEOF_TIME_T < SIZEOF_INT + if ((gint64)tokenval.v.i >= (gint64)TIME_MAX) + conf_parserror(_("value too large")); +#endif + hhmm = (time_t)tokenval.v.i; + break; - save_tapetype(); + case CONF_SIZE: +#if SIZEOF_TIME_T < SIZEOF_SSIZE_T + if ((gint64)tokenval.v.size >= (gint64)TIME_MAX) + conf_parserror(_("value too large")); +#endif + hhmm = (time_t)tokenval.v.size; + break; - allow_overwrites = save_overwrites; -} + case CONF_INT64: +#if SIZEOF_TIME_T < SIZEOF_GINT64 + if ((gint64)tokenval.v.int64 >= (gint64)TIME_MAX) + conf_parserror(_("value too large")); +#endif + hhmm = (time_t)tokenval.v.int64; + break; -static void -init_tapetype_defaults(void) -{ - conf_init_string(&tpcur.value[TAPETYPE_COMMENT] , ""); - conf_init_string(&tpcur.value[TAPETYPE_LBL_TEMPL] , ""); - conf_init_size (&tpcur.value[TAPETYPE_BLOCKSIZE] , DISK_BLOCK_KB); - conf_init_size (&tpcur.value[TAPETYPE_READBLOCKSIZE], MAX_TAPE_BLOCK_KB); - conf_init_am64 (&tpcur.value[TAPETYPE_LENGTH] , (off_t)2000); - conf_init_am64 (&tpcur.value[TAPETYPE_FILEMARK] , (off_t)1); - conf_init_int (&tpcur.value[TAPETYPE_SPEED] , 200); - conf_init_bool (&tpcur.value[TAPETYPE_FILE_PAD] , 1); + case CONF_AMINFINITY: + hhmm = TIME_MAX; + break; + + default: + conf_parserror(_("a time is expected")); + hhmm = 0; + break; + } + return hhmm; } -static void -save_tapetype(void) +static int +get_int( + confunit_t unit) { - tapetype_t *tp, *tp1; + int val; + keytab_t *save_kt; - tp = lookup_tapetype(tpcur.name); + save_kt = keytable; + keytable = numb_keytable; - if(tp != (tapetype_t *)0) { - amfree(tpcur.name); - conf_parserror("tapetype %s already defined on line %d", tp->name, tp->seen); - return; - } + get_conftoken(CONF_ANY); + switch(tok) { + case CONF_INT: + val = tokenval.v.i; + break; - tp = alloc(sizeof(tapetype_t)); - *tp = tpcur; - /* add at end of list */ - if(!tapelist) - tapelist = tp; - else { - tp1 = tapelist; - while (tp1->next != NULL) { - tp1 = tp1->next; - } - tp1->next = tp; - } -} + case CONF_SIZE: +#if SIZEOF_INT < SIZEOF_SSIZE_T + if ((gint64)tokenval.v.size > (gint64)INT_MAX) + conf_parserror(_("value too large")); + if ((gint64)tokenval.v.size < (gint64)INT_MIN) + conf_parserror(_("value too small")); +#endif + val = (int)tokenval.v.size; + break; -static void -copy_tapetype(void) -{ - tapetype_t *tp; - int i; + case CONF_INT64: +#if SIZEOF_INT < SIZEOF_GINT64 + if (tokenval.v.int64 > (gint64)INT_MAX) + conf_parserror(_("value too large")); + if (tokenval.v.int64 < (gint64)INT_MIN) + conf_parserror(_("value too small")); +#endif + val = (int)tokenval.v.int64; + break; - tp = lookup_tapetype(tokenval.v.s); + case CONF_AMINFINITY: + val = INT_MAX; + break; - if(tp == NULL) { - conf_parserror("tape type parameter expected"); - return; + default: + conf_parserror(_("an integer is expected")); + val = 0; + break; } - for(i=0; i < TAPETYPE_TAPETYPE; i++) { - if(tp->value[i].seen) { - free_val_t(&tpcur.value[i]); - copy_val_t(&tpcur.value[i], &tp->value[i]); - } - } -} + /* get multiplier, if any */ + val = get_multiplier(val, unit); -t_conf_var interface_var [] = { - { CONF_COMMENT, CONFTYPE_STRING, read_string, INTER_COMMENT , NULL }, - { CONF_USE , CONFTYPE_INT , read_int , INTER_MAXUSAGE, validate_positive1 }, - { CONF_UNKNOWN, CONFTYPE_INT , NULL , INTER_INTER , NULL } -}; + keytable = save_kt; + return val; +} -static void -get_interface(void) +static ssize_t +get_size( + confunit_t unit) { - int save_overwrites; - char *prefix; + ssize_t val; + keytab_t *save_kt; - save_overwrites = allow_overwrites; - allow_overwrites = 1; + save_kt = keytable; + keytable = numb_keytable; - init_interface_defaults(); + get_conftoken(CONF_ANY); - get_conftoken(CONF_IDENT); - ifcur.name = stralloc(tokenval.v.s); - ifcur.seen = conf_line_num; + switch(tok) { + case CONF_SIZE: + val = tokenval.v.size; + break; - prefix = vstralloc( "INTERFACE:", ifcur.name, ":", NULL); - read_block(program_options, interface_var, server_keytab, ifcur.value, - prefix, "interface parameter expected", 1, ©_interface); - amfree(prefix); - get_conftoken(CONF_NL); + case CONF_INT: +#if SIZEOF_SIZE_T < SIZEOF_INT + if ((gint64)tokenval.v.i > (gint64)SSIZE_MAX) + conf_parserror(_("value too large")); + if ((gint64)tokenval.v.i < (gint64)SSIZE_MIN) + conf_parserror(_("value too small")); +#endif + val = (ssize_t)tokenval.v.i; + break; - save_interface(); + case CONF_INT64: +#if SIZEOF_SIZE_T < SIZEOF_GINT64 + if (tokenval.v.int64 > (gint64)SSIZE_MAX) + conf_parserror(_("value too large")); + if (tokenval.v.int64 < (gint64)SSIZE_MIN) + conf_parserror(_("value too small")); +#endif + val = (ssize_t)tokenval.v.int64; + break; - allow_overwrites = save_overwrites; + case CONF_AMINFINITY: + val = (ssize_t)SSIZE_MAX; + break; - return; -} + default: + conf_parserror(_("an integer is expected")); + val = 0; + break; + } -static void -init_interface_defaults(void) -{ - conf_init_string(&ifcur.value[INTER_COMMENT] , ""); - conf_init_int (&ifcur.value[INTER_MAXUSAGE], 300); + /* get multiplier, if any */ + val = get_multiplier(val, unit); - ifcur.curusage = 0; + keytable = save_kt; + return val; } -static void -save_interface(void) +static gint64 +get_int64( + confunit_t unit) { - interface_t *ip, *ip1; + gint64 val; + keytab_t *save_kt; - ip = lookup_interface(ifcur.name); + save_kt = keytable; + keytable = numb_keytable; - if(ip != (interface_t *)0) { - conf_parserror("interface %s already defined on line %d", ip->name, - ip->seen); - return; - } + get_conftoken(CONF_ANY); - ip = alloc(sizeof(interface_t)); - *ip = ifcur; - /* add at end of list */ - if(!interface_list) { - interface_list = ip; - } else { - ip1 = interface_list; - while (ip1->next != NULL) { - ip1 = ip1->next; - } - ip1->next = ip; + switch(tok) { + case CONF_INT: + val = (gint64)tokenval.v.i; + break; + + case CONF_SIZE: + val = (gint64)tokenval.v.size; + break; + + case CONF_INT64: + val = tokenval.v.int64; + break; + + case CONF_AMINFINITY: + val = G_MAXINT64; + break; + + default: + conf_parserror(_("an integer is expected")); + val = 0; + break; } + + /* get multiplier, if any */ + val = get_multiplier(val, unit); + + keytable = save_kt; + + return val; } -static void -copy_interface(void) +gint64 +get_multiplier( + gint64 val, + confunit_t unit) { -/* - int i; - t_xxx *np; - keytab_t *kt; - - val_t val; -*/ - interface_t *ip; - int i; - - ip = lookup_interface(tokenval.v.s); + /* get multiplier, if any */ + get_conftoken(CONF_ANY); - if(ip == NULL) { - conf_parserror("interface parameter expected"); - return; + if (tok == CONF_NL || tok == CONF_END) { /* no multiplier */ + val = val; + } else if (tok == CONF_MULT1 && unit == CONF_UNIT_K) { + val /= 1024; + } else if (tok == CONF_MULT1 || + (tok == CONF_MULT1K && unit == CONF_UNIT_K)) { + val *= 1; /* multiply by one */ + } else if (tok == CONF_MULT7) { + if (val > G_MAXINT64/7 || val < ((gint64)G_MININT64)/7) + conf_parserror(_("value too large")); + val *= 7; + } else if (tok == CONF_MULT1K || + (tok == CONF_MULT1M && unit == CONF_UNIT_K)) { + if (val > G_MAXINT64/1024 || val < ((gint64)G_MININT64)/1024) + conf_parserror(_("value too large")); + val *= 1024; + } else if (tok == CONF_MULT1M || + (tok == CONF_MULT1G && unit == CONF_UNIT_K)) { + if (val > G_MAXINT64/(1024*1024) || val < ((gint64)G_MININT64)/(1024*1024)) + conf_parserror(_("value too large")); + val *= 1024*1024; + } else if (tok == CONF_MULT1G || + (tok == CONF_MULT1T && unit == CONF_UNIT_K)) { + if (val > G_MAXINT64/(1024*1024*1024) || val < ((gint64)G_MININT64)/(1024*1024*1024)) + conf_parserror(_("value too large")); + val *= 1024*1024*1024; + } else if (tok == CONF_MULT1T) { + if (val > G_MAXINT64/(1024*1024*1024*1024LL) || val < ((gint64)G_MININT64)/(1024*1024*1024*1024LL)) + conf_parserror(_("value too large")); + val *= 1024*1024*1024*1024LL; + } else { + val *= 1; + unget_conftoken(); } - for(i=0; i < INTER_INTER; i++) { - if(ip->value[i].seen) { - free_val_t(&ifcur.value[i]); - copy_val_t(&ifcur.value[i], &ip->value[i]); - } - } + return val; } -static void -get_comprate( - t_conf_var *np, - val_t *val) +static int +get_bool(void) { - np = np; - get_conftoken(CONF_REAL); - val->v.rate[0] = tokenval.v.r; - val->v.rate[1] = tokenval.v.r; - val->seen = tokenval.seen; - if(tokenval.v.r < 0) { - conf_parserror("full compression rate must be >= 0"); - } + int val; + keytab_t *save_kt; + + save_kt = keytable; + keytable = bool_keytable; get_conftoken(CONF_ANY); + switch(tok) { - case CONF_NL: - return; + case CONF_INT: + if (tokenval.v.i != 0) + val = 1; + else + val = 0; + break; - case CONF_END: - return; + case CONF_SIZE: + if (tokenval.v.size != (size_t)0) + val = 1; + else + val = 0; + break; + + case CONF_INT64: + if (tokenval.v.int64 != (gint64)0) + val = 1; + else + val = 0; + break; + + case CONF_ATRUE: + val = 1; + break; - case CONF_COMMA: + case CONF_AFALSE: + val = 0; break; + case CONF_NL: + unget_conftoken(); + val = 2; /* no argument - most likely TRUE */ + break; default: unget_conftoken(); + val = 3; /* a bad argument - most likely TRUE */ + conf_parserror(_("YES, NO, TRUE, FALSE, ON, OFF, 0, 1 expected")); + break; } - get_conftoken(CONF_REAL); - val->v.rate[1] = tokenval.v.r; - if(tokenval.v.r < 0) { - conf_parserror("incremental compression rate must be >= 0"); - } + keytable = save_kt; + return val; } -static void -read_intrange( - t_conf_var *np, - val_t *val) +static int +get_no_yes_all(void) { - np = np; - get_conftoken(CONF_INT); - val->v.intrange[0] = tokenval.v.i; - val->v.intrange[1] = tokenval.v.i; - val->seen = tokenval.seen; + int val; + keytab_t *save_kt; + + save_kt = keytable; + keytable = no_yes_all_keytable; get_conftoken(CONF_ANY); + switch(tok) { - case CONF_NL: - return; + case CONF_INT: + val = tokenval.v.i; + break; - case CONF_END: - return; + case CONF_SIZE: + val = tokenval.v.size; + break; - case CONF_COMMA: + case CONF_INT64: + val = tokenval.v.int64; + break; + + case CONF_ALL: + val = 2; + break; + + case CONF_ATRUE: + val = 1; + break; + + case CONF_AFALSE: + val = 0; break; + case CONF_NL: + unget_conftoken(); + val = 3; /* no argument - most likely TRUE */ + break; default: unget_conftoken(); + val = 3; /* a bad argument - most likely TRUE */ + conf_parserror(_("%d: YES, NO, ALL, TRUE, FALSE, ON, OFF, 0, 1, 2 expected"), tok); + break; } - get_conftoken(CONF_INT); - val->v.intrange[1] = tokenval.v.i; + if (val > 2 || val < 0) + val = 1; + keytable = save_kt; + return val; } -static void -get_compress( - t_conf_var *np, - val_t *val) +void +ckseen( + seen_t *seen) { - int serv, clie, none, fast, best, custom; - int done; - comp_t comp; - - np = np; - ckseen(&val->seen); - - serv = clie = none = fast = best = custom = 0; - - done = 0; - do { - get_conftoken(CONF_ANY); - switch(tok) { - case CONF_NONE: none = 1; break; - case CONF_FAST: fast = 1; break; - case CONF_BEST: best = 1; break; - case CONF_CLIENT: clie = 1; break; - case CONF_SERVER: serv = 1; break; - case CONF_CUSTOM: custom=1; break; - case CONF_NL: done = 1; break; - case CONF_END: done = 1; break; - default: - done = 1; - serv = clie = 1; /* force an error */ - } - } while(!done); - - if(serv + clie == 0) clie = 1; /* default to client */ - if(none + fast + best + custom == 0) fast = 1; /* default to fast */ + if (seen->linenum && !allow_overwrites && current_line_num != -2) { + conf_parserror(_("duplicate parameter; previous definition %s:%d"), + seen->filename, seen->linenum); + } + seen->block = current_block; + seen->filename = current_filename; + seen->linenum = current_line_num; +} - comp = -1; +/* Validation functions */ - if(!serv && clie) { - if(none && !fast && !best && !custom) comp = COMP_NONE; - if(!none && fast && !best && !custom) comp = COMP_FAST; - if(!none && !fast && best && !custom) comp = COMP_BEST; - if(!none && !fast && !best && custom) comp = COMP_CUST; +static void +validate_nonnegative( + struct conf_var_s *np, + val_t *val) +{ + switch(val->type) { + case CONFTYPE_INT: + if(val_t__int(val) < 0) + conf_parserror(_("%s must be nonnegative"), get_token_name(np->token)); + break; + case CONFTYPE_INT64: + if(val_t__int64(val) < 0) + conf_parserror(_("%s must be nonnegative"), get_token_name(np->token)); + break; + case CONFTYPE_SIZE: + if(val_t__size(val) < 0) + conf_parserror(_("%s must be positive"), get_token_name(np->token)); + break; + default: + conf_parserror(_("validate_nonnegative invalid type %d\n"), val->type); } +} - if(serv && !clie) { - if(none && !fast && !best && !custom) comp = COMP_NONE; - if(!none && fast && !best && !custom) comp = COMP_SERVER_FAST; - if(!none && !fast && best && !custom) comp = COMP_SERVER_BEST; - if(!none && !fast && !best && custom) comp = COMP_SERVER_CUST; +static void +validate_non_zero( + struct conf_var_s *np, + val_t *val) +{ + switch(val->type) { + case CONFTYPE_INT: + if(val_t__int(val) == 0) + conf_parserror(_("%s must not be 0"), get_token_name(np->token)); + break; + case CONFTYPE_INT64: + if(val_t__int64(val) == 0) + conf_parserror(_("%s must not be 0"), get_token_name(np->token)); + break; + case CONFTYPE_TIME: + if(val_t__time(val) == 0) + conf_parserror(_("%s must not be 0"), get_token_name(np->token)); + break; + case CONFTYPE_SIZE: + if(val_t__size(val) == 0) + conf_parserror(_("%s must not be 0"), get_token_name(np->token)); + break; + default: + conf_parserror(_("validate_non_zero invalid type %d\n"), val->type); } +} - if((int)comp == -1) { - conf_parserror("NONE, CLIENT FAST, CLIENT BEST, CLIENT CUSTOM, SERVER FAST, SERVER BEST or SERVER CUSTOM expected"); - comp = COMP_NONE; +static void +validate_positive( + struct conf_var_s *np, + val_t *val) +{ + switch(val->type) { + case CONFTYPE_INT: + if(val_t__int(val) < 1) + conf_parserror(_("%s must be positive"), get_token_name(np->token)); + break; + case CONFTYPE_INT64: + if(val_t__int64(val) < 1) + conf_parserror(_("%s must be positive"), get_token_name(np->token)); + break; + case CONFTYPE_TIME: + if(val_t__time(val) < 1) + conf_parserror(_("%s must be positive"), get_token_name(np->token)); + break; + case CONFTYPE_SIZE: + if(val_t__size(val) < 1) + conf_parserror(_("%s must be positive"), get_token_name(np->token)); + break; + default: + conf_parserror(_("validate_positive invalid type %d\n"), val->type); } - - val->v.i = (int)comp; } static void -get_encrypt( - t_conf_var *np, - val_t *val) +validate_runspercycle( + struct conf_var_s *np G_GNUC_UNUSED, + val_t *val) { - encrypt_t encrypt; - - np = np; - ckseen(&val->seen); - - get_conftoken(CONF_ANY); - switch(tok) { - case CONF_NONE: - encrypt = ENCRYPT_NONE; - break; - - case CONF_CLIENT: - encrypt = ENCRYPT_CUST; - break; - - case CONF_SERVER: - encrypt = ENCRYPT_SERV_CUST; - break; - - default: - conf_parserror("NONE, CLIENT or SERVER expected"); - encrypt = ENCRYPT_NONE; - break; - } - - val->v.i = (int)encrypt; + if(val_t__int(val) < -1) + conf_parserror(_("runspercycle must be >= -1")); } static void -get_holding( - t_conf_var *np, - val_t *val) +validate_bumppercent( + struct conf_var_s *np G_GNUC_UNUSED, + val_t *val) { - dump_holdingdisk_t holding; - - np = np; - ckseen(&val->seen); - - get_conftoken(CONF_ANY); - switch(tok) { - case CONF_NEVER: - holding = HOLD_NEVER; - break; + if(val_t__int(val) < 0 || val_t__int(val) > 100) + conf_parserror(_("bumppercent must be between 0 and 100")); +} - case CONF_AUTO: - holding = HOLD_AUTO; - break; +static void +validate_inparallel( + struct conf_var_s *np G_GNUC_UNUSED, + val_t *val) +{ + if(val_t__int(val) < 1 || val_t__int(val) >MAX_DUMPERS) + conf_parserror(_("inparallel must be between 1 and MAX_DUMPERS (%d)"), + MAX_DUMPERS); +} - case CONF_REQUIRED: - holding = HOLD_REQUIRED; - break; +static void +validate_bumpmult( + struct conf_var_s *np G_GNUC_UNUSED, + val_t *val) +{ + if(val_t__real(val) < 0.999) { + conf_parserror(_("bumpmult must one or more")); + } +} - default: /* can be a BOOLEAN */ - unget_conftoken(); - holding = (dump_holdingdisk_t)get_bool(); - if (holding == 0) - holding = HOLD_NEVER; - else if (holding == 1 || holding == 2) - holding = HOLD_AUTO; - else - conf_parserror("NEVER, AUTO or REQUIRED expected"); - break; - } +static void +validate_displayunit( + struct conf_var_s *np G_GNUC_UNUSED, + val_t *val G_GNUC_UNUSED) +{ + char *s = val_t__str(val); + if (strlen(s) == 1) { + switch (s[0]) { + case 'K': + case 'M': + case 'G': + case 'T': + return; /* all good */ + + /* lower-case values should get folded to upper case */ + case 'k': + case 'm': + case 'g': + case 't': + s[0] = toupper(s[0]); + return; + + default: /* bad */ + break; + } + } + conf_parserror(_("displayunit must be k,m,g or t.")); +} - val->v.i = (int)holding; +static void +validate_reserve( + struct conf_var_s *np G_GNUC_UNUSED, + val_t *val) +{ + if(val_t__int(val) < 0 || val_t__int(val) > 100) + conf_parserror(_("reserve must be between 0 and 100")); } static void -get_taperalgo( - t_conf_var *np, - val_t *val) +validate_use( + struct conf_var_s *np G_GNUC_UNUSED, + val_t *val) { - np = np; - ckseen(&val->seen); + val_t__int64(val) = am_floor(val_t__int64(val), DISK_BLOCK_KB); +} - get_conftoken(CONF_ANY); - switch(tok) { - case CONF_FIRST: val->v.i = ALGO_FIRST; break; - case CONF_FIRSTFIT: val->v.i = ALGO_FIRSTFIT; break; - case CONF_LARGEST: val->v.i = ALGO_LARGEST; break; - case CONF_LARGESTFIT: val->v.i = ALGO_LARGESTFIT; break; - case CONF_SMALLEST: val->v.i = ALGO_SMALLEST; break; - case CONF_LAST: val->v.i = ALGO_LAST; break; - default: - conf_parserror("FIRST, FIRSTFIT, LARGEST, LARGESTFIT, SMALLEST or LAST expected"); +static void +validate_chunksize( + struct conf_var_s *np G_GNUC_UNUSED, + val_t *val) +{ + /* NOTE: this function modifies the target value (rounding) */ + if(val_t__int64(val) == 0) { + val_t__int64(val) = ((G_MAXINT64 / 1024) - (2 * DISK_BLOCK_KB)); + } + else if(val_t__int64(val) < 0) { + conf_parserror(_("Negative chunksize (%lld) is no longer supported"), (long long)val_t__int64(val)); + } + val_t__int64(val) = am_floor(val_t__int64(val), (gint64)DISK_BLOCK_KB); + if (val_t__int64(val) < 2*DISK_BLOCK_KB) { + conf_parserror("chunksize must be at least %dkb", 2*DISK_BLOCK_KB); } } static void -get_priority( - t_conf_var *np, - val_t *val) +validate_blocksize( + struct conf_var_s *np G_GNUC_UNUSED, + val_t *val) { - int pri; + if(val_t__size(val) < DISK_BLOCK_KB) { + conf_parserror(_("Tape blocksize must be at least %d KBytes"), + DISK_BLOCK_KB); + } +} - np = np; - ckseen(&val->seen); +static void +validate_debug( + struct conf_var_s *np G_GNUC_UNUSED, + val_t *val) +{ + if(val_t__int(val) < 0 || val_t__int(val) > 9) { + conf_parserror(_("Debug must be between 0 and 9")); + } +} - get_conftoken(CONF_ANY); - switch(tok) { - case CONF_LOW: pri = 0; break; - case CONF_MEDIUM: pri = 1; break; - case CONF_HIGH: pri = 2; break; - case CONF_INT: pri = tokenval.v.i; break; - default: - conf_parserror("LOW, MEDIUM, HIGH or integer expected"); - pri = 0; +static void +validate_port_range( + val_t *val, + int smallest, + int largest) +{ + int i; + /* check both values are in range */ + for (i = 0; i < 2; i++) { + if(val_t__intrange(val)[0] < smallest || val_t__intrange(val)[0] > largest) { + conf_parserror(_("portrange must be in the range %d to %d, inclusive"), smallest, largest); + } + } + + /* and check they're in the right order and not equal */ + if (val_t__intrange(val)[0] > val_t__intrange(val)[1]) { + conf_parserror(_("portranges must be in order from low to high")); } - val->v.i = pri; } static void -get_strategy( - t_conf_var *np, - val_t *val) +validate_reserved_port_range( + struct conf_var_s *np G_GNUC_UNUSED, + val_t *val) { - int strat; - - np = np; - ckseen(&val->seen); - - get_conftoken(CONF_ANY); - switch(tok) { - case CONF_SKIP: - strat = DS_SKIP; - break; - case CONF_STANDARD: - strat = DS_STANDARD; - break; - case CONF_NOFULL: - strat = DS_NOFULL; - break; - case CONF_NOINC: - strat = DS_NOINC; - break; - case CONF_HANOI: - strat = DS_HANOI; - break; - case CONF_INCRONLY: - strat = DS_INCRONLY; - break; - default: - conf_parserror("STANDARD or NOFULL expected"); - strat = DS_STANDARD; - } - val->v.i = strat; + validate_port_range(val, 1, IPPORT_RESERVED-1); } static void -get_estimate( - t_conf_var *np, - val_t *val) +validate_unreserved_port_range( + struct conf_var_s *np G_GNUC_UNUSED, + val_t *val) { - int estime; + validate_port_range(val, IPPORT_RESERVED, 65535); +} - np = np; - ckseen(&val->seen); +/* + * Validate tmpdir, the directory must exist and be writable by the user. + */ - get_conftoken(CONF_ANY); - switch(tok) { - case CONF_CLIENT: - estime = ES_CLIENT; - break; - case CONF_SERVER: - estime = ES_SERVER; - break; - case CONF_CALCSIZE: - estime = ES_CALCSIZE; - break; - default: - conf_parserror("CLIENT, SERVER or CALCSIZE expected"); - estime = ES_CLIENT; +static void validate_tmpdir(conf_var_t *var G_GNUC_UNUSED, val_t *value) +{ + struct stat stat_buf; + gchar *tmpdir = val_t_to_str(value); + + if (stat(tmpdir, &stat_buf)) { + conf_parserror(_("invalid TMPDIR: directory '%s': %s."), + tmpdir, strerror(errno)); + } else if (!S_ISDIR(stat_buf.st_mode)) { + conf_parserror(_("invalid TMPDIR: '%s' is not a directory."), + tmpdir); + } else { + gchar *dir = g_strconcat(tmpdir, "/.", NULL); + if (access(dir, R_OK|W_OK) == -1) { + conf_parserror(_("invalid TMPDIR: '%s': can not read/write: %s."), + tmpdir, strerror(errno)); + } + g_free(dir); } - val->v.i = estime; } -static void -get_exclude( - t_conf_var *np, - val_t *val) +/* + * Initialization Implementation + */ + +cfgerr_level_t +config_init( + config_init_flags flags, + char *arg_config_name) { - int file, got_one = 0; - sl_t *exclude; - int optional = 0; + if (!(flags & CONFIG_INIT_OVERLAY)) { + /* Clear out anything that's already in there */ + config_uninit(); - np = np; - get_conftoken(CONF_ANY); - if(tok == CONF_LIST) { - file = 0; - get_conftoken(CONF_ANY); - exclude = val->v.exinclude.sl_list; + /* and set everything to default values */ + init_defaults(); + + allow_overwrites = FALSE; + } else { + if (!config_initialized) { + error(_("Attempt to overlay configuration with no existing configuration")); + /* NOTREACHED */ + } + + allow_overwrites = TRUE; } - else { - file = 1; - if(tok == CONF_EFILE) get_conftoken(CONF_ANY); - exclude = val->v.exinclude.sl_file; + + /* store away our client-ness for later reference */ + config_client = flags & CONFIG_INIT_CLIENT; + + /* if we're using an explicit name, but the name is '.', then we're using the + * current directory */ + if ((flags & CONFIG_INIT_EXPLICIT_NAME) && arg_config_name) { + if (0 == strcmp(arg_config_name, ".")) + flags = (flags & (~CONFIG_INIT_EXPLICIT_NAME)) | CONFIG_INIT_USE_CWD; } - ckseen(&val->seen); - if(tok == CONF_OPTIONAL) { - get_conftoken(CONF_ANY); - optional = 1; + if ((flags & CONFIG_INIT_EXPLICIT_NAME) && arg_config_name) { + config_name = newstralloc(config_name, arg_config_name); + config_dir = newvstralloc(config_dir, CONFIG_DIR, "/", arg_config_name, NULL); + } else if (flags & CONFIG_INIT_USE_CWD) { + char * cwd; + + cwd = get_original_cwd(); + if (!cwd) { + /* (this isn't a config error, so it's always fatal) */ + error(_("Cannot determine current working directory")); + /* NOTREACHED */ + } + + config_dir = stralloc2(cwd, "/"); + if ((config_name = strrchr(cwd, '/')) != NULL) { + config_name = stralloc(config_name + 1); + } + + } else if (flags & CONFIG_INIT_CLIENT) { + amfree(config_name); + config_dir = newstralloc(config_dir, CONFIG_DIR); + } else { + /* ok, then, we won't read anything (for e.g., amrestore) */ + amfree(config_name); + amfree(config_dir); } - if(tok == CONF_APPEND) { - get_conftoken(CONF_ANY); + /* setup for apply_config_overrides */ + if (flags & CONFIG_INIT_CLIENT) { + keytable = client_keytab; + parsetable = client_var; + } else { + keytable = server_keytab; + parsetable = server_var; } - else { - free_sl(exclude); - exclude = NULL; + + if (config_overrides) { + int i; + for (i = 0; i < config_overrides->n_used; i++) { + config_overrides->ovr[i].applied = FALSE; + } } - while(tok == CONF_STRING) { - exclude = append_sl(exclude, tokenval.v.s); - got_one = 1; - get_conftoken(CONF_ANY); + /* apply config overrides to default setting */ + apply_config_overrides(config_overrides, NULL); + + /* If we have a config_dir, we can try reading something */ + if (config_dir) { + if (flags & CONFIG_INIT_CLIENT) { + config_filename = newvstralloc(config_filename, config_dir, "/amanda-client.conf", NULL); + } else { + config_filename = newvstralloc(config_filename, config_dir, "/amanda.conf", NULL); + } + + read_conffile(config_filename, + flags & CONFIG_INIT_CLIENT, + flags & CONFIG_INIT_CLIENT); + } else { + amfree(config_filename); } - unget_conftoken(); - if(got_one == 0) { free_sl(exclude); exclude = NULL; } + /* apply config overrides to default setting */ + apply_config_overrides(config_overrides, NULL); - if (file == 0) - val->v.exinclude.sl_list = exclude; - else - val->v.exinclude.sl_file = exclude; - val->v.exinclude.optional = optional; + if (config_overrides) { + int i; + for (i = 0; i < config_overrides->n_used; i++) { + if (config_overrides->ovr[i].applied == FALSE) { + conf_parserror(_("unknown parameter '%s'"), + config_overrides->ovr[i].key); + } + } + } + + update_derived_values(flags & CONFIG_INIT_CLIENT); + + return cfgerr_level; } -/* -static void get_include(np, val) - t_conf_var *np; - val_t *val; +void +config_uninit(void) { - int list, got_one = 0; - sl_t *include; - int optional = 0; - int append = 0; + GSList *hp; + holdingdisk_t *hd; + dumptype_t *dp, *dpnext; + tapetype_t *tp, *tpnext; + interface_t *ip, *ipnext; + application_t *ap, *apnext; + pp_script_t *pp, *ppnext; + device_config_t *dc, *dcnext; + changer_config_t *cc, *ccnext; + interactivity_t *iv, *ivnext; + taperscan_t *ts, *tsnext; + int i; - get_conftoken(CONF_ANY); - if(tok == CONF_LIST) { - list = 1; - include = dpcur.value[DUMPTYPE_INCLUDE_LIST].v.sl; - ckseen(&dpcur.value[DUMPTYPE_INCLUDE_LIST].seen); - get_conftoken(CONF_ANY); + if (!config_initialized) return; + + for(hp=holdinglist; hp != NULL; hp = hp->next) { + hd = hp->data; + amfree(hd->name); + for(i=0; ivalue[i]); + } } - else { - list = 0; - include = dpcur.value[DUMPTYPE_INCLUDE_FILE].v.sl; - ckseen(&dpcur.value[DUMPTYPE_INCLUDE_FILE].seen); - if(tok == CONF_EFILE) get_conftoken(CONF_ANY); + slist_free_full(holdinglist, g_free); + holdinglist = NULL; + + for(dp=dumplist; dp != NULL; dp = dpnext) { + amfree(dp->name); + for(i=0; ivalue[i]); + } + dpnext = dp->next; + amfree(dp); } + dumplist = NULL; - if(tok == CONF_OPTIONAL) { - get_conftoken(CONF_ANY); - optional = 1; + for(tp=tapelist; tp != NULL; tp = tpnext) { + amfree(tp->name); + for(i=0; ivalue[i]); + } + tpnext = tp->next; + amfree(tp); } + tapelist = NULL; - if(tok == CONF_APPEND) { - get_conftoken(CONF_ANY); - append = 1; + for(ip=interface_list; ip != NULL; ip = ipnext) { + amfree(ip->name); + for(i=0; ivalue[i]); + } + ipnext = ip->next; + amfree(ip); } - else { - free_sl(include); - include = NULL; - append = 0; + interface_list = NULL; + + for(ap=application_list; ap != NULL; ap = apnext) { + amfree(ap->name); + for(i=0; ivalue[i]); + } + apnext = ap->next; + amfree(ap); } + application_list = NULL; - while(tok == CONF_STRING) { - include = append_sl(include, tokenval.v.s); - got_one = 1; - get_conftoken(CONF_ANY); + for(pp=pp_script_list; pp != NULL; pp = ppnext) { + amfree(pp->name); + for(i=0; ivalue[i]); + } + ppnext = pp->next; + amfree(pp); } - unget_conftoken(); + pp_script_list = NULL; - if(got_one == 0) { free_sl(include); include = NULL; } + for(dc=device_config_list; dc != NULL; dc = dcnext) { + amfree(dc->name); + for(i=0; ivalue[i]); + } + dcnext = dc->next; + amfree(dc); + } + device_config_list = NULL; - if(list == 0) - dpcur.value[DUMPTYPE_INCLUDE_FILE].v.sl = include; - else { - dpcur.value[DUMPTYPE_INCLUDE_LIST].v.sl = include; - if(!append || optional) - dpcur.value[DUMPTYPE_INCLUDE_OPTIONAL].v.i = optional; + for(cc=changer_config_list; cc != NULL; cc = ccnext) { + amfree(cc->name); + for(i=0; ivalue[i]); + } + ccnext = cc->next; + amfree(cc); } -} -*/ + changer_config_list = NULL; -/* ------------------------ */ + for(iv=interactivity_list; iv != NULL; iv = ivnext) { + amfree(iv->name); + for(i=0; ivalue[i]); + } + ivnext = iv->next; + amfree(iv); + } + interactivity_list = NULL; -int -ColumnDataCount(void ) -{ - return (int)(SIZEOF(ColumnData) / SIZEOF(ColumnData[0])); -} + for(ts=taperscan_list; ts != NULL; ts = tsnext) { + amfree(ts->name); + for(i=0; ivalue[i]); + } + tsnext = ts->next; + amfree(ts); + } + taperscan_list = NULL; -/* conversion from string to table index - */ -int -StringToColumn( - char *s) -{ - int cn; + for(i=0; i ColumnData[cn].Precision) - ColumnData[cn].Precision= Width; - } - else if (Width < ColumnData[cn].Precision) - ColumnData[cn].Precision = Width; - s= strchr(eon+1, ','); - if (s != NULL) - s++; - } - return 0; -} + conf_init_send_amreport (&conf_data[CNF_SEND_AMREPORT_ON], SEND_AMREPORT_ALL); + conf_init_autolabel(&conf_data[CNF_AUTOLABEL]); + conf_init_str(&conf_data[CNF_META_AUTOLABEL], NULL); + conf_init_host_limit(&conf_data[CNF_RECOVERY_LIMIT]); + conf_init_str(&conf_data[CNF_INTERACTIVITY], NULL); + conf_init_str(&conf_data[CNF_TAPERSCAN], NULL); + + /* reset internal variables */ + config_clear_errors(); + cfgerr_level = CFGERR_OK; + allow_overwrites = 0; + token_pushed = 0; + + /* create some predefined dumptypes for backwards compatability */ + init_dumptype_defaults(); + dpcur.name = stralloc("NO-COMPRESS"); + dpcur.seen.linenum = -1; + free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]); + val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_NONE; + val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]).linenum = -1; + save_dumptype(); + init_dumptype_defaults(); + dpcur.name = stralloc("COMPRESS-FAST"); + dpcur.seen.linenum = -1; + free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]); + val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_FAST; + val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]).linenum = -1; + save_dumptype(); -long int -getconf_unit_divisor(void) -{ - return unit_divisor; -} + init_dumptype_defaults(); + dpcur.name = stralloc("COMPRESS-BEST"); + dpcur.seen.linenum = -1; + free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]); + val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_BEST; + val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]).linenum = -1; + save_dumptype(); + + init_dumptype_defaults(); + dpcur.name = stralloc("COMPRESS-CUST"); + dpcur.seen.linenum = -1; + free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]); + val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_CUST; + val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]).linenum = -1; + save_dumptype(); -/* ------------------------ */ + init_dumptype_defaults(); + dpcur.name = stralloc("SRVCOMPRESS"); + dpcur.seen.linenum = -1; + free_val_t(&dpcur.value[DUMPTYPE_COMPRESS]); + val_t__compress(&dpcur.value[DUMPTYPE_COMPRESS]) = COMP_SERVER_FAST; + val_t__seen(&dpcur.value[DUMPTYPE_COMPRESS]).linenum = -1; + save_dumptype(); + init_dumptype_defaults(); + dpcur.name = stralloc("BSD-AUTH"); + dpcur.seen.linenum = -1; + free_val_t(&dpcur.value[DUMPTYPE_AUTH]); + val_t__str(&dpcur.value[DUMPTYPE_AUTH]) = stralloc("BSD"); + val_t__seen(&dpcur.value[DUMPTYPE_AUTH]).linenum = -1; + save_dumptype(); -void -dump_configuration( - char *filename) -{ - tapetype_t *tp; - dumptype_t *dp; - interface_t *ip; - holdingdisk_t *hp; - int i; - t_conf_var *np; - keytab_t *kt; - char *prefix; - char kt_prefix[100]; + init_dumptype_defaults(); + dpcur.name = stralloc("BSDTCP-AUTH"); + dpcur.seen.linenum = -1; + free_val_t(&dpcur.value[DUMPTYPE_AUTH]); + val_t__str(&dpcur.value[DUMPTYPE_AUTH]) = stralloc("BSDTCP"); + val_t__seen(&dpcur.value[DUMPTYPE_AUTH]).linenum = -1; + save_dumptype(); + + init_dumptype_defaults(); + dpcur.name = stralloc("NO-RECORD"); + dpcur.seen.linenum = -1; + free_val_t(&dpcur.value[DUMPTYPE_RECORD]); + val_t__int(&dpcur.value[DUMPTYPE_RECORD]) = 0; + val_t__seen(&dpcur.value[DUMPTYPE_RECORD]).linenum = -1; + save_dumptype(); + + init_dumptype_defaults(); + dpcur.name = stralloc("NO-HOLD"); + dpcur.seen.linenum = -1; + free_val_t(&dpcur.value[DUMPTYPE_HOLDINGDISK]); + val_t__holding(&dpcur.value[DUMPTYPE_HOLDINGDISK]) = HOLD_NEVER; + val_t__seen(&dpcur.value[DUMPTYPE_HOLDINGDISK]).linenum = -1; + save_dumptype(); + + init_dumptype_defaults(); + dpcur.name = stralloc("NO-FULL"); + dpcur.seen.linenum = -1; + free_val_t(&dpcur.value[DUMPTYPE_STRATEGY]); + val_t__strategy(&dpcur.value[DUMPTYPE_STRATEGY]) = DS_NOFULL; + val_t__seen(&dpcur.value[DUMPTYPE_STRATEGY]).linenum = -1; + save_dumptype(); - printf("AMANDA CONFIGURATION FROM FILE \"%s\":\n\n", filename); + /* And we're initialized! */ + config_initialized = 1; +} - for(np=server_var; np->token != CONF_UNKNOWN; np++) { - for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) - if (np->token == kt->token) break; +char ** +get_config_options( + int first) +{ + char **config_options; + char **config_option; + int n_config_overrides = 0; + int i; - if(kt->token == CONF_UNKNOWN) - error("server bad token"); + if (config_overrides) + n_config_overrides = config_overrides->n_used; + + config_options = alloc((first+n_config_overrides+1)*SIZEOF(char *)); + config_option = config_options + first; - if (kt->token != CONF_IDENT) - snprintf(kt_prefix, 100, "%-21s ", kt->keyword); - printf("%s\n", - conf_print(&conf_data[np->parm], 1, kt_prefix)); + for (i = 0; i < n_config_overrides; i++) { + char *key = config_overrides->ovr[i].key; + char *value = config_overrides->ovr[i].value; + *config_option = vstralloc("-o", key, "=", value, NULL); + config_option++; } - for(hp = holdingdisks; hp != NULL; hp = hp->next) { - printf("\nHOLDINGDISK %s {\n", hp->name); - for(i=0; i < HOLDING_HOLDING; i++) { - for(np=holding_var; np->token != CONF_UNKNOWN; np++) { - if(np->parm == i) - break; - } - if(np->token == CONF_UNKNOWN) - error("holding bad value"); + *config_option = NULL; /* add terminating sentinel */ - for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) { - if(kt->token == np->token) - break; - } - if(kt->token == CONF_UNKNOWN) - error("holding bad token"); + return config_options; +} - snprintf(kt_prefix, 100, " %-9s ", kt->keyword); - printf("%s\n", conf_print(&hp->value[i], 1, kt_prefix)); +static void +update_derived_values( + gboolean is_client) +{ + interface_t *ip; + identlist_t il; + holdingdisk_t *hd; + + if (!is_client) { + /* Add a 'default' interface if one doesn't already exist */ + if (!(ip = lookup_interface("default"))) { + init_interface_defaults(); + ifcur.name = stralloc("default"); + ifcur.seen = val_t__seen(getconf(CNF_NETUSAGE)); + save_interface(); + + ip = lookup_interface("default"); } - printf("}\n"); - } - for(tp = tapelist; tp != NULL; tp = tp->next) { - printf("\nDEFINE TAPETYPE %s {\n", tp->name); - for(i=0; i < TAPETYPE_TAPETYPE; i++) { - for(np=tapetype_var; np->token != CONF_UNKNOWN; np++) - if(np->parm == i) break; - if(np->token == CONF_UNKNOWN) - error("tapetype bad value"); + /* .. and set its maxusage from 'netusage' */ + if (!interface_seen(ip, INTER_MAXUSAGE)) { + val_t *v; - for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) - if(kt->token == np->token) break; - if(kt->token == CONF_UNKNOWN) - error("tapetype bad token"); + v = interface_getconf(ip, INTER_COMMENT); + free_val_t(v); + val_t__str(v) = stralloc(_("implicit from NETUSAGE")); + val_t__seen(v) = val_t__seen(getconf(CNF_NETUSAGE)); - snprintf(kt_prefix, 100, " %-9s ", kt->keyword); - printf("%s\n", conf_print(&tp->value[i], 1, kt_prefix)); + v = interface_getconf(ip, INTER_MAXUSAGE); + free_val_t(v); + val_t__int(v) = getconf_int(CNF_NETUSAGE); + val_t__seen(v) = val_t__seen(getconf(CNF_NETUSAGE)); } - printf("}\n"); - } - for(dp = dumplist; dp != NULL; dp = dp->next) { - if (strncmp(dp->name, "custom(", 7) != 0) { - if(dp->seen == -1) - prefix = "#"; - else - prefix = ""; - printf("\n%sDEFINE DUMPTYPE %s {\n", prefix, dp->name); - for(i=0; i < DUMPTYPE_DUMPTYPE; i++) { - for(np=dumptype_var; np->token != CONF_UNKNOWN; np++) - if(np->parm == i) break; - if(np->token == CONF_UNKNOWN) - error("dumptype bad value"); + /* Check the tapetype is defined */ + if (lookup_tapetype(getconf_str(CNF_TAPETYPE)) == NULL) { + /* Create a default tapetype so that other code has + * something to refer to, but don't pretend it's real */ + if (!getconf_seen(CNF_TAPETYPE) && + strcmp(getconf_str(CNF_TAPETYPE), "DEFAULT_TAPE") == 0 && + !lookup_tapetype("DEFAULT_TAPE")) { + init_tapetype_defaults(); + tpcur.name = stralloc("DEFAULT_TAPE"); + tpcur.seen = val_t__seen(getconf(CNF_TAPETYPE)); + save_tapetype(); + } else { + conf_parserror(_("tapetype %s is not defined"), + getconf_str(CNF_TAPETYPE)); + } + } - for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) - if(kt->token == np->token) break; - if(kt->token == CONF_UNKNOWN) - error("dumptype bad token"); + /* Check the holdingdisk are defined */ + for (il = getconf_identlist(CNF_HOLDINGDISK); + il != NULL; il = il->next) { + hd = lookup_holdingdisk(il->data); + if (!hd) { + conf_parserror(_("holdingdisk %s is not defined"), + (char *)il->data); + } + } - snprintf(kt_prefix, 100, "%s %-19s ", prefix,kt->keyword); - printf("%s\n", conf_print(&dp->value[i], 1, kt_prefix)); + if ((getconf_seen(CNF_LABEL_NEW_TAPES) > 0 && + getconf_seen(CNF_AUTOLABEL) > 0) || + (getconf_seen(CNF_LABEL_NEW_TAPES) < 0 && + getconf_seen(CNF_AUTOLABEL) < 0)) { + conf_parserror(_("Can't specify both label-new-tapes and autolabel")); + } + if ((getconf_seen(CNF_LABEL_NEW_TAPES) != 0 && + getconf_seen(CNF_AUTOLABEL) == 0) || + (getconf_seen(CNF_LABEL_NEW_TAPES) < 0 && + getconf_seen(CNF_AUTOLABEL) >= 0)) { + autolabel_t *autolabel = &(conf_data[CNF_AUTOLABEL].v.autolabel); + autolabel->template = g_strdup(getconf_str(CNF_LABEL_NEW_TAPES)); + if (!autolabel->template || autolabel->template == '\0') { + autolabel->template = NULL; + autolabel->autolabel = 0; + } else { + autolabel->autolabel = AL_VOLUME_ERROR | AL_EMPTY; } - printf("%s}\n", prefix); + } + + if (!getconf_seen(CNF_REPORT_USE_MEDIA) && + getconf_seen(CNF_MAX_DLE_BY_VOLUME)) { + conf_init_bool(&conf_data[CNF_REPORT_USE_MEDIA], FALSE); + } + if (!getconf_seen(CNF_REPORT_NEXT_MEDIA) && + getconf_seen(CNF_MAX_DLE_BY_VOLUME)) { + conf_init_bool(&conf_data[CNF_REPORT_NEXT_MEDIA], FALSE); } } - for(ip = interface_list; ip != NULL; ip = ip->next) { - if(strcmp(ip->name,"default") == 0) - prefix = "#"; - else - prefix = ""; - printf("\n%sDEFINE INTERFACE %s {\n", prefix, ip->name); - for(i=0; i < INTER_INTER; i++) { - for(np=interface_var; np->token != CONF_UNKNOWN; np++) - if(np->parm == i) break; - if(np->token == CONF_UNKNOWN) - error("interface bad value"); + /* fill in the debug_* values */ + debug_amandad = getconf_int(CNF_DEBUG_AMANDAD); + debug_recovery = getconf_int(CNF_DEBUG_RECOVERY); + debug_amidxtaped = getconf_int(CNF_DEBUG_AMIDXTAPED); + debug_amindexd = getconf_int(CNF_DEBUG_AMINDEXD); + debug_amrecover = getconf_int(CNF_DEBUG_AMRECOVER); + debug_auth = getconf_int(CNF_DEBUG_AUTH); + debug_event = getconf_int(CNF_DEBUG_EVENT); + debug_holding = getconf_int(CNF_DEBUG_HOLDING); + debug_protocol = getconf_int(CNF_DEBUG_PROTOCOL); + debug_planner = getconf_int(CNF_DEBUG_PLANNER); + debug_driver = getconf_int(CNF_DEBUG_DRIVER); + debug_dumper = getconf_int(CNF_DEBUG_DUMPER); + debug_chunker = getconf_int(CNF_DEBUG_CHUNKER); + debug_taper = getconf_int(CNF_DEBUG_TAPER); + debug_selfcheck = getconf_int(CNF_DEBUG_SELFCHECK); + debug_sendsize = getconf_int(CNF_DEBUG_SENDSIZE); + debug_sendbackup = getconf_int(CNF_DEBUG_SENDBACKUP); - for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) - if(kt->token == np->token) break; - if(kt->token == CONF_UNKNOWN) - error("interface bad token"); + /* And finally, display unit */ + switch (getconf_str(CNF_DISPLAYUNIT)[0]) { + case 'k': + case 'K': + unit_divisor = 1; + break; - snprintf(kt_prefix, 100, "%s %-19s ", prefix, kt->keyword); - printf("%s\n", conf_print(&ip->value[i], 1, kt_prefix)); - } - printf("%s}\n",prefix); - } + case 'm': + case 'M': + unit_divisor = 1024; + break; + + case 'g': + case 'G': + unit_divisor = 1024*1024; + break; + case 't': + case 'T': + unit_divisor = 1024*1024*1024; + break; + + default: + error(_("Invalid displayunit missed by validate_displayunit")); + /* NOTREACHED */ + } } -char * -generic_get_security_conf( - char *string, - void *arg) +static void +conf_init_int( + val_t *val, + confunit_t unit, + int i) { - arg = arg; - if(!string || !*string) - return(NULL); + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_INT; + val->unit = unit; + val_t__int(val) = i; +} - if(strcmp(string, "krb5principal")==0) { - return(getconf_str(CNF_KRB5PRINCIPAL)); - } else if(strcmp(string, "krb5keytab")==0) { - return(getconf_str(CNF_KRB5KEYTAB)); - } - return(NULL); +static void +conf_init_int64( + val_t *val, + confunit_t unit, + gint64 l) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_INT64; + val->unit = unit; + val_t__int64(val) = l; } -char * -get_token_name( - tok_t token) +static void +conf_init_real( + val_t *val, + float r) { - keytab_t *kt; + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_REAL; + val->unit = CONF_UNIT_NONE; + val_t__real(val) = r; +} - if (my_keytab == NULL) { - error("my_keytab == NULL"); - /*NOTREACHED*/ - } +static void +conf_init_str( + val_t *val, + char *s) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_STR; + val->unit = CONF_UNIT_NONE; + if(s) + val->v.s = stralloc(s); + else + val->v.s = NULL; +} - for(kt = my_keytab; kt->token != CONF_UNKNOWN; kt++) - if(kt->token == token) break; +static void +conf_init_ident( + val_t *val, + char *s) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_IDENT; + val->unit = CONF_UNIT_NONE; + if(s) + val->v.s = stralloc(s); + else + val->v.s = NULL; +} - if(kt->token == CONF_UNKNOWN) - return(""); - return(kt->keyword); +static void +conf_init_identlist( + val_t *val, + char *s) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_IDENTLIST; + val->unit = CONF_UNIT_NONE; + val->v.identlist = NULL; + if (s) + val->v.identlist = g_slist_append(val->v.identlist, stralloc(s)); } -void -parse_conf( - int parse_argc, - char **parse_argv, - int *new_argc, - char ***new_argv) +static void +conf_init_time( + val_t *val, + time_t t) { - int i; - char **my_argv; - char *myarg, *value; - command_option_t *program_option; - - program_options = alloc((size_t)(parse_argc+1) * SIZEOF(*program_options)); - program_options_size = parse_argc+1; - program_option = program_options; - program_option->name = NULL; - - my_argv = alloc((size_t)parse_argc * SIZEOF(char *)); - *new_argv = my_argv; - *new_argc = 0; - i=0; - while(i 2) - myarg = &parse_argv[i][2]; - else { - i++; - if(i >= parse_argc) - error("expect something after -o"); - myarg = parse_argv[i]; - } - value = index(myarg,'='); - if (value == NULL) { - conf_parserror("Must specify a value for %s.\n", myarg); - } else { - *value = '\0'; - value++; - program_option->used = 0; - program_option->name = stralloc(myarg); - program_option->value = stralloc(value); - program_option++; - program_option->name = NULL; - } - } - else { - my_argv[*new_argc] = stralloc(parse_argv[i]); - *new_argc += 1; - } - i++; - } + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_TIME; + val->unit = CONF_UNIT_NONE; + val_t__time(val) = t; } -char ** -get_config_options( - int first) +static void +conf_init_size( + val_t *val, + confunit_t unit, + ssize_t sz) { - char **config_options; - char **config_option; - command_option_t *command_options; - - config_options = alloc((first+program_options_size+1)*SIZEOF(char *)); - for(command_options = program_options, - config_option = config_options + first; - command_options->name != NULL; command_options++) { - *config_option = vstralloc("-o", command_options->name, "=", - command_options->value, NULL); - config_option++; - } - *config_option = NULL; - return(config_options); + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_SIZE; + val->unit = unit; + val_t__size(val) = sz; } -void -report_bad_conf_arg(void) +static void +conf_init_bool( + val_t *val, + int i) { - command_option_t *command_option; + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_BOOLEAN; + val->unit = CONF_UNIT_NONE; + val_t__boolean(val) = i; +} - for(command_option = program_options; command_option->name != NULL; - command_option++) { - if(command_option->used == 0) { - fprintf(stderr,"argument -o%s=%s not used\n", - command_option->name, command_option->value); - } - } +static void +conf_init_no_yes_all( + val_t *val, + int i) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_NO_YES_ALL; + val->unit = CONF_UNIT_NONE; + val_t__int(val) = i; } -void -free_server_config(void) +static void +conf_init_compress( + val_t *val, + comp_t i) { - holdingdisk_t *hp, *hpnext; - dumptype_t *dp, *dpnext; - tapetype_t *tp, *tpnext; - interface_t *ip, *ipnext; - command_option_t *server_option; - int i; + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_COMPRESS; + val->unit = CONF_UNIT_NONE; + val_t__compress(val) = (int)i; +} - for(hp=holdingdisks; hp != NULL; hp = hpnext) { - amfree(hp->name); - for(i=0; ivalue[i]); - } - hpnext = hp->next; - amfree(hp); - } +static void +conf_init_encrypt( + val_t *val, + encrypt_t i) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_ENCRYPT; + val->unit = CONF_UNIT_NONE; + val_t__encrypt(val) = (int)i; +} - for(dp=dumplist; dp != NULL; dp = dpnext) { - amfree(dp->name); - for(i=0; ivalue[i]); - } - dpnext = dp->next; - amfree(dp); - } +static void +conf_init_part_cache_type( + val_t *val, + part_cache_type_t i) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_PART_CACHE_TYPE; + val->unit = CONF_UNIT_NONE; + val_t__part_cache_type(val) = (int)i; +} - for(tp=tapelist; tp != NULL; tp = tpnext) { - amfree(tp->name); - for(i=0; ivalue[i]); - } - tpnext = tp->next; - amfree(tp); - } +static void +conf_init_host_limit( + val_t *val) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_HOST_LIMIT; + val->unit = CONF_UNIT_NONE; + val_t__host_limit(val).match_pats = NULL; + val_t__host_limit(val).same_host = FALSE; + val_t__host_limit(val).server = FALSE; +} - for(ip=interface_list; ip != NULL; ip = ipnext) { - amfree(ip->name); - for(i=0; ivalue[i]); - } - ipnext = ip->next; - amfree(ip); - } +static void +conf_init_host_limit_server( + val_t *val) +{ + conf_init_host_limit(val); + val_t__host_limit(val).server = TRUE; +} - if(program_options) { - for(server_option = program_options; server_option->name != NULL; - server_option++) { - amfree(server_option->name); - amfree(server_option->value); - } - amfree(program_options); - } +static void +conf_init_data_path( + val_t *val, + data_path_t i) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_DATA_PATH; + val->unit = CONF_UNIT_NONE; + val_t__data_path(val) = (int)i; +} - for(i=0; iseen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_HOLDING; + val->unit = CONF_UNIT_NONE; + val_t__holding(val) = (int)i; } +static void +conf_init_estimatelist( + val_t *val, + estimate_t i) +{ + GSList *estimates = NULL; + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_ESTIMATELIST; + val->unit = CONF_UNIT_NONE; + estimates = g_slist_append(estimates, GINT_TO_POINTER(i)); + val_t__estimatelist(val) = estimates; +} +static void +conf_init_strategy( + val_t *val, + strategy_t i) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->unit = CONF_UNIT_NONE; + val->type = CONFTYPE_STRATEGY; + val_t__strategy(val) = i; +} -/* configuration parameters */ -static char *cln_config_dir = NULL; +static void +conf_init_taperalgo( + val_t *val, + taperalgo_t i) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_TAPERALGO; + val->unit = CONF_UNIT_NONE; + val_t__taperalgo(val) = i; +} -/* predeclare local functions */ +static void +conf_init_priority( + val_t *val, + int i) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_PRIORITY; + val->unit = CONF_UNIT_NONE; + val_t__priority(val) = i; +} -static void read_client_conffile_recursively(char *filename); -static int read_client_confline(void); +static void +conf_init_rate( + val_t *val, + float r1, + float r2) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_RATE; + val->unit = CONF_UNIT_NONE; + val_t__rate(val)[0] = r1; + val_t__rate(val)[1] = r2; +} -static int first_file = 1; +static void +conf_init_exinclude( + val_t *val) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_EXINCLUDE; + val->unit = CONF_UNIT_NONE; + val_t__exinclude(val).optional = 0; + val_t__exinclude(val).sl_list = NULL; + val_t__exinclude(val).sl_file = NULL; +} -/* -** ------------------------ -** External entry points -** ------------------------ -*/ +static void +conf_init_intrange( + val_t *val, + int i1, + int i2) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_INTRANGE; + val->unit = CONF_UNIT_NONE; + val_t__intrange(val)[0] = i1; + val_t__intrange(val)[1] = i2; +} -/* return 0 on success */ -/* return 1 on error */ -/* return -1 if file not found */ +static void +conf_init_autolabel( + val_t *val) { + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_AUTOLABEL; + val->unit = CONF_UNIT_NONE; + val->v.autolabel.template = NULL; + val->v.autolabel.autolabel = 0; +} -int read_clientconf( - char *filename) +void +free_property_t( + gpointer p) { - my_keytab = server_keytab; - my_var = client_var; + property_t *propery = (property_t *)p; + slist_free_full(propery->values, g_free); + amfree(propery); +} - if(first_file == 1) { - init_defaults(); - first_file = 0; - } else { - allow_overwrites = 1; - } +static void +conf_init_proplist( + val_t *val) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_PROPLIST; + val->unit = CONF_UNIT_NONE; + val_t__proplist(val) = + g_hash_table_new_full(g_str_amanda_hash, g_str_amanda_equal, + &g_free, &free_property_t); +} - /* We assume that conf_confname & conf are initialized to NULL above */ - read_client_conffile_recursively(filename); +static void +conf_init_execute_on( + val_t *val, + int i) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_EXECUTE_ON; + val->unit = CONF_UNIT_NONE; + val->v.i = i; +} - command_overwrite(program_options, client_var, client_keytab, conf_data, - ""); +static void +conf_init_execute_where( + val_t *val, + int i) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_EXECUTE_WHERE; + val->unit = CONF_UNIT_NONE; + val->v.i = i; +} - debug_amandad = getconf_int(CNF_DEBUG_AMANDAD); - debug_amidxtaped = getconf_int(CNF_DEBUG_AMIDXTAPED); - debug_amindexd = getconf_int(CNF_DEBUG_AMINDEXD); - debug_amrecover = getconf_int(CNF_DEBUG_AMRECOVER); - debug_auth = getconf_int(CNF_DEBUG_AUTH); - debug_event = getconf_int(CNF_DEBUG_EVENT); - debug_holding = getconf_int(CNF_DEBUG_HOLDING); - debug_protocol = getconf_int(CNF_DEBUG_PROTOCOL); - debug_planner = getconf_int(CNF_DEBUG_PLANNER); - debug_driver = getconf_int(CNF_DEBUG_DRIVER); - debug_dumper = getconf_int(CNF_DEBUG_DUMPER); - debug_chunker = getconf_int(CNF_DEBUG_CHUNKER); - debug_taper = getconf_int(CNF_DEBUG_TAPER); - debug_selfcheck = getconf_int(CNF_DEBUG_SELFCHECK); - debug_sendsize = getconf_int(CNF_DEBUG_SENDSIZE); - debug_sendbackup = getconf_int(CNF_DEBUG_SENDBACKUP); +static void +conf_init_send_amreport( + val_t *val, + send_amreport_t i) +{ + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_SEND_AMREPORT_ON; + val->unit = CONF_UNIT_NONE; + val->v.i = i; +} - return got_parserror; +static void conf_init_application(val_t *val) { + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; + val->type = CONFTYPE_APPLICATION; + val->unit = CONF_UNIT_NONE; + val->v.s = NULL; } /* -** ------------------------ -** Internal routines -** ------------------------ -*/ - + * Config access implementation + */ -static void -read_client_conffile_recursively( - char * filename) +val_t * +getconf(confparm_key key) { - /* Save globals used in read_client_confline(), elsewhere. */ - int save_line_num = conf_line_num; - FILE *save_conf = conf_conf; - char *save_confname = conf_confname; - int rc; + assert(key < CNF_CNF); + return &conf_data[key]; +} - if (*filename == '/' || cln_config_dir == NULL) { - conf_confname = stralloc(filename); - } else { - conf_confname = stralloc2(cln_config_dir, filename); - } +GSList * +getconf_list( + char *listname) +{ + tapetype_t *tp; + dumptype_t *dp; + interface_t *ip; + holdingdisk_t *hd; + GSList *hp; + application_t *ap; + pp_script_t *pp; + device_config_t *dc; + changer_config_t *cc; + interactivity_t *iv; + taperscan_t *ts; + GSList *rv = NULL; - if((conf_conf = fopen(conf_confname, "r")) == NULL) { - dbprintf(("Could not open conf file \"%s\": %s\n", conf_confname, - strerror(errno))); - amfree(conf_confname); - got_parserror = -1; - return; + if (strcasecmp(listname,"tapetype") == 0) { + for(tp = tapelist; tp != NULL; tp=tp->next) { + rv = g_slist_append(rv, tp->name); + } + } else if (strcasecmp(listname,"dumptype") == 0) { + for(dp = dumplist; dp != NULL; dp=dp->next) { + rv = g_slist_append(rv, dp->name); + } + } else if (strcasecmp(listname,"holdingdisk") == 0) { + for(hp = holdinglist; hp != NULL; hp=hp->next) { + hd = hp->data; + rv = g_slist_append(rv, hd->name); + } + } else if (strcasecmp(listname,"interface") == 0) { + for(ip = interface_list; ip != NULL; ip=ip->next) { + rv = g_slist_append(rv, ip->name); + } + } else if (strcasecmp(listname,"application_tool") == 0 + || strcasecmp(listname,"application-tool") == 0 + || strcasecmp(listname,"application") == 0) { + for(ap = application_list; ap != NULL; ap=ap->next) { + rv = g_slist_append(rv, ap->name); + } + } else if (strcasecmp(listname,"script_tool") == 0 + || strcasecmp(listname,"script-tool") == 0 + || strcasecmp(listname,"script") == 0) { + for(pp = pp_script_list; pp != NULL; pp=pp->next) { + rv = g_slist_append(rv, pp->name); + } + } else if (strcasecmp(listname,"device") == 0) { + for(dc = device_config_list; dc != NULL; dc=dc->next) { + rv = g_slist_append(rv, dc->name); + } + } else if (strcasecmp(listname,"changer") == 0) { + for(cc = changer_config_list; cc != NULL; cc=cc->next) { + rv = g_slist_append(rv, cc->name); + } + } else if (strcasecmp(listname,"interactivity") == 0) { + for(iv = interactivity_list; iv != NULL; iv=iv->next) { + rv = g_slist_append(rv, iv->name); + } + } else if (strcasecmp(listname,"taperscan") == 0) { + for(ts = taperscan_list; ts != NULL; ts=ts->next) { + rv = g_slist_append(rv, ts->name); + } } - dbprintf(("Reading conf file \"%s\".\n", conf_confname)); - - conf_line_num = 0; - - /* read_client_confline() can invoke us recursively via "includefile" */ - do { - rc = read_client_confline(); - } while (rc != 0); - afclose(conf_conf); - - amfree(conf_confname); - - /* Restore globals */ - conf_line_num = save_line_num; - conf_conf = save_conf; - conf_confname = save_confname; + return rv; } +val_t * +getconf_byname( + char *key) +{ + val_t *rv = NULL; -/* ------------------------ */ + if (!parm_key_info(key, NULL, &rv)) + return NULL; + return rv; +} -static int -read_client_confline(void) +tapetype_t * +lookup_tapetype( + char *str) { - t_conf_var *np; + tapetype_t *p; - keytable = client_keytab; + for(p = tapelist; p != NULL; p = p->next) { + if(strcasecmp(p->name, str) == 0) return p; + } + return NULL; +} - conf_line_num += 1; - get_conftoken(CONF_ANY); - switch(tok) { - case CONF_INCLUDEFILE: - { - char *fn; +val_t * +tapetype_getconf( + tapetype_t *ttyp, + tapetype_key key) +{ + assert(ttyp != NULL); + assert(key < TAPETYPE_TAPETYPE); + return &ttyp->value[key]; +} - get_conftoken(CONF_STRING); - fn = tokenval.v.s; - read_client_conffile_recursively(fn); - } - break; +static void +validate_program( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) +{ + if (strcmp(val->v.s, "DUMP") != 0 && + strcmp(val->v.s, "GNUTAR") != 0 && + strcmp(val->v.s, "STAR") != 0 && + strcmp(val->v.s, "APPLICATION") != 0) + conf_parserror("program must be \"DUMP\", \"GNUTAR\", \"STAR\" or \"APPLICATION\""); +} - case CONF_NL: /* empty line */ - break; +static void +validate_dump_limit( + conf_var_t *np G_GNUC_UNUSED, + val_t *val) +{ + if (val->v.host_limit.match_pats) { + conf_parserror("dump-limit can't specify hostname"); + } +} - case CONF_END: /* end of file */ - return 0; +char * +tapetype_name( + tapetype_t *ttyp) +{ + assert(ttyp != NULL); + return ttyp->name; +} - default: - { - for(np = client_var; np->token != CONF_UNKNOWN; np++) - if(np->token == tok) break; +dumptype_t * +lookup_dumptype( + char *str) +{ + dumptype_t *p; - if(np->token == CONF_UNKNOWN) { - conf_parserror("configuration keyword expected"); - } else { - np->read_function(np, &conf_data[np->parm]); - if(np->validate) - np->validate(np, &conf_data[np->parm]); - } - } + for(p = dumplist; p != NULL; p = p->next) { + if(strcasecmp(p->name, str) == 0) return p; } - if(tok != CONF_NL) - get_conftoken(CONF_NL); - return 1; + return NULL; } +val_t * +dumptype_getconf( + dumptype_t *dtyp, + dumptype_key key) +{ + assert(dtyp != NULL); + assert(key < DUMPTYPE_DUMPTYPE); + return &dtyp->value[key]; +} char * -generic_client_get_security_conf( - char * string, - void * arg) +dumptype_name( + dumptype_t *dtyp) { - (void)arg; /* Quiet unused parameter warning */ - - if(!string || !*string) - return(NULL); - - if(strcmp(string, "conf")==0) { - return(getconf_str(CNF_CONF)); - } else if(strcmp(string, "index_server")==0) { - return(getconf_str(CNF_INDEX_SERVER)); - } else if(strcmp(string, "tape_server")==0) { - return(getconf_str(CNF_TAPE_SERVER)); - } else if(strcmp(string, "tapedev")==0) { - return(getconf_str(CNF_TAPEDEV)); - } else if(strcmp(string, "auth")==0) { - return(getconf_str(CNF_AUTH)); - } else if(strcmp(string, "ssh_keys")==0) { - return(getconf_str(CNF_SSH_KEYS)); - } else if(strcmp(string, "amandad_path")==0) { - return(getconf_str(CNF_AMANDAD_PATH)); - } else if(strcmp(string, "client_username")==0) { - return(getconf_str(CNF_CLIENT_USERNAME)); - } else if(strcmp(string, "gnutar_list_dir")==0) { - return(getconf_str(CNF_GNUTAR_LIST_DIR)); - } else if(strcmp(string, "amandates")==0) { - return(getconf_str(CNF_AMANDATES)); - } else if(strcmp(string, "krb5principal")==0) { - return(getconf_str(CNF_KRB5PRINCIPAL)); - } else if(strcmp(string, "krb5keytab")==0) { - return(getconf_str(CNF_KRB5KEYTAB)); - } - return(NULL); + assert(dtyp != NULL); + return dtyp->name; } - -/* return 0 on success */ -/* return -1 if it is already there */ -/* return -2 if other failure */ -int -add_client_conf( - confparm_t parm, - char *value) +interface_t * +lookup_interface( + char *str) { - t_conf_var *np; - keytab_t *kt; - command_option_t *command_option; - int nb_option; + interface_t *p; - for(np = client_var; np->token != CONF_UNKNOWN; np++) - if(np->parm == (int)parm) break; + for(p = interface_list; p != NULL; p = p->next) { + if(strcasecmp(p->name, str) == 0) return p; + } + return NULL; +} - if(np->token == CONF_UNKNOWN) return -2; +val_t * +interface_getconf( + interface_t *iface, + interface_key key) +{ + assert(iface != NULL); + assert(key < INTER_INTER); + return &iface->value[key]; +} - for(kt = client_keytab; kt->token != CONF_UNKNOWN; kt++) - if(kt->token == np->token) break; +char * +interface_name( + interface_t *iface) +{ + assert(iface != NULL); + return iface->name; +} - if(kt->token == CONF_UNKNOWN) return -2; +holdingdisk_t * +lookup_holdingdisk( + char *str) +{ + GSList *hp; + holdingdisk_t *hd; - /* Try to find it */ - nb_option = 0; - for(command_option = program_options; command_option->name != NULL; - command_option++) { - nb_option++; + for (hp = holdinglist; hp != NULL; hp = hp->next) { + hd = hp->data; + if (strcasecmp(hd->name, str) == 0) return hd; } + return NULL; +} - /* Increase size of program_options if needed */ - if(nb_option >= program_options_size-1) { - program_options_size *= 2; - program_options = realloc(program_options, - program_options_size * SIZEOF(*program_options)); - if (program_options == NULL) { - error("Can't realloc program_options: %s\n", strerror(errno)); - /*NOTREACHED*/ - } - for(command_option = program_options; command_option->name != NULL; - command_option++) { - } - } +GSList * +getconf_holdingdisks( + void) +{ + return holdinglist; +} + +val_t * +holdingdisk_getconf( + holdingdisk_t *hdisk, + holdingdisk_key key) +{ + assert(hdisk != NULL); + assert(key < HOLDING_HOLDING); + return &hdisk->value[key]; +} - /* add it */ - command_option->used = 0; - command_option->name = stralloc(kt->keyword); - command_option->value = stralloc(value); - command_option++; - command_option->name = NULL; - return 0; +char * +holdingdisk_name( + holdingdisk_t *hdisk) +{ + assert(hdisk != NULL); + return hdisk->name; } -/* -static t_conf_var * -get_np( - t_conf_var *get_var, - int parm) +application_t * +lookup_application( + char *str) { - t_conf_var *np; + application_t *p; - for(np = get_var; np->token != CONF_UNKNOWN; np++) { - if(np->parm == parm) - break; + for(p = application_list; p != NULL; p = p->next) { + if(strcasecmp(p->name, str) == 0) return p; } + return NULL; +} - if(np->token == CONF_UNKNOWN) { - error("error [unknown get_np parm: %d]", parm); - NOTREACHED - } - return np; +val_t * +application_getconf( + application_t *ap, + application_key key) +{ + assert(ap != NULL); + assert(key < APPLICATION_APPLICATION); + return &ap->value[key]; } -*/ -static time_t -get_time(void) +char * +application_name( + application_t *ap) { - time_t hhmm; + assert(ap != NULL); + return ap->name; +} - get_conftoken(CONF_ANY); - switch(tok) { - case CONF_INT: -#if SIZEOF_TIME_T < SIZEOF_INT - if ((off_t)tokenval.v.i >= (off_t)TIME_MAX) - conf_parserror("value too large"); -#endif - hhmm = (time_t)tokenval.v.i; - break; +interactivity_t * +lookup_interactivity( + char *str) +{ + interactivity_t *p; - case CONF_LONG: -#if SIZEOF_TIME_T < SIZEOF_LONG - if ((off_t)tokenval.v.l >= (off_t)TIME_MAX) - conf_parserror("value too large"); -#endif - hhmm = (time_t)tokenval.v.l; - break; + for(p = interactivity_list; p != NULL; p = p->next) { + if(strcasecmp(p->name, str) == 0) return p; + } + return NULL; +} - case CONF_SIZE: -#if SIZEOF_TIME_T < SIZEOF_SSIZE_T - if ((off_t)tokenval.v.size >= (off_t)TIME_MAX) - conf_parserror("value too large"); -#endif - hhmm = (time_t)tokenval.v.size; - break; +val_t * +interactivity_getconf( + interactivity_t *iv, + interactivity_key key) +{ + assert(iv != NULL); + assert(key < INTERACTIVITY_INTERACTIVITY); + return &iv->value[key]; +} - case CONF_AM64: -#if SIZEOF_TIME_T < SIZEOF_LONG_LONG - if ((off_t)tokenval.v.am64 >= (off_t)TIME_MAX) - conf_parserror("value too large"); -#endif - hhmm = (time_t)tokenval.v.am64; - break; +char * +interactivity_name( + interactivity_t *iv) +{ + assert(iv != NULL); + return iv->name; +} - case CONF_AMINFINITY: - hhmm = TIME_MAX; - break; +taperscan_t * +lookup_taperscan( + char *str) +{ + taperscan_t *p; - default: - conf_parserror("a time is expected"); - hhmm = 0; - break; + for(p = taperscan_list; p != NULL; p = p->next) { + if(strcasecmp(p->name, str) == 0) return p; } - return hhmm; + return NULL; } -keytab_t numb_keytable[] = { - { "B", CONF_MULT1 }, - { "BPS", CONF_MULT1 }, - { "BYTE", CONF_MULT1 }, - { "BYTES", CONF_MULT1 }, - { "DAY", CONF_MULT1 }, - { "DAYS", CONF_MULT1 }, - { "INF", CONF_AMINFINITY }, - { "K", CONF_MULT1K }, - { "KB", CONF_MULT1K }, - { "KBPS", CONF_MULT1K }, - { "KBYTE", CONF_MULT1K }, - { "KBYTES", CONF_MULT1K }, - { "KILOBYTE", CONF_MULT1K }, - { "KILOBYTES", CONF_MULT1K }, - { "KPS", CONF_MULT1K }, - { "M", CONF_MULT1M }, - { "MB", CONF_MULT1M }, - { "MBPS", CONF_MULT1M }, - { "MBYTE", CONF_MULT1M }, - { "MBYTES", CONF_MULT1M }, - { "MEG", CONF_MULT1M }, - { "MEGABYTE", CONF_MULT1M }, - { "MEGABYTES", CONF_MULT1M }, - { "G", CONF_MULT1G }, - { "GB", CONF_MULT1G }, - { "GBPS", CONF_MULT1G }, - { "GBYTE", CONF_MULT1G }, - { "GBYTES", CONF_MULT1G }, - { "GIG", CONF_MULT1G }, - { "GIGABYTE", CONF_MULT1G }, - { "GIGABYTES", CONF_MULT1G }, - { "MPS", CONF_MULT1M }, - { "TAPE", CONF_MULT1 }, - { "TAPES", CONF_MULT1 }, - { "WEEK", CONF_MULT7 }, - { "WEEKS", CONF_MULT7 }, - { NULL, CONF_IDENT } -}; - -static int -get_int(void) +val_t * +taperscan_getconf( + taperscan_t *ts, + taperscan_key key) { - int val; - keytab_t *save_kt; + assert(ts != NULL); + assert(key < TAPERSCAN_TAPERSCAN); + return &ts->value[key]; +} - save_kt = keytable; - keytable = numb_keytable; +char * +taperscan_name( + taperscan_t *ts) +{ + assert(ts != NULL); + return ts->name; +} - get_conftoken(CONF_ANY); - switch(tok) { - case CONF_INT: - val = tokenval.v.i; - break; +pp_script_t * +lookup_pp_script( + char *str) +{ + pp_script_t *pps; - case CONF_LONG: -#if SIZEOF_INT < SIZEOF_LONG - if ((off_t)tokenval.v.l > (off_t)INT_MAX) - conf_parserror("value too large"); - if ((off_t)tokenval.v.l < (off_t)INT_MIN) - conf_parserror("value too small"); -#endif - val = (int)tokenval.v.l; - break; + for(pps = pp_script_list; pps != NULL; pps = pps->next) { + if(strcasecmp(pps->name, str) == 0) return pps; + } + return NULL; +} - case CONF_SIZE: -#if SIZEOF_INT < SIZEOF_SSIZE_T - if ((off_t)tokenval.v.size > (off_t)INT_MAX) - conf_parserror("value too large"); - if ((off_t)tokenval.v.size < (off_t)INT_MIN) - conf_parserror("value too small"); -#endif - val = (int)tokenval.v.size; - break; +val_t * +pp_script_getconf( + pp_script_t *pps, + pp_script_key key) +{ + assert(pps != NULL); + assert(key < PP_SCRIPT_PP_SCRIPT); + return &pps->value[key]; +} - case CONF_AM64: -#if SIZEOF_INT < SIZEOF_LONG_LONG - if (tokenval.v.am64 > (off_t)INT_MAX) - conf_parserror("value too large"); - if (tokenval.v.am64 < (off_t)INT_MIN) - conf_parserror("value too small"); -#endif - val = (int)tokenval.v.am64; - break; +char * +pp_script_name( + pp_script_t *pps) +{ + assert(pps != NULL); + return pps->name; +} - case CONF_AMINFINITY: - val = INT_MAX; - break; +device_config_t * +lookup_device_config( + char *str) +{ + device_config_t *devconf; - default: - conf_parserror("an integer is expected"); - val = 0; - break; + for(devconf = device_config_list; devconf != NULL; devconf = devconf->next) { + if(strcasecmp(devconf->name, str) == 0) return devconf; } + return NULL; +} - /* get multiplier, if any */ - get_conftoken(CONF_ANY); - switch(tok) { - case CONF_NL: /* multiply by one */ - case CONF_END: - case CONF_MULT1: - case CONF_MULT1K: - break; - - case CONF_MULT7: - if (val > (INT_MAX / 7)) - conf_parserror("value too large"); - if (val < (INT_MIN / 7)) - conf_parserror("value too small"); - val *= 7; - break; +val_t * +device_config_getconf( + device_config_t *devconf, + device_config_key key) +{ + assert(devconf != NULL); + assert(key < DEVICE_CONFIG_DEVICE_CONFIG); + return &devconf->value[key]; +} - case CONF_MULT1M: - if (val > (INT_MAX / 1024)) - conf_parserror("value too large"); - if (val < (INT_MIN / 1024)) - conf_parserror("value too small"); - val *= 1024; - break; +char * +device_config_name( + device_config_t *devconf) +{ + assert(devconf != NULL); + return devconf->name; +} - case CONF_MULT1G: - if (val > (INT_MAX / (1024 * 1024))) - conf_parserror("value too large"); - if (val < (INT_MIN / (1024 * 1024))) - conf_parserror("value too small"); - val *= 1024 * 1024; - break; +changer_config_t * +lookup_changer_config( + char *str) +{ + changer_config_t *devconf; - default: /* it was not a multiplier */ - unget_conftoken(); - break; + for(devconf = changer_config_list; devconf != NULL; devconf = devconf->next) { + if(strcasecmp(devconf->name, str) == 0) return devconf; } + return NULL; +} - keytable = save_kt; - return val; +val_t * +changer_config_getconf( + changer_config_t *devconf, + changer_config_key key) +{ + assert(devconf != NULL); + assert(key < CHANGER_CONFIG_CHANGER_CONFIG); + return &devconf->value[key]; } -/* -static long -get_long(void) +char * +changer_config_name( + changer_config_t *devconf) { - long val; - keytab_t *save_kt; + assert(devconf != NULL); + return devconf->name; +} - save_kt = keytable; - keytable = numb_keytable; +long int +getconf_unit_divisor(void) +{ + return unit_divisor; +} - get_conftoken(CONF_ANY); +/* + * Command-line Handling Implementation + */ - switch(tok) { - case CONF_LONG: - val = tokenval.v.l; - break; +config_overrides_t * +new_config_overrides( + int size_estimate) +{ + config_overrides_t *co; - case CONF_INT: -#if SIZEOF_LONG < SIZEOF_INT - if ((off_t)tokenval.v.i > (off_t)LONG_MAX) - conf_parserror("value too large"); - if ((off_t)tokenval.v.i < (off_t)LONG_MIN) - conf_parserror("value too small"); -#endif - val = (long)tokenval.v.i; - break; + if (size_estimate <= 0) + size_estimate = 10; - case CONF_SIZE: -#if SIZEOF_LONG < SIZEOF_SSIZE_T - if ((off_t)tokenval.v.size > (off_t)LONG_MAX) - conf_parserror("value too large"); - if ((off_t)tokenval.v.size < (off_t)LONG_MIN) - conf_parserror("value too small"); -#endif - val = (long)tokenval.v.size; - break; + co = alloc(sizeof(*co)); + co->ovr = alloc(sizeof(*co->ovr) * size_estimate); + co->n_allocated = size_estimate; + co->n_used = 0; - case CONF_AM64: -#if SIZEOF_LONG < SIZEOF_LONG_LONG - if (tokenval.v.am64 > (off_t)LONG_MAX) - conf_parserror("value too large"); - if (tokenval.v.am64 < (off_t)LONG_MIN) - conf_parserror("value too small"); -#endif - val = (long)tokenval.v.am64; - break; + return co; +} - case CONF_AMINFINITY: - val = (long)LONG_MAX; - break; +void +free_config_overrides( + config_overrides_t *co) +{ + int i; - default: - conf_parserror("an integer is expected"); - val = 0; - break; + if (!co) return; + for (i = 0; i < co->n_used; i++) { + amfree(co->ovr[i].key); + amfree(co->ovr[i].value); } + amfree(co->ovr); + amfree(co); +} - get_conftoken(CONF_ANY); - - switch(tok) { - case CONF_NL: - case CONF_MULT1: - case CONF_MULT1K: - break; - - case CONF_MULT7: - if (val > (LONG_MAX / 7L)) - conf_parserror("value too large"); - if (val < (LONG_MIN / 7L)) - conf_parserror("value too small"); - val *= 7L; - break; - - case CONF_MULT1M: - if (val > (LONG_MAX / 1024L)) - conf_parserror("value too large"); - if (val < (LONG_MIN / 1024L)) - conf_parserror("value too small"); - val *= 1024L; - break; - - case CONF_MULT1G: - if (val > (LONG_MAX / (1024L * 1024L))) - conf_parserror("value too large"); - if (val < (LONG_MIN / (1024L * 1024L))) - conf_parserror("value too small"); - val *= 1024L * 1024L; - break; - - default: - unget_conftoken(); - break; +void add_config_override( + config_overrides_t *co, + char *key, + char *value) +{ + /* reallocate if necessary */ + if (co->n_used == co->n_allocated) { + co->n_allocated *= 2; + co->ovr = realloc(co->ovr, co->n_allocated * sizeof(*co->ovr)); + if (!co->ovr) { + error(_("Cannot realloc; out of memory")); + /* NOTREACHED */ + } } - keytable = save_kt; - return val; + co->ovr[co->n_used].key = stralloc(key); + co->ovr[co->n_used].value = stralloc(value); + co->n_used++; } -*/ -static ssize_t -get_size(void) +void +add_config_override_opt( + config_overrides_t *co, + char *optarg) { - ssize_t val; - keytab_t *save_kt; + char *value; + assert(optarg != NULL); - save_kt = keytable; - keytable = numb_keytable; - - get_conftoken(CONF_ANY); - - switch(tok) { - case CONF_SIZE: - val = tokenval.v.size; - break; - - case CONF_INT: -#if SIZEOF_SIZE_T < SIZEOF_INT - if ((off_t)tokenval.v.i > (off_t)SSIZE_MAX) - conf_parserror("value too large"); - if ((off_t)tokenval.v.i < (off_t)SSIZE_MIN) - conf_parserror("value too small"); -#endif - val = (ssize_t)tokenval.v.i; - break; - - case CONF_LONG: -#if SIZEOF_SIZE_T < SIZEOF_LONG - if ((off_t)tokenval.v.l > (off_t)SSIZE_MAX) - conf_parserror("value too large"); - if ((off_t)tokenval.v.l < (off_t)SSIZE_MIN) - conf_parserror("value too small"); -#endif - val = (ssize_t)tokenval.v.l; - break; - - case CONF_AM64: -#if SIZEOF_SIZE_T < SIZEOF_LONG_LONG - if (tokenval.v.am64 > (off_t)SSIZE_MAX) - conf_parserror("value too large"); - if (tokenval.v.am64 < (off_t)SSIZE_MIN) - conf_parserror("value too small"); -#endif - val = (ssize_t)tokenval.v.am64; - break; - - case CONF_AMINFINITY: - val = (ssize_t)SSIZE_MAX; - break; - - default: - conf_parserror("an integer is expected"); - val = 0; - break; + value = strchr(optarg, '='); + if (value == NULL) { + error(_("Must specify a value for %s."), optarg); + /* NOTREACHED */ } - /* get multiplier, if any */ - get_conftoken(CONF_ANY); + *value = '\0'; + add_config_override(co, optarg, value+1); + *value = '='; +} + +config_overrides_t * +extract_commandline_config_overrides( + int *argc, + char ***argv) +{ + int i, j, moveup; + config_overrides_t *co = new_config_overrides(*argc/2); - switch(tok) { - case CONF_NL: /* multiply by one */ - case CONF_MULT1: - case CONF_MULT1K: - break; + i = 0; + while (i<*argc) { + if(strncmp((*argv)[i],"-o",2) == 0) { + if(strlen((*argv)[i]) > 2) { + add_config_override_opt(co, (*argv)[i]+2); + moveup = 1; + } + else { + if (i+1 >= *argc) error(_("expect something after -o")); + add_config_override_opt(co, (*argv)[i+1]); + moveup = 2; + } - case CONF_MULT7: - if (val > (ssize_t)(SSIZE_MAX / 7)) - conf_parserror("value too large"); - if (val < (ssize_t)(SSIZE_MIN / 7)) - conf_parserror("value too small"); - val *= (ssize_t)7; - break; + /* move up remaining argment array */ + for (j = i; j+moveup<*argc; j++) { + (*argv)[j] = (*argv)[j+moveup]; + } + *argc -= moveup; + } else { + i++; + } + } - case CONF_MULT1M: - if (val > (ssize_t)(SSIZE_MAX / (ssize_t)1024)) - conf_parserror("value too large"); - if (val < (ssize_t)(SSIZE_MIN / (ssize_t)1024)) - conf_parserror("value too small"); - val *= (ssize_t)1024; - break; + return co; +} - case CONF_MULT1G: - if (val > (ssize_t)(SSIZE_MAX / (1024 * 1024))) - conf_parserror("value too large"); - if (val < (ssize_t)(SSIZE_MIN / (1024 * 1024))) - conf_parserror("value too small"); - val *= (ssize_t)(1024 * 1024); - break; +void +set_config_overrides( + config_overrides_t *co) +{ + int i; - default: /* it was not a multiplier */ - unget_conftoken(); - break; + config_overrides = co; + + for (i = 0; i < co->n_used; i++) { + g_debug("config_overrides: %s %s", co->ovr[i].key, co->ovr[i].value); } - keytable = save_kt; - return val; + return; } -static off_t -get_am64_t(void) +static cfgerr_level_t +apply_config_overrides( + config_overrides_t *co, + char *key_ovr) { - off_t val; - keytab_t *save_kt; + int i; - save_kt = keytable; - keytable = numb_keytable; + if(!co) return cfgerr_level; + assert(keytable != NULL); + assert(parsetable != NULL); - get_conftoken(CONF_ANY); + for (i = 0; i < co->n_used; i++) { + char *key = co->ovr[i].key; + char *value = co->ovr[i].value; + val_t *key_val; + conf_var_t *key_parm; - switch(tok) { - case CONF_INT: - val = (off_t)tokenval.v.i; - break; + if (key_ovr && strncasecmp(key_ovr, key, strlen(key_ovr)) != 0) { + continue; + } - case CONF_LONG: - val = (off_t)tokenval.v.l; - break; + if (!parm_key_info(key, &key_parm, &key_val)) { + /* not an error, only default config is loaded */ + continue; + } - case CONF_SIZE: - val = (off_t)tokenval.v.size; - break; + /* now set up a fake line and use the relevant read_function to + * parse it. This is sneaky! */ + if (key_parm->type == CONFTYPE_STR) { + current_line = quote_string_always(value); + } else { + current_line = stralloc(value); + } - case CONF_AM64: - val = tokenval.v.am64; - break; + current_char = current_line; + token_pushed = 0; + current_line_num = -2; + allow_overwrites = 1; + co->ovr[i].applied = TRUE; - case CONF_AMINFINITY: - val = AM64_MAX; - break; + key_parm->read_function(key_parm, key_val); + if ((key_parm)->validate_function) + key_parm->validate_function(key_parm, key_val); - default: - conf_parserror("an integer is expected"); - val = 0; - break; + amfree(current_line); + current_char = NULL; } - /* get multiplier, if any */ - get_conftoken(CONF_ANY); - - switch(tok) { - case CONF_NL: /* multiply by one */ - case CONF_MULT1: - case CONF_MULT1K: - break; + return cfgerr_level; +} - case CONF_MULT7: - if (val > AM64_MAX/7 || val < AM64_MIN/7) - conf_parserror("value too large"); - val *= 7; - break; +/* + * val_t Management Implementation + */ - case CONF_MULT1M: - if (val > AM64_MAX/1024 || val < AM64_MIN/1024) - conf_parserror("value too large"); - val *= 1024; - break; +int +val_t_to_int( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_INT) { + error(_("val_t_to_int: val.type is not CONFTYPE_INT")); + /*NOTREACHED*/ + } + return val_t__int(val); +} - case CONF_MULT1G: - if (val > AM64_MAX/(1024*1024) || val < AM64_MIN/(1024*1024)) - conf_parserror("value too large"); - val *= 1024*1024; - break; +gint64 +val_t_to_int64( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_INT64) { + error(_("val_t_to_int64: val.type is not CONFTYPE_INT64")); + /*NOTREACHED*/ + } + return val_t__int64(val); +} - default: /* it was not a multiplier */ - unget_conftoken(); - break; +float +val_t_to_real( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_REAL) { + error(_("val_t_to_real: val.type is not CONFTYPE_REAL")); + /*NOTREACHED*/ } + return val_t__real(val); +} - keytable = save_kt; +char * +val_t_to_str( + val_t *val) +{ + assert(config_initialized); + /* support CONFTYPE_IDENT, too */ + if (val->type != CONFTYPE_STR && val->type != CONFTYPE_IDENT) { + error(_("val_t_to_str: val.type is not CONFTYPE_STR nor CONFTYPE_IDENT")); + /*NOTREACHED*/ + } + return val_t__str(val); +} - return val; +char * +val_t_to_ident( + val_t *val) +{ + assert(config_initialized); + /* support CONFTYPE_STR, too */ + if (val->type != CONFTYPE_STR && val->type != CONFTYPE_IDENT) { + error(_("val_t_to_ident: val.type is not CONFTYPE_IDENT nor CONFTYPE_STR")); + /*NOTREACHED*/ + } + return val_t__str(val); } -keytab_t bool_keytable[] = { - { "Y", CONF_ATRUE }, - { "YES", CONF_ATRUE }, - { "T", CONF_ATRUE }, - { "TRUE", CONF_ATRUE }, - { "ON", CONF_ATRUE }, - { "N", CONF_AFALSE }, - { "NO", CONF_AFALSE }, - { "F", CONF_AFALSE }, - { "FALSE", CONF_AFALSE }, - { "OFF", CONF_AFALSE }, - { NULL, CONF_IDENT } -}; +identlist_t +val_t_to_identlist( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_IDENTLIST) { + error(_("val_t_to_ident: val.type is not CONFTYPE_IDENTLIST")); + /*NOTREACHED*/ + } + return val_t__identlist(val); +} -static int -get_bool(void) +time_t +val_t_to_time( + val_t *val) { - int val; - keytab_t *save_kt; + assert(config_initialized); + if (val->type != CONFTYPE_TIME) { + error(_("val_t_to_time: val.type is not CONFTYPE_TIME")); + /*NOTREACHED*/ + } + return val_t__time(val); +} - save_kt = keytable; - keytable = bool_keytable; +ssize_t +val_t_to_size( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_SIZE) { + error(_("val_t_to_size: val.type is not CONFTYPE_SIZE")); + /*NOTREACHED*/ + } + return val_t__size(val); +} - get_conftoken(CONF_ANY); +int +val_t_to_boolean( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_BOOLEAN) { + error(_("val_t_to_bool: val.type is not CONFTYPE_BOOLEAN")); + /*NOTREACHED*/ + } + return val_t__boolean(val); +} - switch(tok) { - case CONF_INT: - if (tokenval.v.i != 0) - val = 1; - else - val = 0; - break; +int +val_t_to_no_yes_all( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_NO_YES_ALL) { + error(_("val_t_to_no_yes_all: val.type is not CONFTYPE_NO_YES_ALL")); + /*NOTREACHED*/ + } + return val_t__no_yes_all(val); +} - case CONF_LONG: - if (tokenval.v.l != 0L) - val = 1; - else - val = 0; - break; +comp_t +val_t_to_compress( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_COMPRESS) { + error(_("val_t_to_compress: val.type is not CONFTYPE_COMPRESS")); + /*NOTREACHED*/ + } + return val_t__compress(val); +} - case CONF_SIZE: - if (tokenval.v.size != (size_t)0) - val = 1; - else - val = 0; - break; +encrypt_t +val_t_to_encrypt( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_ENCRYPT) { + error(_("val_t_to_encrypt: val.type is not CONFTYPE_ENCRYPT")); + /*NOTREACHED*/ + } + return val_t__encrypt(val); +} - case CONF_AM64: - if (tokenval.v.am64 != (off_t)0) - val = 1; - else - val = 0; - break; +part_cache_type_t +val_t_to_part_cache_type( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_PART_CACHE_TYPE) { + error(_("val_t_to_part_cache_type: val.type is not CONFTYPE_PART_CACHE_TYPE")); + /*NOTREACHED*/ + } + return val_t__part_cache_type(val); +} - case CONF_ATRUE: - val = 1; - break; +host_limit_t * +val_t_to_host_limit( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_HOST_LIMIT) { + error(_("val_t_to_host_limit: val.type is not CONFTYPE_HOST_LIMIT")); + /*NOTREACHED*/ + } + return &val_t__host_limit(val); +} - case CONF_AFALSE: - val = 0; - break; +dump_holdingdisk_t +val_t_to_holding( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_HOLDING) { + error(_("val_t_to_hold: val.type is not CONFTYPE_HOLDING")); + /*NOTREACHED*/ + } + return val_t__holding(val); +} - case CONF_NL: - unget_conftoken(); - val = 2; /* no argument - most likely TRUE */ - break; - default: - unget_conftoken(); - val = 3; /* a bad argument - most likely TRUE */ - conf_parserror("YES, NO, TRUE, FALSE, ON, OFF expected"); - break; +estimatelist_t +val_t_to_estimatelist( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_ESTIMATELIST) { + error(_("val_t_to_estimatelist: val.type is not CONFTYPE_ESTIMATELIST")); + /*NOTREACHED*/ } + return val_t__estimatelist(val); +} - keytable = save_kt; - return val; +strategy_t +val_t_to_strategy( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_STRATEGY) { + error(_("val_t_to_strategy: val.type is not CONFTYPE_STRATEGY")); + /*NOTREACHED*/ + } + return val_t__strategy(val); } -void -ckseen( - int *seen) +taperalgo_t +val_t_to_taperalgo( + val_t *val) { - if (*seen && !allow_overwrites && conf_line_num != -2) { - conf_parserror("duplicate parameter, prev def on line %d", *seen); + assert(config_initialized); + if (val->type != CONFTYPE_TAPERALGO) { + error(_("val_t_to_taperalgo: val.type is not CONFTYPE_TAPERALGO")); + /*NOTREACHED*/ } - *seen = conf_line_num; + return val_t__taperalgo(val); } -printf_arglist_function(void conf_parserror, const char *, format) +send_amreport_t +val_t_to_send_amreport( + val_t *val) { - va_list argp; + assert(config_initialized); + if (val->type != CONFTYPE_SEND_AMREPORT_ON) { + error(_("val_t_to_send_amreport: val.type is not CONFTYPE_SEND_AMREPORT_ON")); + /*NOTREACHED*/ + } + return val_t__send_amreport(val); +} - /* print error message */ +data_path_t +val_t_to_data_path( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_DATA_PATH) { + error(_("val_t_to_data_path: val.type is not CONFTYPE_DATA_PATH")); + /*NOTREACHED*/ + } + return val_t__data_path(val); +} - if(conf_line) - fprintf(stderr, "argument \"%s\": ", conf_line); - else - fprintf(stderr, "\"%s\", line %d: ", conf_confname, conf_line_num); - arglist_start(argp, format); - vfprintf(stderr, format, argp); - arglist_end(argp); - fputc('\n', stderr); +int +val_t_to_priority( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_PRIORITY) { + error(_("val_t_to_priority: val.type is not CONFTYPE_PRIORITY")); + /*NOTREACHED*/ + } + return val_t__priority(val); +} - got_parserror = 1; +float * +val_t_to_rate( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_RATE) { + error(_("val_t_to_rate: val.type is not CONFTYPE_RATE")); + /*NOTREACHED*/ + } + return val_t__rate(val); } -tok_t -lookup_keyword( - char * str) +exinclude_t +val_t_to_exinclude( + val_t *val) { - keytab_t *kwp; + assert(config_initialized); + if (val->type != CONFTYPE_EXINCLUDE) { + error(_("val_t_to_exinclude: val.type is not CONFTYPE_EXINCLUDE")); + /*NOTREACHED*/ + } + return val_t__exinclude(val); +} - /* switch to binary search if performance warrants */ - for(kwp = keytable; kwp->keyword != NULL; kwp++) { - if (strcasecmp(kwp->keyword, str) == 0) break; +int * +val_t_to_intrange( + val_t *val) +{ + assert(config_initialized); + if (val->type != CONFTYPE_INTRANGE) { + error(_("val_t_to_intrange: val.type is not CONFTYPE_INTRANGE")); + /*NOTREACHED*/ } - return kwp->token; + return val_t__intrange(val); } -char tkbuf[4096]; - -/* push the last token back (can only unget ANY tokens) */ -static void -unget_conftoken(void) +proplist_t +val_t_to_proplist( + val_t *val) { - token_pushed = 1; - pushed_tok = tok; - tok = CONF_UNKNOWN; - return; + assert(config_initialized); + if (val->type != CONFTYPE_PROPLIST) { + error(_("val_t_to_proplist: val.type is not CONFTYPE_PROPLIST")); + /*NOTREACHED*/ + } + return val_t__proplist(val); } -static int -conftoken_getc(void) +autolabel_t +val_t_to_autolabel( + val_t *val) { - if(conf_line == NULL) - return getc(conf_conf); - if(*conf_char == '\0') - return -1; - return(*conf_char++); + assert(config_initialized); + if (val->type != CONFTYPE_AUTOLABEL) { + error(_("val_t_to_autolabel: val.type is not CONFTYPE_AUTOLABEL")); + /*NOTREACHED*/ + } + return val_t__autolabel(val); } -static int -conftoken_ungetc( - int c) +static void +merge_val_t( + val_t *valdst, + val_t *valsrc) { - if(conf_line == NULL) - return ungetc(c, conf_conf); - else if(conf_char > conf_line) { - if(c == -1) - return c; - conf_char--; - if(*conf_char != c) { - error("*conf_char != c : %c %c", *conf_char, c); - /* NOTREACHED */ + if (valsrc->type == CONFTYPE_PROPLIST) { + if (valsrc->v.proplist) { + if (valdst->v.proplist == NULL || + g_hash_table_size(valdst->v.proplist) == 0) { + valdst->seen.block = current_block; + valdst->seen.filename = current_filename; + valdst->seen.linenum = current_line_num; + } + if (valdst->v.proplist == NULL) { + valdst->v.proplist = g_hash_table_new_full(g_str_amanda_hash, + g_str_amanda_equal, + &g_free, + &free_property_t); + g_hash_table_foreach(valsrc->v.proplist, + ©_proplist_foreach_fn, + valdst->v.proplist); + } else { + g_hash_table_foreach(valsrc->v.proplist, + &merge_proplist_foreach_fn, + valdst->v.proplist); + } + } + } else if (valsrc->type == CONFTYPE_IDENTLIST) { + if (valsrc->v.identlist) { + identlist_t il; + for (il = valsrc->v.identlist; il != NULL; il = il->next) { + valdst->v.identlist = g_slist_append(valdst->v.identlist, + stralloc((char *)il->data)); + } } } else { - error("conf_char == conf_line"); - /* NOTREACHED */ + free_val_t(valdst); + copy_val_t(valdst, valsrc); } - return c; } static void -get_conftoken( - tok_t exp) +copy_val_t( + val_t *valdst, + val_t *valsrc) { - int ch, d; - off_t am64; - char *buf; - char *tmps; - int token_overflow; - int inquote = 0; - int escape = 0; - int sign; + GSList *ia; - if (token_pushed) { - token_pushed = 0; - tok = pushed_tok; + if(valsrc->seen.linenum) { + valdst->type = valsrc->type; + valdst->seen = valsrc->seen; + switch(valsrc->type) { + case CONFTYPE_INT: + case CONFTYPE_BOOLEAN: + case CONFTYPE_NO_YES_ALL: + case CONFTYPE_COMPRESS: + case CONFTYPE_ENCRYPT: + case CONFTYPE_HOLDING: + case CONFTYPE_EXECUTE_ON: + case CONFTYPE_EXECUTE_WHERE: + case CONFTYPE_SEND_AMREPORT_ON: + case CONFTYPE_DATA_PATH: + case CONFTYPE_STRATEGY: + case CONFTYPE_TAPERALGO: + case CONFTYPE_PRIORITY: + case CONFTYPE_PART_CACHE_TYPE: + valdst->v.i = valsrc->v.i; + break; - /* - ** If it looked like a key word before then look it - ** up again in the current keyword table. - */ - switch(tok) { - case CONF_LONG: case CONF_AM64: case CONF_SIZE: - case CONF_INT: case CONF_REAL: case CONF_STRING: - case CONF_LBRACE: case CONF_RBRACE: case CONF_COMMA: - case CONF_NL: case CONF_END: case CONF_UNKNOWN: - case CONF_TIME: + case CONFTYPE_SIZE: + valdst->v.size = valsrc->v.size; break; - default: - if (exp == CONF_IDENT) - tok = CONF_IDENT; - else - tok = lookup_keyword(tokenval.v.s); + case CONFTYPE_INT64: + valdst->v.int64 = valsrc->v.int64; break; - } - } - else { - ch = conftoken_getc(); - while(ch != EOF && ch != '\n' && isspace(ch)) - ch = conftoken_getc(); - if (ch == '#') { /* comment - eat everything but eol/eof */ - while((ch = conftoken_getc()) != EOF && ch != '\n') { - (void)ch; /* Quiet empty loop complaints */ - } - } + case CONFTYPE_REAL: + valdst->v.r = valsrc->v.r; + break; - if (isalpha(ch)) { /* identifier */ - buf = tkbuf; - token_overflow = 0; - do { - if (buf < tkbuf+sizeof(tkbuf)-1) { - *buf++ = (char)ch; - } else { - *buf = '\0'; - if (!token_overflow) { - conf_parserror("token too long: %.20s...", tkbuf); - } - token_overflow = 1; - } - ch = conftoken_getc(); - } while(isalnum(ch) || ch == '_' || ch == '-'); + case CONFTYPE_RATE: + valdst->v.rate[0] = valsrc->v.rate[0]; + valdst->v.rate[1] = valsrc->v.rate[1]; + break; - if (ch != EOF && conftoken_ungetc(ch) == EOF) { - if (ferror(conf_conf)) { - conf_parserror("Pushback of '%c' failed: %s", - ch, strerror(ferror(conf_conf))); - } else { - conf_parserror("Pushback of '%c' failed: EOF", ch); - } + case CONFTYPE_IDENT: + case CONFTYPE_STR: + valdst->v.s = stralloc(valsrc->v.s); + break; + + case CONFTYPE_IDENTLIST: + valdst->v.identlist = NULL; + for (ia = valsrc->v.identlist; ia != NULL; ia = ia->next) { + valdst->v.identlist = g_slist_append(valdst->v.identlist, + stralloc(ia->data)); } - *buf = '\0'; + break; - tokenval.v.s = tkbuf; + case CONFTYPE_HOST_LIMIT: + valdst->v.host_limit = valsrc->v.host_limit; + valdst->v.host_limit.match_pats = NULL; + for (ia = valsrc->v.host_limit.match_pats; ia != NULL; ia = ia->next) { + valdst->v.host_limit.match_pats = + g_slist_append(valdst->v.host_limit.match_pats, g_strdup(ia->data)); + } + break; - if (token_overflow) tok = CONF_UNKNOWN; - else if (exp == CONF_IDENT) tok = CONF_IDENT; - else tok = lookup_keyword(tokenval.v.s); + case CONFTYPE_TIME: + valdst->v.t = valsrc->v.t; + break; + + case CONFTYPE_ESTIMATELIST: { + estimatelist_t estimates = valsrc->v.estimatelist; + estimatelist_t dst_estimates = NULL; + while (estimates != NULL) { + dst_estimates = g_slist_append(dst_estimates, estimates->data); + estimates = estimates->next; + } + valdst->v.estimatelist = dst_estimates; + break; } - else if (isdigit(ch)) { /* integer */ - sign = 1; -negative_number: /* look for goto negative_number below sign is set there */ - am64 = 0; - do { - am64 = am64 * 10 + (ch - '0'); - ch = conftoken_getc(); - } while (isdigit(ch)); + case CONFTYPE_EXINCLUDE: + valdst->v.exinclude.optional = valsrc->v.exinclude.optional; + valdst->v.exinclude.sl_list = duplicate_sl(valsrc->v.exinclude.sl_list); + valdst->v.exinclude.sl_file = duplicate_sl(valsrc->v.exinclude.sl_file); + break; - if (ch != '.') { - if (exp == CONF_INT) { - tok = CONF_INT; - tokenval.v.i = sign * (int)am64; - } else if (exp == CONF_LONG) { - tok = CONF_LONG; - tokenval.v.l = (long)sign * (long)am64; - } else if (exp != CONF_REAL) { - tok = CONF_AM64; - tokenval.v.am64 = (off_t)sign * am64; - } else { - /* automatically convert to real when expected */ - tokenval.v.r = (double)sign * (double)am64; - tok = CONF_REAL; - } - } else { - /* got a real number, not an int */ - tokenval.v.r = sign * (double) am64; - am64 = 0; - d = 1; - ch = conftoken_getc(); - while (isdigit(ch)) { - am64 = am64 * 10 + (ch - '0'); - d = d * 10; - ch = conftoken_getc(); - } - tokenval.v.r += sign * ((double)am64) / d; - tok = CONF_REAL; - } + case CONFTYPE_INTRANGE: + valdst->v.intrange[0] = valsrc->v.intrange[0]; + valdst->v.intrange[1] = valsrc->v.intrange[1]; + break; - if (ch != EOF && conftoken_ungetc(ch) == EOF) { - if (ferror(conf_conf)) { - conf_parserror("Pushback of '%c' failed: %s", - ch, strerror(ferror(conf_conf))); - } else { - conf_parserror("Pushback of '%c' failed: EOF", ch); - } - } - } else switch(ch) { - case '"': /* string */ - buf = tkbuf; - token_overflow = 0; - inquote = 1; - *buf++ = (char)ch; - while (inquote && ((ch = conftoken_getc()) != EOF)) { - if (ch == '\n') { - if (!escape) - break; - escape = 0; - buf--; /* Consume escape in buffer */ - } else if (ch == '\\') { - escape = 1; - } else { - if (ch == '"') { - if (!escape) - inquote = 0; - } - escape = 0; - } + case CONFTYPE_PROPLIST: + if (valsrc->v.proplist) { + valdst->v.proplist = g_hash_table_new_full(g_str_amanda_hash, + g_str_amanda_equal, + &g_free, + &free_property_t); - if(buf >= &tkbuf[sizeof(tkbuf) - 1]) { - if (!token_overflow) { - conf_parserror("string too long: %.20s...", tkbuf); - } - token_overflow = 1; - break; - } - *buf++ = (char)ch; + g_hash_table_foreach(valsrc->v.proplist, + ©_proplist_foreach_fn, + valdst->v.proplist); + } else { + valdst->v.proplist = NULL; } - *buf = '\0'; + break; - /* - * A little manuver to leave a fully unquoted, unallocated string - * in tokenval.v.s - */ - tmps = unquote_string(tkbuf); - strncpy(tkbuf, tmps, sizeof(tkbuf)); - amfree(tmps); - tokenval.v.s = tkbuf; + case CONFTYPE_APPLICATION: + valdst->v.s = stralloc(valsrc->v.s); + break; - tok = (token_overflow) ? CONF_UNKNOWN : - (exp == CONF_IDENT) ? CONF_IDENT : CONF_STRING; + case CONFTYPE_AUTOLABEL: + valdst->v.autolabel.template = stralloc(valsrc->v.autolabel.template); + valdst->v.autolabel.autolabel = valsrc->v.autolabel.autolabel; break; + } + } +} - case '-': - ch = conftoken_getc(); - if (isdigit(ch)) { - sign = -1; - goto negative_number; - } - else { - if (ch != EOF && conftoken_ungetc(ch) == EOF) { - if (ferror(conf_conf)) { - conf_parserror("Pushback of '%c' failed: %s", - ch, strerror(ferror(conf_conf))); - } else { - conf_parserror("Pushback of '%c' failed: EOF", ch); - } - } - tok = CONF_UNKNOWN; - } +static void +merge_proplist_foreach_fn( + gpointer key_p, + gpointer value_p, + gpointer user_data_p) +{ + char *property_s = key_p; + property_t *property = value_p; + proplist_t proplist = user_data_p; + GSList *elem = NULL; + int new_prop = 0; + property_t *new_property = g_hash_table_lookup(proplist, property_s); + if (new_property && !property->append) { + g_hash_table_remove(proplist, property_s); + new_property = NULL; + } + if (!new_property) { + new_property = malloc(sizeof(property_t)); + new_property->seen = property->seen; + new_property->append = property->append; + new_property->priority = property->priority; + new_property->values = NULL; + new_prop = 1; + } + + for(elem = property->values;elem != NULL; elem=elem->next) { + new_property->values = g_slist_append(new_property->values, + stralloc(elem->data)); + } + if (new_prop) + g_hash_table_insert(proplist, stralloc(property_s), new_property); +} + +static void +copy_proplist_foreach_fn( + gpointer key_p, + gpointer value_p, + gpointer user_data_p) +{ + char *property_s = key_p; + property_t *property = value_p; + proplist_t proplist = user_data_p; + GSList *elem = NULL; + property_t *new_property = malloc(sizeof(property_t)); + new_property->append = property->append; + new_property->priority = property->priority; + new_property->seen = property->seen; + new_property->values = NULL; + + for(elem = property->values;elem != NULL; elem=elem->next) { + new_property->values = g_slist_append(new_property->values, + stralloc(elem->data)); + } + g_hash_table_insert(proplist, stralloc(property_s), new_property); +} + +static void +free_val_t( + val_t *val) +{ + switch(val->type) { + case CONFTYPE_INT: + case CONFTYPE_BOOLEAN: + case CONFTYPE_NO_YES_ALL: + case CONFTYPE_COMPRESS: + case CONFTYPE_ENCRYPT: + case CONFTYPE_HOLDING: + case CONFTYPE_EXECUTE_WHERE: + case CONFTYPE_EXECUTE_ON: + case CONFTYPE_SEND_AMREPORT_ON: + case CONFTYPE_DATA_PATH: + case CONFTYPE_STRATEGY: + case CONFTYPE_SIZE: + case CONFTYPE_TAPERALGO: + case CONFTYPE_PRIORITY: + case CONFTYPE_INT64: + case CONFTYPE_REAL: + case CONFTYPE_RATE: + case CONFTYPE_INTRANGE: + case CONFTYPE_PART_CACHE_TYPE: break; - case ',': - tok = CONF_COMMA; + case CONFTYPE_IDENT: + case CONFTYPE_STR: + case CONFTYPE_APPLICATION: + amfree(val->v.s); + break; + + case CONFTYPE_IDENTLIST: + slist_free_full(val->v.identlist, g_free); break; - case '{': - tok = CONF_LBRACE; + case CONFTYPE_HOST_LIMIT: + slist_free_full(val->v.host_limit.match_pats, g_free); break; - case '}': - tok = CONF_RBRACE; + case CONFTYPE_TIME: break; - case '\n': - tok = CONF_NL; + case CONFTYPE_ESTIMATELIST: + g_slist_free(val->v.estimatelist); break; - case EOF: - tok = CONF_END; + case CONFTYPE_EXINCLUDE: + free_sl(val_t__exinclude(val).sl_list); + free_sl(val_t__exinclude(val).sl_file); break; - default: - tok = CONF_UNKNOWN; + case CONFTYPE_PROPLIST: + g_hash_table_destroy(val_t__proplist(val)); + break; + + case CONFTYPE_AUTOLABEL: + amfree(val->v.autolabel.template); break; - } } + val->seen.linenum = 0; + val->seen.filename = NULL; + val->seen.block = NULL; +} - if (exp != CONF_ANY && tok != exp) { - char *str; - keytab_t *kwp; +/* + * Utilities Implementation + */ - switch(exp) { - case CONF_LBRACE: - str = "\"{\""; - break; +char * +generic_get_security_conf( + char *string, + void *arg) +{ + arg = arg; + if(!string || !*string) + return(NULL); - case CONF_RBRACE: - str = "\"}\""; - break; + if(strcmp(string, "krb5principal")==0) { + return(getconf_str(CNF_KRB5PRINCIPAL)); + } else if(strcmp(string, "krb5keytab")==0) { + return(getconf_str(CNF_KRB5KEYTAB)); + } + return(NULL); +} - case CONF_COMMA: - str = "\",\""; - break; +char * +generic_client_get_security_conf( + char * string, + void * arg) +{ + (void)arg; /* Quiet unused parameter warning */ - case CONF_NL: - str = "end of line"; - break; + if(!string || !*string) + return(NULL); - case CONF_END: - str = "end of file"; - break; + if(strcmp(string, "conf")==0) { + return(getconf_str(CNF_CONF)); + } else if(strcmp(string, "amdump_server")==0) { + return(getconf_str(CNF_AMDUMP_SERVER)); + } else if(strcmp(string, "index_server")==0) { + return(getconf_str(CNF_INDEX_SERVER)); + } else if(strcmp(string, "tape_server")==0) { + return(getconf_str(CNF_TAPE_SERVER)); + } else if(strcmp(string, "tapedev")==0) { + return(getconf_str(CNF_TAPEDEV)); + } else if(strcmp(string, "auth")==0) { + return(getconf_str(CNF_AUTH)); + } else if(strcmp(string, "ssh_keys")==0) { + return(getconf_str(CNF_SSH_KEYS)); + } else if(strcmp(string, "amandad_path")==0) { + return(getconf_str(CNF_AMANDAD_PATH)); + } else if(strcmp(string, "client_username")==0) { + return(getconf_str(CNF_CLIENT_USERNAME)); + } else if(strcmp(string, "client_port")==0) { + return(getconf_str(CNF_CLIENT_PORT)); + } else if(strcmp(string, "gnutar_list_dir")==0) { + return(getconf_str(CNF_GNUTAR_LIST_DIR)); + } else if(strcmp(string, "amandates")==0) { + return(getconf_str(CNF_AMANDATES)); + } else if(strcmp(string, "krb5principal")==0) { + return(getconf_str(CNF_KRB5PRINCIPAL)); + } else if(strcmp(string, "krb5keytab")==0) { + return(getconf_str(CNF_KRB5KEYTAB)); + } + return(NULL); +} - case CONF_INT: - str = "an integer"; - break; +void +dump_configuration( + gboolean print_default, + gboolean print_source) +{ + tapetype_t *tp; + dumptype_t *dp; + interface_t *ip; + holdingdisk_t *hd; + GSList *hp; + application_t *ap; + pp_script_t *ps; + device_config_t *dc; + changer_config_t *cc; + interactivity_t *iv; + taperscan_t *ts; + int i; + conf_var_t *np; + keytab_t *kt; + char *prefix; - case CONF_REAL: - str = "a real number"; - break; + if (config_client) { + error(_("Don't know how to dump client configurations.")); + /* NOTREACHED */ + } - case CONF_STRING: - str = "a quoted string"; - break; + g_printf(_("# AMANDA CONFIGURATION FROM FILE \"%s\":\n\n"), config_filename); - case CONF_IDENT: - str = "an identifier"; - break; + for(np=server_var; np->token != CONF_UNKNOWN; np++) { + for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) + if (np->token == kt->token) break; - default: - for(kwp = keytable; kwp->keyword != NULL; kwp++) { - if (exp == kwp->token) + if(kt->token == CONF_UNKNOWN) + error(_("server bad token")); + + val_t_print_token(print_default, print_source, stdout, NULL, "%-21s ", kt, &conf_data[np->parm]); + } + + for(hp = holdinglist; hp != NULL; hp = hp->next) { + hd = hp->data; + g_printf("\nDEFINE HOLDINGDISK %s {\n", hd->name); + for(i=0; i < HOLDING_HOLDING; i++) { + for(np=holding_var; np->token != CONF_UNKNOWN; np++) { + if(np->parm == i) + break; + } + if(np->token == CONF_UNKNOWN) + error(_("holding bad value")); + + for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) { + if(kt->token == np->token) break; } - if (kwp->keyword == NULL) - str = "token not"; + if(kt->token == CONF_UNKNOWN) + error(_("holding bad token")); + + val_t_print_token(print_default, print_source, stdout, NULL, " %-9s ", kt, &hd->value[i]); + } + g_printf("}\n"); + } + + for(tp = tapelist; tp != NULL; tp = tp->next) { + if(tp->seen.linenum == -1) + prefix = "#"; + else + prefix = ""; + g_printf("\n%sDEFINE TAPETYPE %s {\n", prefix, tp->name); + for(i=0; i < TAPETYPE_TAPETYPE; i++) { + for(np=tapetype_var; np->token != CONF_UNKNOWN; np++) + if(np->parm == i) break; + if(np->token == CONF_UNKNOWN) + error(_("tapetype bad value")); + + for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) + if(kt->token == np->token) break; + if(kt->token == CONF_UNKNOWN) + error(_("tapetype bad token")); + + val_t_print_token(print_default, print_source, stdout, prefix, " %-9s ", kt, &tp->value[i]); + } + g_printf("%s}\n", prefix); + } + + for(dp = dumplist; dp != NULL; dp = dp->next) { + if (strncmp_const(dp->name, "custom(") != 0) { /* don't dump disklist-derived dumptypes */ + if(dp->seen.linenum == -1) + prefix = "#"; else - str = kwp->keyword; - break; + prefix = ""; + g_printf("\n%sDEFINE DUMPTYPE %s {\n", prefix, dp->name); + for(i=0; i < DUMPTYPE_DUMPTYPE; i++) { + for(np=dumptype_var; np->token != CONF_UNKNOWN; np++) + if(np->parm == i) break; + if(np->token == CONF_UNKNOWN) + error(_("dumptype bad value")); + + for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) + if(kt->token == np->token) break; + if(kt->token == CONF_UNKNOWN) + error(_("dumptype bad token")); + + val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &dp->value[i]); + } + g_printf("%s}\n", prefix); } - conf_parserror("%s is expected", str); - tok = exp; - if (tok == CONF_INT) - tokenval.v.i = 0; + } + + for(ip = interface_list; ip != NULL; ip = ip->next) { + seen_t *netusage_seen = &val_t__seen(getconf(CNF_NETUSAGE)); + if (ip->seen.linenum == netusage_seen->linenum && + ip->seen.filename && netusage_seen->filename && + 0 == strcmp(ip->seen.filename, netusage_seen->filename)) + prefix = "#"; else - tokenval.v.s = ""; + prefix = ""; + g_printf("\n%sDEFINE INTERFACE %s {\n", prefix, ip->name); + for(i=0; i < INTER_INTER; i++) { + for(np=interface_var; np->token != CONF_UNKNOWN; np++) + if(np->parm == i) break; + if(np->token == CONF_UNKNOWN) + error(_("interface bad value")); + + for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) + if(kt->token == np->token) break; + if(kt->token == CONF_UNKNOWN) + error(_("interface bad token")); + + val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &ip->value[i]); + } + g_printf("%s}\n",prefix); } -} + for(ap = application_list; ap != NULL; ap = ap->next) { + if(strcmp(ap->name,"default") == 0) + prefix = "#"; + else + prefix = ""; + g_printf("\n%sDEFINE APPLICATION %s {\n", prefix, ap->name); + for(i=0; i < APPLICATION_APPLICATION; i++) { + for(np=application_var; np->token != CONF_UNKNOWN; np++) + if(np->parm == i) break; + if(np->token == CONF_UNKNOWN) + error(_("application bad value")); -static void -read_string( - t_conf_var *np, - val_t *val) -{ - np = np; - ckseen(&val->seen); - get_conftoken(CONF_STRING); - val->v.s = newstralloc(val->v.s, tokenval.v.s); -} + for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) + if(kt->token == np->token) break; + if(kt->token == CONF_UNKNOWN) + error(_("application bad token")); -static void -read_ident( - t_conf_var *np, - val_t *val) -{ - np = np; - ckseen(&val->seen); - get_conftoken(CONF_IDENT); - val->v.s = newstralloc(val->v.s, tokenval.v.s); -} + val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &ap->value[i]); + } + g_printf("%s}\n",prefix); + } -static void -read_int( - t_conf_var *np, - val_t *val) -{ - np = np; - ckseen(&val->seen); - val->v.i = get_int(); -} + for(ps = pp_script_list; ps != NULL; ps = ps->next) { + if(strcmp(ps->name,"default") == 0) + prefix = "#"; + else + prefix = ""; + g_printf("\n%sDEFINE SCRIPT %s {\n", prefix, ps->name); + for(i=0; i < PP_SCRIPT_PP_SCRIPT; i++) { + for(np=pp_script_var; np->token != CONF_UNKNOWN; np++) + if(np->parm == i) break; + if(np->token == CONF_UNKNOWN) + error(_("script bad value")); -/* -static void -read_long( - t_conf_var *np, - val_t *val) -{ - np = np; - ckseen(&val->seen); - val->v.l = get_long(); -} -*/ + for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) + if(kt->token == np->token) break; + if(kt->token == CONF_UNKNOWN) + error(_("script bad token")); -static void -read_size( - t_conf_var *np, - val_t *val) -{ - np = np; - ckseen(&val->seen); - val->v.size = get_size(); -} + val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &ps->value[i]); + } + g_printf("%s}\n",prefix); + } -static void -read_am64( - t_conf_var *np, - val_t *val) -{ - np = np; - ckseen(&val->seen); - val->v.am64 = get_am64_t(); -} + for(dc = device_config_list; dc != NULL; dc = dc->next) { + prefix = ""; + g_printf("\n%sDEFINE DEVICE %s {\n", prefix, dc->name); + for(i=0; i < DEVICE_CONFIG_DEVICE_CONFIG; i++) { + for(np=device_config_var; np->token != CONF_UNKNOWN; np++) + if(np->parm == i) break; + if(np->token == CONF_UNKNOWN) + error(_("device bad value")); -static void -read_bool( - t_conf_var *np, - val_t *val) -{ - np = np; - ckseen(&val->seen); - val->v.i = get_bool(); -} + for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) + if(kt->token == np->token) break; + if(kt->token == CONF_UNKNOWN) + error(_("device bad token")); -static void -read_real( - t_conf_var *np, - val_t *val) -{ - np = np; - ckseen(&val->seen); - get_conftoken(CONF_REAL); - val->v.r = tokenval.v.r; -} + val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &dc->value[i]); + } + g_printf("%s}\n",prefix); + } -static void -read_time( - t_conf_var *np, - val_t *val) -{ - np = np; - ckseen(&val->seen); - val->v.t = get_time(); -} + for(cc = changer_config_list; cc != NULL; cc = cc->next) { + prefix = ""; + g_printf("\n%sDEFINE CHANGER %s {\n", prefix, cc->name); + for(i=0; i < CHANGER_CONFIG_CHANGER_CONFIG; i++) { + for(np=changer_config_var; np->token != CONF_UNKNOWN; np++) + if(np->parm == i) break; + if(np->token == CONF_UNKNOWN) + error(_("changer bad value")); -static void -copy_val_t( - val_t *valdst, - val_t *valsrc) -{ - if(valsrc->seen) { - valdst->type = valsrc->type; - valdst->seen = valsrc->seen; - switch(valsrc->type) { - case CONFTYPE_INT: - case CONFTYPE_BOOL: - case CONFTYPE_COMPRESS: - case CONFTYPE_ENCRYPT: - case CONFTYPE_HOLDING: - case CONFTYPE_ESTIMATE: - case CONFTYPE_STRATEGY: - case CONFTYPE_TAPERALGO: - case CONFTYPE_PRIORITY: - valdst->v.i = valsrc->v.i; - break; + for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) + if(kt->token == np->token) break; + if(kt->token == CONF_UNKNOWN) + error(_("changer bad token")); - case CONFTYPE_LONG: - valdst->v.l = valsrc->v.l; - break; + val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &cc->value[i]); + } + g_printf("%s}\n",prefix); + } - case CONFTYPE_SIZE: - valdst->v.size = valsrc->v.size; - break; + for(iv = interactivity_list; iv != NULL; iv = iv->next) { + prefix = ""; + g_printf("\n%sDEFINE INTERACTIVITY %s {\n", prefix, iv->name); + for(i=0; i < INTERACTIVITY_INTERACTIVITY; i++) { + for(np=interactivity_var; np->token != CONF_UNKNOWN; np++) + if(np->parm == i) break; + if(np->token == CONF_UNKNOWN) + error(_("interactivity bad value")); - case CONFTYPE_AM64: - valdst->v.am64 = valsrc->v.am64; - break; + for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) + if(kt->token == np->token) break; + if(kt->token == CONF_UNKNOWN) + error(_("interactivity bad token")); - case CONFTYPE_REAL: - valdst->v.r = valsrc->v.r; - break; + val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &iv->value[i]); + } + g_printf("%s}\n",prefix); + } - case CONFTYPE_RATE: - valdst->v.rate[0] = valsrc->v.rate[0]; - valdst->v.rate[1] = valsrc->v.rate[1]; - break; + for(ts = taperscan_list; ts != NULL; ts = ts->next) { + prefix = ""; + g_printf("\n%sDEFINE TAPERSCAN %s {\n", prefix, ts->name); + for(i=0; i < TAPERSCAN_TAPERSCAN; i++) { + for(np=taperscan_var; np->token != CONF_UNKNOWN; np++) + if(np->parm == i) break; + if(np->token == CONF_UNKNOWN) + error(_("taperscan bad value")); - case CONFTYPE_IDENT: - case CONFTYPE_STRING: - valdst->v.s = stralloc(valsrc->v.s); - break; + for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) + if(kt->token == np->token) break; + if(kt->token == CONF_UNKNOWN) + error(_("taperscan bad token")); - case CONFTYPE_TIME: - valdst->v.t = valsrc->v.t; - break; + val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &ts->value[i]); + } + g_printf("%s}\n",prefix); + } +} - case CONFTYPE_SL: - valdst->v.sl = duplicate_sl(valsrc->v.sl); - break; +void dump_dumptype( + dumptype_t *dp, + char *prefix, + gboolean print_default, + gboolean print_source) +{ + int i; + conf_var_t *np; + keytab_t *kt; - case CONFTYPE_EXINCLUDE: - valdst->v.exinclude.optional = valsrc->v.exinclude.optional; - valdst->v.exinclude.sl_list = duplicate_sl(valsrc->v.exinclude.sl_list); - valdst->v.exinclude.sl_file = duplicate_sl(valsrc->v.exinclude.sl_file); - break; + for(i=0; i < DUMPTYPE_DUMPTYPE; i++) { + for(np=dumptype_var; np->token != CONF_UNKNOWN; np++) + if(np->parm == i) break; + if(np->token == CONF_UNKNOWN) + error(_("dumptype bad value")); - case CONFTYPE_INTRANGE: - valdst->v.intrange[0] = valsrc->v.intrange[0]; - valdst->v.intrange[1] = valsrc->v.intrange[1]; - break; + for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) + if(kt->token == np->token) break; + if(kt->token == CONF_UNKNOWN) + error(_("dumptype bad token")); - } + val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &dp->value[i]); } } static void -free_val_t( - val_t *val) +val_t_print_token( + gboolean print_default, + gboolean print_source, + FILE *output, + char *prefix, + char *format, + keytab_t *kt, + val_t *val) { - switch(val->type) { - case CONFTYPE_INT: - case CONFTYPE_BOOL: - case CONFTYPE_COMPRESS: - case CONFTYPE_ENCRYPT: - case CONFTYPE_HOLDING: - case CONFTYPE_ESTIMATE: - case CONFTYPE_STRATEGY: - case CONFTYPE_SIZE: - case CONFTYPE_TAPERALGO: - case CONFTYPE_PRIORITY: - case CONFTYPE_LONG: - case CONFTYPE_AM64: - case CONFTYPE_REAL: - case CONFTYPE_RATE: - case CONFTYPE_INTRANGE: - break; + char **dispstrs, **dispstr; - case CONFTYPE_IDENT: - case CONFTYPE_STRING: - amfree(val->v.s); - break; + if (print_default == 0 && !val_t_seen(val)) { + return; + } - case CONFTYPE_TIME: - break; + dispstrs = val_t_display_strs(val, 1, print_source, TRUE); - case CONFTYPE_SL: - free_sl(val->v.sl); - break; + /* For most configuration types, this outputs + * PREFIX KEYWORD DISPSTR + * for each of the display strings. For identifiers, however, it + * simply prints the first line of the display string. + */ - case CONFTYPE_EXINCLUDE: - free_sl(val->v.exinclude.sl_list); - free_sl(val->v.exinclude.sl_file); - break; + /* Print the keyword for anything that is not itself an identifier */ + if (kt->token != CONF_IDENT) { + for(dispstr=dispstrs; *dispstr!=NULL; dispstr++) { + if (prefix) + g_fprintf(output, "%s", prefix); + g_fprintf(output, format, str_keyword(kt)); + g_fprintf(output, "%s\n", *dispstr); + } + } else { + /* for identifiers, assume there's at most one display string */ + assert(g_strv_length(dispstrs) <= 1); + if (*dispstrs) { + g_fprintf(output, "%s\n", *dispstrs); + } } - val->seen = 0; + + g_strfreev(dispstrs); } -char * -taperalgo2str( - int taperalgo) +typedef struct proplist_display_str_foreach_user_data { + char **msg; + gboolean print_source; +} proplist_display_str_foreach_user_data; + +char *source_string(seen_t *seen); +char *source_string( + seen_t *seen) { - if(taperalgo == ALGO_FIRST) return "FIRST"; - if(taperalgo == ALGO_FIRSTFIT) return "FIRSTFIT"; - if(taperalgo == ALGO_LARGEST) return "LARGEST"; - if(taperalgo == ALGO_LARGESTFIT) return "LARGESTFIT"; - if(taperalgo == ALGO_SMALLEST) return "SMALLEST"; - if(taperalgo == ALGO_LAST) return "LAST"; - return "UNKNOWN"; -} + char *buf; -static char buffer_conf_print[2049]; + if (seen->linenum) { + if (seen->block) { + buf = g_strdup_printf(" (%s file %s line %d)", + seen->block, seen->filename, seen->linenum); + } else { + buf = g_strdup_printf(" (file %s line %d)", + seen->filename, seen->linenum); + } + } else { + buf = g_strdup(" (default)"); + } + return buf; +} -static char * -conf_print( +char ** +val_t_display_strs( val_t *val, int str_need_quote, - char *prefix) + gboolean print_source, + gboolean print_unit) { - char *buf; - int free_space; + gboolean add_source = TRUE; + int i; + char **buf; + buf = malloc(3*SIZEOF(char *)); + buf[0] = NULL; + buf[1] = NULL; + buf[2] = NULL; - buffer_conf_print[0] = '\0'; - snprintf(buffer_conf_print, SIZEOF(buffer_conf_print), prefix); - free_space = SIZEOF(buffer_conf_print) - strlen(buffer_conf_print); - buf = buffer_conf_print + strlen(buffer_conf_print); switch(val->type) { case CONFTYPE_INT: - snprintf(buf, free_space, "%d", val->v.i); - break; - - case CONFTYPE_LONG: - snprintf(buf, free_space, "%ld", val->v.l); + buf[0] = vstrallocf("%d ", val_t__int(val)); + i = strlen(buf[0]) - 1; + if (print_unit && val->unit == CONF_UNIT_K) { + buf[0][i] = 'K'; + } else { + buf[0][i] = '\0'; + } break; case CONFTYPE_SIZE: - snprintf(buf, free_space, SSIZE_T_FMT, (SSIZE_T_FMT_TYPE)val->v.size); + buf[0] = vstrallocf("%zd ", (ssize_t)val_t__size(val)); + i = strlen(buf[0]) - 1; + if (print_unit && val->unit == CONF_UNIT_K) { + buf[0][i] = 'K'; + } else { + buf[0][i] = '\0'; + } break; - case CONFTYPE_AM64: - snprintf(buf, free_space, OFF_T_FMT, (OFF_T_FMT_TYPE)val->v.am64); + case CONFTYPE_INT64: + buf[0] = vstrallocf("%lld ", (long long)val_t__int64(val)); + i = strlen(buf[0]) - 1; + if (print_unit && val->unit == CONF_UNIT_K) { + buf[0][i] = 'K'; + } else { + buf[0][i] = '\0'; + } break; case CONFTYPE_REAL: - snprintf(buf, free_space, "%0.5f" , val->v.r); + buf[0] = vstrallocf("%0.5f", val_t__real(val)); break; case CONFTYPE_RATE: - snprintf(buf, free_space, "%0.5f %0.5f", - val->v.rate[0], val->v.rate[1]); + buf[0] = vstrallocf("%0.5f %0.5f", val_t__rate(val)[0], val_t__rate(val)[1]); break; case CONFTYPE_INTRANGE: - snprintf(buf, free_space, "%d,%d", - val->v.intrange[0], val->v.intrange[1]); + buf[0] = vstrallocf("%d,%d", val_t__intrange(val)[0], val_t__intrange(val)[1]); break; case CONFTYPE_IDENT: if(val->v.s) { - strncpy(buf, val->v.s, free_space); + buf[0] = stralloc(val->v.s); + } else { + buf[0] = stralloc(""); + } + break; + + case CONFTYPE_IDENTLIST: + { + GSList *ia; + int first = 1; + + buf[0] = NULL; + for (ia = val->v.identlist; ia != NULL; ia = ia->next) { + if (first) { + buf[0] = stralloc(ia->data); + first = 0; + } else { + strappend(buf[0], " "); + strappend(buf[0], ia->data); + } + } } break; - case CONFTYPE_STRING: + case CONFTYPE_STR: if(str_need_quote) { - *buf++ = '"'; - free_space++; if(val->v.s) { - strncpy(buf, val->v.s, free_space); - buffer_conf_print[SIZEOF(buffer_conf_print) - 2] = '\0'; - buffer_conf_print[strlen(buffer_conf_print)] = '"'; - buffer_conf_print[strlen(buffer_conf_print) + 1] = '\0'; + buf[0] = quote_string_always(val->v.s); } else { - *buf++ = '"'; - *buf++ = '\0'; - free_space -= 2; + buf[0] = stralloc("\"\""); } } else { if(val->v.s) { - strncpy(buf, val->v.s, free_space); + buf[0] = stralloc(val->v.s); + } else { + buf[0] = stralloc(""); + } + } + break; + + case CONFTYPE_AUTOLABEL: + { + buf[0] = quote_string_always(val->v.autolabel.template); + if (val->v.autolabel.autolabel & AL_OTHER_CONFIG) { + buf[0] = vstrextend(&buf[0], " OTHER-CONFIG", NULL); + } + if (val->v.autolabel.autolabel & AL_NON_AMANDA) { + buf[0] = vstrextend(&buf[0], " NON-AMANDA", NULL); + } + if (val->v.autolabel.autolabel & AL_VOLUME_ERROR) { + buf[0] = vstrextend(&buf[0], " VOLUME-ERROR", NULL); + } + if (val->v.autolabel.autolabel & AL_EMPTY) { + buf[0] = vstrextend(&buf[0], " EMPTY", NULL); } } break; case CONFTYPE_TIME: - snprintf(buf, free_space, "%2d%02d", - (int)val->v.t/100, (int)val->v.t % 100); + buf[0] = vstrallocf("%2d%02d", + (int)val_t__time(val)/100, (int)val_t__time(val) % 100); break; - case CONFTYPE_SL: + case CONFTYPE_EXINCLUDE: { + buf[0] = exinclude_display_str(val, 0); + buf[1] = exinclude_display_str(val, 1); break; + } - case CONFTYPE_EXINCLUDE: - buf = buffer_conf_print; - free_space = SIZEOF(buffer_conf_print); - - conf_print_exinclude(val, 1, 0, prefix, &buf ,&free_space); - *buf++ = '\n'; - free_space -= 1; - - conf_print_exinclude(val, 1, 1, prefix, &buf, &free_space); + case CONFTYPE_BOOLEAN: + if(val_t__boolean(val)) + buf[0] = stralloc("yes"); + else + buf[0] = stralloc("no"); break; - case CONFTYPE_BOOL: - if(val->v.i) - strncpy(buf, "yes", free_space); - else - strncpy(buf, "no", free_space); + case CONFTYPE_NO_YES_ALL: + switch(val_t__no_yes_all(val)) { + case 0: + buf[0] = stralloc("no"); + break; + case 1: + buf[0] = stralloc("yes"); + break; + case 2: + buf[0] = stralloc("all"); + break; + } break; case CONFTYPE_STRATEGY: - switch(val->v.i) { + switch(val_t__strategy(val)) { case DS_SKIP: - strncpy(buf, "SKIP", free_space); + buf[0] = vstrallocf("SKIP"); break; case DS_STANDARD: - strncpy(buf, "STANDARD", free_space); + buf[0] = vstrallocf("STANDARD"); break; case DS_NOFULL: - strncpy(buf, "NOFULL", free_space); + buf[0] = vstrallocf("NOFULL"); break; case DS_NOINC: - strncpy(buf, "NOINC", free_space); + buf[0] = vstrallocf("NOINC"); break; case DS_HANOI: - strncpy(buf, "HANOI", free_space); + buf[0] = vstrallocf("HANOI"); break; case DS_INCRONLY: - strncpy(buf, "INCRONLY", free_space); + buf[0] = vstrallocf("INCRONLY"); break; } break; case CONFTYPE_COMPRESS: - switch(val->v.i) { + switch(val_t__compress(val)) { case COMP_NONE: - strncpy(buf, "NONE", free_space); + buf[0] = vstrallocf("NONE"); break; case COMP_FAST: - strncpy(buf, "CLIENT FAST", free_space); + buf[0] = vstrallocf("CLIENT FAST"); break; case COMP_BEST: - strncpy(buf, "CLIENT BEST", free_space); + buf[0] = vstrallocf("CLIENT BEST"); break; case COMP_CUST: - strncpy(buf, "CLIENT CUSTOM", free_space); + buf[0] = vstrallocf("CLIENT CUSTOM"); break; case COMP_SERVER_FAST: - strncpy(buf, "SERVER FAST", free_space); + buf[0] = vstrallocf("SERVER FAST"); break; case COMP_SERVER_BEST: - strncpy(buf, "SERVER FAST", free_space); + buf[0] = vstrallocf("SERVER BEST"); break; case COMP_SERVER_CUST: - strncpy(buf, "SERVER CUSTOM", free_space); + buf[0] = vstrallocf("SERVER CUSTOM"); break; } break; - case CONFTYPE_ESTIMATE: + case CONFTYPE_ESTIMATELIST: { + estimatelist_t es = val_t__estimatelist(val); + buf[0] = stralloc(""); + while (es) { + switch((estimate_t)GPOINTER_TO_INT(es->data)) { + case ES_CLIENT: + strappend(buf[0], "CLIENT"); + break; + + case ES_SERVER: + strappend(buf[0], "SERVER"); + break; + + case ES_CALCSIZE: + strappend(buf[0], "CALCSIZE"); + break; + + case ES_ES: + break; + } + es = es->next; + if (es) + strappend(buf[0], " "); + } + break; + } + + case CONFTYPE_EXECUTE_WHERE: switch(val->v.i) { case ES_CLIENT: - strncpy(buf, "CLIENT", free_space); + buf[0] = vstrallocf("CLIENT"); break; case ES_SERVER: - strncpy(buf, "SERVER", free_space); + buf[0] = vstrallocf("SERVER"); break; + } + break; - case ES_CALCSIZE: - strncpy(buf, "CALCSIZE", free_space); + case CONFTYPE_SEND_AMREPORT_ON: + switch(val->v.i) { + case SEND_AMREPORT_ALL: + buf[0] = vstrallocf("ALL"); + break; + case SEND_AMREPORT_STRANGE: + buf[0] = vstrallocf("STRANGE"); + break; + case SEND_AMREPORT_ERROR: + buf[0] = vstrallocf("ERROR"); + break; + case SEND_AMREPORT_NEVER: + buf[0] = vstrallocf("NEVER"); break; } break; + case CONFTYPE_DATA_PATH: + buf[0] = g_strdup(data_path_to_string(val->v.i)); + break; + case CONFTYPE_ENCRYPT: - switch(val->v.i) { + switch(val_t__encrypt(val)) { case ENCRYPT_NONE: - strncpy(buf, "NONE", free_space); + buf[0] = vstrallocf("NONE"); break; case ENCRYPT_CUST: - strncpy(buf, "CLIENT", free_space); + buf[0] = vstrallocf("CLIENT"); break; case ENCRYPT_SERV_CUST: - strncpy(buf, "SERVER", free_space); + buf[0] = vstrallocf("SERVER"); + break; + } + break; + + case CONFTYPE_PART_CACHE_TYPE: + switch(val_t__part_cache_type(val)) { + case PART_CACHE_TYPE_NONE: + buf[0] = vstrallocf("NONE"); + break; + + case PART_CACHE_TYPE_DISK: + buf[0] = vstrallocf("DISK"); + break; + + case PART_CACHE_TYPE_MEMORY: + buf[0] = vstrallocf("MEMORY"); + break; + } + break; + + case CONFTYPE_HOST_LIMIT: { + GSList *iter = val_t__host_limit(val).match_pats; + + if (val_t__host_limit(val).same_host) + buf[0] = stralloc("SAME-HOST "); + else + buf[0] = stralloc(""); + + if (val_t__host_limit(val).server) + strappend(buf[0], "SERVER "); + + while (iter) { + strappend(buf[0], quote_string_always((char *)iter->data)); + strappend(buf[0], " "); + iter = iter->next; + } + break; + } + + case CONFTYPE_HOLDING: + switch(val_t__holding(val)) { + case HOLD_NEVER: + buf[0] = vstrallocf("NEVER"); + break; + + case HOLD_AUTO: + buf[0] = vstrallocf("AUTO"); + break; + + case HOLD_REQUIRED: + buf[0] = vstrallocf("REQUIRED"); + break; + } + break; + + case CONFTYPE_TAPERALGO: + buf[0] = vstrallocf("%s", taperalgo2str(val_t__taperalgo(val))); + break; + + case CONFTYPE_PRIORITY: + switch(val_t__priority(val)) { + case 0: + buf[0] = vstrallocf("LOW"); + break; + + case 1: + buf[0] = vstrallocf("MEDIUM"); + break; + + case 2: + buf[0] = vstrallocf("HIGH"); break; } - break; + break; + + case CONFTYPE_PROPLIST: { + int nb_property; + proplist_display_str_foreach_user_data user_data; + + nb_property = g_hash_table_size(val_t__proplist(val)); + g_free(buf); + buf = malloc((nb_property+1)*SIZEOF(char*)); + buf[nb_property] = NULL; + user_data.msg = buf; + user_data.print_source = print_source; + g_hash_table_foreach(val_t__proplist(val), + proplist_display_str_foreach_fn, + &user_data); + add_source = FALSE; + break; + } + + case CONFTYPE_APPLICATION: { + if (val->v.s) { + buf[0] = quote_string_always(val->v.s); + } else { + buf[0] = stralloc(""); + } + break; + } + + case CONFTYPE_EXECUTE_ON: + buf[0] = stralloc(""); + if (val->v.i != 0) { + char *sep = ""; + if (val->v.i & EXECUTE_ON_PRE_AMCHECK) { + buf[0] = vstrextend(&buf[0], sep, "PRE-AMCHECK", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_PRE_DLE_AMCHECK) { + buf[0] = vstrextend(&buf[0], sep, "PRE-DLE-AMCHECK", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_PRE_HOST_AMCHECK) { + buf[0] = vstrextend(&buf[0], sep, "PRE-HOST-AMCHECK", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_POST_DLE_AMCHECK) { + buf[0] = vstrextend(&buf[0], sep, "POST-DLE-AMCHECK", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_POST_HOST_AMCHECK) { + buf[0] = vstrextend(&buf[0], sep, "POST-HOST-AMCHECK", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_POST_AMCHECK) { + buf[0] = vstrextend(&buf[0], sep, "POST-AMCHECK", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_PRE_ESTIMATE) { + buf[0] = vstrextend(&buf[0], sep, "PRE-ESTIMATE", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_PRE_DLE_ESTIMATE) { + buf[0] = vstrextend(&buf[0], sep, "PRE-DLE-ESTIMATE", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_PRE_HOST_ESTIMATE) { + buf[0] = vstrextend(&buf[0], sep, "PRE-HOST-ESTIMATE", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_POST_DLE_ESTIMATE) { + buf[0] = vstrextend(&buf[0], sep, "POST-DLE-ESTIMATE", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_POST_HOST_ESTIMATE) { + buf[0] = vstrextend(&buf[0], sep, "POST-HOST-ESTIMATE", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_POST_ESTIMATE) { + buf[0] = vstrextend(&buf[0], sep, "POST-ESTIMATE", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_PRE_BACKUP) { + buf[0] = vstrextend(&buf[0], sep, "PRE-BACKUP", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_PRE_DLE_BACKUP) { + buf[0] = vstrextend(&buf[0], sep, "PRE-DLE-BACKUP", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_PRE_HOST_BACKUP) { + buf[0] = vstrextend(&buf[0], sep, "PRE-HOST-BACKUP", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_POST_BACKUP) { + buf[0] = vstrextend(&buf[0], sep, "POST-BACKUP", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_POST_DLE_BACKUP) { + buf[0] = vstrextend(&buf[0], sep, "POST-DLE-BACKUP", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_POST_HOST_BACKUP) { + buf[0] = vstrextend(&buf[0], sep, "POST-HOST-BACKUP", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_PRE_RECOVER) { + buf[0] = vstrextend(&buf[0], sep, "PRE-RECOVER", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_POST_RECOVER) { + buf[0] = vstrextend(&buf[0], sep, "POST-RECOVER", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_PRE_LEVEL_RECOVER) { + buf[0] = vstrextend(&buf[0], sep, "PRE-LEVEL-RECOVER", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_POST_LEVEL_RECOVER) { + buf[0] = vstrextend(&buf[0], sep, "POST-LEVEL-RECOVER", NULL); + sep = ", "; + } + if (val->v.i & EXECUTE_ON_INTER_LEVEL_RECOVER) { + buf[0] = vstrextend(&buf[0], sep, "INTER-LEVEL-RECOVER", NULL); + sep = ", "; + } + } + break; - case CONFTYPE_HOLDING: - switch(val->v.i) { - case HOLD_NEVER: - strncpy(buf, "NEVER", free_space); - break; - - case HOLD_AUTO: - strncpy(buf, "AUTO", free_space); - break; + } - case HOLD_REQUIRED: - strncpy(buf, "REQUIRED", free_space); - break; + /* add source */ + if (print_source && add_source) { + char **buf1; + for (buf1 = buf; *buf1 != NULL; buf1++) { + char *buf2 = g_strjoin("", *buf1, source_string(&val->seen), NULL); + g_free(*buf1); + *buf1 = buf2; } - break; + } + return buf; +} - case CONFTYPE_TAPERALGO: - strncpy(buf, taperalgo2str(val->v.i), free_space); - break; +int +val_t_to_execute_on( + val_t *val) +{ + if (val->type != CONFTYPE_EXECUTE_ON) { + error(_("get_conftype_execute_on: val.type is not CONFTYPE_EXECUTE_ON")); + /*NOTREACHED*/ + } + return val_t__execute_on(val); +} - case CONFTYPE_PRIORITY: - switch(val->v.i) { - case 0: - strncpy(buf, "LOW", free_space); - break; +int +val_t_to_execute_where( + val_t *val) +{ + if (val->type != CONFTYPE_EXECUTE_WHERE) { + error(_("get_conftype_execute_where: val.type is not CONFTYPE_EXECUTE_WHERE")); + /*NOTREACHED*/ + } + return val->v.i; +} - case 1: - strncpy(buf, "MEDIUM", free_space); - break; +char * +val_t_to_application( + val_t *val) +{ + if (val->type != CONFTYPE_APPLICATION) { + error(_("get_conftype_applicaiton: val.type is not CONFTYPE_APPLICATION")); + /*NOTREACHED*/ + } + return val->v.s; +} - case 2: - strncpy(buf, "HIGH", free_space); - break; - } - break; + +static void +proplist_display_str_foreach_fn( + gpointer key_p, + gpointer value_p, + gpointer user_data_p) +{ + char *property_s = quote_string_always(key_p); + property_t *property = value_p; + GSList *value; + proplist_display_str_foreach_user_data *user_data = user_data_p; + char ***msg = (char ***)&user_data->msg; + + /* What to do with property->append? it should be printed only on client */ + if (property->priority) { + **msg = vstralloc("priority ", property_s, NULL); + amfree(property_s); + } else { + **msg = property_s; + property_s = NULL; } - buffer_conf_print[SIZEOF(buffer_conf_print) - 1] = '\0'; - return buffer_conf_print; + for(value=property->values; value != NULL; value = value->next) { + char *qstr = quote_string_always((char *)value->data); + **msg = vstrextend(*msg, " ", qstr, NULL); + amfree(qstr); + } + if (user_data->print_source) { + **msg = vstrextend(*msg, source_string(&property->seen)); + } + (*msg)++; } -void conf_print_exinclude( +static char * +exinclude_display_str( val_t *val, - int str_need_quote, - int file, - char *prefix, - char **buf, - int *free_space) + int file) { - sl_t *sl; + am_sl_t *sl; sle_t *excl; + char *rval; - (void)str_need_quote; + assert(val->type == CONFTYPE_EXINCLUDE); - snprintf(*buf, *free_space, prefix); - *free_space -= strlen(prefix); - *buf += strlen(prefix); - - if (val->type != CONFTYPE_EXINCLUDE) { - strcpy(*buf, - "ERROR: conf_print_exinclude called for type != CONFTYPE_EXINCLUDE"); - return; - } + rval = stralloc(""); if (file == 0) { - sl = val->v.exinclude.sl_list; - strncpy(*buf, "LIST ", *free_space); - *buf += 5; - *free_space -= 5; + sl = val_t__exinclude(val).sl_list; + strappend(rval, "LIST"); } else { - sl = val->v.exinclude.sl_file; - strncpy(*buf, "FILE ", *free_space); - *buf += 5; - *free_space -= 5; + sl = val_t__exinclude(val).sl_file; + strappend(rval, "FILE"); } - if (val->v.exinclude.optional == 1) { - strncpy(*buf, "OPTIONAL ", *free_space); - *buf += 9; - *free_space -= 9; + if (val_t__exinclude(val).optional == 1) { + strappend(rval, " OPTIONAL"); } if (sl != NULL) { for(excl = sl->first; excl != NULL; excl = excl->next) { - if (3 + (int)strlen(excl->name) < *free_space) { - *(*buf)++ = ' '; - *(*buf)++ = '"'; - strcpy(*buf, excl->name); - *buf += strlen(excl->name); - *(*buf)++ = '"'; - *free_space -= 3 + strlen(excl->name); - } + char *qstr = quote_string_always(excl->name); + vstrextend(&rval, " ", qstr, NULL); + amfree(qstr); } } - return; -} - -static void -conf_init_string( - val_t *val, - char *s) -{ - val->seen = 0; - val->type = CONFTYPE_STRING; - if(s) - val->v.s = stralloc(s); - else - val->v.s = NULL; -} - -static void -conf_init_ident( - val_t *val, - char *s) -{ - val->seen = 0; - val->type = CONFTYPE_IDENT; - if(s) - val->v.s = stralloc(s); - else - val->v.s = NULL; + return rval; } -static void -conf_init_int( - val_t *val, - int i) +char * +taperalgo2str( + taperalgo_t taperalgo) { - val->seen = 0; - val->type = CONFTYPE_INT; - val->v.i = i; + if(taperalgo == ALGO_FIRST) return "FIRST"; + if(taperalgo == ALGO_FIRSTFIT) return "FIRSTFIT"; + if(taperalgo == ALGO_LARGEST) return "LARGEST"; + if(taperalgo == ALGO_LARGESTFIT) return "LARGESTFIT"; + if(taperalgo == ALGO_SMALLEST) return "SMALLEST"; + if(taperalgo == ALGO_LAST) return "LAST"; + return "UNKNOWN"; } -static void -conf_init_bool( - val_t *val, - int i) +char * +config_dir_relative( + char *filename) { - val->seen = 0; - val->type = CONFTYPE_BOOL; - val->v.i = i; + if (*filename == '/' || config_dir == NULL) { + return stralloc(filename); + } else { + if (config_dir[strlen(config_dir)-1] == '/') { + return vstralloc(config_dir, filename, NULL); + } else { + return vstralloc(config_dir, "/", filename, NULL); + } + } } -static void -conf_init_strategy( - val_t *val, - int i) +static int +parm_key_info( + char *key, + conf_var_t **parm, + val_t **val) { - val->seen = 0; - val->type = CONFTYPE_STRATEGY; - val->v.i = i; -} + conf_var_t *np; + keytab_t *kt; + char *s; + char ch; + char *subsec_type; + char *subsec_name; + char *subsec_key; + tapetype_t *tp; + dumptype_t *dp; + interface_t *ip; + holdingdisk_t *hp; + application_t *ap; + pp_script_t *pp; + device_config_t *dc; + changer_config_t *cc; + taperscan_t *ts; + interactivity_t *iv; + int success = FALSE; -static void -conf_init_estimate( - val_t *val, - int i) -{ - val->seen = 0; - val->type = CONFTYPE_ESTIMATE; - val->v.i = i; -} + /* WARNING: assumes globals keytable and parsetable are set correctly. */ + assert(keytable != NULL); + assert(parsetable != NULL); -static void -conf_init_taperalgo( - val_t *val, - int i) -{ - val->seen = 0; - val->type = CONFTYPE_TAPERALGO; - val->v.i = i; -} + /* make a copy we can stomp on */ + key = stralloc(key); -static void -conf_init_priority( - val_t *val, - int i) -{ - val->seen = 0; - val->type = CONFTYPE_PRIORITY; - val->v.i = i; -} + /* uppercase the key */ + for (s = key; (ch = *s) != 0; s++) { + if (islower((int)ch)) + *s = (char)toupper(ch); + } -static void -conf_init_compress( - val_t *val, - comp_t i) -{ - val->seen = 0; - val->type = CONFTYPE_COMPRESS; - val->v.i = (int)i; -} + subsec_name = strchr(key, ':'); + if (subsec_name) { + subsec_type = key; -static void -conf_init_encrypt( - val_t *val, - encrypt_t i) -{ - val->seen = 0; - val->type = CONFTYPE_ENCRYPT; - val->v.i = (int)i; -} + *subsec_name = '\0'; + subsec_name++; -static void -conf_init_holding( - val_t *val, - dump_holdingdisk_t i) -{ - val->seen = 0; - val->type = CONFTYPE_HOLDING; - val->v.i = (int)i; -} + /* convert subsec_type '-' to '_' */ + for (s = subsec_type; (ch = *s) != 0; s++) { + if (*s == '-') *s = '_'; + } -/* -static void -conf_init_long( - val_t *val, - long l) -{ - val->seen = 0; - val->type = CONFTYPE_LONG; - val->v.l = l; -} -*/ + subsec_key = strrchr(subsec_name,':'); + if(!subsec_key) goto out; /* failure */ -static void -conf_init_size( - val_t *val, - ssize_t sz) -{ - val->seen = 0; - val->type = CONFTYPE_SIZE; - val->v.size = sz; -} + *subsec_key = '\0'; + subsec_key++; -static void -conf_init_am64( - val_t *val, - off_t l) -{ - val->seen = 0; - val->type = CONFTYPE_AM64; - val->v.am64 = l; -} + /* convert subsec_key '-' to '_' */ + for (s = subsec_key; (ch = *s) != 0; s++) { + if (*s == '-') *s = '_'; + } -static void -conf_init_real( - val_t *val, - double r) -{ - val->seen = 0; - val->type = CONFTYPE_REAL; - val->v.r = r; -} + /* If the keyword doesn't exist, there's no need to look up the + * subsection -- we know it's invalid */ + for(kt = keytable; kt->token != CONF_UNKNOWN; kt++) { + if(kt->keyword && strcmp(kt->keyword, subsec_key) == 0) + break; + } + if(kt->token == CONF_UNKNOWN) goto out; -static void -conf_init_rate( - val_t *val, - double r1, - double r2) -{ - val->seen = 0; - val->type = CONFTYPE_RATE; - val->v.rate[0] = r1; - val->v.rate[1] = r2; -} + /* Otherwise, figure out which kind of subsection we're dealing with, + * and parse against that. */ + if (strcmp(subsec_type, "TAPETYPE") == 0) { + tp = lookup_tapetype(subsec_name); + if (!tp) goto out; + for(np = tapetype_var; np->token != CONF_UNKNOWN; np++) { + if(np->token == kt->token) + break; + } + if (np->token == CONF_UNKNOWN) goto out; + + if (val) *val = &tp->value[np->parm]; + if (parm) *parm = np; + success = TRUE; + } else if (strcmp(subsec_type, "DUMPTYPE") == 0) { + dp = lookup_dumptype(subsec_name); + if (!dp) goto out; + for(np = dumptype_var; np->token != CONF_UNKNOWN; np++) { + if(np->token == kt->token) + break; + } + if (np->token == CONF_UNKNOWN) goto out; + + if (val) *val = &dp->value[np->parm]; + if (parm) *parm = np; + success = TRUE; + } else if (strcmp(subsec_type, "HOLDINGDISK") == 0) { + hp = lookup_holdingdisk(subsec_name); + if (!hp) goto out; + for(np = holding_var; np->token != CONF_UNKNOWN; np++) { + if(np->token == kt->token) + break; + } + if (np->token == CONF_UNKNOWN) goto out; + + if (val) *val = &hp->value[np->parm]; + if (parm) *parm = np; + success = TRUE; + } else if (strcmp(subsec_type, "INTERFACE") == 0) { + ip = lookup_interface(subsec_name); + if (!ip) goto out; + for(np = interface_var; np->token != CONF_UNKNOWN; np++) { + if(np->token == kt->token) + break; + } + if (np->token == CONF_UNKNOWN) goto out; + + if (val) *val = &ip->value[np->parm]; + if (parm) *parm = np; + success = TRUE; + /* accept the old name here, too */ + } else if (strcmp(subsec_type, "APPLICATION_TOOL") == 0 + || strcmp(subsec_type, "APPLICATION") == 0) { + ap = lookup_application(subsec_name); + if (!ap) goto out; + for(np = application_var; np->token != CONF_UNKNOWN; np++) { + if(np->token == kt->token) + break; + } + if (np->token == CONF_UNKNOWN) goto out; + + if (val) *val = &ap->value[np->parm]; + if (parm) *parm = np; + success = TRUE; + /* accept the old name here, too */ + } else if (strcmp(subsec_type, "SCRIPT_TOOL") == 0 + || strcmp(subsec_type, "SCRIPT") == 0) { + pp = lookup_pp_script(subsec_name); + if (!pp) goto out; + for(np = pp_script_var; np->token != CONF_UNKNOWN; np++) { + if(np->token == kt->token) + break; + } + if (np->token == CONF_UNKNOWN) goto out; + + if (val) *val = &pp->value[np->parm]; + if (parm) *parm = np; + success = TRUE; + } else if (strcmp(subsec_type, "DEVICE") == 0) { + dc = lookup_device_config(subsec_name); + if (!dc) goto out; + for(np = device_config_var; np->token != CONF_UNKNOWN; np++) { + if(np->token == kt->token) + break; + } + if (np->token == CONF_UNKNOWN) goto out; + + if (val) *val = &dc->value[np->parm]; + if (parm) *parm = np; + success = TRUE; + } else if (strcmp(subsec_type, "CHANGER") == 0) { + cc = lookup_changer_config(subsec_name); + if (!cc) goto out; + for(np = changer_config_var; np->token != CONF_UNKNOWN; np++) { + if(np->token == kt->token) + break; + } + if (np->token == CONF_UNKNOWN) goto out; + + if (val) *val = &cc->value[np->parm]; + if (parm) *parm = np; + success = TRUE; + } else if (g_str_equal(subsec_type, "INTERACTIVITY")) { + iv = lookup_interactivity(subsec_name); + if (!iv) goto out; + for(np = interactivity_var; np->token != CONF_UNKNOWN; np++) { + if(np->token == kt->token) + break; + } + if (np->token == CONF_UNKNOWN) goto out; + + if (val) *val = &iv->value[np->parm]; + if (parm) *parm = np; + success = TRUE; + } else if (g_str_equal(subsec_type, "TAPERSCAN")) { + ts = lookup_taperscan(subsec_name); + if (!ts) goto out; + for(np = taperscan_var; np->token != CONF_UNKNOWN; np++) { + if(np->token == kt->token) + break; + } + if (np->token == CONF_UNKNOWN) goto out; -static void -conf_init_intrange( - val_t *val, - int i1, - int i2) -{ - val->seen = 0; - val->type = CONFTYPE_INTRANGE; - val->v.intrange[0] = i1; - val->v.intrange[1] = i2; -} + if (val) *val = &ts->value[np->parm]; + if (parm) *parm = np; + success = TRUE; + } -static void -conf_init_time( - val_t *val, - time_t t) -{ - val->seen = 0; - val->type = CONFTYPE_TIME; - val->v.t = t; -} + /* No delimiters -- we're referencing a global config parameter */ + } else { + /* convert key '-' to '_' */ + for (s = key; (ch = *s) != 0; s++) { + if (*s == '-') *s = '_'; + } -/* -static void -conf_init_sl( - val_t *val, - sl_t *sl) -{ - val->seen = 0; - val->type = CONFTYPE_AM64; - val->v.sl = sl; -} -*/ + /* look up the keyword */ + for(kt = keytable; kt->token != CONF_UNKNOWN; kt++) { + if(kt->keyword && strcmp(kt->keyword, key) == 0) + break; + } + if(kt->token == CONF_UNKNOWN) goto out; -static void -conf_init_exinclude( - val_t *val) -{ - val->seen = 0; - val->type = CONFTYPE_EXINCLUDE; - val->v.exinclude.optional = 0; - val->v.exinclude.sl_list = NULL; - val->v.exinclude.sl_file = NULL; -} + /* and then look that up in the parse table */ + for(np = parsetable; np->token != CONF_UNKNOWN; np++) { + if(np->token == kt->token) + break; + } + if(np->token == CONF_UNKNOWN) goto out; + + if (val) *val = &conf_data[np->parm]; + if (parm) *parm = np; + success = TRUE; + } + +out: + amfree(key); + return success; +} + +gint64 +find_multiplier( + char * str) +{ + keytab_t * table_entry; + + str = g_strdup(str); + g_strstrip(str); + + if (*str == '\0') { + g_free(str); + return 1; + } + + for (table_entry = numb_keytable; table_entry->keyword != NULL; + table_entry ++) { + if (strcasecmp(str, table_entry->keyword) == 0) { + g_free(str); + switch (table_entry->token) { + case CONF_MULT1K: + return 1024; + case CONF_MULT1M: + return 1024*1024; + case CONF_MULT1G: + return 1024*1024*1024; + case CONF_MULT1T: + return (gint64)1024*1024*1024*1024; + case CONF_MULT7: + return 7; + case CONF_AMINFINITY: + return G_MAXINT64; + case CONF_MULT1: + case CONF_IDENT: + return 1; + default: + /* Should not happen. */ + return 0; + } + } + } -static void -conf_set_string( - val_t *val, - char *s) -{ - val->seen = -1; - val->type = CONFTYPE_STRING; - amfree(val->v.s); - val->v.s = stralloc(s); + /* None found; this is an error. */ + g_free(str); + return 0; } -/* -static void -conf_set_int( - val_t *val, - int i) +int +string_to_boolean( + const char *str) { - val->seen = -1; - val->type = CONFTYPE_INT; - val->v.i = i; -} -*/ + keytab_t * table_entry; -static void -conf_set_bool( - val_t *val, - int i) -{ - val->seen = -1; - val->type = CONFTYPE_BOOL; - val->v.i = i; -} + if (str == NULL || *str == '\0') { + return -1; + } -static void -conf_set_compress( - val_t *val, - comp_t i) -{ - val->seen = -1; - val->type = CONFTYPE_COMPRESS; - val->v.i = (int)i; + /* 0 and 1 are not in the table, as they are parsed as ints */ + if (0 == strcmp(str, "0")) + return 0; + if (0 == strcmp(str, "1")) + return 1; + + for (table_entry = bool_keytable; table_entry->keyword != NULL; + table_entry ++) { + if (strcasecmp(str, table_entry->keyword) == 0) { + switch (table_entry->token) { + case CONF_ATRUE: + return 1; + case CONF_AFALSE: + return 0; + default: + return -1; + } + } + } + + return -1; } /* -static void -conf_set_encrypt( - val_t *val, - encrypt_t i) -{ - val->seen = -1; - val->type = CONFTYPE_COMPRESS; - val->v.i = (int)i; -} -*/ + * Error Handling Implementaiton + */ -static void -conf_set_holding( - val_t *val, - dump_holdingdisk_t i) +void config_add_error( + cfgerr_level_t level, + char * errmsg) { - val->seen = -1; - val->type = CONFTYPE_HOLDING; - val->v.i = (int)i; -} + cfgerr_level = max(cfgerr_level, level); -static void -conf_set_strategy( - val_t *val, - int i) -{ - val->seen = -1; - val->type = CONFTYPE_STRATEGY; - val->v.i = i; + g_debug("%s", errmsg); + cfgerr_errors = g_slist_append(cfgerr_errors, errmsg); } - -int -get_conftype_int( - val_t *val) +static void conf_error_common( + cfgerr_level_t level, + const char * format, + va_list argp) { - if (val->type != CONFTYPE_INT) { - error("get_conftype_int: val.type is not CONFTYPE_INT"); - /*NOTREACHED*/ - } - return val->v.i; -} + char *msg = g_strdup_vprintf(format, argp); + char *errstr = NULL; -long -get_conftype_long( - val_t *val) -{ - if (val->type != CONFTYPE_LONG) { - error("get_conftype_long: val.type is not CONFTYPE_LONG"); - /*NOTREACHED*/ - } - return val->v.l; -} + if(current_line) + errstr = g_strdup_printf(_("argument \"%s\": %s"), + current_line, msg); + else if (current_filename && current_line_num > 0) + errstr = g_strdup_printf(_("\"%s\", line %d: %s"), + current_filename, current_line_num, msg); + else + errstr = g_strdup_printf(_("parse error: %s"), msg); + amfree(msg); -off_t -get_conftype_am64( - val_t *val) -{ - if (val->type != CONFTYPE_AM64) { - error("get_conftype_am64: val.type is not CONFTYPE_AM64"); - /*NOTREACHED*/ - } - return val->v.am64; + config_add_error(level, errstr); } -double -get_conftype_real( - val_t *val) +printf_arglist_function(void conf_parserror, const char *, format) { - if (val->type != CONFTYPE_REAL) { - error("get_conftype_real: val.type is not CONFTYPE_REAL"); - /*NOTREACHED*/ - } - return val->v.r; + va_list argp; + + arglist_start(argp, format); + conf_error_common(CFGERR_ERRORS, format, argp); + arglist_end(argp); } -char * -get_conftype_string( - val_t *val) -{ - if (val->type != CONFTYPE_STRING) { - error("get_conftype_string: val.type is not CONFTYPE_STRING"); - /*NOTREACHED*/ - } - return val->v.s; +printf_arglist_function(void conf_parswarn, const char *, format) { + va_list argp; + + arglist_start(argp, format); + conf_error_common(CFGERR_WARNINGS, format, argp); + arglist_end(argp); } -char * -get_conftype_ident( - val_t *val) +cfgerr_level_t +config_errors(GSList **errstr) { - if (val->type != CONFTYPE_IDENT) { - error("get_conftype_ident: val.type is not CONFTYPE_IDENT"); - /*NOTREACHED*/ - } - return val->v.s; + if (errstr) + *errstr = cfgerr_errors; + return cfgerr_level; } -time_t -get_conftype_time( - val_t *val) +void +config_clear_errors(void) { - if (val->type != CONFTYPE_TIME) { - error("get_conftype_time: val.type is not CONFTYPE_TIME"); - /*NOTREACHED*/ - } - return val->v.t; -} + slist_free_full(cfgerr_errors, g_free); -ssize_t -get_conftype_size( - val_t *val) -{ - if (val->type != CONFTYPE_SIZE) { - error("get_conftype_size: val.type is not CONFTYPE_SIZE"); - /*NOTREACHED*/ - } - return val->v.size; + cfgerr_errors = NULL; + cfgerr_level = CFGERR_OK; } -sl_t * -get_conftype_sl( - val_t *val) +void +config_print_errors(void) { - if (val->type != CONFTYPE_SL) { - error("get_conftype_size: val.type is not CONFTYPE_SL"); - /*NOTREACHED*/ - } - return val->v.sl; -} + GSList *iter; -int -get_conftype_bool( - val_t *val) -{ - if (val->type != CONFTYPE_BOOL) { - error("get_conftype_bool: val.type is not CONFTYPE_BOOL"); - /*NOTREACHED*/ + for (iter = cfgerr_errors; iter; iter = g_slist_next(iter)) { + g_fprintf(stderr, "%s\n", (char *)iter->data); } - return val->v.i; } -int -get_conftype_hold( - val_t *val) +/* Get the config name */ +char *get_config_name(void) { - if (val->type != CONFTYPE_HOLDING) { - error("get_conftype_hold: val.type is not CONFTYPE_HOLDING"); - /*NOTREACHED*/ - } - return val->v.i; + return config_name; } -int -get_conftype_compress( - val_t *val) +/* Get the config directory */ +char *get_config_dir(void) { - if (val->type != CONFTYPE_COMPRESS) { - error("get_conftype_compress: val.type is not CONFTYPE_COMPRESS"); - /*NOTREACHED*/ - } - return val->v.i; + return config_dir; } -int -get_conftype_encrypt( - val_t *val) +/* Get the config filename */ +char *get_config_filename(void) { - if (val->type != CONFTYPE_ENCRYPT) { - error("get_conftype_encrypt: val.type is not CONFTYPE_ENCRYPT"); - /*NOTREACHED*/ - } - return val->v.i; + return config_filename; } -int -get_conftype_estimate( - val_t *val) +char * +anonymous_value(void) { - if (val->type != CONFTYPE_ESTIMATE) { - error("get_conftype_extimate: val.type is not CONFTYPE_ESTIMATE"); - /*NOTREACHED*/ - } - return val->v.i; -} + static char number[NUM_STR_SIZE]; + static int value=1; -int -get_conftype_strategy( - val_t *val) -{ - if (val->type != CONFTYPE_STRATEGY) { - error("get_conftype_strategy: val.type is not CONFTYPE_STRATEGY"); - /*NOTREACHED*/ - } - return val->v.i; -} + g_snprintf(number, sizeof(number), "%d", value); -int -get_conftype_taperalgo( - val_t *val) -{ - if (val->type != CONFTYPE_TAPERALGO) { - error("get_conftype_taperalgo: val.type is not CONFTYPE_TAPERALGO"); - /*NOTREACHED*/ - } - return val->v.i; + value++; + return number; } -int -get_conftype_priority( - val_t *val) +gint compare_pp_script_order( + gconstpointer a, + gconstpointer b) { - if (val->type != CONFTYPE_PRIORITY) { - error("get_conftype_priority: val.type is not CONFTYPE_PRIORITY"); - /*NOTREACHED*/ - } - return val->v.i; + return pp_script_get_order(lookup_pp_script((char *)a)) > pp_script_get_order(lookup_pp_script((char *)b)); } -exinclude_t -get_conftype_exinclude( - val_t *val) +char * +data_path_to_string( + data_path_t data_path) { - if (val->type != CONFTYPE_EXINCLUDE) { - error("get_conftype_exinclude: val.type is not CONFTYPE_EXINCLUDE"); - /*NOTREACHED*/ + switch (data_path) { + case DATA_PATH_AMANDA : return "AMANDA"; + case DATA_PATH_DIRECTTCP: return "DIRECTTCP"; } - return val->v.exinclude; + error(_("datapath is not DATA_PATH_AMANDA or DATA_PATH_DIRECTTCP")); + /* NOTREACHED */ } - -static void -read_block( - command_option_t *command_options, - t_conf_var *read_var, - keytab_t *keytab, - val_t *valarray, - char *prefix, - char *errormsg, - int read_brace, - void (*copy_function)(void)) +data_path_t +data_path_from_string( + char *data) { - t_conf_var *np; - int saved_conf_line_num; - int done; - - if(read_brace) { - get_conftoken(CONF_LBRACE); - get_conftoken(CONF_NL); - } - - done = 0; - do { - conf_line_num += 1; - get_conftoken(CONF_ANY); - switch(tok) { - case CONF_RBRACE: - done = 1; - break; - case CONF_NL: /* empty line */ - break; - case CONF_END: /* end of file */ - done = 1; - break; - case CONF_IDENT: - case CONF_STRING: - if(copy_function) - copy_function(); - else - conf_parserror("ident not expected"); - break; - default: - { - for(np = read_var; np->token != CONF_UNKNOWN; np++) - if(np->token == tok) break; - - if(np->token == CONF_UNKNOWN) - conf_parserror(errormsg); - else { - np->read_function(np, &valarray[np->parm]); - if(np->validate) - np->validate(np, &valarray[np->parm]); - } - } - } - if(tok != CONF_NL && tok != CONF_END && tok != CONF_RBRACE) - get_conftoken(CONF_NL); - } while(!done); - - /* overwrite with command line option */ - saved_conf_line_num = conf_line_num; - command_overwrite(command_options, read_var, keytab, valarray, prefix); - conf_line_num = saved_conf_line_num; + if (strcmp(data, "AMANDA") == 0) + return DATA_PATH_AMANDA; + if (strcmp(data, "DIRECTTCP") == 0) + return DATA_PATH_DIRECTTCP; + error(_("datapath is not AMANDA or DIRECTTCP :%s:"), data); + /* NOTREACHED */ } -void -command_overwrite( - command_option_t *command_options, - t_conf_var *overwrite_var, - keytab_t *keytab, - val_t *valarray, - char *prefix) +gchar * +amandaify_property_name( + const gchar *name) { - t_conf_var *np; - keytab_t *kt; - char *myprefix; - command_option_t *command_option; - int duplicate; + gchar *ret, *cur_r; + const gchar *cur_o; + if (!name) return NULL; - if(!command_options) return; - - for(np = overwrite_var; np->token != CONF_UNKNOWN; np++) { - for(kt = keytab; kt->token != CONF_UNKNOWN; kt++) - if(kt->token == np->token) break; - - if(kt->token == CONF_UNKNOWN) { - error("command_overwrite: invalid token"); - /* NOTREACHED */ - } + ret = g_malloc0(strlen(name)+1); + cur_r = ret; + for (cur_o = name; *cur_o; cur_o++) { + if ('_' == *cur_o) + *cur_r = '-'; + else + *cur_r = g_ascii_tolower(*cur_o); - for(command_option = command_options; command_option->name != NULL; - command_option++) { - myprefix = stralloc2(prefix, kt->keyword); - if(strcasecmp(myprefix, command_option->name) == 0) { - duplicate = 0; - if (command_option->used == 0 && - valarray[np->parm].seen == -2) { - duplicate = 1; - } - command_option->used = 1; - valarray[np->parm].seen = -2; - if(np->type == CONFTYPE_STRING && - command_option->value[0] != '"') { - conf_line = vstralloc("\"", command_option->value, "\"", - NULL); - } - else { - conf_line = stralloc(command_option->value); - } - conf_char = conf_line; - token_pushed = 0; - conf_line_num = -2; - np->read_function(np, &valarray[np->parm]); - amfree(conf_line); - conf_line = conf_char = NULL; - - if (np->validate) - np->validate(np, &valarray[np->parm]); - if (duplicate == 1) { - fprintf(stderr,"Duplicate %s option, using %s\n", - command_option->name, command_option->value); - } - } - amfree(myprefix); - } + cur_r++; } -} -void -free_new_argv( - int new_argc, - char **new_argv) -{ - int i; - for(i=0; ikeyword; + char *s = keyword_str; - tape = lookup_tapetype(conf_tapetype); - if (!tape) - return MAX_TAPE_BLOCK_KB; - return tapetype_get_readblocksize(tape); + while(*p != '\0') { + if (*p == '_') { + *s = '-'; + } else { + *s = *p; + } + p++; + s++; } + *s = '\0'; - return MAX_TAPE_BLOCK_KB; + return keyword_str; }