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

FreeBSD Manual Pages

  
 
  

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

NAME
       app_config -- application configuration system

LIBRARY
       PDEL Library (libpdel, -lpdel)

SYNOPSIS
       #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);

       int
       app_config_uninit(struct	app_config_ctx **ctxp);

       void *
       app_config_get_cookie(struct app_config_ctx *ctx);

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

       int
       app_config_reload(struct	app_config_ctx *ctx);

       void *
       app_config_new(struct app_config_ctx *ctx);

       int
       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);

       void
       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;

DESCRIPTION
       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	struc-
       ture 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	behav-
       ior  depends on (some part of) the configuration	object.	 When the con-
       figuration object is changed, those subsystems that require it are  au-
       tomatically stopped and then restarted with the new configuration.

       The application may provide methods for:

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

       Each subsystem may provide methods for:

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

       In  the	steady state, there is a single	currently active configuration
       object.	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  ob-
       ject is constructed and the app_config library is told to apply the new
       configuration  object.	After  a  configurable delay (for hysteresis),
       those subsystems	affected by the	change are stopped, the	new configura-
       tion object is installed	in place of the	old one, and the stopped  sub-
       systems are restarted.

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

   Subsystems
       A  subsystem is defined as anything that	can be started and/or stopped.
       A subsystem typically depends on	some portion of	the configuration  ob-
       ject  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 ter-
       minate 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 suc-
       cessful,	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 ob-
       ject.

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

       In the above methods, the configuration object argument(s)  become  in-
       valid 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  configuration object on which this subsystem depends.  The subsys-
       tem 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	speci-
       fied as NULL.  In the case of startup() and shutdown(), NULL means  "do
       nothing".  willrun() being NULL is equivalent to	it always returning 1.
       changed()  being	 NULL is equivalent to it always returning 0.  deplist
       being NULL is equivalent	to an empty list.

   Application
       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  ver-
       sion  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
       modify the config as appropriate	to get the generic default  configura-
       tion.   init()  returns	zero on	success, or -1 on error	with errno set
       appropriately.

       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
       objects are needed.  getnew() is	only invoked once, at the beginning of
       application startup, when there is no  previously  saved	 configuration
       found.  Therefore, the behavior of init() should	not be affected	by the
       "environment", 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  ob-
       ject  contains redundant	information, or	information that can be	repre-
       sented 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 initialized 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 configura-
       tion object, structs_get_string(3)  to  get  their  ASCII  values,  and
       structs_set_string(3)  to  set the same values in the new configuration
       object.

   API
       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
       release	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 desired.

       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,
       nothing happens.

       app_config_get_cookie() retrieves the application  cookie  provided  to
       app_config_init().

       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
       using 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.,
       rewritten)  every  time	the  application configuration object changes.
       Updates are done	atomically by creating a temporary file	with the  suf-
       fix ".new" and renaming it (see rename(2)).

       In  theory,  one	 call  to app_config_load() in an application's	main()
       routine 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  re-
       sponse 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 configura-
       tion 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 er-
       rors.

       If  config is NULL, all running subsystems will be shut down.  Any con-
       figurations passed to app_config_set() subsequent  to  passing  a  NULL
       configuration, but before the shutdown operation	has completed, are ig-
       nored.	This  guarantees that a	NULL configuration does	actually shut-
       down the	application.

       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
       serially	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_free().

       app_config_get_type()  returns  the structs(3) for the application con-
       figuration 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().

       app_config_free()  destroys  the	 configuration	object	pointed	 to by
       *configp.  Upon return, *configp	will be	set to NULL.  If  *configp  is
       already 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 ap-
       plication.  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 con-
       figuration object that configures logging for the alog(3) logging chan-
       nel 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
       configuration.	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	appli-
       cation'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.	 Typi-
       cally the app_config_curconf_subsystem will be first  in	 the  list  of
       subsystems,  so that curconf is always updated before any other subsys-
       tem starts.  Then at any	time *curconf can be  examined	for  the  cur-
       rently active configuration.

       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
       current working directory will be set according to the  value  of  this
       field.

       app_config_pidfile_subsystem  handles  "PID files", i.e., exclusive ap-
       plication 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.

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

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

HISTORY
       The   PDEL   library   was   developed	at   Packet    Design,	  LLC.
       http://www.packetdesign.com/

AUTHORS
       Archie Cobbs <archie@freebsd.org>

BUGS
       There should be explicit	support	for subsystems that require other sub-
       systems	to be running before they may run.  As it stands now, such de-
       pendencies must be implicitly encoded into the willrun()	and  changed()
       methods.	  Even	so, the	dependent subsystem cannot detect if the other
       subsystem 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  applica-
       tion.

       It should be possible to	start and shutdown subsystems individually.

FreeBSD	ports 15.0		April 22, 2002			 APP_CONFIG(3)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=app_config_free&sektion=3&manpath=FreeBSD+Ports+15.0>

home | help