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

  
 
  

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 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  de-
     pends  on	(some part of) the configuration object.  When the configuration
     object is changed, those  subsystems  that  require  it  are  automatically
     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 ob-
     ject.  Only those subsystems that are supposed to be running are.	All run-
     ning subsystems are running with their configurations based on (i.e.,  con-
     sistent 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 configu-
     ration object.  After a configurable delay (for hysteresis), those  subsys-
     tems  affected  by  the change are stopped, the new configuration object is
     installed in  place  of  the  old	one,  and  the	stopped  subsystems  are
     restarted.

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

   Subsystems
     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  successful,  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 configu-
     ration 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  au-
     tomatically  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 nothing".
     willrun() being NULL is equivalent to it always returning 1.  changed() be-
     ing  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 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 modify
     the config as appropriate to get the generic default configuration.  init()
     returns zero on success, or -1 on error with errno set appropriately.

     getnew() is invoked when no existing configuration  is  found  by	app_con-
     fig_load()  (see  below).	 The  config is as returned by init().	getnew()
     should apply any further initialization required for this	particular  sys-
     tem.   getnew()  returns zero on success, or -1 on error with errno set ap-
     propriately.

     The distinction between init() and getnew() is somewhat subtle: init() sim-
     ply 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 object con-
     tains 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  ac-
     cording 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 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 object.

   API
     app_config_init()	should be called at application startup time to initial-
     ize 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 inde-
     pendent 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 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 hap-
     pens.

     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 au-
     tomatically 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 suffix ".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  response  to
     receiving a SIGHUP signal.

     app_config_new()  creates a new configuration object with the application's
     default values as specified by the application's init()  method.	The  re-
     turned  pointer  should be cast to the appropriate type.  The caller is re-
     sponsible for eventually freeing the returned configuration object by call-
     ing 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 configu-
     rations passed to app_config_set() subsequent to passing a NULL  configura-
     tion,  but  before the shutdown operation has completed, are ignored.  This
     guarantees that a NULL configuration does actually  shutdown  the	applica-
     tion.

     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 ob-
     ject.   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_con-
     fig_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 configura-
     tion 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_con-
     fig_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 applica-
     tion.  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 configura-
     tion 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 efficient
     access  to the currently active configuration.  This subsystem assumes 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_con-
     fig, 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  application'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  configura-
     tion.

     app_config_directory_subsystem  handles configuring the current working di-
     rectory 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	applica-
     tion  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  con-
     figuration 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 subsys-
     tems to be running before they may run.  As it stands now,  such  dependen-
     cies  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  allocated
     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 ports 15.quarterly	 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_pidfile_subsystem&sektion=3&manpath=FreeBSD+Ports+15.1.quarterly>

home | help