Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages


home | help
APP_CONFIG(3)	       FreeBSD Library Functions Manual		 APP_CONFIG(3)

     app_config	-- application configuration system

     PDEL Library (libpdel, -lpdel)

     #include <sys/types.h>
     #include <pdel/config/app_config.h>

     struct app_config_ctx *
     app_config_init(struct pevent_ctx *ctx, const struct app_config *info,
	 void *cookie);

     app_config_uninit(struct app_config_ctx **ctxp);

     void *
     app_config_get_cookie(struct app_config_ctx *ctx);

     app_config_load(struct app_config_ctx *ctx, const char *path,
	 int allow_writeback);

     app_config_reload(struct app_config_ctx *ctx);

     void *
     app_config_new(struct app_config_ctx *ctx);

     app_config_set(struct app_config_ctx *ctx,	const void *config,
	 u_long	delay, char *ebuf, int emax);

     void *
     app_config_get(struct app_config_ctx *ctx,	int pending);

     const struct structs_type *
     app_config_get_type(struct	app_config_ctx *ctx);

     void *
     app_config_copy(struct app_config_ctx *ctx, const void *config);

     app_config_free(struct app_config_ctx *ctx, void **configp);

     extern const struct app_subsystem app_config_alog_subsystem;
     extern const struct app_subsystem app_config_curconf_subsystem;
     extern const struct app_subsystem app_config_directory_subsystem;
     extern const struct app_subsystem app_config_pidfile_subsystem;

     These functions implement an application configuration framework.

   Application model
     The app_config model assumes that the application's configuration is
     stored in a single	configuration object, which can	be any data structure
     that is describable by a structs(3) type.	The configuration can be
     stored in an XML file which is automatically updated.

     The application itself consists of	one or more subsystems.	 A subsystem
     is	an abstract activity that can be started or stopped and	whose behavior
     depends on	(some part of) the configuration object.  When the configura-
     tion object is changed, those subsystems that require it are automati-
     cally stopped and then restarted with the new configuration.

     The application may provide methods for:

	+o   Creating a new, default configuration object
	+o   Initializing a new configuration object for	the current system
	+o   Checking a configuration object for	overall	validity
	+o   Normalizing	a configuration	object
	+o   Upgrading a	configuration object from an old version

     Each subsystem may	provide	methods	for:

	+o   Starting the subsystem
	+o   Stopping the subsystem
	+o   Determining	if the subsystem will run
	+o   Determining	if the subsystem needs to be restarted

     In	the steady state, there	is a single currently active configuration ob-
     ject.  Only those subsystems that are supposed to be running are.	All
     running subsystems	are running with their configurations based on (i.e.,
     consistent	with) the active configuration object.

     When there	needs to be a configuration change, a new configuration	object
     is	constructed and	the app_config library is told to apply	the new	con-
     figuration	object.	 After a configurable delay (for hysteresis), those
     subsystems	affected by the	change are stopped, the	new configuration ob-
     ject is installed in place	of the old one,	and the	stopped	subsystems are

     The app_config library guarantees that only "valid" configurations	may be
     applied, where the	meaning	of "valid" is determined by the	application.

     A subsystem is defined as anything	that can be started and/or stopped.  A
     subsystem typically depends on some portion of the	configuration object
     such that it must be stopped and restarted	when that portion changes.

     A subsystem is defined by a struct	app_subsystem:

	struct app_subsystem {
	    const char		*name;	    /* name, null to end list */
	    void		*arg;	    /* opaque subsystem	argument */
	    app_ss_startup_t	*start;	    /* start subsystem */
	    app_ss_shutdown_t	*stop;	    /* stop subsystem */
	    app_ss_willrun_t	*willrun;   /* will subsystem run? */
	    app_ss_changed_t	*changed;   /* subsystem config	changed? */
	    const char		**deplist;  /* config items dependent on */

     The name is currently used	only for debugging, but	must be	NULL to	termi-
     nate the list of subsystems (see below).  The arg is ignored and is for
     the application's private use.  The start,	stop, willrun, and changed
     fields must be pointers to	functions having these types:

	typedef	int  app_ss_startup_t(struct app_config_ctx *ctx,
			const struct app_subsystem *ss,	const void *config);
	typedef	void app_ss_shutdown_t(struct app_config_ctx *ctx,
			const struct app_subsystem *ss,	const void *config);
	typedef	int  app_ss_willrun_t(struct app_config_ctx *ctx,
			const struct app_subsystem *ss,	const void *config);
	typedef	int  app_ss_changed_t(struct app_config_ctx *ctx,
			const struct app_subsystem *ss,
			const void *config1, const void	*config2);

     start() starts the	subsystem; config points to a copy of the current
     (i.e., new) configuration object.	start()	should return zero if success-
     ful, or else -1 with errno	set on failure.	 In the	latter case, the
     stop() method will	not be called.

     stop() stops the subsystem; config	points to a copy of the	current	con-
     figuration	object.

     willrun() should return non-zero if the subsystem needs to	run at all.
     config points to a	copy of	the current (i.e., new)	configuration object.

     changed() determines if the subsystem needs to be restarted during	a con-
     figuration	change from config1 to config2.	 It should return 1 if so,
     zero otherwise.

     In	the above methods, the configuration object argument(s)	become invalid
     after the method returns.

     Alternately, or in	conjunction with the changed() method, the deplist may
     point to a	NULL terminated	list of	structs(3) names of fields in the con-
     figuration	object on which	this subsystem depends.	 The subsystem will
     automatically be restarted	if any of the named fields differ between
     config1 and config2, as determined	by structs_equal(3).

     All four of the above subsystem methods are optional and may be specified
     as	NULL.  In the case of startup()	and shutdown(),	NULL means "do noth-
     ing".  willrun() being NULL is equivalent to it always returning 1.
     changed() being NULL is equivalent	to it always returning 0.  deplist be-
     ing NULL is equivalent to an empty	list.

     An	application itself is described	by a struct app_config:

	struct app_config {
	    u_int			version;    /* current version # */
	    const struct structs_type	**types;    /* all version types */
	    const struct app_subsystem	**slist;    /* list of subsystems */
	    app_config_init_t		*init;	    /* initialize defaults */
	    app_config_getnew_t		*getnew;    /* generate	new config */
	    app_config_checker_t	*checker;   /* validate	a config */
	    app_config_normalize_t	*normalize; /* normalize a config */
	    app_config_upgrade_t	*upgrade;   /* upgrade a config	*/

     The list of subsystems supported by the application is pointed to by
     slist.  This list must be terminated with an entry	whose name is NULL.

     Subsystems	are always started in the order	they are listed	in slist, and
     they are always shutdown in the reverse order.

     The version is the	configuration object version number (the first version
     is	zero), and types points	to an array of version + 1 pointers to
     structs(3)	types for the configuration object, where types[i] is the
     structs(3)	type for version i of the configuration	object.

     The remaining fields are pointers to functions having these types:

	typedef	int  app_config_init_t(struct app_config_ctx *ctx,
			 void *config);
	typedef	int  app_config_getnew_t(struct	app_config_ctx *ctx,
			 void *config);
	typedef	int  app_config_checker_t(struct app_config_ctx	*ctx,
			 const void *config, char *errbuf, size_t ebufsize);
	typedef	void app_config_normalize_t(struct app_config_ctx *ctx,
			 void *config);
	typedef	int  app_config_upgrade_t(struct app_config_ctx	*ctx,
			 const void *old_conf, u_int old_version,
			 void *new_conf);

     If	the default configuration object is not	equal to what is provided by
     structs_init(3), then init() may be implemented.  It should further mod-
     ify the config as appropriate to get the generic default configuration.
     init() returns zero on success, or	-1 on error with errno set appropri-

     getnew() is invoked when no existing configuration	is found by
     app_config_load() (see below).  The config	is as returned by init().
     getnew() should apply any further initialization required for this	par-
     ticular system.  getnew() returns zero on success,	or -1 on error with
     errno set appropriately.

     The distinction between init() and	getnew() is somewhat subtle: init()
     simply initializes	a new configuration object.  It	may be invoked many
     times during the normal operation of the application as configuration ob-
     jects are needed.	getnew() is only invoked once, at the beginning	of ap-
     plication startup,	when there is no previously saved configuration	found.
     Therefore,	the behavior of	init() should not be affected by the "environ-
     ment", while the behavior of getnew() often is.

     checker() determines whether the config is	valid, returning 1 if so or 0
     if	not.  In the latter case, it may print an error	message	(including
     '\0') into	the buffer errbuf, which has size ebufsize (see	snprintf(3)).

     normalize() gives the application a chance	to normalize an	otherwise
     valid configuration object.  This is useful when the configuration	object
     contains redundant	information, or	information that can be	represented in
     more than one way.

     All configurations	that are applied by app_config are guaranteed to have
     been checked and normalized.  All configurations passed to	checker() are
     guaranteed	to have	been passed through normalize()	first.

     Note: the configurations returned by init() and getnew() must be valid
     according to checker.

     upgrade() is invoked when an older	version	of the configuration object is
     read in from an XML file.	The configuration version number is stored as
     the "version" attribute of	the XML	document element.  old_conf is the old
     object, which has version old_version, and	new_conf is a newly initial-
     ized configuration	object of the current version.	upgrade() should copy
     the configuration information from	old_conf to new_conf.

     A quick and dirty way to do this when most	of the fields are the same is
     to	use structs_traverse(3)	to list	the fields in the old configuration
     object, structs_get_string(3) to get their	ASCII values, and
     structs_set_string(3) to set the same values in the new configuration ob-

     app_config_init() should be called	at application startup time to ini-
     tialize app_config	for the	application described by info.	A pevent(3)
     context ctx must be supplied.  app_config_init() returns an application
     context, with which all configuration and subsystems are associated.
     Multiple independent application contexts may exist at the	same time.
     The cookie	is saved along with the	context	but is otherwise ignored.

     app_config_uninit() should	be called at application shutdown time to re-
     lease resources allocated by app_config.  It may only be called when all
     subsystems	are shutdown (i.e., the	current	configuration object pointer
     is	NULL).	This enables app_config_init() to be called again, if so de-

     Upon return from app_config_uninit(), *ctxp will be set to	NULL.  If
     *ctxp is already equal to NULL when app_config_uninit() is	invoked, noth-
     ing happens.

     app_config_get_cookie() retrieves the application cookie provided to

     app_config_load() reads in	an application configuration object from the
     XML file at path and applies it, making it	the current configuration.  If
     path is empty or non-existent, a new configuration	object is created us-
     ing the application's getnew() method.

     If	the file contains an old version of the	configuration object, it is
     automatically upgraded to the current version.  If	allow_writeback	is
     non-zero, then path is remembered and the file is updated (i.e., rewrit-
     ten) every	time the application configuration object changes.  Updates
     are done atomically by creating a temporary file with the suffix ".new"
     and renaming it (see rename(2)).

     In	theory,	one call to app_config_load() in an application's main() rou-
     tine is all that is required to get things	going.

     app_config_reload() reloads the configuration file	previously specified
     to	app_config_load() and applies it.  This	would be the typical response
     to	receiving a SIGHUP signal.

     app_config_new() creates a	new configuration object with the applica-
     tion's default values as specified	by the application's init() method.
     The returned pointer should be cast to the	appropriate type.  The caller
     is	responsible for	eventually freeing the returned	configuration object
     by	calling	app_config_free().

     app_config_set() changes the application's	current	configuration to be a
     copy of the configuration pointed to by config.  If this configuration is
     invalid, -1 is returned with errno	set to EINVAL, and if ebuf is not
     NULL, the buffer pointed to by ebuf and having size emax is filled	in
     with a '\0'-terminated error message.  app_config_set() may also return
     -1	with errno set to other	values in the case of system errors.

     If	config is NULL,	all running subsystems will be shut down.  Any config-
     urations passed to	app_config_set() subsequent to passing a NULL configu-
     ration, but before	the shutdown operation has completed, are ignored.
     This guarantees that a NULL configuration does actually shutdown the ap-

     The new configuration (or shutdown) takes effect after a delay of delay
     milliseconds after	app_config_set() has successfully returned zero.  The
     appropriate subsystem stop(), and then start() methods are	invoked	seri-
     ally from a new thread.

     app_config_get() returns a	copy of	the current or pending configuration
     object.  The returned pointer should be cast to the appropriate type.  If
     pending is	zero, then the configuration object currently in use is
     copied.  Otherwise, the configuration object most recently	applied	via
     app_config_set() is copied.  These	will be	different when there is	a
     pending, but not yet applied, configuration.  The caller is responsible
     for eventually freeing the	returned configuration object by calling

     app_config_get_type() returns the structs(3) for the application configu-
     ration object.

     app_config_copy() copies a	configuration object.  The returned pointer
     should be cast to the appropriate type.  The caller is responsible	for
     eventually	freeing	the returned configuration object by calling

     app_config_free() destroys	the configuration object pointed to by
     *configp.	Upon return, *configp will be set to NULL.  If *configp	is al-
     ready NULL	when app_config_free() is invoked, nothing happens.

   Pre-defined subsystems
     The app_config library comes with some predefined subsystem templates.

     app_config_alog_subsystem handles configuring error logging for an	appli-
     cation.  To use app_config_alog_subsystem,	copy the structure and set the
     arg field to point	to a struct app_config_alog_info:

	struct app_config_alog_info {
	    const char	*name;	    /* field name */
	    int		channel;    /* alog channel */

     The name should be	the structs(3) field name of the field in the configu-
     ration object that	configures logging for the alog(3) logging channel
     channel.  This field should be a struct alog_config.

     app_config_curconf_subsystem is useful when the application needs effi-
     cient access to the currently active configuration.  This subsystem as-
     sumes that	there is a global pointer variable (call it curconf) which by
     definition	always points to a read-only copy of the currently active con-
     figuration.  For example, if the application's configuration object is a
     struct my_config, then curconf would be defined as:

	const struct my_config *const curconf;

     Then the function of app_config_curconf_subsystem is to automatically
     keep this variable	up to date.  (The const	keywords reflect the applica-
     tion's point of view: the first is	because	the structure is read-only,
     while the second is because the pointer itself is read-only.)

     To	use app_config_curconf_subsystem, copy the structure and set the arg
     field to point to the application's curconf pointer variable.  Typically
     the app_config_curconf_subsystem will be first in the list	of subsystems,
     so	that curconf is	always updated before any other	subsystem starts.
     Then at any time *curconf can be examined for the currently active	con-

     app_config_directory_subsystem handles configuring	the current working
     directory for the process.	 To use	app_config_directory_subsystem,	copy
     the structure and set the arg field to point to a string containing the
     structs(3)	name of	the field in the configuration object that contains
     the directory name.  If this name is not the empty	string,	then the cur-
     rent working directory will be set	according to the value of this field.

     app_config_pidfile_subsystem handles "PID files", i.e., exclusive appli-
     cation lock files into which the process ID is written.  These guard
     against two instances of the same application running at the same time.
     To	use app_config_pidfile_subsystem, copy the structure and set the arg
     field to point to a string	containing the structs(3) name of the field in
     the configuration object that contains the	PID file pathname.

     All of the	app_config functions return NULL or -1 to indicate an error
     and set errno appropriately.

     alog(3), libpdel(3), pevent(3), structs(3), typed_mem(3)

     The PDEL library was developed at Packet Design, LLC.

     Archie Cobbs <>

     There should be explicit support for subsystems that require other	sub-
     systems to	be running before they may run.	 As it stands now, such	depen-
     dencies must be implicitly	encoded	into the willrun() and changed() meth-
     ods.  Even	so, the	dependent subsystem cannot detect if the other subsys-
     tem fails to start.

     Subsystems	should be defined more like objects using dynamically allo-
     cated structures that can be added	and removed from the subsystem list at
     any time, without having to shutdown and restart the whole	application.

     It	should be possible to start and	shutdown subsystems individually.

FreeBSD	13.0			April 22, 2002			  FreeBSD 13.0


Want to link to this manual page? Use this URL:

home | help