+/* (convenience macros)
+ * fetch a particular parameter; caller must know the correct type.
+ *
+ * @param ttyp: the application to examine
+ * @returns: various
+ */
+#define application_get_comment(application) (val_t_to_str(application_getconf((application), APPLICATION_COMMENT))
+#define application_get_plugin(application) (val_t_to_str(application_getconf((application), APPLICATION_PLUGIN)))
+#define application_get_property(application) (val_t_to_proplist(application_getconf((application), APPLICATION_PROPERTY)))
+
+application_t *read_application(char *name, FILE *from, char *fname, int *linenum);
+
+/* A pp-script-tool interface */
+typedef enum pp_script_e {
+ PP_SCRIPT_COMMENT,
+ PP_SCRIPT_PLUGIN,
+ PP_SCRIPT_PROPERTY,
+ PP_SCRIPT_EXECUTE_ON,
+ PP_SCRIPT_EXECUTE_WHERE,
+ PP_SCRIPT_PP_SCRIPT
+} pp_script_key;
+
+/* opaque object */
+typedef struct pp_script_s pp_script_t;
+
+/* Given the name of the pp_script, return a pp_script object. Returns NULL
+ * if no matching pp_script exists. Note that the match is case-insensitive.
+ *
+ * @param identifier: name of the desired pp_script
+ * @returns: object or NULL
+ */
+
+pp_script_t *lookup_pp_script(char *identifier);
+
+/* Given a pp_script and a key, return a pointer to the corresponding val_t.
+ *
+ * @param ttyp: the pp_script to examine
+ * @param key: pp_script (one of the PP_SCRIPT_* constants)
+ * @returns: pointer to value
+ */
+val_t *pp_script_getconf(pp_script_t *pps, pp_script_key key);
+
+/* Get the name of this pp_script.
+ *
+ * @param ttyp: the pp_script to examine
+ * @returns: name of the pp_script
+ */
+char *pp_script_name(pp_script_t *pps);
+
+/* (convenience macro) has this parameter been seen in this pp_script? This
+ * applies to the specific parameter *within* the pp_script.
+ *
+ * @param key: pp_script_key
+ * @returns: boolean
+ */
+#define pp_script_seen(pps, key) (val_t_seen(pp_script_getconf((pps), (key))))
+
+/* (convenience macros)
+ * fetch a particular parameter; caller must know the correct type.
+ *
+ * @param ttyp: the pp_script to examine
+ * @returns: various
+ */
+
+#define pp_script_get_comment(pp_script) (val_t_to_str(pp_script_getconf((pp_script), PP_SCRIPT_COMMENT)))
+#define pp_script_get_plugin(pp_script) (val_t_to_str(pp_script_getconf((pp_script), PP_SCRIPT_PLUGIN)))
+#define pp_script_get_property(pp_script) (val_t_to_proplist(pp_script_getconf((pp_script), PP_SCRIPT_PROPERTY)))
+#define pp_script_get_execute_on(pp_script) (val_t_to_execute_on(pp_script_getconf((pp_script), PP_SCRIPT_EXECUTE_ON)))
+#define pp_script_get_execute_where(pp_script) (val_t_to_execute_where(pp_script_getconf((pp_script), PP_SCRIPT_EXECUTE_WHERE)))
+
+pp_script_t *read_pp_script(char *name, FILE *from, char *fname, int *linenum);
+pp_script_t *lookup_pp_script(char *identifier);
+
+/* A device definition */
+typedef enum {
+ DEVICE_CONFIG_COMMENT,
+ DEVICE_CONFIG_TAPEDEV,
+ DEVICE_CONFIG_DEVICE_PROPERTY,
+ DEVICE_CONFIG_DEVICE_CONFIG
+} device_config_key;
+
+/* opaque object */
+typedef struct device_config_s device_config_t;
+
+/* Given the name of the device, return a device_config_t object. Returns NULL
+ * if no matching device exists. Note that the match is case-insensitive.
+ *
+ * @param identifier: name of the desired device
+ * @returns: object or NULL
+ */
+
+device_config_t *lookup_device_config(char *identifier);
+
+/* Given a device_config and a key, return a pointer to the corresponding val_t.
+ *
+ * @param ttyp: the device_config to examine
+ * @param key: device_config (one of the DEVICE_CONFIG_* constants)
+ * @returns: pointer to value
+ */
+val_t *device_config_getconf(device_config_t *devconf, device_config_key key);
+
+/* Get the name of this device_config.
+ *
+ * @param ttyp: the device_config to examine
+ * @returns: name of the device_config
+ */
+char *device_config_name(device_config_t *devconf);
+
+/* (convenience macro) has this parameter been seen in this device_config? This
+ * applies to the specific parameter *within* the device_config.
+ *
+ * @param key: device_config_key
+ * @returns: boolean
+ */
+#define device_config_seen(devconf, key) (val_t_seen(device_config_getconf((devconf), (key))))
+
+/* (convenience macros)
+ * fetch a particular parameter; caller must know the correct type.
+ *
+ * @param devconf: the device_config to examine
+ * @returns: various
+ */
+
+#define device_config_get_comment(devconf) (val_t_to_str(device_config_getconf((devconf), DEVICE_CONFIG_COMMENT)))
+#define device_config_get_tapedev(devconf) (val_t_to_str(device_config_getconf((devconf), DEVICE_CONFIG_TAPEDEV)))
+#define device_config_get_property(devconf) (val_t_to_proplist(device_config_getconf((devconf), DEVICE_CONFIG_DEVICE_PROPERTY)))
+
+device_config_t *read_device_config(char *name, FILE *from, char *fname, int *linenum);
+device_config_t *lookup_device_config(char *identifier);
+
+/* A changer definition */
+typedef enum {
+ CHANGER_CONFIG_COMMENT,
+ CHANGER_CONFIG_TAPEDEV,
+ CHANGER_CONFIG_TPCHANGER,
+ CHANGER_CONFIG_CHANGERDEV,
+ CHANGER_CONFIG_CHANGERFILE,
+ CHANGER_CONFIG_CHANGER_CONFIG
+} changer_config_key;
+
+/* opaque object */
+typedef struct changer_config_s changer_config_t;
+
+/* Given the name of the changer, return a changer_config_t object. Returns NULL
+ * if no matching changer exists. Note that the match is case-insensitive.
+ *
+ * @param identifier: name of the desired changer
+ * @returns: object or NULL
+ */
+
+changer_config_t *lookup_changer_config(char *identifier);
+
+/* Given a changer_config and a key, return a pointer to the corresponding val_t.
+ *
+ * @param ttyp: the changer_config to examine
+ * @param key: changer_config (one of the DEVICE_CONFIG_* constants)
+ * @returns: pointer to value
+ */
+val_t *changer_config_getconf(changer_config_t *devconf, changer_config_key key);
+
+/* Get the name of this changer_config.
+ *
+ * @param ttyp: the changer_config to examine
+ * @returns: name of the changer_config
+ */
+char *changer_config_name(changer_config_t *devconf);
+
+/* (convenience macro) has this parameter been seen in this changer_config? This
+ * applies to the specific parameter *within* the changer_config.
+ *
+ * @param key: changer_config_key
+ * @returns: boolean
+ */
+#define changer_config_seen(devconf, key) (val_t_seen(changer_config_getconf((devconf), (key))))
+
+/* (convenience macros)
+ * fetch a particular parameter; caller must know the correct type.
+ *
+ * @param devconf: the changer_config to examine
+ * @returns: various
+ */
+
+#define changer_config_get_comment(devconf) (val_t_to_str(changer_config_getconf((devconf), DEVICE_CONFIG_COMMENT)))
+#define changer_config_get_tapedev(devconf) (val_t_to_str(changer_config_getconf((devconf), DEVICE_CONFIG_TAPEDEV)))
+#define changer_config_get_tpchanger(devconf) (val_t_to_str(changer_config_getconf((devconf), DEVICE_CONFIG_TPCHANGER)))
+#define changer_config_get_changerdev(devconf) (val_t_to_str(changer_config_getconf((devconf), DEVICE_CONFIG_CHANGERDEV)))
+#define changer_config_get_changerfile(devconf) (val_t_to_str(changer_config_getconf((devconf), DEVICE_CONFIG_CHANGERFILE)))
+
+changer_config_t *read_changer_config(char *name, FILE *from, char *fname, int *linenum);
+changer_config_t *lookup_changer_config(char *identifier);
+
+/*
+ * Error Handling
+ */
+
+typedef enum {
+ /* No errors or warnings */
+ CFGERR_OK = 0,
+
+ /* warnings were encountered */
+ CFGERR_WARNINGS = 1,
+
+ /* errors (and maybe some warnings too, who knows) were encountered */
+ CFGERR_ERRORS = 2,
+} cfgerr_level_t;
+
+/*
+ * Errors
+ */
+
+/* Get a GSList of all error and warning messages accumulated so far.
+ *
+ * @param (output) errlist: pointer to the list of error strings; allocated
+ * memory remains the responsibility of the config module. If errlist is
+ * NULL, the list is not returned.
+ * @returns: current error level
+ */
+cfgerr_level_t config_errors(GSList **errlist);
+
+/* Clear any error conditions.
+ */
+void config_clear_errors(void);
+
+/* Print the list of current error and warning messages, one per line,
+ * to stderr. This is a convenience function for command-line
+ * applications.
+ */
+void config_print_errors(void);
+
+/* Add an error message to the list of errors, and make sure tha the
+ * error level is at least LEVEL. This is used by the diskfile module
+ * to insert its errors into this module's error list.
+ *
+ * @param level: level for this error
+ * @param errmsg: error message; conffile takes responsibility for freeing
+ * this string.
+ */
+void config_add_error(cfgerr_level_t level, char *errmsg);
+
+/*
+ * Command-line handling
+ */
+
+/* opaque type */
+typedef struct config_overwrites_s config_overwrites_t;
+
+/* Create a new, empty config_overwrites object.
+ *
+ * @param size_estimate: a guess at the number of overwrites; argc/2 is a
+ * good estimate.
+ * @returns: new object
+ */
+config_overwrites_t *new_config_overwrites(int size_estimate);
+
+/* Free a config_overwrites object. This usually won't be needed, as
+ * apply_config_overwrites takes ownership of the overwrites for you.
+ *
+ * @param co: config_overwrites object
+ */
+void free_config_overwrites(config_overwrites_t *co);
+
+/* Add an overwrite to a config_overwrites object.
+ *
+ * @param co: the config_overwrites object
+ * @param key: the configuration parameter's key, possibly with the format
+ * SUBTYPE:NAME:KEYWORD
+ * @param value: the value for the parameter, as would be seen in amanda.conf
+ */
+void add_config_overwrite(config_overwrites_t *co,
+ char *key,
+ char *value);
+
+/* Add an overwrite option from the command line to a config_overwrites
+ * object. Calls error() with any errors
+ *
+ * @param co: the config_overwrites object
+ * @param optarg: the value of the command-line option
+ */
+void add_config_overwrite_opt(config_overwrites_t *co,
+ char *optarg);
+
+/* Given a command line, represented as argc/argv, extract any -o options
+ * as config overwrites. This function modifies argc and argv in place.
+ *
+ * This is the deprecated way to extract config overwrites, for applications
+ * which do not use getopt. The preferred method is to use getopt and
+ * call add_config_overwrite_opt for any -o options.
+ *
+ * @param argc: (in/out) command-line length
+ * @param argv: (in/out) command-line strings
+ * @returns: newly allocated config_overwrites object
+ */
+config_overwrites_t *
+extract_commandline_config_overwrites(int *argc,
+ char ***argv);
+
+/* Apply configuration overwrites to the current configuration and take
+ * ownership of the config_overwrites object. It is the caller's
+ * responsibility to handle any errors.
+ *
+ * @param co: the config_overwrites object
+ * @returns: current error level
+ */
+cfgerr_level_t apply_config_overwrites(config_overwrites_t *co);
+
+/*
+ * Initialization
+ */
+
+/* Constants for config_init */
+typedef enum {
+ /* Use arg_config_name, if not NULL */
+ CONFIG_INIT_EXPLICIT_NAME = 1 << 0,
+
+ /* Use the current working directory if an explicit name is not available */
+ CONFIG_INIT_USE_CWD = 1 << 1,
+
+ /* This is a client application (server is default) */
+ CONFIG_INIT_CLIENT = 1 << 2,
+
+ /* New configuration should "overlay" existing configuration; this
+ * is used by clients to load multiple amanda-client.conf files. */
+ CONFIG_INIT_OVERLAY = 1 << 3,
+} config_init_flags;
+
+/* Initialize this application's configuration, with the specific actions
+ * based on 'flags':
+ * - if CONFIG_INIT_OVERLAY is not set, configuration values are reset
+ * to their defaults
+ * - if CONFIG_INIT_EXPLICIT_NAME and arg_config_name is not NULL,
+ * use CONFIG_DIR/arg_config_name as config_dir arg_config_name as
+ * config_name.
+ * - otherwise, if CONFIG_USE_CWD is set, use the directory in which
+ * the application was started as config_dir, and its filename as
+ * config_name.
+ * - otherwise, for the client only, se config_dir to CONFIG_DIR and
+ * config_name to NULL.
+ * - depending on CONFIG_INIT_CLIENT, read amanda.conf or amanda-client.conf
+ *
+ * @param flags: flags indicating desired behavior, as above
+ * @param arg_config_name: config name to use (from e.g., argv[1])
+ * @returns: current error level
+ */
+cfgerr_level_t config_init(
+ config_init_flags flags,
+ char *arg_config_name);
+
+/* Free all memory allocated for the configuration. This effectively
+ * reverses the effects of config_init().
+ */
+void config_uninit(void);
+
+/* Encode any applied config_overwrites into a strv format suitale for
+ * executing another Amanda tool.
+ *
+ * The * result is dynamically allocated and NULL terminated. There is no
+ * provision to free the result, as this function is always called just
+ * before execve(..).
+ *
+ * First gives the number of array elements to leave for the caller to
+ * fill in. The usual calling pattern is this:
+ * command_line = get_config_options(3);
+ * command_line[0] = "appname";
+ * command_line[1] = config_name;
+ * command_line[2] = "--foo";
+ * execve(command_line[0], command_line, safe_env());
+ *
+ * @param first: number of unused elements to leave at the beginning of
+ * the array.
+ * @returns: NULL-terminated string array suitable for execve
+ */
+char **get_config_options(int first);
+
+/* Get the config name */
+char *get_config_name(void);
+
+/* Get the config directory */
+char *get_config_dir(void);
+
+/* Get the config filename */
+char *get_config_filename(void);
+
+/*
+ * Utilities
+ */
+
+/* Security plugins get their configuration information through a callback
+ * with the signature:
+ * char *callback(char *key, void *userpointer);
+ * where key is the name of the desired parameter, which may not match the
+ * name used in this module. See the implementations of these functions
+ * to learn which keys they support, or to add new keys.
+ */