Show Contents Previous Page Next Page
Chapter 11 - C API Reference Guide, Part II Customizing the Configuration Process In this section... Introduction Show Contents Go to Top Previous Page Next Page
If Apache's standard configuration mechanism isn't sufficient for you, or you want to do something wild like generating dynamic configuration files on the fly (as mod_perl does in its <Perl> sections), you can reach into the internals of Apache's configuration machinery and make it do what you want. This section covers the more obscure parts of Apache's configuration system and shows you how to achieve advanced effects such as redirecting the configuration process from your own data source.
The configfile_t Structure Show Contents Go to Top Previous Page Next Page
Apache uses a clever abstraction for its configuration process. Instead of reading the text of the configuration file directly from a FILE* or file descriptor, Apache interposes the concept of an abstract "configuration stream," the configfile_t pointer. Configuration streams are much like ordinary files, allowing your programs to read from them character by character or line by line, and they are often attached to real files. However, a configfile_t pointer may just as easily be attached to another process or even to a set of internal subroutines that read configuration information from a database. By creating a custom configfile_t pointer, your module can dynamically generate configuration text to feed directly into the Apache configuration machinery.
The configfile_t struct is defined in httpd.h. Its definition
is reproduced in Example 11-4. The most important
fields are the first three, which are pointers to callback functions that act
like the getc(), fgets(), and close() standard I/O
library functions. These three functions are used to implement the routines
that fetch data from whatever file, process, or internal routine is attached
to the data stream. The fourth field, param , is a void*
that holds stream-specific data. In a configuration stream attached to a file,
this might be the FILE* . In a stream attached to routines that
read data from a database, this might be the database handle. This field is
passed to the callback functions at runtime. The last two fields, name
and line_number , contain a description of the data source and the
number of the last-read line. These fields are used for reporting configuration
syntax errors.
Example 11-4. The configfile_t Struct
(from httpd.h)
typedef struct {
int (*getch) (void *param); /* a getc()-like function */
/* an fgets()-like function */
void *(*getstr) (void *buf, size_t bufsiz, void *param);
int (*close) (void *param); /* a close() function */
void *param; /* the argument passed to getch/getstr/close */
const char *name; /* the filename / description */
unsigned line_number; /* current line number, starting at 1 */
} configfile_t;
Directive processing handlers can find a pointer to the currently active configfile_t stream by examining the config_file field of the passed parms argument.
Using Configuration Streams Show Contents Go to Top Previous Page Next Page
The API calls listed in this section allow you to open configfile_t pointers on files, to read configuration data from them, and to create custom configfile_t streams that fetch their data from arbitrary sources. For the most part, you should access the configfile_t fields via the appropriate API functions listed in this section. Do not attempt to modify any of the fields directly.
The following short code fragment shows the basic outline for opening a configuration file, reading it line by line, then closing it:
char line[MAX_STRING_LEN];
configfile_t *cfg = ap_pcfg_openfile(p, file);
if(!cfg) {
ap_log_error(APLOG_MARK, APLOG_CRIT, s,
"unable to open config file %s", file);
exit(1);
}
while (!(ap_cfg_getline(line, sizeof(line), cfg))) {
if(*line == '#' || !*line) {
continue; /* skip comments and empty lines */
}
/* ... do something with the line ... */
}
ap_pcfg_closefile(cfg);
configfile_t *ap_pcfg_openfile (pool *p, const char *name)
The most common type of configfile_t is one that is opened
on an ordinary text file. Examples include Apache's httpd.conf, srm.conf,
and access.conf configuration files. The ap_pcfg_openfile() function takes a resource pool pointer and
the path of the configuration file to open. If successful, the function fills
in the stream's param field with a FILE* opened
on the requested file and sets up the first three fields so as to call back
to functions that read data from the FILE* .2 If an error occurs while opening the file, the function logs an error message
and returns NULL .
int ap_cfg_getline (char *buf, size_t bufsize, configfile_t *cfp)
The ap_cfg_getline() function reads a line of data from the given
configfile_t pointer. The arguments consist of a character buffer,
(buf), the maximum size of the buffer (bufsize), and the
configfile_t pointer itself. The function fills the buffer with
a line of configuration file data up to the maximum specified in bufsize,
and returns the number of characters read as the function result. The function
returns 0 if no more data is left to read or if an error occurred. The definition of a configuration file "line" is different from the usual
one. The returned line is stripped of leading and trailing whitespace, and
runs of space characters and other whitespace are replaced with single spaces,
unless they are enclosed within quotes. The ap_cfg_getline() function
also correctly handles continuation lines. Lines ending with the backslash
character (\ ) are merged into single lines, and the newlines
replaced with single spaces. For each line read, the configfile_t 's
line_number field is incremented by one.
int ap_cfg_getc (configfile_t *cfp)
The ap_cfg_getc() function acts like getc() to return
a single character from the configfile_t stream. The character
is returned as the function result, or EOF is returned when there is no more
data to be read. The line_number field is incremented when a
linefeed character is seen, but continuation characters do not receive
special treatment.
int ap_cfg_closefile (configfile_t *cfp)
Once you are done reading from a configfile_t , call ap_cfg_closefile()
to close the file or release other resources.
configfile_t *ap_pcfg_open_custom (pool *p, const char *descr, void
*param, int(*getc_func)(void*), void *(*gets_func) (void*, size_t, void*),
int(*close_func)(void*))
The ap_pcfg_open_custom() function can be used to open and initialize
a new configuration stream. The long prototype for this function may seem
intimidating, but it's actually straightforward. The first argument is a resource
pool pointer, typically the pool pointer located in the server_rec
passed to your module initialization handler. The second argument is a char*
containing a description of the stream for use in error reporting. The third
argument, param , is a generic pointer to any data you want to
pass to the three callbacks. The fourth, fifth, and sixth arguments are function
pointers to the callbacks themselves, corresponding to the routines that implement
getc_func(), fgets_func(), and close_func() behavior.
The prototypes for these three callbacks are as follows:
int getc_func (void *param);
int gets_func (void *buffer, size_t bufsize, void *param);
int close_func (void *param);
The getc_func() should return a single character from the data
stream. gets_func() should return a whole line or the number of characters
specified in bufsize , whichever is smaller. close_func()
should do whatever is necessary to close and deallocate the stream. Apache's
core configuration routines only use ap_cfg_getline() to read from
configuration streams, so it is possible in some circumstances to pass NULL
for the getc_func() pointer. The only example of using ap_pcfg_open_custom() in the standard
distribution is in http_ config.c, where it is used to process the
Apache -C and -c command line
arguments. mod_ perl also uses this function during processing
of <Perl> sections. You'll see an example of using this function
shortly.
const char *ap_srm_command_loop (cmd_parms *parms, void *cfgvector)
The ap_srm_command_loop() function is the core of Apache's internal
configuration process. The function operates on the configuration stream contained
within the passed cmd_parms pointer and the vector of per-directory
module-specific configuration pointers contained within the server record's
lookup_defaults field. The return value is NULL
if the entire configuration stream was parsed correctly or a character string
indicating the error if the loop terminated prematurely because of a syntax
error. Within the function, Apache reads one line of configuration data after another
with ap_ cfg_getline(). It parses each line into directive name and
arguments, searches through the modules' command tables for the handler for
this directive, then locates the correct per- directory configuration pointer
within the configuration vector. The command parameters, configuration pointer,
and directive arguments are then passed to the handler for processing.
If your module wishes to take over Apache's configuration process and configure everything from information stored within, say, a database, it can do so. For instance, your module might declare a ConfigFromDatabase directive that takes a single argument, the data source from which to read the configuration information:
ConfigFromDatabase ODBC:ApacheConfig
Then, to implement this directive, the directive handler can be written like this:
static const char *cfg_from_db_cmd(cmd_parms *parms, db_cfg *cfg,
char *dsn)
{
db *dbhandle = db_open(dsn);
configfile_t old_cfg = parms->config_file; /*save old config stream */
parms->config_file =
ap_pcfg_open_custom(p,
"Database config",
(void *)dbhandle,
NULL,
db_getline,
db_close);
char *errmsg = ap_srm_command_loop(parms,
parms->server->lookup_defaults);
if (errmsg) {
ap_log_error(APLOG_MARK, APLOG_CRIT, s,
"unable to config from database %s" );
return errmsg;
}
ap_cfg_closefile(parms->config_file);
parms->config_file = old_cfg; /* restore configuration stream */
return NULL;
}
Your code has to supply the db_open() and db_close() routines to open and close the database handle, as well as the db_getline() routine. This last routine must return directive strings in exactly the same way they would appear in an ordinary configuration file, such as:
Group apache
Show Contents Go to Top Previous Page Next Page Copyright © 1999 by O'Reilly & Associates, Inc. |