/* * 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. * Copyright (c) 2013-2016 Carbonite, Inc. All Rights Reserved. * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: James da Silva, Systems Design and Analysis Group * Computer Science Department * University of Maryland at College Park */ /* * $Id: conffile.c,v 1.156 2006/07/26 15:17:37 martinea Exp $ * * read configuration file */ #include "amanda.h" #include "amutil.h" #include "conffile.h" #include "clock.h" #include /* * Lexical analysis */ /* This module implements its own quixotic lexer and parser, present for historical * reasons. If this were written from scratch, it would use flex/bison. */ /* 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, CONF_REPORT_FORMAT, CONF_RETRY_DUMP, CONF_TAPEPOOL, CONF_POLICY, CONF_STORAGE, CONF_VAULT_STORAGE, CONF_CMDFILE, CONF_REST_API_PORT, CONF_REST_SSL_CERT, CONF_REST_SSL_KEY, CONF_ACTIVE_STORAGE, /* storage setting */ CONF_SET_NO_REUSE, CONF_ERASE_VOLUME, CONF_ERASE_ON_FAILURE, CONF_COMPRESS_INDEX, CONF_SORT_INDEX, CONF_ERASE_ON_FULL, /* 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, CONF_TAG, CONF_SSL_FINGERPRINT_FILE, CONF_SSL_CERT_FILE, CONF_SSL_KEY_FILE, CONF_SSL_CA_CERT_FILE, CONF_SSL_CIPHER_LIST, CONF_SSL_CHECK_HOST, CONF_SSL_CHECK_CERTIFICATE_HOST, CONF_SSL_DIR, CONF_SSL_CHECK_FINGERPRINT, /* 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, CONF_HOSTNAME, /* 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, */ CONF_SRC_IP, /* 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, /* labelstr */ CONF_MATCH_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, /* property */ CONF_HIDDEN, CONF_VISIBLE, /* numbers */ CONF_AMINFINITY, CONF_MULT1, CONF_MULT7, CONF_MULT1K, CONF_MULT1M, CONF_MULT1G, CONF_MULT1T, /* boolean */ CONF_ATRUE, CONF_AFALSE, CONF_CLIENT_NAME, /* retention */ CONF_RETENTION_TAPES, CONF_RETENTION_DAYS, CONF_RETENTION_RECOVER, CONF_RETENTION_FULL, /* dump_selection */ CONF_DUMP_SELECTION, CONF_FULL, CONF_INCR, CONF_OTHER, /* storage */ CONF_VAULT, /* internal */ CONF_PREFERED_IDENT, } 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); /* 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); /* 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); static gboolean is_valid_label(char *template); /* * 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. */ struct tapetype_s { struct tapetype_s *next; seen_t seen; char *name; val_t value[TAPETYPE_TAPETYPE]; }; struct dumptype_s { struct dumptype_s *next; seen_t seen; char *name; val_t value[DUMPTYPE_DUMPTYPE]; }; struct interface_s { struct interface_s *next; seen_t seen; char *name; val_t value[INTER_INTER]; }; struct holdingdisk_s { seen_t seen; char *name; val_t value[HOLDING_HOLDING]; }; struct application_s { struct application_s *next; seen_t seen; char *name; val_t value[APPLICATION_APPLICATION]; }; struct pp_script_s { struct pp_script_s *next; seen_t seen; char *name; val_t value[PP_SCRIPT_PP_SCRIPT]; }; struct device_config_s { struct device_config_s *next; seen_t seen; char *name; val_t value[DEVICE_CONFIG_DEVICE_CONFIG]; }; struct changer_config_s { struct changer_config_s *next; seen_t seen; char *name; val_t value[CHANGER_CONFIG_CHANGER_CONFIG]; }; struct interactivity_s { struct interactivity_s *next; seen_t seen; char *name; val_t value[INTERACTIVITY_INTERACTIVITY]; }; struct taperscan_s { struct taperscan_s *next; seen_t seen; char *name; val_t value[TAPERSCAN_TAPERSCAN]; }; struct policy_s { struct policy_s *next; seen_t seen; char *name; val_t value[POLICY_POLICY]; }; struct storage_s { struct storage_s *next; seen_t seen; char *name; val_t value[STORAGE_STORAGE]; }; /* The current parser table */ static conf_var_t *parsetable = NULL; static gboolean generate_errors = TRUE; /* 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); /* 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 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); static policy_s pocur; static void get_policy(void); static void init_policy_defaults(void); static void save_policy(void); static void copy_policy(void); static storage_t stcur; static void get_storage(void); static void init_storage_defaults(void); static void save_storage(void); static void copy_storage(void); /* read_functions -- these fit into the read_function slot in a parser * table entry, and are responsible for calling get_conftoken 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_str_list(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_dpolicy(conf_var_t *, val_t *); //static void read_dstorage(conf_var_t *, val_t *); static void read_dpp_script(conf_var_t *, val_t *); static void read_hidden_property(conf_var_t *, val_t *); static void read_visible_property(conf_var_t *, val_t *); static void read_property(val_t *val, property_t *property); 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_labelstr(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 void read_storage_identlist(conf_var_t *, val_t *); static void read_dump_selection(conf_var_t *, val_t *); static void read_vault_list(conf_var_t *np G_GNUC_UNUSED, val_t *val); 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); static policy_s *read_policy(char *name, FILE *from, char *fname, int *linenum); static storage_t *read_storage(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 slot in * a parser table entry. They call conf_parserror if the value in their * second argument is invalid. */ static void validate_name(tok_t token, val_t *val); static void validate_no_space_dquote(conf_var_t *, val_t *); 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_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_columnspec(conf_var_t *, val_t *); static void validate_tmpdir(conf_var_t *, val_t *); static void validate_deprecated_changerfile(conf_var_t *, val_t *); gint compare_pp_script_order(gconstpointer a, gconstpointer b); static void free_dump_selection(gpointer p); static void free_vault(gpointer p); /* * 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; static policy_s *policy_list = NULL; static storage_t *storage_list = NULL; /* storage for derived values */ static long int unit_divisor = 1; char *prepend_prefix = NULL; 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_str_list(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_labelstr(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); static void conf_init_dump_selection(val_t *val); static void conf_init_vault_list(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))); /* * Tables */ /* First, the keyword tables for client and server */ keytab_t client_keytab[] = { { "AMANDAD_PATH", CONF_AMANDAD_PATH }, { "AMANDATES", CONF_AMANDATES }, { "AMDUMP_SERVER", CONF_AMDUMP_SERVER }, { "APPEND", CONF_APPEND }, { "APPLICATION", CONF_APPLICATION }, { "APPLICATION_TOOL", CONF_APPLICATION_TOOL }, { "AUTH", CONF_AUTH }, { "CLIENT", CONF_CLIENT }, { "CLIENT_NAME", CONF_CLIENT_NAME }, { "CLIENT_USERNAME", CONF_CLIENT_USERNAME }, { "CLIENT_PORT", CONF_CLIENT_PORT }, { "CTIMEOUT", CONF_CTIMEOUT }, { "COMMENT", CONF_COMMENT }, { "CONF", CONF_CONF }, { "CONNECT_TRIES", CONF_CONNECT_TRIES }, { "DEBUG_AMANDAD", CONF_DEBUG_AMANDAD }, { "DEBUG_AMIDXTAPED", CONF_DEBUG_AMIDXTAPED }, { "DEBUG_AMINDEXD", CONF_DEBUG_AMINDEXD }, { "DEBUG_AMRECOVER", CONF_DEBUG_AMRECOVER }, { "DEBUG_AUTH", CONF_DEBUG_AUTH }, { "DEBUG_CHUNKER", CONF_DEBUG_CHUNKER }, { "DEBUG_DAYS", CONF_DEBUG_DAYS }, { "DEBUG_DRIVER", CONF_DEBUG_DRIVER }, { "DEBUG_DUMPER", CONF_DEBUG_DUMPER }, { "DEBUG_EVENT", CONF_DEBUG_EVENT }, { "DEBUG_HOLDING", CONF_DEBUG_HOLDING }, { "DEBUG_PLANNER", CONF_DEBUG_PLANNER }, { "DEBUG_PROTOCOL", CONF_DEBUG_PROTOCOL }, { "DEBUG_RECOVERY", CONF_DEBUG_RECOVERY }, { "DEBUG_SELFCHECK", CONF_DEBUG_SELFCHECK }, { "DEBUG_SENDBACKUP", CONF_DEBUG_SENDBACKUP }, { "DEBUG_SENDSIZE", CONF_DEBUG_SENDSIZE }, { "DEBUG_TAPER", CONF_DEBUG_TAPER }, { "DEFINE", CONF_DEFINE }, { "EXECUTE_ON", CONF_EXECUTE_ON }, { "EXECUTE_WHERE", CONF_EXECUTE_WHERE }, { "GNUTAR_LIST_DIR", CONF_GNUTAR_LIST_DIR }, { "HIDDEN", CONF_HIDDEN }, { "HOSTNAME", CONF_HOSTNAME }, { "INCLUDEFILE", CONF_INCLUDEFILE }, { "INDEX_SERVER", CONF_INDEX_SERVER }, { "INTER_LEVEL_RECOVER", CONF_INTER_LEVEL_RECOVER }, { "KRB5KEYTAB", CONF_KRB5KEYTAB }, { "KRB5PRINCIPAL", CONF_KRB5PRINCIPAL }, { "MAILER", CONF_MAILER }, { "ORDER", CONF_ORDER }, { "PLUGIN", CONF_PLUGIN }, { "PRE_AMCHECK", CONF_PRE_AMCHECK }, { "PRE_DLE_AMCHECK", CONF_PRE_DLE_AMCHECK }, { "PRE_HOST_AMCHECK", CONF_PRE_HOST_AMCHECK }, { "PRE_ESTIMATE", CONF_PRE_ESTIMATE }, { "PRE_DLE_ESTIMATE", CONF_PRE_DLE_ESTIMATE }, { "PRE_HOST_ESTIMATE", CONF_PRE_HOST_ESTIMATE }, { "PRE_BACKUP", CONF_PRE_BACKUP }, { "PRE_DLE_BACKUP", CONF_PRE_DLE_BACKUP }, { "PRE_HOST_BACKUP", CONF_PRE_HOST_BACKUP }, { "PRE_RECOVER", CONF_PRE_RECOVER }, { "PRE_LEVEL_RECOVER", CONF_PRE_LEVEL_RECOVER }, { "POST_AMCHECK", CONF_POST_AMCHECK }, { "POST_DLE_AMCHECK", CONF_POST_DLE_AMCHECK }, { "POST_HOST_AMCHECK", CONF_POST_HOST_AMCHECK }, { "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 }, { "POST_RECOVER", CONF_POST_RECOVER }, { "POST_LEVEL_RECOVER", CONF_POST_LEVEL_RECOVER }, { "PRIORITY", CONF_PRIORITY }, { "PROPERTY", CONF_PROPERTY }, { "REP_TRIES", CONF_REP_TRIES }, { "REQ_TRIES", CONF_REQ_TRIES }, { "RESERVED_UDP_PORT", CONF_RESERVED_UDP_PORT }, { "RESERVED_TCP_PORT", CONF_RESERVED_TCP_PORT }, { "SCRIPT", CONF_SCRIPT }, { "SCRIPT_TOOL", CONF_SCRIPT_TOOL }, { "SERVER", CONF_SERVER }, { "SSL_CA_CERT_FILE", CONF_SSL_CA_CERT_FILE }, { "SSL_CERT_FILE", CONF_SSL_CERT_FILE }, { "SSL_CHECK_CERTIFICATE_HOST", CONF_SSL_CHECK_CERTIFICATE_HOST }, { "SSL_CHECK_FINGERPRINT", CONF_SSL_CHECK_FINGERPRINT }, { "SSL_CHECK_HOST", CONF_SSL_CHECK_HOST }, { "SSL_CIPHER_LIST", CONF_SSL_CIPHER_LIST }, { "SSL_DIR", CONF_SSL_DIR }, { "SSL_FINGERPRINT_FILE", CONF_SSL_FINGERPRINT_FILE }, { "SSH_KEYS", CONF_SSH_KEYS }, { "SSL_KEY_FILE", CONF_SSL_KEY_FILE }, { "TAPE_SERVER", CONF_TAPE_SERVER }, { "TAPEDEV", CONF_TAPEDEV }, { "UNRESERVED_TCP_PORT", CONF_UNRESERVED_TCP_PORT }, { "VISIBLE", CONF_VISIBLE }, { NULL, CONF_IDENT }, { NULL, CONF_UNKNOWN } }; keytab_t server_keytab[] = { { "ACTIVE_STORAGE", CONF_ACTIVE_STORAGE }, { "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 }, { "VAULT_STORAGE", CONF_VAULT_STORAGE }, { "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 }, { "BUMPMULT", CONF_BUMPMULT }, { "BUMPPERCENT", CONF_BUMPPERCENT }, { "BUMPSIZE", CONF_BUMPSIZE }, { "CALCSIZE", CONF_CALCSIZE }, { "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_PORT", CONF_CLIENT_PORT }, { "CLIENT_USERNAME", CONF_CLIENT_USERNAME }, { "COLUMNSPEC", CONF_COLUMNSPEC }, { "COMMAND_FILE", CONF_CMDFILE }, { "COMMENT", CONF_COMMENT }, { "COMPRATE", CONF_COMPRATE }, { "COMPRESS", CONF_COMPRESS }, { "COMPRESS_INDEX", CONF_COMPRESS_INDEX }, { "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 }, { "DEBUG_AUTH" , CONF_DEBUG_AUTH }, { "DEBUG_EVENT" , CONF_DEBUG_EVENT }, { "DEBUG_HOLDING" , CONF_DEBUG_HOLDING }, { "DEBUG_PROTOCOL" , CONF_DEBUG_PROTOCOL }, { "DEBUG_PLANNER" , CONF_DEBUG_PLANNER }, { "DEBUG_DRIVER" , CONF_DEBUG_DRIVER }, { "DEBUG_DUMPER" , CONF_DEBUG_DUMPER }, { "DEBUG_CHUNKER" , CONF_DEBUG_CHUNKER }, { "DEBUG_TAPER" , CONF_DEBUG_TAPER }, { "DEBUG_SELFCHECK" , CONF_DEBUG_SELFCHECK }, { "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 }, { "DUMPCYCLE", CONF_DUMPCYCLE }, { "DUMPORDER", CONF_DUMPORDER }, { "DUMPTYPE", CONF_DUMPTYPE }, { "DUMPUSER", CONF_DUMPUSER }, { "DUMP_LIMIT", CONF_DUMP_LIMIT }, { "DUMP_SELECTION", CONF_DUMP_SELECTION }, { "EJECT_VOLUME", CONF_EJECT_VOLUME }, { "ERASE_VOLUME", CONF_ERASE_VOLUME }, { "ERASE_ON_FAILURE", CONF_ERASE_ON_FAILURE }, { "ERASE_ON_FULL", CONF_ERASE_ON_FULL }, { "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 }, { "EXECUTE_ON", CONF_EXECUTE_ON }, { "EXECUTE_WHERE", CONF_EXECUTE_WHERE }, { "FALLBACK_SPLITSIZE", CONF_FALLBACK_SPLITSIZE }, { "FAST", CONF_FAST }, { "FILE", CONF_EFILE }, { "FILEMARK", CONF_FILEMARK }, { "FIRST", CONF_FIRST }, { "FIRSTFIT", CONF_FIRSTFIT }, { "FULL", CONF_FULL }, { "HANOI", CONF_HANOI }, { "HIDDEN", CONF_HIDDEN }, { "HIGH", CONF_HIGH }, { "HOLDINGDISK", CONF_HOLDING }, { "IGNORE", CONF_IGNORE }, { "INCLUDE", CONF_INCLUDE }, { "INCLUDEFILE", CONF_INCLUDEFILE }, { "INCR", CONF_INCR }, { "INCRONLY", CONF_INCRONLY }, { "INDEX", CONF_INDEX }, { "INDEXDIR", CONF_INDEXDIR }, { "INFOFILE", CONF_INFOFILE }, { "INPARALLEL", CONF_INPARALLEL }, { "INTERACTIVITY", CONF_INTERACTIVITY }, { "INTERFACE", CONF_INTERFACE }, { "KENCRYPT", CONF_KENCRYPT }, { "KRB5KEYTAB", CONF_KRB5KEYTAB }, { "KRB5PRINCIPAL", CONF_KRB5PRINCIPAL }, { "LABELSTR", CONF_LABELSTR }, { "LABEL_NEW_TAPES", CONF_LABEL_NEW_TAPES }, { "LARGEST", CONF_LARGEST }, { "LARGESTFIT", CONF_LARGESTFIT }, { "LAST", CONF_LAST }, { "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 }, { "MATCH_AUTOLABEL", CONF_MATCH_AUTOLABEL }, { "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 }, { "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", CONF_OTHER }, { "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 }, { "POLICY", CONF_POLICY }, { "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 }, { "PROPERTY", CONF_PROPERTY }, { "RECORD", CONF_RECORD }, { "RECOVERY_LIMIT", CONF_RECOVERY_LIMIT }, { "REP_TRIES", CONF_REP_TRIES }, { "REPORT_FORMAT", CONF_REPORT_FORMAT }, { "REPORT_NEXT_MEDIA", CONF_REPORT_NEXT_MEDIA }, { "REPORT_USE_MEDIA", CONF_REPORT_USE_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 }, { "REST_API_PORT", CONF_REST_API_PORT }, { "REST_SSL_CERT", CONF_REST_SSL_CERT }, { "REST_SSL_KEY", CONF_REST_SSL_KEY }, { "RETRY_DUMP", CONF_RETRY_DUMP }, { "RETENTION_DAYS", CONF_RETENTION_DAYS }, { "RETENTION_FULL", CONF_RETENTION_FULL }, { "RETENTION_RECOVER", CONF_RETENTION_RECOVER }, { "RETENTION_TAPES", CONF_RETENTION_TAPES }, { "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 }, { "SERVER", CONF_SERVER }, { "SERVER_CUSTOM_COMPRESS", CONF_SRVCOMPPROG }, { "SERVER_DECRYPT_OPTION", CONF_SRV_DECRYPT_OPT }, { "SERVER_ENCRYPT", CONF_SRV_ENCRYPT }, { "SET_NO_REUSE", CONF_SET_NO_REUSE }, { "SKIP", CONF_SKIP }, { "SKIP_FULL", CONF_SKIP_FULL }, { "SKIP_INCR", CONF_SKIP_INCR }, { "SINGLE_EXECUTION", CONF_SINGLE_EXECUTION }, { "SMALLEST", CONF_SMALLEST }, { "SORT_INDEX", CONF_SORT_INDEX }, { "SPEED", CONF_SPEED }, { "SPLIT_DISKBUFFER", CONF_SPLIT_DISKBUFFER }, { "SRC_IP", CONF_SRC_IP }, { "SSH_KEYS", CONF_SSH_KEYS }, { "SSL_CA_CERT_FILE", CONF_SSL_CA_CERT_FILE }, { "SSL_CERT_FILE", CONF_SSL_CERT_FILE }, { "SSL_CHECK_CERTIFICATE_HOST", CONF_SSL_CHECK_CERTIFICATE_HOST }, { "SSL_CIPHER_LIST", CONF_SSL_CIPHER_LIST }, { "SSL_DIR", CONF_SSL_DIR }, { "SSL_FINGERPRINT_FILE", CONF_SSL_FINGERPRINT_FILE }, { "SSL_CHECK_HOST", CONF_SSL_CHECK_HOST }, { "SSL_CHECK_CERTIFICATE_HOST", CONF_SSL_CHECK_CERTIFICATE_HOST }, { "SSL_CHECK_FINGERPRINT", CONF_SSL_CHECK_FINGERPRINT }, { "SSL_KEY_FILE", CONF_SSL_KEY_FILE }, { "STANDARD", CONF_STANDARD }, { "STARTTIME", CONF_STARTTIME }, { "STORAGE", CONF_STORAGE }, { "STRANGE", CONF_STRANGE }, { "STRATEGY", CONF_STRATEGY }, { "DEVICE_OUTPUT_BUFFER_SIZE", CONF_DEVICE_OUTPUT_BUFFER_SIZE }, { "TAG", CONF_TAG }, { "TAPECYCLE", CONF_TAPECYCLE }, { "TAPEDEV", CONF_TAPEDEV }, { "TAPELIST", CONF_TAPELIST }, { "TAPEPOOL", CONF_TAPEPOOL }, { "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 }, { "USE", CONF_USE }, { "USETIMESTAMPS", CONF_USETIMESTAMPS }, { "VAULT", CONF_VAULT }, { "VISIBLE", CONF_VISIBLE }, { "VOLUME_ERROR", CONF_VOLUME_ERROR }, { NULL, CONF_IDENT }, { NULL, CONF_UNKNOWN } }; /* 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 } }; /* 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 } }; /* 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 } }; /* 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_CTIMEOUT , CONFTYPE_INT , read_int , CNF_CTIMEOUT , validate_positive }, { CONF_SSL_DIR , CONFTYPE_STR , read_str , CNF_SSL_DIR , NULL }, { CONF_SSL_CHECK_FINGERPRINT, CONFTYPE_BOOLEAN, read_bool , CNF_SSL_CHECK_FINGERPRINT , NULL }, { CONF_SSL_FINGERPRINT_FILE, CONFTYPE_STR , read_str , CNF_SSL_FINGERPRINT_FILE , NULL }, { CONF_SSL_CERT_FILE , CONFTYPE_STR , read_str , CNF_SSL_CERT_FILE , NULL }, { CONF_SSL_KEY_FILE , CONFTYPE_STR , read_str , CNF_SSL_KEY_FILE , NULL }, { CONF_SSL_CA_CERT_FILE , CONFTYPE_STR , read_str , CNF_SSL_CA_CERT_FILE , NULL }, { CONF_SSL_CIPHER_LIST , CONFTYPE_STR , read_str , CNF_SSL_CIPHER_LIST , NULL }, { CONF_SSL_CHECK_HOST , CONFTYPE_BOOLEAN , read_bool , CNF_SSL_CHECK_HOST , NULL }, { CONF_SSL_CHECK_CERTIFICATE_HOST, CONFTYPE_BOOLEAN, read_bool, CNF_SSL_CHECK_CERTIFICATE_HOST , 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_hidden_property, CNF_PROPERTY , NULL }, { CONF_APPLICATION , CONFTYPE_STR , read_dapplication, DUMPTYPE_APPLICATION, NULL }, { CONF_SCRIPT , CONFTYPE_STR , read_dpp_script, DUMPTYPE_SCRIPTLIST, NULL }, { CONF_HOSTNAME , CONFTYPE_STR , read_str , CNF_HOSTNAME , NULL }, { CONF_UNKNOWN , CONFTYPE_INT , NULL , CNF_CNF , NULL } }; 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_visible_property, CNF_DEVICE_PROPERTY , NULL }, { CONF_PROPERTY , CONFTYPE_PROPLIST , read_hidden_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 , validate_deprecated_changerfile }, { CONF_LABELSTR , CONFTYPE_LABELSTR , read_labelstr , CNF_LABELSTR , validate_no_space_dquote }, { 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_nonnegative }, { 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_positive }, { 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, NULL }, { CONF_COLUMNSPEC , CONFTYPE_STR , read_str , CNF_COLUMNSPEC , validate_columnspec }, { 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 , validate_no_space_dquote }, { CONF_META_AUTOLABEL , CONFTYPE_STR , read_str , CNF_META_AUTOLABEL , validate_no_space_dquote }, { 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_REPORT_FORMAT , CONFTYPE_STR_LIST , read_str_list , CNF_REPORT_FORMAT , NULL }, { CONF_ACTIVE_STORAGE , CONFTYPE_IDENTLIST, read_storage_identlist, CNF_ACTIVE_STORAGE , NULL }, { CONF_STORAGE , CONFTYPE_IDENTLIST, read_storage_identlist, CNF_STORAGE , NULL }, { CONF_VAULT_STORAGE , CONFTYPE_IDENTLIST, read_storage_identlist, CNF_VAULT_STORAGE , NULL }, { CONF_CMDFILE , CONFTYPE_STR , read_str , CNF_CMDFILE , NULL }, { CONF_REST_API_PORT , CONFTYPE_INT , read_int , CNF_REST_API_PORT , validate_positive }, { CONF_REST_SSL_CERT , CONFTYPE_STR , read_str , CNF_REST_SSL_CERT , NULL }, { CONF_REST_SSL_KEY , CONFTYPE_STR , read_str , CNF_REST_SSL_KEY , NULL }, { CONF_SSL_DIR , CONFTYPE_STR , read_str , CNF_SSL_DIR , NULL }, { CONF_COMPRESS_INDEX , CONFTYPE_BOOLEAN , read_bool , CNF_COMPRESS_INDEX , NULL }, { CONF_SORT_INDEX , CONFTYPE_BOOLEAN , read_bool , CNF_SORT_INDEX , NULL }, { CONF_UNKNOWN , CONFTYPE_INT , NULL , CNF_CNF , NULL } }; 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_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 , validate_nonnegative }, { CONF_BUMPMULT , CONFTYPE_REAL , read_real , DUMPTYPE_BUMPMULT , validate_bumpmult }, { CONF_BUMPSIZE , CONFTYPE_INT64 , read_int64 , DUMPTYPE_BUMPSIZE , validate_positive }, { CONF_BUMPPERCENT , CONFTYPE_INT , read_int , DUMPTYPE_BUMPPERCENT , validate_bumppercent }, { 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_hidden_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_RETRY_DUMP , CONFTYPE_INT , read_int , DUMPTYPE_RETRY_DUMP , validate_positive }, { CONF_TAG , CONFTYPE_STR_LIST , read_str_list , DUMPTYPE_TAG , NULL }, { CONF_SSL_FINGERPRINT_FILE , CONFTYPE_STR , read_str , DUMPTYPE_SSL_FINGERPRINT_FILE , NULL }, { CONF_SSL_CERT_FILE , CONFTYPE_STR , read_str , DUMPTYPE_SSL_CERT_FILE , NULL }, { CONF_SSL_KEY_FILE , CONFTYPE_STR , read_str , DUMPTYPE_SSL_KEY_FILE , NULL }, { CONF_SSL_CA_CERT_FILE , CONFTYPE_STR , read_str , DUMPTYPE_SSL_CA_CERT_FILE , NULL }, { CONF_SSL_CIPHER_LIST , CONFTYPE_STR , read_str , DUMPTYPE_SSL_CIPHER_LIST , NULL }, { CONF_SSL_CHECK_HOST , CONFTYPE_BOOLEAN , read_bool , DUMPTYPE_SSL_CHECK_HOST , NULL }, { CONF_SSL_CHECK_CERTIFICATE_HOST, CONFTYPE_BOOLEAN , read_bool , DUMPTYPE_SSL_CHECK_CERTIFICATE_HOST, NULL }, { CONF_SSL_CHECK_FINGERPRINT , CONFTYPE_BOOLEAN , read_bool , DUMPTYPE_SSL_CHECK_FINGERPRINT , NULL }, { CONF_UNKNOWN , CONFTYPE_INT , NULL , DUMPTYPE_DUMPTYPE , NULL } }; 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 } }; 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_SRC_IP , CONFTYPE_STR , read_str , INTER_SRC_IP , NULL }, { CONF_UNKNOWN, CONFTYPE_INT , NULL , INTER_INTER , NULL } }; 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_visible_property, APPLICATION_PROPERTY , NULL }, { CONF_CLIENT_NAME, CONFTYPE_STR , read_str , APPLICATION_CLIENT_NAME, NULL }, { CONF_UNKNOWN , CONFTYPE_INT , NULL , APPLICATION_APPLICATION, NULL } }; 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_visible_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 } }; conf_var_t device_config_var [] = { { CONF_COMMENT , CONFTYPE_STR , read_str , DEVICE_CONFIG_COMMENT , NULL }, { CONF_DEVICE_PROPERTY , CONFTYPE_PROPLIST , read_visible_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 } }; 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_visible_property, CHANGER_CONFIG_PROPERTY , NULL }, { CONF_DEVICE_PROPERTY , CONFTYPE_PROPLIST , read_visible_property, CHANGER_CONFIG_DEVICE_PROPERTY, NULL }, { CONF_UNKNOWN , CONFTYPE_INT , NULL , CHANGER_CONFIG_CHANGER_CONFIG , NULL } }; 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_visible_property, INTERACTIVITY_PROPERTY , NULL }, { CONF_UNKNOWN , CONFTYPE_INT , NULL , INTERACTIVITY_INTERACTIVITY , NULL } }; 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_visible_property, TAPERSCAN_PROPERTY , NULL }, { CONF_UNKNOWN , CONFTYPE_INT , NULL , TAPERSCAN_TAPERSCAN , NULL } }; conf_var_t policy_var [] = { { CONF_COMMENT , CONFTYPE_STR , read_str , POLICY_COMMENT , NULL }, { CONF_RETENTION_TAPES , CONFTYPE_INT , read_int , POLICY_RETENTION_TAPES , NULL }, { CONF_RETENTION_DAYS , CONFTYPE_INT , read_int , POLICY_RETENTION_DAYS , NULL }, { CONF_RETENTION_RECOVER, CONFTYPE_INT , read_int , POLICY_RETENTION_RECOVER, NULL }, { CONF_RETENTION_FULL , CONFTYPE_INT , read_int , POLICY_RETENTION_FULL , NULL }, { CONF_UNKNOWN , CONFTYPE_INT , NULL , POLICY_POLICY , NULL } }; conf_var_t storage_var [] = { { CONF_COMMENT , CONFTYPE_STR , read_str , STORAGE_COMMENT , NULL }, { CONF_POLICY , CONFTYPE_STR , read_dpolicy , STORAGE_POLICY , NULL }, { CONF_TAPEDEV , CONFTYPE_STR , read_str , STORAGE_TAPEDEV , NULL }, { CONF_TPCHANGER , CONFTYPE_STR , read_str , STORAGE_TPCHANGER , NULL }, { CONF_LABELSTR , CONFTYPE_LABELSTR , read_labelstr , STORAGE_LABELSTR , validate_no_space_dquote }, { CONF_AUTOLABEL , CONFTYPE_AUTOLABEL , read_autolabel , STORAGE_AUTOLABEL , validate_no_space_dquote }, { CONF_META_AUTOLABEL , CONFTYPE_STR , read_str , STORAGE_META_AUTOLABEL , validate_no_space_dquote }, { CONF_TAPEPOOL , CONFTYPE_STR , read_str , STORAGE_TAPEPOOL , validate_no_space_dquote }, { CONF_RUNTAPES , CONFTYPE_INT , read_int , STORAGE_RUNTAPES , NULL }, { CONF_TAPERSCAN , CONFTYPE_STR , read_str , STORAGE_TAPERSCAN , NULL }, { CONF_TAPETYPE , CONFTYPE_STR , read_str , STORAGE_TAPETYPE , NULL }, { CONF_MAX_DLE_BY_VOLUME , CONFTYPE_INT , read_int , STORAGE_MAX_DLE_BY_VOLUME , NULL }, { CONF_TAPERALGO , CONFTYPE_TAPERALGO , read_taperalgo , STORAGE_TAPERALGO , NULL }, { CONF_TAPER_PARALLEL_WRITE , CONFTYPE_INT , read_int , STORAGE_TAPER_PARALLEL_WRITE , NULL }, { CONF_EJECT_VOLUME , CONFTYPE_BOOLEAN , read_bool , STORAGE_EJECT_VOLUME , NULL }, { CONF_ERASE_VOLUME , CONFTYPE_BOOLEAN , read_bool , STORAGE_ERASE_VOLUME , NULL }, { CONF_DEVICE_OUTPUT_BUFFER_SIZE, CONFTYPE_SIZE , read_size , STORAGE_DEVICE_OUTPUT_BUFFER_SIZE, NULL }, { CONF_AUTOFLUSH , CONFTYPE_NO_YES_ALL , read_no_yes_all , STORAGE_AUTOFLUSH , NULL }, { CONF_FLUSH_THRESHOLD_DUMPED , CONFTYPE_INT , read_int , STORAGE_FLUSH_THRESHOLD_DUMPED , validate_nonnegative }, { CONF_FLUSH_THRESHOLD_SCHEDULED, CONFTYPE_INT , read_int , STORAGE_FLUSH_THRESHOLD_SCHEDULED, validate_nonnegative }, { CONF_TAPERFLUSH , CONFTYPE_INT , read_int , STORAGE_TAPERFLUSH , validate_nonnegative }, { CONF_REPORT_USE_MEDIA , CONFTYPE_BOOLEAN , read_bool , STORAGE_REPORT_USE_MEDIA , NULL }, { CONF_REPORT_NEXT_MEDIA , CONFTYPE_BOOLEAN , read_bool , STORAGE_REPORT_NEXT_MEDIA , NULL }, { CONF_INTERACTIVITY , CONFTYPE_STR , read_dinteractivity, STORAGE_INTERACTIVITY , NULL }, { CONF_SET_NO_REUSE , CONFTYPE_BOOLEAN , read_bool , STORAGE_SET_NO_REUSE , NULL }, { CONF_DUMP_SELECTION , CONFTYPE_DUMP_SELECTION, read_dump_selection, STORAGE_DUMP_SELECTION , NULL }, { CONF_ERASE_ON_FAILURE , CONFTYPE_BOOLEAN , read_bool , STORAGE_ERASE_ON_FAILURE , NULL }, { CONF_ERASE_ON_FULL , CONFTYPE_BOOLEAN , read_bool , STORAGE_ERASE_ON_FULL , NULL }, { CONF_VAULT , CONFTYPE_VAULT_LIST , read_vault_list , STORAGE_VAULT_LIST , NULL }, { CONF_UNKNOWN , CONFTYPE_INT , NULL , STORAGE_STORAGE , NULL } }; /* * Lexical Analysis Implementation */ static char * get_token_name( tok_t token) { keytab_t *kt; if (keytable == NULL) { error(_("keytable == NULL")); /*NOTREACHED*/ } for(kt = keytable; kt->token != CONF_UNKNOWN; kt++) if(kt->token == token) break; if(kt->token == CONF_UNKNOWN) return(""); return(kt->keyword); } static tok_t lookup_keyword( char * str) { keytab_t *kwp; char *str1 = g_strdup(str); char *p = str1; /* Fold '-' to '_' in the token. Note that this modifies str1 * in place. */ while (*p) { if (*p == '-') *p = '_'; p++; } for(kwp = keytable; kwp->keyword != NULL; kwp++) { if (strcasecmp(kwp->keyword, str1) == 0) break; } amfree(str1); return kwp->token; } static void get_conftoken( tok_t exp) { int ch, d; gint64 int64; char *buf; char *tmps; int token_overflow; int inquote = 0; int escape = 0; int sign; gboolean prefered_ident = FALSE; if (exp == CONF_PREFERED_IDENT) { exp = CONF_IDENT; prefered_ident = TRUE; } if (token_pushed) { token_pushed = 0; tok = pushed_tok; /* ** 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 */ default: if (exp == CONF_IDENT) { tok = CONF_IDENT; tokenval.type = CONFTYPE_IDENT; } else { tok = lookup_keyword(tokenval.v.s); } break; } } else { ch = conftoken_getc(); /* 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 (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 (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); } } *buf = '\0'; tokenval.v.s = tkbuf; if (token_overflow) { tok = CONF_UNKNOWN; } else if (exp == CONF_IDENT) { tok = CONF_IDENT; tokenval.type = CONFTYPE_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; } 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); } } } 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; } *buf = '\0'; /* * A little manuver to leave a fully unquoted, unallocated string * in tokenval.v.s */ tmps = unquote_string(tkbuf); g_strlcpy(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; } 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; } 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 (kwp->keyword == NULL) str = _("token not"); else str = str_keyword(kwp); break; } if (!prefered_ident || exp != CONF_IDENT) { 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) { int c; if (current_line == NULL) c = getc(current_file); else if (*current_char == '\0') return -1; else c = (*current_char++); if (c >= -1 && c <= 255) return c; else return 0; } 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 { 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 || errno != ENOENT) conf_parserror(_("could not open conf file '%s': %s"), current_filename, strerror(errno)); goto finish; } g_debug("reading config file %s", current_filename); 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); /* "application" and "script" are now preferred, but accept * "application-tool" and "script-tool" 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 or SCRIPT 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 if(tok == CONF_POLICY) get_policy(); else if(tok == CONF_STORAGE) get_storage(); else conf_parserror(_("DUMPTYPE, INTERFACE, TAPETYPE, HOLDINGDISK, APPLICATION, SCRIPT, DEVICE, CHANGER, INTERACTIVITY, TAPERSCAN, POLICY or STORAGE expected")); current_block = NULL; } break; 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 */ { CONF_USETIMESTAMPS, 0 }, /* exp. in Amanda-3.4 */ { 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 (;;) { int 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 || g_str_equal(istr, filename)) return istr; } istr = g_strdup(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; int save_line_num; 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("%d %s", tok, 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; save_line_num = current_line_num; key_ovr = g_strjoin(NULL, 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; if (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; tok = lookup_keyword(keyword); if (tok == CONF_UNKNOWN) continue; /* find the var in read_var */ for (np = read_var; np->token != CONF_UNKNOWN; np++) if (np->token == tok) 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 = g_strdup(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; } current_line_num = save_line_num; token_pushed = 0; 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; char *saved_block; saved_block = current_block; save_overwrites = allow_overwrites; allow_overwrites = 1; init_holdingdisk_defaults(); get_conftoken(CONF_IDENT); hdcur.name = g_strdup(tokenval.v.s); validate_name(CONF_HOLDING, &tokenval); 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, g_strdup(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 (g_str_equal((char *)il->data, hdcur.name)) { 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, g_strdup(hdcur.name)); } amfree(hdcur.name); get_conftoken(CONF_ANY); if (tok == CONF_IDENT || tok == CONF_STRING) { hdcur.name = g_strdup(tokenval.v.s); } else if (tok != CONF_NL) { conf_parserror(_("IDENT or NL expected")); } } while (tok == CONF_IDENT || tok == CONF_STRING); amfree(hdcur.seen.block); } allow_overwrites = save_overwrites; current_block = saved_block; } static void init_holdingdisk_defaults( void) { hdcur.name = NULL; hdcur.seen.filename = NULL; hdcur.seen.block = NULL; 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 = g_malloc(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; char *saved_block; 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; saved_block = current_block; save_overwrites = allow_overwrites; allow_overwrites = 1; init_dumptype_defaults(); if (name) { dpcur.name = name; } else { get_conftoken(CONF_IDENT); dpcur.name = g_strdup(tokenval.v.s); validate_name(CONF_DUMPTYPE, &tokenval); } 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; current_block = saved_block; 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; dpcur.seen.filename = NULL; dpcur.seen.block = 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_SSL_FINGERPRINT_FILE], ""); conf_init_str (&dpcur.value[DUMPTYPE_SSL_CERT_FILE] , ""); conf_init_str (&dpcur.value[DUMPTYPE_SSL_KEY_FILE] , ""); conf_init_str (&dpcur.value[DUMPTYPE_SSL_CA_CERT_FILE] , ""); conf_init_str (&dpcur.value[DUMPTYPE_SSL_CIPHER_LIST] , ""); conf_init_bool (&dpcur.value[DUMPTYPE_SSL_CHECK_HOST], 1); conf_init_bool (&dpcur.value[DUMPTYPE_SSL_CHECK_CERTIFICATE_HOST], 1); conf_init_bool (&dpcur.value[DUMPTYPE_SSL_CHECK_FINGERPRINT], 1); 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]); conf_init_int (&dpcur.value[DUMPTYPE_RETRY_DUMP] , CONF_UNIT_NONE, 2); conf_init_str_list (&dpcur.value[DUMPTYPE_TAG] , NULL); } 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 = g_malloc(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; char *saved_block; saved_block = current_block; save_overwrites = allow_overwrites; allow_overwrites = 1; init_tapetype_defaults(); get_conftoken(CONF_IDENT); tpcur.name = g_strdup(tokenval.v.s); validate_name(CONF_TAPETYPE, &tokenval); 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; current_block = saved_block; } static void init_tapetype_defaults(void) { tpcur.name = NULL; tpcur.seen.filename = NULL; tpcur.seen.block = NULL; 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 = g_malloc(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; char *saved_block; saved_block = current_block; save_overwrites = allow_overwrites; allow_overwrites = 1; init_interface_defaults(); get_conftoken(CONF_IDENT); ifcur.name = g_strdup(tokenval.v.s); validate_name(CONF_INTERFACE, &tokenval); 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; current_block = saved_block; return; } static void init_interface_defaults(void) { ifcur.name = NULL; ifcur.seen.filename = NULL; ifcur.seen.block = NULL; conf_init_str(&ifcur.value[INTER_COMMENT] , ""); conf_init_int(&ifcur.value[INTER_MAXUSAGE], CONF_UNIT_K, 80000); conf_init_str(&ifcur.value[INTER_SRC_IP], "NULL"); } 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 = g_malloc(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; char *saved_block; 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; saved_block = current_block; save_overwrites = allow_overwrites; allow_overwrites = 1; init_application_defaults(); if (name) { apcur.name = name; } else { get_conftoken(CONF_IDENT); apcur.name = g_strdup(tokenval.v.s); validate_name(CONF_APPLICATION, &tokenval); } 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; current_block = saved_block; 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; apcur.seen.filename = NULL; apcur.seen.block = 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 = g_malloc(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; char *saved_block; 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; saved_block = current_block; save_overwrites = allow_overwrites; allow_overwrites = 1; init_interactivity_defaults(); if (name) { ivcur.name = name; } else { get_conftoken(CONF_IDENT); ivcur.name = g_strdup(tokenval.v.s); validate_name(CONF_INTERACTIVITY, &tokenval); } 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; current_block = saved_block; 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; ivcur.seen.filename = NULL; ivcur.seen.block = 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 = g_malloc(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; char *saved_block; 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; saved_block = current_block; save_overwrites = allow_overwrites; allow_overwrites = 1; init_taperscan_defaults(); if (name) { tscur.name = name; } else { get_conftoken(CONF_IDENT); tscur.name = g_strdup(tokenval.v.s); validate_name(CONF_TAPERSCAN, &tokenval); } 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; current_block = saved_block; 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; tscur.seen.filename = NULL; tscur.seen.block = 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 = g_malloc(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 policy_s * read_policy( char *name, FILE *from, char *fname, int *linenum) { int save_overwrites; FILE *saved_conf = NULL; char *saved_fname = NULL; char *saved_block; 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; saved_block = current_block; save_overwrites = allow_overwrites; allow_overwrites = 1; init_policy_defaults(); if (name) { pocur.name = name; } else { get_conftoken(CONF_IDENT); pocur.name = g_strdup(tokenval.v.s); validate_name(CONF_POLICY, &tokenval); } current_block = g_strconcat("policy ", pocur.name, NULL); pocur.seen.block = current_block; pocur.seen.filename = current_filename; pocur.seen.linenum = current_line_num; read_block(policy_var, pocur.value, _("policy parameter expected"), (name == NULL), *copy_policy, "POLICY", pocur.name); if(!name) get_conftoken(CONF_NL); save_policy(); allow_overwrites = save_overwrites; current_block = saved_block; if (linenum) *linenum = current_line_num; if (fname) current_filename = saved_fname; if (from) current_file = saved_conf; return lookup_policy(pocur.name); } static void get_policy( void) { read_policy(NULL, NULL, NULL, NULL); } static void init_policy_defaults( void) { pocur.name = NULL; pocur.seen.filename = NULL; pocur.seen.block = NULL; conf_init_str(&pocur.value[POLICY_COMMENT] , ""); conf_init_int(&pocur.value[POLICY_RETENTION_TAPES] , CONF_UNIT_NONE, 0); conf_init_int(&pocur.value[POLICY_RETENTION_DAYS] , CONF_UNIT_NONE, 0); conf_init_int(&pocur.value[POLICY_RETENTION_RECOVER], CONF_UNIT_NONE, 0); conf_init_int(&pocur.value[POLICY_RETENTION_FULL] , CONF_UNIT_NONE, 0); } static void save_policy( void) { policy_s *po, *po1; po = lookup_policy(pocur.name); if (po != (policy_s *)0) { conf_parserror(_("policy %s already defined at %s:%d"), po->name, po->seen.filename, po->seen.linenum); return; } po = g_malloc(sizeof(policy_s)); *po = pocur; po->next = NULL; /* add at end of list */ if (!policy_list) policy_list = po; else { po1 = policy_list; while (po1->next != NULL) { po1 = po1->next; } po1->next = po; } } static void copy_policy(void) { policy_s *po; int i; po = lookup_policy(tokenval.v.s); if (po == NULL) { conf_parserror(_("policy parameter expected")); return; } for (i=0; i < POLICY_POLICY; i++) { if(po->value[i].seen.linenum) { merge_val_t(&pocur.value[i], &po->value[i]); } } } static storage_t * read_storage( char *name, FILE *from, char *fname, int *linenum) { int save_overwrites; FILE *saved_conf = NULL; char *saved_fname = NULL; char *saved_block; 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; saved_block = current_block; save_overwrites = allow_overwrites; allow_overwrites = 1; init_storage_defaults(); if (name) { stcur.name = name; } else { get_conftoken(CONF_IDENT); stcur.name = g_strdup(tokenval.v.s); validate_name(CONF_STORAGE, &tokenval); } current_block = g_strconcat("storage ", stcur.name, NULL); stcur.seen.block = current_block; stcur.seen.filename = current_filename; stcur.seen.linenum = current_line_num; read_block(storage_var, stcur.value, _("storage parameter expected"), (name == NULL), *copy_storage, "STORAGE", stcur.name); if(!name) get_conftoken(CONF_NL); save_storage(); allow_overwrites = save_overwrites; current_block = saved_block; if (linenum) *linenum = current_line_num; if (fname) current_filename = saved_fname; if (from) current_file = saved_conf; return lookup_storage(stcur.name); } static void get_storage( void) { read_storage(NULL, NULL, NULL, NULL); } static void init_storage_defaults( void) { stcur.name = NULL; stcur.seen.filename = NULL; stcur.seen.block = NULL; conf_init_str (&stcur.value[STORAGE_COMMENT] , ""); conf_init_str (&stcur.value[STORAGE_POLICY] , ""); conf_init_str (&stcur.value[STORAGE_TAPEDEV] , ""); conf_init_str (&stcur.value[STORAGE_TPCHANGER] , ""); conf_init_labelstr (&stcur.value[STORAGE_LABELSTR]); conf_init_str (&stcur.value[STORAGE_META_AUTOLABEL] , ""); conf_init_autolabel (&stcur.value[STORAGE_AUTOLABEL]); conf_init_str (&stcur.value[STORAGE_TAPEPOOL] , NULL); conf_init_int (&stcur.value[STORAGE_RUNTAPES] , CONF_UNIT_NONE, 1); conf_init_str (&stcur.value[STORAGE_TAPERSCAN] , NULL); conf_init_str (&stcur.value[STORAGE_TAPETYPE] , "DEFAULT_TAPE"); conf_init_int (&stcur.value[STORAGE_MAX_DLE_BY_VOLUME] , CONF_UNIT_NONE, 1000000000); conf_init_taperalgo (&stcur.value[STORAGE_TAPERALGO] , 0); conf_init_int (&stcur.value[STORAGE_TAPER_PARALLEL_WRITE] , CONF_UNIT_NONE, 0); conf_init_bool (&stcur.value[STORAGE_EJECT_VOLUME] , 0); conf_init_bool (&stcur.value[STORAGE_ERASE_VOLUME] , 0); conf_init_size (&stcur.value[STORAGE_DEVICE_OUTPUT_BUFFER_SIZE], CONF_UNIT_NONE, 0); conf_init_no_yes_all (&stcur.value[STORAGE_AUTOFLUSH] , 0); conf_init_int (&stcur.value[STORAGE_FLUSH_THRESHOLD_DUMPED] , CONF_UNIT_NONE, 0); conf_init_int (&stcur.value[STORAGE_FLUSH_THRESHOLD_SCHEDULED], CONF_UNIT_NONE, 0); conf_init_int (&stcur.value[STORAGE_TAPERFLUSH] , CONF_UNIT_NONE, 0); conf_init_bool (&stcur.value[STORAGE_REPORT_USE_MEDIA] , TRUE); conf_init_bool (&stcur.value[STORAGE_REPORT_NEXT_MEDIA] , TRUE); conf_init_str (&stcur.value[STORAGE_INTERACTIVITY] , NULL); conf_init_bool (&stcur.value[STORAGE_SET_NO_REUSE] , FALSE); conf_init_dump_selection(&stcur.value[STORAGE_DUMP_SELECTION]); conf_init_bool (&stcur.value[STORAGE_ERASE_ON_FAILURE] , 0); conf_init_bool (&stcur.value[STORAGE_ERASE_ON_FULL] , 0); conf_init_vault_list (&stcur.value[STORAGE_VAULT_LIST]); } static void save_storage( void) { storage_t *st, *st1; st = lookup_storage(stcur.name); if (st != (storage_t *)0) { conf_parserror(_("storage %s already defined at %s:%d"), st->name, st->seen.filename, st->seen.linenum); return; } st = g_malloc(sizeof(storage_t)); *st = stcur; st->next = NULL; /* add at end of list */ if (!storage_list) storage_list = st; else { st1 = storage_list; while (st1->next != NULL) { st1 = st1->next; } st1->next = st; } } static void copy_storage(void) { storage_t *st; int i; st = lookup_storage(tokenval.v.s); if (st == NULL) { conf_parserror(_("storage parameter expected")); return; } for (i=0; i < STORAGE_STORAGE; i++) { if(st->value[i].seen.linenum) { merge_val_t(&stcur.value[i], &st->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; char *saved_block; 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; saved_block = current_block; save_overwrites = allow_overwrites; allow_overwrites = 1; init_pp_script_defaults(); if (name) { pscur.name = name; } else { get_conftoken(CONF_IDENT); pscur.name = g_strdup(tokenval.v.s); validate_name(CONF_SCRIPT, &tokenval); } 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; current_block = saved_block; 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; pscur.seen.filename = NULL; pscur.seen.block = 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], EXECUTE_WHERE_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 = g_malloc(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; char *saved_block; 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; saved_block = current_block; save_overwrites = allow_overwrites; allow_overwrites = 1; init_device_config_defaults(); if (name) { dccur.name = name; } else { get_conftoken(CONF_IDENT); dccur.name = g_strdup(tokenval.v.s); validate_name(CONF_DEVICE, &tokenval); } 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; current_block = saved_block; 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; dccur.seen.filename = NULL; dccur.seen.block = 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 = g_malloc(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; char *saved_block; 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; saved_block = current_block; save_overwrites = allow_overwrites; allow_overwrites = 1; init_changer_config_defaults(); if (name) { cccur.name = name; } else { get_conftoken(CONF_IDENT); cccur.name = g_strdup(tokenval.v.s); validate_name(CONF_CHANGER, &tokenval); } 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; current_block = saved_block; if (linenum) *linenum = current_line_num; if (fname) current_filename = saved_fname; if (from) current_file = saved_conf; return lookup_changer_config(cccur.name); } static void get_changer_config( void) { read_changer_config(NULL, NULL, NULL, NULL); } static void init_changer_config_defaults( void) { cccur.name = NULL; cccur.seen.filename = NULL; cccur.seen.block = 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]); } static void save_changer_config( void) { changer_config_t *dc, *dc1; 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 = g_malloc(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; } 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]); } } } /* Read functions */ static void read_int( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); val_t__int(val) = get_int(val->unit); } static void read_int64( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); val_t__int64(val) = get_int64(val->unit); } static void read_real( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); get_conftoken(CONF_REAL); val_t__real(val) = tokenval.v.r; } static void read_str( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); get_conftoken(CONF_STRING); g_free(val->v.s); val->v.s = g_strdup(tokenval.v.s); } static void read_str_list( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); get_conftoken(CONF_ANY); if (tok == CONF_APPEND) { get_conftoken(CONF_ANY); } else { free_val_t(val); val->v.identlist = NULL; ckseen(&val->seen); } while (tok == CONF_STRING) { val->v.identlist = g_slist_append(val->v.identlist, g_strdup(tokenval.v.s)); get_conftoken(CONF_ANY); } if (tok != CONF_NL && tok != CONF_END) { conf_parserror(_("string expected")); unget_conftoken(); } } static void read_ident( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); get_conftoken(CONF_IDENT); g_free(val->v.s); val->v.s = g_strdup(tokenval.v.s); } static void read_storage_identlist( conf_var_t *np G_GNUC_UNUSED, val_t *val) { free_val_t(val); ckseen(&val->seen); val->v.identlist = NULL; get_conftoken(CONF_PREFERED_IDENT); while (tok == CONF_STRING || tok == CONF_IDENT) { if (strlen(tokenval.v.s) == 0) { free_val_t(val); } else { val->v.identlist = g_slist_append(val->v.identlist, g_strdup(tokenval.v.s)); } get_conftoken(CONF_PREFERED_IDENT); } if (tok != CONF_NL && tok != CONF_END) { conf_parserror(_("string expected")); unget_conftoken(); } } static void read_dump_selection( conf_var_t *np G_GNUC_UNUSED, val_t *val) { dump_selection_t *ds = g_new0(dump_selection_t, 1); dump_selection_list_t dsl; gboolean found = FALSE; ds->tag = NULL; ds->tag_type = TAG_ALL; ds->level = LEVEL_ALL; ckseen(&val->seen); get_conftoken(CONF_ANY); if (tok == CONF_STRING) { ds->tag_type = TAG_NAME; ds->tag = g_strdup(tokenval.v.s); } else if (tok == CONF_ALL) { ds->tag_type = TAG_ALL; } else if (tok == CONF_OTHER) { ds->tag_type = TAG_OTHER; } else if (tok == CONF_NL || tok == CONF_END) { free_val_t(val); val->v.dump_selection = NULL; ckseen(&val->seen); return; } else { conf_parserror(_("string, ALL or OTHER expected")); } get_conftoken(CONF_ANY); if (tok == CONF_ALL) { ds->level = LEVEL_ALL; } else if (tok == CONF_FULL) { ds->level = LEVEL_FULL; } else if (tok == CONF_INCR) { ds->level = LEVEL_INCR; } else { conf_parserror(_("ALL, FULL or INCR expected")); } get_conftoken(CONF_ANY); if (tok != CONF_NL && tok != CONF_END) { conf_parserror(_("string expected")); unget_conftoken(); } //replace if already exists for (dsl = val->v.dump_selection ; dsl != NULL ; dsl = dsl->next) { dump_selection_t *ds1 = dsl->data; if (ds->tag_type == ds1->tag_type) { if (ds->tag_type != TAG_NAME || g_str_equal(ds->tag, ds1->tag)) { ds1->level = ds->level; found = TRUE; } } } if (!found) { val->v.dump_selection = g_slist_append(val->v.dump_selection, ds); if (ds->tag_type == TAG_NAME && strlen(ds->tag) == 0) { free_val_t(val); } } else { g_free(ds->tag); g_free(ds); } } static void read_time( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); val_t__time(val) = get_time(); } static void read_size( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); val_t__size(val) = get_size(val->unit); } static void read_bool( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); val_t__boolean(val) = get_bool(); } static void read_no_yes_all( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); val_t__int(val) = get_no_yes_all(); } static void read_compress( conf_var_t *np G_GNUC_UNUSED, val_t *val) { 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; } val_t__compress(val) = (int)comp; } static void read_encrypt( conf_var_t *np G_GNUC_UNUSED, val_t *val) { 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); g_slist_free(val->v.estimatelist); 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; } val_t__strategy(val) = strat; } static void read_taperalgo( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); 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")); } } static void read_send_amreport_on( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); 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")); } } static void read_data_path( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); 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")); } } static void read_priority( conf_var_t *np G_GNUC_UNUSED, val_t *val) { int pri; ckseen(&val->seen); get_conftoken(CONF_ANY); switch(tok) { case CONF_LOW: pri = PRIORITY_LOW; break; case CONF_MEDIUM: pri = PRIORITY_MEDIUM; break; case CONF_HIGH: pri = PRIORITY_HIGH; break; case CONF_INT: pri = tokenval.v.i; break; default: conf_parserror(_("LOW, MEDIUM, HIGH or integer expected")); pri = 0; } val_t__priority(val) = pri; } static void read_rate( conf_var_t *np G_GNUC_UNUSED, val_t *val) { 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")); } get_conftoken(CONF_ANY); switch(tok) { case CONF_NL: return; case CONF_END: return; case CONF_COMMA: break; default: unget_conftoken(); } 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")); } } static void read_exinclude( conf_var_t *np G_GNUC_UNUSED, val_t *val) { int file, got_one = 0; am_sl_t *exclude; int optional = 0; 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(tok == CONF_OPTIONAL) { get_conftoken(CONF_ANY); optional = 1; } if(tok == CONF_APPEND) { get_conftoken(CONF_ANY); } else { free_sl(exclude); exclude = NULL; } while(tok == CONF_STRING) { exclude = append_sl(exclude, tokenval.v.s); got_one = 1; get_conftoken(CONF_ANY); } unget_conftoken(); if(got_one == 0) { free_sl(exclude); exclude = NULL; } 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 void read_intrange( conf_var_t *np G_GNUC_UNUSED, val_t *val) { get_conftoken(CONF_INT); val_t__intrange(val)[0] = tokenval.v.i; val_t__intrange(val)[1] = tokenval.v.i; val->seen = tokenval.seen; get_conftoken(CONF_ANY); switch(tok) { case CONF_NL: return; case CONF_END: return; case CONF_COMMA: break; default: unget_conftoken(); } get_conftoken(CONF_INT); val_t__intrange(val)[1] = tokenval.v.i; } static void read_hidden_property( conf_var_t *np G_GNUC_UNUSED, val_t *val) { property_t *property = malloc(sizeof(property_t)); property->append = 0; property->visible = 0; property->priority = 0; property->values = NULL; read_property(val, property); } static void read_visible_property( conf_var_t *np G_GNUC_UNUSED, val_t *val) { property_t *property = malloc(sizeof(property_t)); property->append = 0; property->visible = 1; property->priority = 0; property->values = NULL; read_property(val, property); } static void read_property( val_t *val, property_t *property) { char *key; gboolean set_seen = TRUE; property_t *old_property; 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_HIDDEN) { property->visible = 0; get_conftoken(CONF_ANY); } else if (tok == CONF_VISIBLE) { property->visible = 1; get_conftoken(CONF_ANY); } if (tok != CONF_STRING) { amfree(property); conf_parserror(_("key expected")); amfree(property); return; } key = amandaify_property_name(tokenval.v.s); get_conftoken(CONF_ANY); if (tok == CONF_NL || tok == CONF_END) { g_hash_table_remove(val->v.proplist, key); unget_conftoken(); amfree(property); return; } if (tok != CONF_STRING) { amfree(property); conf_parserror(_("value expected")); return; } if(val->seen.linenum == 0) { ckseen(&val->seen); // first property } 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, g_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 read_dapplication( conf_var_t *np G_GNUC_UNUSED, val_t *val) { application_t *application; amfree(val->v.s); get_conftoken(CONF_ANY); if (tok == CONF_LBRACE) { current_line_num -= 1; application = read_application(custom_escape(g_strjoin(NULL, "custom(DUMPTYPE:", dpcur.name, ")", ".", anonymous_value(),NULL)), NULL, NULL, NULL); current_line_num -= 1; val->v.s = g_strdup(application->name); } else if (tok == CONF_STRING) { application = lookup_application(tokenval.v.s); if (strlen(tokenval.v.s) != 0) { if (application == NULL) { conf_parserror(_("Unknown application named: %s"), tokenval.v.s); return; } val->v.s = g_strdup(application->name); } } else { conf_parserror(_("application name expected: %d %d"), tok, CONF_STRING); return; } ckseen(&val->seen); } static void read_dinteractivity( conf_var_t *np G_GNUC_UNUSED, val_t *val) { interactivity_t *interactivity; amfree(val->v.s); get_conftoken(CONF_ANY); if (tok == CONF_LBRACE) { current_line_num -= 1; interactivity = read_interactivity(custom_escape(g_strjoin(NULL, "custom(iv)", ".", anonymous_value(),NULL)), NULL, NULL, NULL); current_line_num -= 1; val->v.s = g_strdup(interactivity->name); } else if (tok == CONF_STRING) { if (strlen(tokenval.v.s) != 0) { interactivity = lookup_interactivity(tokenval.v.s); if (interactivity == NULL) { conf_parserror(_("Unknown interactivity named: %s"), tokenval.v.s); return; } val->v.s = g_strdup(interactivity->name); } } else { conf_parserror(_("interactivity name expected: %d %d"), tok, CONF_STRING); return; } ckseen(&val->seen); } static void read_dtaperscan( conf_var_t *np G_GNUC_UNUSED, val_t *val) { taperscan_t *taperscan; amfree(val->v.s); get_conftoken(CONF_ANY); if (tok == CONF_LBRACE) { current_line_num -= 1; taperscan = read_taperscan(custom_escape(g_strjoin(NULL, "custom(ts)", ".", anonymous_value(),NULL)), NULL, NULL, NULL); current_line_num -= 1; val->v.s = g_strdup(taperscan->name); } else if (tok == CONF_STRING) { if (strlen(tokenval.v.s) != 0) { taperscan = lookup_taperscan(tokenval.v.s); if (taperscan == NULL) { conf_parserror(_("Unknown taperscan named: %s"), tokenval.v.s); return; } val->v.s = g_strdup(taperscan->name); } } else { conf_parserror(_("taperscan name expected: %d %d"), tok, CONF_STRING); return; } ckseen(&val->seen); } static void read_dpolicy( conf_var_t *np G_GNUC_UNUSED, val_t *val) { policy_s *policy; amfree(val->v.s); get_conftoken(CONF_ANY); if (tok == CONF_LBRACE) { current_line_num -= 1; policy = read_policy(custom_escape(g_strjoin(NULL, "custom(po)", ".", anonymous_value(),NULL)), NULL, NULL, NULL); current_line_num -= 1; val->v.s = g_strdup(policy->name); } else if (tok == CONF_STRING) { if (strlen(tokenval.v.s) != 0) { policy = lookup_policy(tokenval.v.s); if (policy == NULL) { conf_parserror(_("Unknown policy named: %s"), tokenval.v.s); return; } val->v.s = g_strdup(policy->name); } } else { conf_parserror(_("policy name expected: %d %d"), tok, CONF_STRING); return; } ckseen(&val->seen); } /* static void read_dstorage( conf_var_t *np G_GNUC_UNUSED, val_t *val) { storage_t *storage; get_conftoken(CONF_ANY); if (tok == CONF_LBRACE) { current_line_num -= 1; storage = read_storage(custom_escape(g_strjoin(NULL, "custom(po)", ".", anonymous_value(),NULL)), NULL, NULL, NULL); current_line_num -= 1; } else if (tok == CONF_STRING) { storage = lookup_storage(tokenval.v.s); if (storage == NULL) { conf_parserror(_("Unknown storage named: %s"), tokenval.v.s); return; } } else { conf_parserror(_("storage name expected: %d %d"), tok, CONF_STRING); return; } amfree(val->v.s); val->v.s = g_strdup(storage->name); ckseen(&val->seen); } */ 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(custom_escape(g_strjoin(NULL, "custom(DUMPTYPE:", dpcur.name, ")", ".", anonymous_value(),NULL)), NULL, NULL, NULL); current_line_num -= 1; val->v.identlist = g_slist_insert_sorted(val->v.identlist, g_strdup(pp_script->name), &compare_pp_script_order); } else if (tok == CONF_STRING || tok == CONF_IDENT) { while (tok == CONF_STRING || tok == CONF_IDENT) { if (strlen(tokenval.v.s) == 0) { slist_free_full(val->v.identlist, g_free); val->v.identlist = NULL; } else { 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, g_strdup(pp_script->name), &compare_pp_script_order); } get_conftoken(CONF_ANY); } unget_conftoken(); } else { conf_parserror(_("pp_script name expected: %d %d"), tok, CONF_STRING); return; } ckseen(&val->seen); } static void read_execute_on( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); 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); } static void read_execute_where( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); get_conftoken(CONF_ANY); switch(tok) { case CONF_CLIENT: val->v.i = EXECUTE_WHERE_CLIENT; break; case CONF_SERVER: val->v.i = EXECUTE_WHERE_SERVER; break; default: conf_parserror(_("CLIENT or SERVER expected")); } } static void read_int_or_str( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); get_conftoken(CONF_ANY); switch(tok) { case CONF_INT: amfree(val->v.s); val->v.s = g_strdup_printf("%d", tokenval.v.i); break; case CONF_SIZE: amfree(val->v.s); val->v.s = g_strdup_printf("%zu", tokenval.v.size); break; case CONF_INT64: amfree(val->v.s); val->v.s = g_strdup_printf("%jd", (intmax_t)tokenval.v.int64); break; case CONF_STRING: g_free(val->v.s); val->v.s = g_strdup(tokenval.v.s); break; default: conf_parserror(_("an integer or a quoted string is expected")); } } static void read_autolabel( conf_var_t *np G_GNUC_UNUSED, val_t *val) { int data = 0; ckseen(&val->seen); get_conftoken(CONF_ANY); if (tok == CONF_STRING) { data++; g_free(val->v.autolabel.template); val->v.autolabel.template = g_strdup(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 read_labelstr( conf_var_t *np G_GNUC_UNUSED, val_t *val) { ckseen(&val->seen); get_conftoken(CONF_ANY); if (tok == CONF_STRING) { g_free(val->v.labelstr.template); val->v.labelstr.template = g_strdup(tokenval.v.s); val->v.labelstr.match_autolabel = FALSE; get_conftoken(CONF_ANY); if (g_strcasecmp(val->v.labelstr.template, "match-autolabel") == 0 || g_strcasecmp(val->v.labelstr.template, "match_autolabel") == 0) { conf_parswarn("warning: labelstr is set to \"%s\", you probably want the %s keyword, without the double quote", val->v.labelstr.template, val->v.labelstr.template); } } else if (tok == CONF_MATCH_AUTOLABEL) { g_free(val->v.labelstr.template); val->v.labelstr.template = NULL; val->v.labelstr.match_autolabel = TRUE; } else { conf_parserror(_("labelstr template or MATCH_AUTOLABEL expected")); } } static void read_part_cache_type( conf_var_t *np G_GNUC_UNUSED, val_t *val) { part_cache_type_t part_cache_type; ckseen(&val->seen); get_conftoken(CONF_ANY); switch(tok) { case CONF_NONE: part_cache_type = PART_CACHE_TYPE_NONE; break; 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 read_host_limit( conf_var_t *np G_GNUC_UNUSED, val_t *val) { host_limit_t *rl = &val_t__host_limit(val); ckseen(&val->seen); rl->match_pats = NULL; rl->same_host = FALSE; rl->server = FALSE; 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; 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 read_vault_list( conf_var_t *np G_GNUC_UNUSED, val_t *val) { int nb_vault = 0; ckseen(&val->seen); get_conftoken(CONF_ANY); while (tok == CONF_STRING || tok == CONF_IDENT) { char *storage = g_strdup(tokenval.v.s); int days = get_int(CONF_UNIT_NONE); vault_list_t vl; gboolean found = FALSE; // Check if the vault is already in the list (Will only update days) for (vl = val->v.vault_list ; vl != NULL ; vl = vl->next) { vault_el_t *v = vl->data; if (g_str_equal(storage, v->storage)) { v->days = days; found = TRUE; nb_vault++; } } if (!found) { vault_el_t *vault = g_new(vault_el_t, 1); nb_vault++; vault->storage = storage; vault->days = days; val->v.vault_list = g_slist_append(val->v.vault_list, vault); } if (tok != CONF_NL && tok != CONF_END) { get_conftoken(CONF_ANY); } } if (nb_vault == 0) { slist_free_full(val->v.vault_list, free_vault); val->v.vault_list =NULL; } } /* get_* functions */ /* 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. */ #define SIZEOF_GINT64 8 static time_t get_time(void) { time_t hhmm; 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; 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; 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; case CONF_AMINFINITY: hhmm = TIME_MAX; break; default: conf_parserror(_("a time is expected")); hhmm = 0; break; } return hhmm; } static int get_int( confunit_t unit) { int val; keytab_t *save_kt; save_kt = keytable; keytable = numb_keytable; get_conftoken(CONF_ANY); switch(tok) { case CONF_INT: val = tokenval.v.i; break; 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; 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; case CONF_AMINFINITY: val = INT_MAX; 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 ssize_t get_size( confunit_t unit) { ssize_t val; keytab_t *save_kt; 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 ((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; 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; case CONF_AMINFINITY: val = (ssize_t)SSIZE_MAX; 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 gint64 get_int64( confunit_t unit) { gint64 val; keytab_t *save_kt; save_kt = keytable; keytable = numb_keytable; get_conftoken(CONF_ANY); 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; } gint64 get_multiplier( gint64 val, confunit_t unit) { /* get multiplier, if any */ get_conftoken(CONF_ANY); 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(); } return val; } static int get_bool(void) { int val; keytab_t *save_kt; save_kt = keytable; keytable = bool_keytable; get_conftoken(CONF_ANY); switch(tok) { case CONF_INT: if (tokenval.v.i != 0) val = 1; else val = 0; break; 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_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; } keytable = save_kt; return val; } static int get_no_yes_all(void) { int val; keytab_t *save_kt; save_kt = keytable; keytable = no_yes_all_keytable; get_conftoken(CONF_ANY); switch(tok) { case CONF_INT: val = tokenval.v.i; break; case CONF_SIZE: val = tokenval.v.size; break; 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; } if (val > 2 || val < 0) val = 1; keytable = save_kt; return val; } void ckseen( seen_t *seen) { 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; } /* Validation functions */ static void validate_name( tok_t token, val_t *val) { switch (val->type) { case CONFTYPE_STR: case CONFTYPE_IDENT: { char *str = val_t__str(val); if (str && strchr(str, ' ')) conf_parserror("%s must not contains space", get_token_name(token)); if (str && strchr(str, '"')) conf_parserror("%s must not contains double quotes", get_token_name(token)); break; } default: conf_parserror("validate_no_space_dquote invalid type %d\n", val->type); } } static void validate_no_space_dquote( struct conf_var_s *np, val_t *val) { switch (val->type) { case CONFTYPE_STR: { char *str = val_t__str(val); if (str && strchr(str, ' ')) conf_parserror("%s must not contains space", get_token_name(np->token)); if (str && strchr(str, '"')) conf_parserror("%s must not contains double quotes", get_token_name(np->token)); break; } case CONFTYPE_AUTOLABEL: { autolabel_t *autolabel = val_t__autolabel(val); if (autolabel->template && strchr(autolabel->template, ' ')) conf_parserror("%s template must not contains space", get_token_name(np->token)); if (autolabel->template && strchr(autolabel->template, '"')) conf_parserror("%s template must not contains double quotes", get_token_name(np->token)); break; } case CONFTYPE_LABELSTR: { labelstr_s *labelstr = val_t__labelstr(val); if (labelstr->template && strchr(labelstr->template, '"')) conf_parserror("%s template must not contains double quotes", get_token_name(np->token)); if (labelstr->template && strchr(labelstr->template, ' ')) conf_parserror("%s template must not contains space", get_token_name(np->token)); break; } default: conf_parserror("validate_no_space_dquote invalid type %d\n", val->type); } } 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: // Can't be negative //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); } } 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); } } 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); } } static void validate_runspercycle( struct conf_var_s *np G_GNUC_UNUSED, val_t *val) { if(val_t__int(val) < -1) conf_parserror(_("runspercycle must be >= -1")); } static void validate_bumppercent( struct conf_var_s *np G_GNUC_UNUSED, val_t *val) { if(val_t__int(val) < 0 || val_t__int(val) > 100) conf_parserror(_("bumppercent must be between 0 and 100")); } 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")); } } 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.")); } 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 validate_use( struct conf_var_s *np G_GNUC_UNUSED, val_t *val) { val_t__int64(val) = am_floor(val_t__int64(val), DISK_BLOCK_KB); } 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 validate_blocksize( struct conf_var_s *np G_GNUC_UNUSED, val_t *val) { if(val_t__size(val) < DISK_BLOCK_KB) { conf_parserror(_("Tape blocksize must be at least %d KBytes"), DISK_BLOCK_KB); } } 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")); } } 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")); } } static void validate_reserved_port_range( struct conf_var_s *np G_GNUC_UNUSED, val_t *val) { validate_port_range(val, 1, IPPORT_RESERVED-1); } static void validate_unreserved_port_range( struct conf_var_s *np G_GNUC_UNUSED, val_t *val) { validate_port_range(val, IPPORT_RESERVED, 65535); } /* * Columnspec validation */ /* * The list of lowercase string values valid for the first element of a * columnspec. */ static const char *colspec_valid_names[] = { "hostname", "disk", "level", "origkb", "outkb", "compress", "dumptime", "dumprate", "tapetime", "taperate" }; /* * Validate one columnspec element. We do modify the string inline, but that's * OK: the caller won't use it anyway. * * One element is of the form: * * xxxxx=int1:int2:int3 * * where: xxxxx is a string which can only be (case insensitive) one of the values in * the colspec_valid_names array above. Other numbers are ALL optionals, there * may be none at all. Save for int2, they MUST be positive. See amanda.conf(5). * * Yeah, today, nobody ever uses that, but... Ahwell. */ static void validate_one_columnspec(const char *element) { gchar *p, *token; gchar **strings, **ptr; guint i, nr_valid_names = G_N_ELEMENTS(colspec_valid_names); p = strchr(element, '='); if (!p) { conf_parserror("invalid columnspec: %s", element); return; } /* * OK, at this point we at least have a first element. See if we know about * it. */ *p++ = '\0'; token = g_ascii_strdown(element, -1); for (i = 0; i < nr_valid_names; i++) if (g_str_equal(colspec_valid_names[i], token)) /* We have a match */ break; g_free(token); if (i == nr_valid_names) { /* No match! Bye... */ conf_parserror("invalid column name: '%s'", element); return; } /* * Now we must check for numbers. As mentioned above, ALL are optional. If * the second number is present, it is the only one which can be negative. */ i = 0; token = p; strings = g_strsplit(p, ":", 3); for (ptr = strings; *ptr; ptr++) { p = *ptr; /* * Check for a potentially negative number - it is only valid in the * second position. */ if (++i == 2 && *p == '-') p++; for (; *p; p++) if (!g_ascii_isdigit(*p)) { conf_parserror("invalid format: %s", token); goto out; } } out: g_strfreev(strings); } /* * Validate a columnspec input. We split the string against ',' and use * validate_one_columnspec() above to validate each substring returned. */ static void validate_columnspec(conf_var_t *var G_GNUC_UNUSED, val_t *value) { gchar *input = val_t_to_str(value); gchar **elements, **ptr; elements = g_strsplit(input, ",", 0); for (ptr = elements; *ptr; ptr++) validate_one_columnspec(*ptr); g_strfreev(elements); } /* * Validate tmpdir, the directory must exist and be writable by the user. */ 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); } } /* global changerfile deprecated in 3.4 */ /* global changerfile must be removed in 3.4.5 */ static void validate_deprecated_changerfile(conf_var_t *var G_GNUC_UNUSED, val_t *value G_GNUC_UNUSED) { conf_parswarn(_("warning: Global changerfile is deprecated, it must be set in the changer section")); } gboolean config_is_initialized(void) { return config_initialized; } /* * Initialization Implementation */ cfgerr_level_t config_init_with_global( config_init_flags flags, char *arg_config_name) { cfgerr_level_t cfgerr_level; cfgerr_level = config_init(flags|CONFIG_INIT_GLOBAL|CONFIG_OVERRDIDE_NO_ERROR, arg_config_name); //cfgerr_level = config_init(flags|CONFIG_INIT_GLOBAL, arg_config_name); if (config_errors(NULL) >= CFGERR_WARNINGS) { return cfgerr_level; } return config_init(flags|CONFIG_INIT_OVERLAY, arg_config_name); } cfgerr_level_t config_init( config_init_flags flags, char *arg_config_name) { generate_errors = TRUE; if (!(flags & CONFIG_INIT_OVERLAY)) { /* Clear out anything that's already in there */ config_uninit(); /* 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; } /* 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 (g_str_equal(arg_config_name, ".")) flags = (flags & (~CONFIG_INIT_EXPLICIT_NAME)) | CONFIG_INIT_USE_CWD; } if (flags & CONFIG_INIT_GLOBAL) { amfree(config_name); g_free(config_dir); config_dir = g_strdup(CONFIG_DIR); } else if ((flags & CONFIG_INIT_EXPLICIT_NAME) && arg_config_name) { g_free(config_name); config_name = g_strdup(arg_config_name); g_free(config_dir); config_dir = g_strconcat(CONFIG_DIR, "/", arg_config_name, NULL); } else if (flags & CONFIG_INIT_USE_CWD) { char *cwd; char *filename; struct stat statbuf; cwd = get_original_cwd(); if (!cwd) { /* (this isn't a config error, so it's always fatal) */ error(_("Cannot determine current working directory")); /* NOTREACHED */ } filename = g_strconcat(cwd, "/amanda.conf", NULL); if (stat(filename, &statbuf) == 0) { config_dir = g_strconcat(cwd, "/", NULL); if ((config_name = strrchr(cwd, '/')) != NULL) { config_name = g_strdup(config_name + 1); } } else { amfree(config_name); amfree(config_dir); } g_free(filename); } else { /* ok, then, we won't read anything (for e.g., amrestore) */ amfree(config_name); amfree(config_dir); } /* setup for apply_config_overrides */ if (flags & CONFIG_INIT_CLIENT) { keytable = client_keytab; parsetable = client_var; } else { keytable = server_keytab; parsetable = server_var; } if (config_overrides) { int i; for (i = 0; i < config_overrides->n_used; i++) { config_overrides->ovr[i].applied = FALSE; } } /* apply config overrides to default setting */ generate_errors = FALSE; apply_config_overrides(config_overrides, NULL); generate_errors = TRUE; /* If we have a config_dir, we can try reading something */ if (config_dir) { if (flags & CONFIG_INIT_CLIENT) { g_free(config_filename); config_filename = g_strconcat(config_dir, "/amanda-client.conf", NULL); } else { g_free(config_filename); config_filename = g_strconcat(config_dir, "/amanda.conf", NULL); } read_conffile(config_filename, flags & CONFIG_INIT_CLIENT, flags & (CONFIG_INIT_CLIENT|CONFIG_INIT_GLOBAL)); } else { amfree(config_filename); } if (getconf_linenum(CNF_ACTIVE_STORAGE) <= 0) { // default to the configured CNF_STORAGE copy_val_t(&conf_data[CNF_ACTIVE_STORAGE], &conf_data[CNF_STORAGE]); } /* apply config overrides to default setting */ generate_errors = !(flags & CONFIG_OVERRDIDE_NO_ERROR); apply_config_overrides(config_overrides, NULL); generate_errors = TRUE; if (!(flags & CONFIG_INIT_GLOBAL) || !arg_config_name) { 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; } void config_uninit(void) { 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; policy_s *po, *ponext; storage_t *st, *stnext; int i; if (!config_initialized) return; for(hp=holdinglist; hp != NULL; hp = hp->next) { hd = hp->data; amfree(hd->name); for(i=0; ivalue[i]); } g_free(hd->seen.block); } slist_free_full(holdinglist, g_free); holdinglist = NULL; for(dp=dumplist; dp != NULL; dp = dpnext) { amfree(dp->name); for(i=0; ivalue[i]); } g_free(dp->seen.block); dpnext = dp->next; amfree(dp); } dumplist = NULL; for(tp=tapelist; tp != NULL; tp = tpnext) { amfree(tp->name); for(i=0; ivalue[i]); } g_free(tp->seen.block); tpnext = tp->next; amfree(tp); } tapelist = NULL; for(ip=interface_list; ip != NULL; ip = ipnext) { amfree(ip->name); for(i=0; ivalue[i]); } g_free(ip->seen.block); ipnext = ip->next; amfree(ip); } interface_list = NULL; for(ap=application_list; ap != NULL; ap = apnext) { amfree(ap->name); for(i=0; ivalue[i]); } g_free(ap->seen.block); apnext = ap->next; amfree(ap); } application_list = NULL; for(pp=pp_script_list; pp != NULL; pp = ppnext) { amfree(pp->name); for(i=0; ivalue[i]); } g_free(pp->seen.block); ppnext = pp->next; amfree(pp); } pp_script_list = NULL; for(dc=device_config_list; dc != NULL; dc = dcnext) { amfree(dc->name); for(i=0; ivalue[i]); } g_free(dc->seen.block); dcnext = dc->next; amfree(dc); } device_config_list = NULL; for(cc=changer_config_list; cc != NULL; cc = ccnext) { amfree(cc->name); for(i=0; ivalue[i]); } g_free(cc->seen.block); 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]); } g_free(iv->seen.block); ivnext = iv->next; amfree(iv); } interactivity_list = NULL; for(ts=taperscan_list; ts != NULL; ts = tsnext) { amfree(ts->name); for(i=0; ivalue[i]); } g_free(ts->seen.block); tsnext = ts->next; amfree(ts); } taperscan_list = NULL; for(po=policy_list; po != NULL; po = ponext) { amfree(po->name); for(i=0; ivalue[i]); } g_free(po->seen.block); ponext = po->next; amfree(po); } policy_list = NULL; for(st=storage_list; st != NULL; st = stnext) { amfree(st->name); for(i=0; ivalue[i]); } g_free(st->seen.block); stnext = st->next; amfree(st); } storage_list = NULL; for(i=0; in_used; config_options = g_malloc((first+n_config_overrides+1)*sizeof(char *)); config_option = config_options + first; for (i = 0; i < n_config_overrides; i++) { char *key = config_overrides->ovr[i].key; char *value = config_overrides->ovr[i].value; *config_option = g_strjoin(NULL, "-o", key, "=", value, NULL); config_option++; } *config_option = NULL; /* add terminating sentinel */ return config_options; } static void update_derived_values( gboolean is_client) { interface_t *ip; identlist_t il; holdingdisk_t *hd; policy_s *po; storage_t *st; changer_config_t *dc; labelstr_s *labelstr; char *conf_name; autolabel_t *autolabel; char *meta_autolabel; char *org; char *st_name; conf_name = get_config_name(); if (!conf_name) conf_name = "default"; if (!is_client) { /* Add a 'default' interface if one doesn't already exist */ if (!(ip = lookup_interface("default"))) { init_interface_defaults(); ifcur.name = g_strdup("default"); ifcur.seen = val_t__seen(getconf(CNF_NETUSAGE)); save_interface(); ip = lookup_interface("default"); } /* .. and set its maxusage from 'netusage' */ if (!interface_seen(ip, INTER_MAXUSAGE)) { val_t *v; v = interface_getconf(ip, INTER_COMMENT); free_val_t(v); val_t__str(v) = g_strdup(_("implicit from NETUSAGE")); val_t__seen(v) = val_t__seen(getconf(CNF_NETUSAGE)); 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)); } /* 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) && g_str_equal(getconf_str(CNF_TAPETYPE), "DEFAULT_TAPE") && !lookup_tapetype("DEFAULT_TAPE")) { init_tapetype_defaults(); tpcur.name = g_strdup("DEFAULT_TAPE"); tpcur.seen = val_t__seen(getconf(CNF_TAPETYPE)); save_tapetype(); } else { conf_parserror(_("tapetype %s is not defined"), getconf_str(CNF_TAPETYPE)); } } /* 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); } } 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); g_free(autolabel->template); autolabel->template = g_strdup(getconf_str(CNF_LABEL_NEW_TAPES)); if (!autolabel->template || autolabel->template == '\0') { g_free(autolabel->template); autolabel->template = NULL; autolabel->autolabel = 0; } else { autolabel->autolabel = AL_VOLUME_ERROR | AL_EMPTY; } } 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); } labelstr = &(conf_data[CNF_LABELSTR].v.labelstr); autolabel = &(conf_data[CNF_AUTOLABEL].v.autolabel); if (getconf_seen(CNF_LABELSTR) && labelstr->match_autolabel && !getconf_seen(CNF_AUTOLABEL)) { conf_parserror(_("AUTOLABEL not set and LABELSTR set to MATCH-AUTOLABEL")); } else if (labelstr->match_autolabel && !getconf_seen(CNF_AUTOLABEL)) { g_free(labelstr->template); labelstr->template = g_strdup(".*"); labelstr->match_autolabel = FALSE; } else if (labelstr->match_autolabel) { g_free(labelstr->template); labelstr->template = g_strdup(autolabel->template); } il = getconf_identlist(CNF_STORAGE); if (il) { st_name = il->data; } else { st_name = NULL; } /* create a default policy */ if (!(lookup_policy(conf_name))) { init_policy_defaults(); pocur.name = g_strdup(conf_name); free_val_t(&pocur.value[POLICY_COMMENT]); val_t__str(&pocur.value[POLICY_COMMENT]) = g_strdup(_("implicit from global config")); save_policy(); } if (!getconf_seen(CNF_STORAGE) && (!st_name || *st_name == '\0')) { /* create a default storage */ if (!(lookup_storage(conf_name))) { init_storage_defaults(); stcur.name = g_strdup(conf_name); free_val_t(&stcur.value[STORAGE_COMMENT]); val_t__str(&stcur.value[STORAGE_COMMENT]) = g_strdup(_("implicit from global config")); save_storage(); } /* set the default storage */ il = g_slist_append(NULL, g_strdup(conf_name)); val_t__identlist(&conf_data[CNF_STORAGE]) = il; } /* Set default retention_tapes if it is not set */ for (po = policy_list; po != NULL; po = po->next) { if (!policy_seen(po, POLICY_RETENTION_TAPES)) { free_val_t(&po->value[POLICY_RETENTION_TAPES]); copy_val_t(&po->value[POLICY_RETENTION_TAPES], &conf_data[CNF_TAPECYCLE]); po->value[POLICY_RETENTION_TAPES].v.i--; // reduce by 1 } } /* Update many changer setting */ for (dc = changer_config_list; dc != NULL; dc = dc->next) { char *changern = changer_config_name(dc); if (changer_config_seen(dc, CHANGER_CONFIG_CHANGERFILE)) { char *changerfile = changer_config_get_changerfile(dc); char *tpchanger = changer_config_get_tpchanger(dc); char *cf; if ((cf = strstr(changerfile, "$t"))) { char *new_cf = g_malloc(strlen(changerfile)+strlen(changern)-1); int len = cf - changerfile; strncpy(new_cf, changerfile, len); strcpy(new_cf+len, changern); strcpy(new_cf+len+strlen(changern), cf+2); strncpy(new_cf+len+strlen(changern)+strlen(cf+2),"\0",1); free_val_t(&dc->value[CHANGER_CONFIG_CHANGERFILE]); conf_init_str(&dc->value[CHANGER_CONFIG_CHANGERFILE], new_cf); g_free(new_cf); } if ((cf = strstr(tpchanger, "$t"))) { char *new_tp = g_malloc(strlen(tpchanger)+strlen(changern)-1); int len = cf - tpchanger; strncpy(new_tp, tpchanger, len); strcpy(new_tp+len, changern); strcpy(new_tp+len+strlen(changern), cf+2); strncpy(new_tp+len+strlen(changern)+strlen(cf+2),"\0",1); free_val_t(&dc->value[CHANGER_CONFIG_TPCHANGER]); conf_init_str(&dc->value[CHANGER_CONFIG_TPCHANGER], new_tp); g_free(new_tp); } } } /* Set many storage default if they are not set */ for (st = storage_list; st != NULL; st = st->next) { labelstr = storage_get_labelstr(st); autolabel = storage_get_autolabel(st); meta_autolabel = storage_get_meta_autolabel(st); org = getconf_str(CNF_ORG); if (storage_seen(st, STORAGE_LABELSTR) && labelstr->match_autolabel && !storage_seen(st, STORAGE_AUTOLABEL)) { conf_parserror(_("AUTOLABEL not set and LABELSTR set to MATCH-AUTOLABEL")); } else if (labelstr->match_autolabel && !storage_seen(st, STORAGE_AUTOLABEL)) { g_free(labelstr->template); labelstr->template = g_strdup(".*"); labelstr->match_autolabel = FALSE; } else if (labelstr->match_autolabel) { g_free(labelstr->template); labelstr->template = g_strdup(autolabel->template); } if (meta_autolabel) { if (strstr(meta_autolabel, "$o") && !is_valid_label(org)) { conf_parserror("ORG must not contains space if '$0' is in meta_autolabel"); } } if (autolabel && autolabel->template) { if (strstr(autolabel->template, "$o") && !is_valid_label(org)) { conf_parserror("ORG must not contains space if '$0' is in autolabel"); } } if (!storage_seen(st, STORAGE_POLICY)) { free_val_t(&st->value[STORAGE_POLICY]); conf_init_str(&st->value[STORAGE_POLICY], conf_name); } if (!storage_seen(st, STORAGE_TAPEDEV)) { free_val_t(&st->value[STORAGE_TAPEDEV]); copy_val_t(&st->value[STORAGE_TAPEDEV], &conf_data[CNF_TAPEDEV]); } if (!storage_seen(st, STORAGE_TPCHANGER)) { free_val_t(&st->value[STORAGE_TPCHANGER]); copy_val_t(&st->value[STORAGE_TPCHANGER], &conf_data[CNF_TPCHANGER]); } if (!storage_seen(st, STORAGE_LABELSTR)) { free_val_t(&st->value[STORAGE_LABELSTR]); copy_val_t(&st->value[STORAGE_LABELSTR], &conf_data[CNF_LABELSTR]); } if (!storage_seen(st, STORAGE_AUTOLABEL)) { free_val_t(&st->value[STORAGE_AUTOLABEL]); copy_val_t(&st->value[STORAGE_AUTOLABEL], &conf_data[CNF_AUTOLABEL]); } if (!storage_seen(st, STORAGE_META_AUTOLABEL)) { free_val_t(&st->value[STORAGE_META_AUTOLABEL]); copy_val_t(&st->value[STORAGE_META_AUTOLABEL], &conf_data[CNF_META_AUTOLABEL]); } if (!storage_seen(st, STORAGE_RUNTAPES)) { copy_val_t(&st->value[STORAGE_RUNTAPES], &conf_data[CNF_RUNTAPES]); } if (!storage_seen(st, STORAGE_TAPERSCAN)) { free_val_t(&st->value[STORAGE_TAPERSCAN]); copy_val_t(&st->value[STORAGE_TAPERSCAN], &conf_data[CNF_TAPERSCAN]); } if (!storage_seen(st, STORAGE_TAPETYPE)) { free_val_t(&st->value[STORAGE_TAPETYPE]); copy_val_t(&st->value[STORAGE_TAPETYPE], &conf_data[CNF_TAPETYPE]); } if (!storage_seen(st, STORAGE_MAX_DLE_BY_VOLUME)) { copy_val_t(&st->value[STORAGE_MAX_DLE_BY_VOLUME], &conf_data[CNF_MAX_DLE_BY_VOLUME]); } if (!storage_seen(st, STORAGE_TAPERALGO)) { copy_val_t(&st->value[STORAGE_TAPERALGO], &conf_data[CNF_TAPERALGO]); } if (!storage_seen(st, STORAGE_TAPER_PARALLEL_WRITE)) { copy_val_t(&st->value[STORAGE_TAPER_PARALLEL_WRITE], &conf_data[CNF_TAPER_PARALLEL_WRITE]); } if (!storage_seen(st, STORAGE_EJECT_VOLUME)) { copy_val_t(&st->value[STORAGE_EJECT_VOLUME], &conf_data[CNF_EJECT_VOLUME]); } if (!storage_seen(st, STORAGE_DEVICE_OUTPUT_BUFFER_SIZE)) { copy_val_t(&st->value[STORAGE_DEVICE_OUTPUT_BUFFER_SIZE], &conf_data[CNF_DEVICE_OUTPUT_BUFFER_SIZE]); } if (!storage_seen(st, STORAGE_AUTOFLUSH)) { copy_val_t(&st->value[STORAGE_AUTOFLUSH], &conf_data[CNF_AUTOFLUSH]); } if (!storage_seen(st, STORAGE_FLUSH_THRESHOLD_DUMPED)) { copy_val_t(&st->value[STORAGE_FLUSH_THRESHOLD_DUMPED], &conf_data[CNF_FLUSH_THRESHOLD_DUMPED]); } if (!storage_seen(st, STORAGE_FLUSH_THRESHOLD_SCHEDULED)) { copy_val_t(&st->value[STORAGE_FLUSH_THRESHOLD_SCHEDULED], &conf_data[CNF_FLUSH_THRESHOLD_SCHEDULED]); } if (!storage_seen(st, STORAGE_TAPERFLUSH)) { copy_val_t(&st->value[STORAGE_TAPERFLUSH], &conf_data[CNF_TAPERFLUSH]); } if (!storage_seen(st, STORAGE_REPORT_USE_MEDIA)) { copy_val_t(&st->value[STORAGE_REPORT_USE_MEDIA], &conf_data[CNF_REPORT_USE_MEDIA]); } if (!storage_seen(st, STORAGE_REPORT_NEXT_MEDIA)) { copy_val_t(&st->value[STORAGE_REPORT_NEXT_MEDIA], &conf_data[CNF_REPORT_NEXT_MEDIA]); } if (!storage_seen(st, STORAGE_INTERACTIVITY)) { free_val_t(&st->value[STORAGE_INTERACTIVITY]); copy_val_t(&st->value[STORAGE_INTERACTIVITY], &conf_data[CNF_INTERACTIVITY]); } if (!storage_seen(st, STORAGE_TAPEPOOL)) { free_val_t(&st->value[STORAGE_TAPEPOOL]); conf_init_str(&st->value[STORAGE_TAPEPOOL], conf_name); } else { char *pool = storage_get_tapepool(st); gboolean freepool = FALSE; char *p; if ((p = strstr(pool, "$o"))) { char *org = getconf_str(CNF_ORG); char *new_pool = g_malloc(strlen(pool)+strlen(org)-1); int len = p - pool; strncpy(new_pool, pool, len); strcpy(new_pool+len, org); strcpy(new_pool+len+strlen(org), p+2); strncpy(new_pool+len+strlen(org)+strlen(p+2),"\0",1); free_val_t(&st->value[STORAGE_TAPEPOOL]); conf_init_str(&st->value[STORAGE_TAPEPOOL], new_pool); pool = new_pool; freepool = TRUE; } if ((p = strstr(pool, "$c"))) { char *new_pool = g_malloc(strlen(pool)+strlen(conf_name)-1); int len = p - pool; strncpy(new_pool, pool, len); strcpy(new_pool+len, conf_name); strcpy(new_pool+len+strlen(conf_name), p+2); strncpy(new_pool+len+strlen(conf_name)+strlen(p+2),"\0",1); free_val_t(&st->value[STORAGE_TAPEPOOL]); conf_init_str(&st->value[STORAGE_TAPEPOOL], new_pool); if (freepool) g_free(pool); pool = new_pool; freepool = TRUE; } if ((p = strstr(pool, "$r"))) { char *storagen = storage_name(st); char *new_pool = g_malloc(strlen(pool)+strlen(storagen)-1); int len = p - pool; strncpy(new_pool, pool, len); strcpy(new_pool+len, storagen); strcpy(new_pool+len+strlen(storagen), p+2); strncpy(new_pool+len+strlen(storagen)+strlen(p+2),"\0",1); free_val_t(&st->value[STORAGE_TAPEPOOL]); conf_init_str(&st->value[STORAGE_TAPEPOOL], new_pool); if (freepool) g_free(pool); pool = new_pool; freepool = TRUE; } if (freepool) { g_free(pool); } } } for (il = getconf_identlist(CNF_STORAGE); il != NULL; il = il->next) { if (!lookup_storage(il->data)) { conf_parserror(_("storage '%s' is not defined"), (char *)il->data); } } // Add all storage to active-storage for (il = getconf_identlist(CNF_STORAGE); il != NULL; il = il->next) { identlist_t asl; int found = FALSE; for (asl = getconf_identlist(CNF_ACTIVE_STORAGE); asl != NULL; asl = asl->next) { if (strcmp(il->data, asl->data) == 0) { found = TRUE; } } if (!found) { conf_data[CNF_ACTIVE_STORAGE].v.identlist = g_slist_append(conf_data[CNF_ACTIVE_STORAGE].v.identlist, g_strdup(il->data)); } } for (il = getconf_identlist(CNF_ACTIVE_STORAGE); il != NULL; il = il->next) { if (!lookup_storage(il->data)) { conf_parserror(_("storage '%s' is not defined"), (char *)il->data); } } /* Always TRUE */ conf_init_bool(&conf_data[CNF_USETIMESTAMPS], 1); } /* 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); /* And finally, display unit */ switch (getconf_str(CNF_DISPLAYUNIT)[0]) { case 'k': case 'K': unit_divisor = 1; break; 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 */ } } static void conf_init_int( val_t *val, confunit_t unit, int i) { val->seen.linenum = 0; val->seen.filename = NULL; val->seen.block = NULL; val->type = CONFTYPE_INT; val->unit = unit; val_t__int(val) = i; } 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; } static void conf_init_real( val_t *val, float r) { 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; } 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 = g_strdup(s); else val->v.s = NULL; } 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 = g_strdup(s); else val->v.s = NULL; } 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, g_strdup(s)); } static void conf_init_str_list( val_t *val, char *s) { val->seen.linenum = 0; val->seen.filename = NULL; val->seen.block = NULL; val->type = CONFTYPE_STR_LIST; val->unit = CONF_UNIT_NONE; val->v.identlist = NULL; if (s) val->v.identlist = g_slist_append(val->v.identlist, g_strdup(s)); } static void conf_init_time( val_t *val, time_t t) { 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; } static void conf_init_size( val_t *val, confunit_t unit, ssize_t sz) { val->seen.linenum = 0; val->seen.filename = NULL; val->seen.block = NULL; val->type = CONFTYPE_SIZE; val->unit = unit; val_t__size(val) = sz; } static void conf_init_bool( val_t *val, int i) { 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; } 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; } static void conf_init_compress( val_t *val, comp_t 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; } 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; } 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; } 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; } static void conf_init_host_limit_server( val_t *val) { conf_init_host_limit(val); val_t__host_limit(val).server = TRUE; } 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; } static void conf_init_holding( val_t *val, dump_holdingdisk_t i) { val->seen.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; } 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; } 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 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 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; } 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; } 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; } static void conf_init_labelstr( val_t *val) { val->seen.linenum = 0; val->seen.filename = NULL; val->seen.block = NULL; val->type = CONFTYPE_LABELSTR; val->unit = CONF_UNIT_NONE; val->v.labelstr.template = NULL; val->v.labelstr.match_autolabel = TRUE; } void free_property_t( gpointer p) { property_t *propery = (property_t *)p; slist_free_full(propery->values, g_free); amfree(propery); } 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); } 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; } 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; } 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; } 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; } static void conf_init_dump_selection(val_t *val) { val->seen.linenum = 0; val->seen.filename = NULL; val->seen.block = NULL; val->type = CONFTYPE_DUMP_SELECTION; val->unit = CONF_UNIT_NONE; val->v.dump_selection = NULL; } static void conf_init_vault_list(val_t *val) { val->seen.linenum = 0; val->seen.filename = NULL; val->seen.block = NULL; val->type = CONFTYPE_VAULT_LIST; val->unit = CONF_UNIT_NONE; val->v.vault_list = NULL; } /* * Config access implementation */ val_t * getconf(confparm_key key) { assert(key < CNF_CNF); return &conf_data[key]; } 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; policy_s *po; storage_t *st; GSList *rv = NULL; 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); } } else if (strcasecmp(listname,"policy") == 0) { for(po = policy_list; po != NULL; po=po->next) { rv = g_slist_append(rv, po->name); } } else if (strcasecmp(listname,"storage") == 0) { for(st = storage_list; st != NULL; st=st->next) { rv = g_slist_append(rv, st->name); } } return rv; } val_t * getconf_byname( char *key) { val_t *rv = NULL; if (!parm_key_info(key, NULL, &rv)) return NULL; return rv; } char * confparm_key_to_name( int parm) { conf_var_t *np; keytab_t *kt; for (np = server_var; np->token != CONF_UNKNOWN; np++) { if (np->parm == parm) { for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) { if (kt->token == np->token) { return kt->keyword; } } } } return NULL; } tapetype_t * lookup_tapetype( char *str) { tapetype_t *p; for(p = tapelist; p != NULL; p = p->next) { if(strcasecmp(p->name, str) == 0) return p; } return NULL; } val_t * tapetype_getconf( tapetype_t *ttyp, tapetype_key key) { assert(ttyp != NULL); assert(key < TAPETYPE_TAPETYPE); return &ttyp->value[key]; } static void validate_program( conf_var_t *np G_GNUC_UNUSED, val_t *val) { if (!g_str_equal(val->v.s, "DUMP") && !g_str_equal(val->v.s, "GNUTAR") && !g_str_equal(val->v.s, "STAR") && !g_str_equal(val->v.s, "APPLICATION")) conf_parserror("program must be \"DUMP\", \"GNUTAR\", \"STAR\" or \"APPLICATION\""); } 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"); } } char * tapetype_name( tapetype_t *ttyp) { assert(ttyp != NULL); return ttyp->name; } char * tapetype_key_to_name( int parm) { conf_var_t *np; keytab_t *kt; for (np = tapetype_var; np->token != CONF_UNKNOWN; np++) { if (np->parm == parm) { for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) { if (kt->token == np->token) { return kt->keyword; } } } } return NULL; } dumptype_t * lookup_dumptype( char *str) { dumptype_t *p; for(p = dumplist; p != NULL; p = p->next) { if(strcasecmp(p->name, str) == 0) return p; } return NULL; } val_t * dumptype_getconf( dumptype_t *dtyp, dumptype_key key) { assert(dtyp != NULL); assert(key < DUMPTYPE_DUMPTYPE); return &dtyp->value[key]; } char * dumptype_name( dumptype_t *dtyp) { assert(dtyp != NULL); return dtyp->name; } char * dumptype_key_to_name( int parm) { conf_var_t *np; keytab_t *kt; for (np = dumptype_var; np->token != CONF_UNKNOWN; np++) { if (np->parm == parm) { for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) { if (kt->token == np->token) { return kt->keyword; } } } } return NULL; } interface_t * lookup_interface( char *str) { interface_t *p; for(p = interface_list; p != NULL; p = p->next) { if(strcasecmp(p->name, str) == 0) return p; } return NULL; } val_t * interface_getconf( interface_t *iface, interface_key key) { assert(iface != NULL); assert(key < INTER_INTER); return &iface->value[key]; } char * interface_name( interface_t *iface) { assert(iface != NULL); return iface->name; } char * interface_key_to_name( int parm) { conf_var_t *np; keytab_t *kt; for (np = interface_var; np->token != CONF_UNKNOWN; np++) { if (np->parm == parm) { for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) { if (kt->token == np->token) { return kt->keyword; } } } } return NULL; } holdingdisk_t * lookup_holdingdisk( char *str) { GSList *hp; holdingdisk_t *hd; for (hp = holdinglist; hp != NULL; hp = hp->next) { hd = hp->data; if (strcasecmp(hd->name, str) == 0) return hd; } return NULL; } 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]; } char * holdingdisk_name( holdingdisk_t *hdisk) { assert(hdisk != NULL); return hdisk->name; } char * holdingdisk_key_to_name( int parm) { conf_var_t *np; keytab_t *kt; for (np = holding_var; np->token != CONF_UNKNOWN; np++) { if (np->parm == parm) { for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) { if (kt->token == np->token) { return kt->keyword; } } } } return NULL; } application_t * lookup_application( char *str) { application_t *p; for(p = application_list; p != NULL; p = p->next) { if(strcasecmp(p->name, str) == 0) return p; } return NULL; } val_t * application_getconf( application_t *ap, application_key key) { assert(ap != NULL); assert(key < APPLICATION_APPLICATION); return &ap->value[key]; } char * application_name( application_t *ap) { assert(ap != NULL); return ap->name; } char * application_key_to_name( int parm) { conf_var_t *np; keytab_t *kt; for (np = application_var; np->token != CONF_UNKNOWN; np++) { if (np->parm == parm) { for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) { if (kt->token == np->token) { return kt->keyword; } } } } return NULL; } interactivity_t * lookup_interactivity( char *str) { interactivity_t *p; for(p = interactivity_list; p != NULL; p = p->next) { if(strcasecmp(p->name, str) == 0) return p; } return NULL; } val_t * interactivity_getconf( interactivity_t *iv, interactivity_key key) { assert(iv != NULL); assert(key < INTERACTIVITY_INTERACTIVITY); return &iv->value[key]; } char * interactivity_name( interactivity_t *iv) { assert(iv != NULL); return iv->name; } char * interactivity_key_to_name( int parm) { conf_var_t *np; keytab_t *kt; for (np = interactivity_var; np->token != CONF_UNKNOWN; np++) { if (np->parm == parm) { for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) { if (kt->token == np->token) { return kt->keyword; } } } } return NULL; } taperscan_t * lookup_taperscan( char *str) { taperscan_t *p; for(p = taperscan_list; p != NULL; p = p->next) { if(strcasecmp(p->name, str) == 0) return p; } return NULL; } val_t * taperscan_getconf( taperscan_t *ts, taperscan_key key) { assert(ts != NULL); assert(key < TAPERSCAN_TAPERSCAN); return &ts->value[key]; } char * taperscan_name( taperscan_t *ts) { assert(ts != NULL); return ts->name; } char * taperscan_key_to_name( int parm) { conf_var_t *np; keytab_t *kt; for (np = taperscan_var; np->token != CONF_UNKNOWN; np++) { if (np->parm == parm) { for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) { if (kt->token == np->token) { return kt->keyword; } } } } return NULL; } policy_s * lookup_policy( char *str) { policy_s *p; for(p = policy_list; p != NULL; p = p->next) { if(strcasecmp(p->name, str) == 0) return p; } return NULL; } val_t * policy_getconf( policy_s *po, policy_key key) { assert(po != NULL); assert(key < POLICY_POLICY); return &po->value[key]; } char * policy_name( policy_s *po) { assert(po != NULL); return po->name; } char * policy_key_to_name( int parm) { conf_var_t *np; keytab_t *kt; for (np = policy_var; np->token != CONF_UNKNOWN; np++) { if (np->parm == parm) { for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) { if (kt->token == np->token) { return kt->keyword; } } } } return NULL; } storage_t * get_first_storage(void) { return storage_list; } storage_t * get_next_storage(storage_t *st) { return st->next; } char ** get_storage_list(void) { int count = 0; storage_t *p; char **result; char **r; for(p = storage_list; p != NULL; p = p->next) { count++; }; result = g_new0(char *, count+1); for (r = result, p = storage_list; p != NULL; p = p->next, r++) { *r = g_strdup(p->name); } *r = NULL; return result; } storage_t * lookup_storage( char *str) { storage_t *p; for(p = storage_list; p != NULL; p = p->next) { if(strcasecmp(p->name, str) == 0) return p; } return NULL; } val_t * storage_getconf( storage_t *st, storage_key key) { assert(st != NULL); assert(key < STORAGE_STORAGE); return &st->value[key]; } char * storage_name( storage_t *st) { assert(st != NULL); return st->name; } char * storage_key_to_name( int parm) { conf_var_t *np; keytab_t *kt; for (np = storage_var; np->token != CONF_UNKNOWN; np++) { if (np->parm == parm) { for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) { if (kt->token == np->token) { return kt->keyword; } } } } return NULL; } pp_script_t * lookup_pp_script( char *str) { pp_script_t *pps; for(pps = pp_script_list; pps != NULL; pps = pps->next) { if(strcasecmp(pps->name, str) == 0) return pps; } return NULL; } 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]; } char * pp_script_name( pp_script_t *pps) { assert(pps != NULL); return pps->name; } char * pp_script_key_to_name( int parm) { conf_var_t *np; keytab_t *kt; for (np = pp_script_var; np->token != CONF_UNKNOWN; np++) { if (np->parm == parm) { for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) { if (kt->token == np->token) { return kt->keyword; } } } } return NULL; } device_config_t * lookup_device_config( char *str) { device_config_t *devconf; for(devconf = device_config_list; devconf != NULL; devconf = devconf->next) { if(strcasecmp(devconf->name, str) == 0) return devconf; } return NULL; } 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]; } char * device_config_name( device_config_t *devconf) { assert(devconf != NULL); return devconf->name; } char * device_config_key_to_name( int parm) { conf_var_t *np; keytab_t *kt; for (np = device_config_var; np->token != CONF_UNKNOWN; np++) { if (np->parm == parm) { for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) { if (kt->token == np->token) { return kt->keyword; } } } } return NULL; } char ** get_changer_list(void) { int count = 0; changer_config_t *p; char **result; char **r; for(p = changer_config_list; p != NULL; p = p->next) { count++; }; result = g_new0(char *, count+1); for (r = result, p = changer_config_list; p != NULL; p = p->next, r++) { *r = g_strdup(p->name); } *r = NULL; return result; } changer_config_t * lookup_changer_config( char *str) { changer_config_t *devconf; for(devconf = changer_config_list; devconf != NULL; devconf = devconf->next) { if(strcasecmp(devconf->name, str) == 0) return devconf; } return NULL; } 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]; } char * changer_config_name( changer_config_t *devconf) { assert(devconf != NULL); return devconf->name; } char * changer_config_key_to_name( int parm) { conf_var_t *np; keytab_t *kt; for (np = changer_config_var; np->token != CONF_UNKNOWN; np++) { if (np->parm == parm) { for (kt = keytable; kt->token != CONF_UNKNOWN; kt++) { if (kt->token == np->token) { return kt->keyword; } } } } return NULL; } long int getconf_unit_divisor(void) { return unit_divisor; } /* * Command-line Handling Implementation */ config_overrides_t * new_config_overrides( int size_estimate) { config_overrides_t *co; if (size_estimate <= 0) size_estimate = 10; co = g_malloc(sizeof(*co)); co->ovr = g_malloc(sizeof(*co->ovr) * size_estimate); co->n_allocated = size_estimate; co->n_used = 0; return co; } void free_config_overrides( config_overrides_t *co) { int i; 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); } 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 */ } } co->ovr[co->n_used].key = g_strdup(key); co->ovr[co->n_used].value = g_strdup(value); co->n_used++; } void add_config_override_opt( config_overrides_t *co, char *optarg) { char *value; assert(optarg != NULL); value = strchr(optarg, '='); if (value == NULL) { error(_("Must specify a value for %s."), optarg); /* NOTREACHED */ } *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); i = 0; while (i<*argc) { if(g_str_has_prefix((*argv)[i], "-o")) { 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; } /* move up remaining argment array */ for (j = i; j+moveup<*argc; j++) { (*argv)[j] = (*argv)[j+moveup]; } *argc -= moveup; } else { i++; } } return co; } void set_config_overrides( config_overrides_t *co) { int i; 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); } return; } static cfgerr_level_t apply_config_overrides( config_overrides_t *co, char *key_ovr) { int i; if(!co) return cfgerr_level; assert(keytable != NULL); assert(parsetable != NULL); 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; if (key_ovr && strncasecmp(key_ovr, key, strlen(key_ovr)) != 0) { continue; } if (!parm_key_info(key, &key_parm, &key_val)) { /* not an error, only default config is loaded */ continue; } /* 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 = g_strdup(value); } current_char = current_line; token_pushed = 0; current_line_num = -2; allow_overwrites = 1; co->ovr[i].applied = TRUE; key_parm->read_function(key_parm, key_val); if ((key_parm)->validate_function) key_parm->validate_function(key_parm, key_val); amfree(current_line); current_char = NULL; token_pushed = 0; } return cfgerr_level; } /* * val_t Management Implementation */ 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); } 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); } 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); } 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); } 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); } 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); } identlist_t val_t_to_str_list( val_t *val) { assert(config_initialized); if (val->type != CONFTYPE_STR_LIST) { error(_("val_t_to_ident: val.type is not CONFTYPE_STR_LIST")); /*NOTREACHED*/ } return val_t__identlist(val); } time_t val_t_to_time( val_t *val) { 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); } 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); } 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); } 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); } 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); } 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); } 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); } 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); } dump_selection_list_t val_t_to_dump_selection( val_t *val) { assert(config_initialized); if (val->type != CONFTYPE_DUMP_SELECTION) { error(_("val_t_to_dump_selection: val.type is not CONFTYPE_DUMP_SELECTION")); /*NOTREACHED*/ } return val_t__dump_selection(val); } vault_list_t val_t_to_vault_list( val_t *val) { assert(config_initialized); if (val->type != CONFTYPE_VAULT_LIST) { error(_("val_t_to_vault_list: val.type is not CONFTYPE_VAULT_LIST")); /*NOTREACHED*/ } return val_t__vault_list(val); } 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); } 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); } 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); } taperalgo_t val_t_to_taperalgo( val_t *val) { assert(config_initialized); if (val->type != CONFTYPE_TAPERALGO) { error(_("val_t_to_taperalgo: val.type is not CONFTYPE_TAPERALGO")); /*NOTREACHED*/ } return val_t__taperalgo(val); } send_amreport_t val_t_to_send_amreport( val_t *val) { 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); } 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); } 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); } 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); } exinclude_t val_t_to_exinclude( val_t *val) { 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); } 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 val_t__intrange(val); } proplist_t val_t_to_proplist( val_t *val) { 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); } autolabel_t * val_t_to_autolabel( val_t *val) { 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); } labelstr_s * val_t_to_labelstr( val_t *val) { assert(config_initialized); if (val->type != CONFTYPE_LABELSTR) { error(_("val_t_to_labelstr: val.type is not CONFTYPE_LABELSTR")); /*NOTREACHED*/ } return val_t__labelstr(val); } static void merge_val_t( val_t *valdst, val_t *valsrc) { 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 || valsrc->type == CONFTYPE_STR_LIST) { 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, g_strdup((char *)il->data)); } } } else { free_val_t(valdst); copy_val_t(valdst, valsrc); } } static void copy_val_t( val_t *valdst, val_t *valsrc) { GSList *ia; 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; case CONFTYPE_SIZE: valdst->v.size = valsrc->v.size; break; case CONFTYPE_INT64: valdst->v.int64 = valsrc->v.int64; break; case CONFTYPE_REAL: valdst->v.r = valsrc->v.r; break; case CONFTYPE_RATE: valdst->v.rate[0] = valsrc->v.rate[0]; valdst->v.rate[1] = valsrc->v.rate[1]; break; case CONFTYPE_IDENT: case CONFTYPE_STR: valdst->v.s = g_strdup(valsrc->v.s); break; case CONFTYPE_IDENTLIST: case CONFTYPE_STR_LIST: valdst->v.identlist = NULL; for (ia = valsrc->v.identlist; ia != NULL; ia = ia->next) { valdst->v.identlist = g_slist_append(valdst->v.identlist, g_strdup(ia->data)); } break; 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; 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; } 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; case CONFTYPE_INTRANGE: valdst->v.intrange[0] = valsrc->v.intrange[0]; valdst->v.intrange[1] = valsrc->v.intrange[1]; break; 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); g_hash_table_foreach(valsrc->v.proplist, ©_proplist_foreach_fn, valdst->v.proplist); } else { valdst->v.proplist = NULL; } break; case CONFTYPE_APPLICATION: valdst->v.s = g_strdup(valsrc->v.s); break; case CONFTYPE_AUTOLABEL: valdst->v.autolabel.template = g_strdup(valsrc->v.autolabel.template); valdst->v.autolabel.autolabel = valsrc->v.autolabel.autolabel; break; case CONFTYPE_LABELSTR: valdst->v.labelstr.template = g_strdup(valsrc->v.labelstr.template); valdst->v.labelstr.match_autolabel = valsrc->v.labelstr.match_autolabel; break; case CONFTYPE_DUMP_SELECTION: valdst->v.dump_selection= NULL; for (ia = valsrc->v.dump_selection; ia != NULL; ia = ia->next) { dump_selection_t *src_dump_s = ia->data; dump_selection_t *dst_dump_s = g_new0(dump_selection_t, 1); dst_dump_s->tag_type = src_dump_s->tag_type; dst_dump_s->tag = g_strdup(src_dump_s->tag); dst_dump_s->level = src_dump_s->level; valdst->v.dump_selection = g_slist_append(valdst->v.dump_selection, dst_dump_s); } break; case CONFTYPE_VAULT_LIST: valdst->v.vault_list= NULL; for (ia = valsrc->v.vault_list; ia != NULL; ia = ia->next) { vault_el_t *src_vault_s = ia->data; vault_el_t *dst_vault_s = g_new0(vault_el_t, 1); dst_vault_s->storage = g_strdup(src_vault_s->storage); dst_vault_s->days = src_vault_s->days; valdst->v.vault_list = g_slist_append(valdst->v.vault_list, dst_vault_s); } break; } } 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->visible = property->visible; 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, g_strdup(elem->data)); } if (new_prop) g_hash_table_insert(proplist, g_strdup(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->visible = property->visible; 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, g_strdup(elem->data)); } g_hash_table_insert(proplist, g_strdup(property_s), new_property); } static void free_dump_selection( gpointer p) { dump_selection_t *dump_s = p; g_free(dump_s->tag); g_free(dump_s); } static void free_vault( gpointer p) { vault_el_t *vault_s = p; g_free(vault_s->storage); } 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 CONFTYPE_IDENT: case CONFTYPE_STR: case CONFTYPE_APPLICATION: amfree(val->v.s); break; case CONFTYPE_IDENTLIST: case CONFTYPE_STR_LIST: slist_free_full(val->v.identlist, g_free); break; case CONFTYPE_HOST_LIMIT: slist_free_full(val->v.host_limit.match_pats, g_free); break; case CONFTYPE_TIME: break; case CONFTYPE_ESTIMATELIST: g_slist_free(val->v.estimatelist); break; case CONFTYPE_EXINCLUDE: free_sl(val_t__exinclude(val).sl_list); free_sl(val_t__exinclude(val).sl_file); break; case CONFTYPE_PROPLIST: g_hash_table_destroy(val_t__proplist(val)); break; case CONFTYPE_AUTOLABEL: amfree(val->v.autolabel.template); break; case CONFTYPE_LABELSTR: amfree(val->v.labelstr.template); break; case CONFTYPE_DUMP_SELECTION: slist_free_full(val->v.dump_selection, free_dump_selection); break; case CONFTYPE_VAULT_LIST: slist_free_full(val->v.vault_list, free_vault); break; } val->seen.linenum = 0; val->seen.filename = NULL; val->seen.block = NULL; } /* * Utilities Implementation */ char * generic_get_security_conf( char *string, void *arg G_GNUC_UNUSED) { char *result = NULL; if(!string || !*string) return(NULL); if (g_str_equal(string, "krb5principal")) { result = getconf_str(CNF_KRB5PRINCIPAL); } else if (g_str_equal(string, "krb5keytab")) { result = getconf_str(CNF_KRB5KEYTAB); } if (result && strlen(result) == 0) result = NULL; return(result); } char * generic_client_get_security_conf( char *string, void *arg G_GNUC_UNUSED) { char *result = NULL; if(!string || !*string) return(NULL); if (g_str_equal(string, "conf")) { result = getconf_str(CNF_CONF); } else if (g_str_equal(string, "amdump_server")) { result = getconf_str(CNF_AMDUMP_SERVER); } else if (g_str_equal(string, "index_server")) { result = getconf_str(CNF_INDEX_SERVER); } else if (g_str_equal(string, "tape_server")) { result = getconf_str(CNF_TAPE_SERVER); } else if (g_str_equal(string, "tapedev")) { result = getconf_str(CNF_TAPEDEV); } else if (g_str_equal(string, "auth")) { result = getconf_str(CNF_AUTH); } else if (g_str_equal(string, "ssh_keys")) { result = getconf_str(CNF_SSH_KEYS); } else if (g_str_equal(string, "amandad_path")) { result = getconf_str(CNF_AMANDAD_PATH); } else if (g_str_equal(string, "client_username")) { result = getconf_str(CNF_CLIENT_USERNAME); } else if (g_str_equal(string, "client_port")) { result = getconf_str(CNF_CLIENT_PORT); } else if (g_str_equal(string, "gnutar_list_dir")) { result = getconf_str(CNF_GNUTAR_LIST_DIR); } else if (g_str_equal(string, "amandates")) { result = getconf_str(CNF_AMANDATES); } else if (g_str_equal(string, "krb5principal")) { result = getconf_str(CNF_KRB5PRINCIPAL); } else if (g_str_equal(string, "krb5keytab")) { result = getconf_str(CNF_KRB5KEYTAB); } else if (g_str_equal(string, "ssl_dir")) { result = getconf_str(CNF_SSL_DIR); } else if (g_str_equal(string, "ssl_fingerprint_file")) { result = getconf_str(CNF_SSL_FINGERPRINT_FILE); } else if (g_str_equal(string, "ssl_cert_file")) { result = getconf_str(CNF_SSL_CERT_FILE); } else if (g_str_equal(string, "ssl_key_file")) { result = getconf_str(CNF_SSL_KEY_FILE); } else if (g_str_equal(string, "ssl_ca_cert_file")) { result = getconf_str(CNF_SSL_CA_CERT_FILE); } else if (g_str_equal(string, "ssl_cipher_list")) { result = getconf_str(CNF_SSL_CIPHER_LIST); } else if (g_str_equal(string, "ssl_check_host")) { if (getconf_boolean(CNF_SSL_CHECK_HOST)) result = "1"; else result = "0"; } else if (g_str_equal(string, "ssl_check_certificate_host")) { if (getconf_boolean(CNF_SSL_CHECK_CERTIFICATE_HOST)) result = "1"; else result = "0"; } else if (g_str_equal(string, "ssl_check_fingerprint")) { if (getconf_boolean(CNF_SSL_CHECK_FINGERPRINT)) result = "1"; else result = "0"; } if (result && strlen(result) == 0) result = NULL; return(result); } 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; policy_s *po; storage_t *st; int i; conf_var_t *np; keytab_t *kt; char *prefix; if (config_client) { error(_("Don't know how to dump client configurations.")); /* NOTREACHED */ } g_printf(_("# AMANDA CONFIGURATION FROM FILE '%s':\n\n"), config_filename); for(np=server_var; np->token != CONF_UNKNOWN; np++) { for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) if (np->token == kt->token) break; 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(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 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); } } 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 && g_str_equal(ip->seen.filename, netusage_seen->filename)) prefix = "#"; else 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(g_str_equal(ap->name, "default")) 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")); for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) if(kt->token == np->token) break; if(kt->token == CONF_UNKNOWN) error(_("application bad token")); val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &ap->value[i]); } g_printf("%s}\n",prefix); } for(ps = pp_script_list; ps != NULL; ps = ps->next) { if(g_str_equal(ps->name, "default")) 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")); for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) if(kt->token == np->token) break; if(kt->token == CONF_UNKNOWN) error(_("script bad token")); val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &ps->value[i]); } g_printf("%s}\n",prefix); } 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")); for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) if(kt->token == np->token) break; if(kt->token == CONF_UNKNOWN) error(_("device bad token")); val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &dc->value[i]); } g_printf("%s}\n",prefix); } 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")); for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) if(kt->token == np->token) break; if(kt->token == CONF_UNKNOWN) error(_("changer bad token")); val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &cc->value[i]); } g_printf("%s}\n",prefix); } 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")); for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) if(kt->token == np->token) break; if(kt->token == CONF_UNKNOWN) error(_("interactivity bad token")); val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &iv->value[i]); } g_printf("%s}\n",prefix); } 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")); for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) if(kt->token == np->token) break; if(kt->token == CONF_UNKNOWN) error(_("taperscan bad token")); val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &ts->value[i]); } g_printf("%s}\n",prefix); } for(po = policy_list; po != NULL; po = po->next) { prefix = ""; g_printf("\n%sDEFINE POLICY %s {\n", prefix, po->name); for(i=0; i < POLICY_POLICY; i++) { for(np=policy_var; np->token != CONF_UNKNOWN; np++) if(np->parm == i) break; if(np->token == CONF_UNKNOWN) error(_("policy bad value")); for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) if(kt->token == np->token) break; if(kt->token == CONF_UNKNOWN) error(_("policy bad token")); val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &po->value[i]); } g_printf("%s}\n",prefix); } for(st = storage_list; st != NULL; st = st->next) { prefix = ""; g_printf("\n%sDEFINE STORAGE %s {\n", prefix, st->name); for(i=0; i < STORAGE_STORAGE; i++) { for(np=storage_var; np->token != CONF_UNKNOWN; np++) if(np->parm == i) break; if(np->token == CONF_UNKNOWN) error(_("storage bad value")); for(kt = server_keytab; kt->token != CONF_UNKNOWN; kt++) if(kt->token == np->token) break; if(kt->token == CONF_UNKNOWN) error(_("storage bad token")); val_t_print_token(print_default, print_source, stdout, prefix, " %-19s ", kt, &st->value[i]); } g_printf("%s}\n",prefix); } } void dump_dumptype( dumptype_t *dp, char *prefix, gboolean print_default, gboolean print_source) { int i; conf_var_t *np; keytab_t *kt; 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]); } } static void val_t_print_token( gboolean print_default, gboolean print_source, FILE *output, char *prefix, char *format, keytab_t *kt, val_t *val) { char **dispstrs, **dispstr; if (print_default == 0 && !val_t_seen(val)) { return; } dispstrs = val_t_display_strs(val, 1, print_source, TRUE); /* 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. */ /* 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); } } g_strfreev(dispstrs); } 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) { char *buf; 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; } char ** val_t_display_strs( val_t *val, int str_need_quote, gboolean print_source, gboolean print_unit) { gboolean add_source = TRUE; int i; char **buf; buf = malloc(3*sizeof(char *)); buf[0] = NULL; buf[1] = NULL; buf[2] = NULL; switch(val->type) { case CONFTYPE_INT: buf[0] = g_strdup_printf("%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: buf[0] = g_strdup_printf("%zu ", (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_INT64: buf[0] = g_strdup_printf("%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: buf[0] = g_strdup_printf("%0.5f", val_t__real(val)); break; case CONFTYPE_RATE: buf[0] = g_strdup_printf("%0.5f %0.5f", val_t__rate(val)[0], val_t__rate(val)[1]); break; case CONFTYPE_INTRANGE: buf[0] = g_strdup_printf("%d,%d", val_t__intrange(val)[0], val_t__intrange(val)[1]); break; case CONFTYPE_IDENT: if(val->v.s) { buf[0] = g_strdup(val->v.s); } else { buf[0] = g_strdup(""); } break; case CONFTYPE_IDENTLIST: { GSList *ia; int first = 1; buf[0] = NULL; if (!val->v.identlist) { strappend(buf[0], "\"\""); } else { for (ia = val->v.identlist; ia != NULL; ia = ia->next) { if (first) { buf[0] = g_strdup(ia->data); first = 0; } else { strappend(buf[0], " "); strappend(buf[0], ia->data); } } } } break; case CONFTYPE_STR_LIST: { GSList *ia; int first = 1; buf[0] = NULL; for (ia = val->v.identlist; ia != NULL; ia = ia->next) { if (first) { buf[0] = quote_string_always(ia->data); first = 0; } else { char *qdata = quote_string_always(ia->data); strappend(buf[0], " "); strappend(buf[0], qdata); g_free(qdata); } } } break; case CONFTYPE_STR: if(str_need_quote) { if(val->v.s) { buf[0] = quote_string_always(val->v.s); } else { buf[0] = g_strdup("\"\""); } } else { if(val->v.s) { buf[0] = g_strdup(val->v.s); } else { buf[0] = g_strdup(""); } } break; case CONFTYPE_AUTOLABEL: { autolabel_set_t autolabel = val->v.autolabel.autolabel; char *template = quote_string_always(val->v.autolabel.template); GString *strbuf = g_string_new(template); g_free(template); if (autolabel & AL_OTHER_CONFIG) g_string_append(strbuf, " OTHER-CONFIG"); if (autolabel & AL_NON_AMANDA) g_string_append(strbuf, " NON-AMANDA"); if (autolabel & AL_VOLUME_ERROR) g_string_append(strbuf, " VOLUME-ERROR"); if (autolabel & AL_EMPTY) g_string_append(strbuf, " EMPTY"); buf[0] = g_string_free(strbuf, FALSE); } break; case CONFTYPE_LABELSTR: { if (val->v.labelstr.match_autolabel) { buf[0] = g_strdup("MATCH-AUTOLABEL"); } else { buf[0] = quote_string_always(val->v.labelstr.template); } } break; case CONFTYPE_TIME: buf[0] = g_strdup_printf("%2d%02d", (int)val_t__time(val)/100, (int)val_t__time(val) % 100); break; case CONFTYPE_EXINCLUDE: { buf[0] = exinclude_display_str(val, 0); buf[1] = exinclude_display_str(val, 1); break; } case CONFTYPE_BOOLEAN: if(val_t__boolean(val)) buf[0] = g_strdup("yes"); else buf[0] = g_strdup("no"); break; case CONFTYPE_NO_YES_ALL: switch(val_t__no_yes_all(val)) { case 0: buf[0] = g_strdup("no"); break; case 1: buf[0] = g_strdup("yes"); break; case 2: buf[0] = g_strdup("all"); break; } break; case CONFTYPE_STRATEGY: switch(val_t__strategy(val)) { case DS_SKIP: buf[0] = g_strdup("SKIP"); break; case DS_STANDARD: buf[0] = g_strdup("STANDARD"); break; case DS_NOFULL: buf[0] = g_strdup("NOFULL"); break; case DS_NOINC: buf[0] = g_strdup("NOINC"); break; case DS_HANOI: buf[0] = g_strdup("HANOI"); break; case DS_INCRONLY: buf[0] = g_strdup("INCRONLY"); break; } break; case CONFTYPE_COMPRESS: switch(val_t__compress(val)) { case COMP_NONE: buf[0] = g_strdup("NONE"); break; case COMP_FAST: buf[0] = g_strdup("CLIENT FAST"); break; case COMP_BEST: buf[0] = g_strdup("CLIENT BEST"); break; case COMP_CUST: buf[0] = g_strdup("CLIENT CUSTOM"); break; case COMP_SERVER_FAST: buf[0] = g_strdup("SERVER FAST"); break; case COMP_SERVER_BEST: buf[0] = g_strdup("SERVER BEST"); break; case COMP_SERVER_CUST: buf[0] = g_strdup("SERVER CUSTOM"); break; } break; case CONFTYPE_ESTIMATELIST: { estimatelist_t es = val_t__estimatelist(val); buf[0] = g_strdup(""); 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 EXECUTE_WHERE_CLIENT: buf[0] = g_strdup("CLIENT"); break; case EXECUTE_WHERE_SERVER: buf[0] = g_strdup("SERVER"); break; } break; case CONFTYPE_SEND_AMREPORT_ON: switch(val->v.i) { case SEND_AMREPORT_ALL: buf[0] = g_strdup("ALL"); break; case SEND_AMREPORT_STRANGE: buf[0] = g_strdup("STRANGE"); break; case SEND_AMREPORT_ERROR: buf[0] = g_strdup("ERROR"); break; case SEND_AMREPORT_NEVER: buf[0] = g_strdup("NEVER"); break; } break; case CONFTYPE_DATA_PATH: buf[0] = g_strdup(data_path_to_string(val->v.i)); break; case CONFTYPE_ENCRYPT: switch(val_t__encrypt(val)) { case ENCRYPT_NONE: buf[0] = g_strdup("NONE"); break; case ENCRYPT_CUST: buf[0] = g_strdup("CLIENT"); break; case ENCRYPT_SERV_CUST: buf[0] = g_strdup("SERVER"); break; } break; case CONFTYPE_PART_CACHE_TYPE: switch(val_t__part_cache_type(val)) { case PART_CACHE_TYPE_NONE: buf[0] = g_strdup("NONE"); break; case PART_CACHE_TYPE_DISK: buf[0] = g_strdup("DISK"); break; case PART_CACHE_TYPE_MEMORY: buf[0] = g_strdup("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] = g_strdup("SAME-HOST "); else buf[0] = g_strdup(""); if (val_t__host_limit(val).server) strappend(buf[0], "SERVER "); while (iter) { char *qbuf = quote_string_always((char *)iter->data); strappend(buf[0], qbuf); strappend(buf[0], " "); amfree(qbuf); iter = iter->next; } break; } case CONFTYPE_HOLDING: switch(val_t__holding(val)) { case HOLD_NEVER: buf[0] = g_strdup("NEVER"); break; case HOLD_AUTO: buf[0] = g_strdup("AUTO"); break; case HOLD_REQUIRED: buf[0] = g_strdup("REQUIRED"); break; } break; case CONFTYPE_TAPERALGO: buf[0] = g_strdup_printf("%s", taperalgo2str(val_t__taperalgo(val))); break; case CONFTYPE_PRIORITY: switch(val_t__priority(val)) { case PRIORITY_LOW: buf[0] = g_strdup("LOW"); break; case PRIORITY_MEDIUM: buf[0] = g_strdup("MEDIUM"); break; case PRIORITY_HIGH: buf[0] = g_strdup("HIGH"); break; default: buf[0] = g_strdup_printf("%d", val_t__priority(val)); 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 = g_new0(char *, nb_property+1); 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] = g_strdup(""); } break; } case CONFTYPE_EXECUTE_ON: buf[0] = execute_on_to_string(val->v.i, ", "); break; case CONFTYPE_DUMP_SELECTION: { int nb_selection = g_slist_length(val_t__dump_selection(val)); dump_selection_list_t dsl; int i = 0; g_free(buf); buf = malloc((nb_selection+1)*sizeof(char*)); buf[nb_selection] = NULL; for (dsl = val->v.dump_selection ; dsl != NULL ; dsl = dsl->next) { dump_selection_t *ds = dsl->data; char *tag = NULL; char *level = NULL; switch (ds->tag_type) { case TAG_NAME: tag = quote_string_always(ds->tag); break; case TAG_ALL: tag = "ALL"; break; case TAG_OTHER: tag = "OTHER"; break; } switch (ds->level) { case LEVEL_ALL: level = "ALL"; break; case LEVEL_FULL: level = "FULL"; break; case LEVEL_INCR: level = "INCR"; break; } buf[i++] = g_strdup_printf("%s %s", tag, level); if (ds->tag_type == TAG_NAME) { g_free(tag); } } break; } case CONFTYPE_VAULT_LIST: { int nb_selection = g_slist_length(val_t__vault_list(val)); vault_list_t vl; int i = 0; g_free(buf); buf = malloc((nb_selection+1)*sizeof(char*)); buf[nb_selection] = NULL; for (vl = val->v.vault_list ; vl != NULL ; vl = vl->next) { vault_el_t *v = vl->data; char *s = quote_string_always(v->storage); buf[i++] = g_strdup_printf("%s %d", s, v->days); g_free(s); } break; } } /* add source */ if (print_source && add_source) { char **buf1; for (buf1 = buf; *buf1 != NULL; buf1++) { char *ss = source_string(&val->seen); char *buf2 = g_strjoin("", *buf1, ss, NULL); g_free(*buf1); g_free(ss); *buf1 = buf2; } } return buf; } 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); } execute_where_t 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; } 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; } static void proplist_display_str_foreach_fn( gpointer key_p, gpointer value_p, gpointer user_data_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; GPtrArray *array = g_ptr_array_new(); gchar **strings; /* What to do with property->append? it should be printed only on client */ if (property->visible) g_ptr_array_add(array, g_strdup("visible")); else g_ptr_array_add(array, g_strdup("hidden")); if (property->priority) g_ptr_array_add(array, g_strdup("priority")); g_ptr_array_add(array, quote_string_always(key_p)); for (value = property->values; value; value = value->next) g_ptr_array_add(array, quote_string_always((char *)value->data)); if (user_data->print_source) { g_ptr_array_add(array, source_string(&property->seen)); } g_ptr_array_add(array, NULL); strings = (gchar **)g_ptr_array_free(array, FALSE); **msg = g_strjoinv(" ", strings); g_strfreev(strings); (*msg)++; } static char * exinclude_display_str( val_t *val, int file) { am_sl_t *sl; sle_t *excl; char *rval; GPtrArray *array = g_ptr_array_new(); gchar **strings; assert(val->type == CONFTYPE_EXINCLUDE); if (file == 0) { sl = val_t__exinclude(val).sl_list; g_ptr_array_add(array, g_strdup("LIST")); } else { sl = val_t__exinclude(val).sl_file; g_ptr_array_add(array, g_strdup("FILE")); } if (val_t__exinclude(val).optional == 1) g_ptr_array_add(array, g_strdup("OPTIONAL")); if (sl != NULL) for(excl = sl->first; excl; excl = excl->next) g_ptr_array_add(array, quote_string_always(excl->name)); g_ptr_array_add(array, NULL); strings = (gchar **)g_ptr_array_free(array, FALSE); rval = g_strjoinv(" ", strings); g_strfreev(strings); return rval; } char * taperalgo2str( taperalgo_t taperalgo) { 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 * config_dir_relative( char *filename) { char *cdir = NULL; if (*filename == '/' || config_dir == NULL) { cdir = g_strdup(filename); } else { if (config_dir[strlen(config_dir)-1] == '/') { cdir = g_strjoin(NULL, config_dir, filename, NULL); } else { cdir = g_strjoin(NULL, config_dir, "/", filename, NULL); } } if (prepend_prefix) { char *cdir1 = g_strconcat(prepend_prefix, "/", cdir, NULL); g_free(cdir); cdir = cdir1; } return cdir; } static int parm_key_info( char *key, conf_var_t **parm, val_t **val) { 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; policy_s *po; storage_t *st; interactivity_t *iv; int success = FALSE; /* WARNING: assumes globals keytable and parsetable are set correctly. */ assert(keytable != NULL); assert(parsetable != NULL); /* make a copy we can stomp on */ key = g_strdup(key); /* uppercase the key */ for (s = key; (ch = *s) != 0; s++) { if (islower((int)ch)) *s = (char)toupper(ch); } subsec_name = strchr(key, ':'); if (subsec_name) { subsec_type = key; *subsec_name = '\0'; subsec_name++; /* convert subsec_type '-' to '_' */ for (s = subsec_type; (ch = *s) != 0; s++) { if (*s == '-') *s = '_'; } subsec_key = strrchr(subsec_name,':'); if(!subsec_key) goto out; /* failure */ *subsec_key = '\0'; subsec_key++; /* convert subsec_key '-' to '_' */ for (s = subsec_key; (ch = *s) != 0; s++) { if (*s == '-') *s = '_'; } /* 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 && g_str_equal(kt->keyword, subsec_key)) break; } if(kt->token == CONF_UNKNOWN) goto out; /* Otherwise, figure out which kind of subsection we're dealing with, * and parse against that. */ if (g_str_equal(subsec_type, "TAPETYPE")) { 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 (g_str_equal(subsec_type, "DUMPTYPE")) { 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 (g_str_equal(subsec_type, "HOLDINGDISK")) { 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 (g_str_equal(subsec_type, "INTERFACE")) { 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 (g_str_equal(subsec_type, "APPLICATION_TOOL") || g_str_equal(subsec_type, "APPLICATION")) { 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 (g_str_equal(subsec_type, "SCRIPT_TOOL") || g_str_equal(subsec_type, "SCRIPT")) { 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 (g_str_equal(subsec_type, "DEVICE")) { 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 (g_str_equal(subsec_type, "CHANGER")) { 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; if (val) *val = &ts->value[np->parm]; if (parm) *parm = np; success = TRUE; } else if (g_str_equal(subsec_type, "POLICY")) { po = lookup_policy(subsec_name); if (!po) goto out; for(np = policy_var; np->token != CONF_UNKNOWN; np++) { if(np->token == kt->token) break; } if (np->token == CONF_UNKNOWN) goto out; if (val) *val = &po->value[np->parm]; if (parm) *parm = np; success = TRUE; } else if (g_str_equal(subsec_type, "STORAGE")) { st = lookup_storage(subsec_name); if (!st) goto out; for(np = storage_var; np->token != CONF_UNKNOWN; np++) { if(np->token == kt->token) break; } if (np->token == CONF_UNKNOWN) goto out; if (val) *val = &st->value[np->parm]; if (parm) *parm = np; success = TRUE; } /* No delimiters -- we're referencing a global config parameter */ } else { /* convert key '-' to '_' */ for (s = key; (ch = *s) != 0; s++) { if (*s == '-') *s = '_'; } /* look up the keyword */ for(kt = keytable; kt->token != CONF_UNKNOWN; kt++) { if(kt->keyword && g_str_equal(kt->keyword, key)) break; } if(kt->token == CONF_UNKNOWN) goto out; /* 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; } } } /* None found; this is an error. */ g_free(str); return 0; } int string_to_boolean( const char *str) { keytab_t * table_entry; if (str == NULL || *str == '\0') { return -1; } /* 0 and 1 are not in the table, as they are parsed as ints */ if (g_str_equal(str, "0")) return 0; if (g_str_equal(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; } /* * Error Handling Implementaiton */ void config_add_error( cfgerr_level_t level, char * errmsg) { cfgerr_level = max(cfgerr_level, level); g_debug("%s", errmsg); cfgerr_errors = g_slist_append(cfgerr_errors, errmsg); } static void conf_error_common( cfgerr_level_t level, const char * format, va_list argp) { char *msg = NULL; char *errstr = NULL; if (!generate_errors) return; msg = g_strdup_vprintf(format, argp); 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); config_add_error(level, errstr); } G_GNUC_PRINTF(1, 2) static void conf_parserror(const char *format, ...) { va_list argp; arglist_start(argp, format); conf_error_common(CFGERR_ERRORS, format, argp); arglist_end(argp); } G_GNUC_PRINTF(1, 2) static void conf_parswarn(const char *format, ...) { va_list argp; arglist_start(argp, format); conf_error_common(CFGERR_WARNINGS, format, argp); arglist_end(argp); } cfgerr_level_t config_errors(GSList **errstr) { if (errstr) *errstr = cfgerr_errors; return cfgerr_level; } void config_clear_errors(void) { slist_free_full(cfgerr_errors, g_free); cfgerr_errors = NULL; cfgerr_level = CFGERR_OK; } void config_print_errors(void) { GSList *iter; for (iter = cfgerr_errors; iter; iter = g_slist_next(iter)) { g_fprintf(stderr, "%s\n", (char *)iter->data); } } void config_print_errors_as_message(void) { GSList *iter; for (iter = cfgerr_errors; iter; iter = g_slist_next(iter)) { g_fprintf(stdout, " {\n" \ " \"source_filename\" : \"%s\",\n" \ " \"source_line\" : \"%d\",\n" \ " \"severity\" : \"error\",\n" \ " \"code\" : \"%d\",\n" \ " \"message\" : \"%s\"\n" \ " \"process\" : \"%s\"\n" \ " \"running_on\" : \"%s\"\n" \ " \"component\" : \"%s\"\n" \ " \"module\" : \"%s\"\n" \ " },\n", AMANDA_FILE, __LINE__, 1500016 , get_pname(), get_running_on(), get_pcomponent(), get_pmodule(), (char *)iter->data); } } /* Get the config name */ char *get_config_name(void) { return config_name; } /* Get the config directory */ char *get_config_dir(void) { return config_dir; } /* Get the config filename */ char *get_config_filename(void) { return config_filename; } char * get_running_on(void) { if (!config_client) { return "amanda-server"; } else { return "amanda-client"; } } char * anonymous_value(void) { static char number[NUM_STR_SIZE]; static int value=1; g_snprintf(number, sizeof(number), "%d", value); value++; return number; } gint compare_pp_script_order( gconstpointer a, gconstpointer b) { return pp_script_get_order(lookup_pp_script((char *)a)) > pp_script_get_order(lookup_pp_script((char *)b)); } char * data_path_to_string( data_path_t data_path) { switch (data_path) { case DATA_PATH_AMANDA : return "AMANDA"; case DATA_PATH_DIRECTTCP: return "DIRECTTCP"; } error(_("datapath is not DATA_PATH_AMANDA or DATA_PATH_DIRECTTCP")); /* NOTREACHED */ } data_path_t data_path_from_string( char *data) { if (g_str_equal(data, "AMANDA")) return DATA_PATH_AMANDA; if (g_str_equal(data, "DIRECTTCP")) return DATA_PATH_DIRECTTCP; error(_("datapath is not AMANDA or DIRECTTCP :%s:"), data); /* NOTREACHED */ } gchar * amandaify_property_name( const gchar *name) { gchar *ret, *cur_r; const gchar *cur_o; if (!name) return NULL; 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); cur_r++; } return ret; } static char keyword_str[1024]; static char * str_keyword( keytab_t *kt) { char *p = kt->keyword; char *s = keyword_str; while(*p != '\0') { if (*p == '_') { *s = '-'; } else { *s = *p; } p++; s++; } *s = '\0'; return keyword_str; } /* * The CONFTYPE_EXECUTE_ON keywork has LOTS of flags in it, and two call sites * need to build a string out of it. * * In order to avoid having to modify both call sites in case one flag is added, * create a helper function which gives back a string to the caller. The array * defined below MUST be kept in sync with conffile.h! */ static keytab_t execute_on_strings[] = { { "PRE-AMCHECK", EXECUTE_ON_PRE_AMCHECK }, { "PRE-DLE-AMCHECK", EXECUTE_ON_PRE_DLE_AMCHECK }, { "PRE-HOST-AMCHECK", EXECUTE_ON_PRE_HOST_AMCHECK }, { "POST-DLE-AMCHECK", EXECUTE_ON_POST_DLE_AMCHECK }, { "POST-HOST-AMCHECK", EXECUTE_ON_POST_HOST_AMCHECK }, { "POST-AMCHECK", EXECUTE_ON_POST_AMCHECK }, { "PRE-ESTIMATE", EXECUTE_ON_PRE_ESTIMATE }, { "PRE-DLE-ESTIMATE", EXECUTE_ON_PRE_DLE_ESTIMATE }, { "PRE-HOST-ESTIMATE", EXECUTE_ON_PRE_HOST_ESTIMATE }, { "POST-DLE-ESTIMATE", EXECUTE_ON_POST_DLE_ESTIMATE }, { "POST-HOST-ESTIMATE", EXECUTE_ON_POST_HOST_ESTIMATE }, { "POST-ESTIMATE", EXECUTE_ON_POST_ESTIMATE }, { "PRE-BACKUP", EXECUTE_ON_PRE_BACKUP }, { "PRE-DLE-BACKUP", EXECUTE_ON_PRE_DLE_BACKUP }, { "PRE-HOST-BACKUP", EXECUTE_ON_PRE_HOST_BACKUP }, { "POST-BACKUP", EXECUTE_ON_POST_BACKUP }, { "POST-DLE-BACKUP", EXECUTE_ON_POST_DLE_BACKUP }, { "POST-HOST-BACKUP", EXECUTE_ON_POST_HOST_BACKUP }, { "PRE-RECOVER", EXECUTE_ON_PRE_RECOVER }, { "POST-RECOVER", EXECUTE_ON_POST_RECOVER }, { "PRE-LEVEL-RECOVER", EXECUTE_ON_PRE_LEVEL_RECOVER }, { "POST-LEVEL-RECOVER", EXECUTE_ON_POST_LEVEL_RECOVER }, { "INTER-LEVEL-RECOVER", EXECUTE_ON_INTER_LEVEL_RECOVER }, { NULL, 0 } }; char *execute_on_to_string(int flags, char *separator) { char *ret; GPtrArray *array = g_ptr_array_new(); gchar **strings; keytab_t *entry; for (entry = execute_on_strings; entry->token; entry++) if (flags & entry->token) g_ptr_array_add(array, entry->keyword); g_ptr_array_add(array, NULL); strings = (gchar **)g_ptr_array_free(array, FALSE); ret = g_strjoinv(separator, strings); /* * We MUST NOT free the strings in the array... */ g_free(strings); return ret; } char * custom_escape( char *str) { char *s; for (s = str; *s != '\0'; s++) { if (*s == '/') *s = '_'; } return str; } val_t * getconf_human( confparm_key key) { return getconf(key); } val_t * dumptype_getconf_human( dumptype_t *dtyp, dumptype_key key) { return dumptype_getconf(dtyp, key); } val_t * tapetype_getconf_human( tapetype_t *typ, tapetype_key key) { return tapetype_getconf(typ, key); } val_t * application_getconf_human( application_t *typ, application_key key) { return application_getconf(typ, key); } val_t * device_config_getconf_human( device_config_t *typ, device_config_key key) { return device_config_getconf(typ, key); } val_t * changer_config_getconf_human( changer_config_t *typ, changer_config_key key) { return changer_config_getconf(typ, key); } val_t * storage_getconf_human( storage_t *typ, storage_key key) { return storage_getconf(typ, key); } val_t * pp_script_getconf_human( pp_script_t *typ, pp_script_key key) { return pp_script_getconf(typ, key); } val_t * holdingdisk_getconf_human( holdingdisk_t *typ, holdingdisk_key key) { return holdingdisk_getconf(typ, key); } val_t * interface_getconf_human( interface_t *typ, interface_key key) { return interface_getconf(typ, key); } val_t * interactivity_getconf_human( interactivity_t *typ, interactivity_key key) { return interactivity_getconf(typ, key); } val_t * taperscan_getconf_human( taperscan_t *typ, taperscan_key key) { return taperscan_getconf(typ, key); } val_t * policy_getconf_human( policy_s *typ, policy_key key) { return policy_getconf(typ, key); } static gboolean is_valid_label( char *template) { char *t; for (t=template; *t != '\0'; t++) { if (*t <= 32 || *t == '"') return FALSE; } return TRUE; }