Main Page | Modules | Namespace List | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages | Examples

config.c

Go to the documentation of this file.
00001 /* Copyright 1999-2005 The Apache Software Foundation or its licensors, as
00002  * applicable.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 /*
00018  * http_config.c: once was auxillary functions for reading httpd's config
00019  * file and converting filenames into a namespace
00020  *
00021  * Rob McCool
00022  *
00023  * Wall-to-wall rewrite for Apache... commands which are part of the
00024  * server core can now be found next door in "http_core.c".  Now contains
00025  * general command loop, and functions which do bookkeeping for the new
00026  * Apache config stuff (modules and configuration vectors).
00027  *
00028  * rst
00029  *
00030  */
00031 
00032 #include "apr.h"
00033 #include "apr_strings.h"
00034 #include "apr_portable.h"
00035 #include "apr_file_io.h"
00036 #include "apr_fnmatch.h"
00037 
00038 #define APR_WANT_STDIO
00039 #define APR_WANT_STRFUNC
00040 #include "apr_want.h"
00041 
00042 #define CORE_PRIVATE
00043 
00044 #include "ap_config.h"
00045 #include "httpd.h"
00046 #include "http_config.h"
00047 #include "http_protocol.h"
00048 #include "http_core.h"
00049 #include "http_log.h"           /* for errors in parse_htaccess */
00050 #include "http_request.h"       /* for default_handler (see invoke_handler) */
00051 #include "http_main.h"
00052 #include "http_vhost.h"
00053 #include "util_cfgtree.h"
00054 #include "mpm.h"
00055 
00056 
00057 AP_DECLARE_DATA const char *ap_server_argv0 = NULL;
00058 
00059 AP_DECLARE_DATA const char *ap_server_root = NULL;
00060 
00061 AP_DECLARE_DATA apr_array_header_t *ap_server_pre_read_config = NULL;
00062 AP_DECLARE_DATA apr_array_header_t *ap_server_post_read_config = NULL;
00063 AP_DECLARE_DATA apr_array_header_t *ap_server_config_defines = NULL;
00064 
00065 AP_DECLARE_DATA ap_directive_t *ap_conftree = NULL;
00066 
00067 APR_HOOK_STRUCT(
00068            APR_HOOK_LINK(header_parser)
00069            APR_HOOK_LINK(pre_config)
00070            APR_HOOK_LINK(post_config)
00071            APR_HOOK_LINK(open_logs)
00072            APR_HOOK_LINK(child_init)
00073            APR_HOOK_LINK(handler)
00074            APR_HOOK_LINK(quick_handler)
00075            APR_HOOK_LINK(optional_fn_retrieve)
00076 )
00077 
00078 AP_IMPLEMENT_HOOK_RUN_ALL(int, header_parser,
00079                           (request_rec *r), (r), OK, DECLINED)
00080 
00081 AP_IMPLEMENT_HOOK_RUN_ALL(int, pre_config,
00082                           (apr_pool_t *pconf, apr_pool_t *plog,
00083                            apr_pool_t *ptemp),
00084                           (pconf, plog, ptemp), OK, DECLINED)
00085 
00086 AP_IMPLEMENT_HOOK_RUN_ALL(int, post_config,
00087                           (apr_pool_t *pconf, apr_pool_t *plog,
00088                            apr_pool_t *ptemp, server_rec *s),
00089                           (pconf, plog, ptemp, s), OK, DECLINED)
00090 
00091 /* During the course of debugging I expanded this macro out, so
00092  * rather than remove all the useful information there is in the
00093  * following lines, I'm going to leave it here in case anyone
00094  * else finds it useful.
00095  *
00096  * Ben has looked at it and thinks it correct :)
00097  *
00098 AP_DECLARE(int) ap_hook_post_config(ap_HOOK_post_config_t *pf,
00099                                     const char * const *aszPre,
00100                                     const char * const *aszSucc,
00101                                     int nOrder)
00102 {
00103     ap_LINK_post_config_t *pHook;
00104 
00105     if (!_hooks.link_post_config) {
00106         _hooks.link_post_config = apr_array_make(apr_hook_global_pool, 1,
00107                                                  sizeof(ap_LINK_post_config_t));
00108         apr_hook_sort_register("post_config", &_hooks.link_post_config);
00109     }
00110 
00111     pHook = apr_array_push(_hooks.link_post_config);
00112     pHook->pFunc = pf;
00113     pHook->aszPredecessors = aszPre;
00114     pHook->aszSuccessors = aszSucc;
00115     pHook->nOrder = nOrder;
00116     pHook->szName = apr_hook_debug_current;
00117 
00118     if (apr_hook_debug_enabled)
00119         apr_hook_debug_show("post_config", aszPre, aszSucc);
00120 }
00121 
00122 AP_DECLARE(apr_array_header_t *) ap_hook_get_post_config(void) {
00123     return _hooks.link_post_config;
00124 }
00125 
00126 AP_DECLARE(int) ap_run_post_config(apr_pool_t *pconf,
00127                                    apr_pool_t *plog,
00128                                    apr_pool_t *ptemp,
00129                                    server_rec *s)
00130 {
00131     ap_LINK_post_config_t *pHook;
00132     int n;
00133 
00134     if(!_hooks.link_post_config)
00135         return;
00136 
00137     pHook = (ap_LINK_post_config_t *)_hooks.link_post_config->elts;
00138     for (n = 0; n < _hooks.link_post_config->nelts; ++n)
00139         pHook[n].pFunc (pconf, plog, ptemp, s);
00140 }
00141  */
00142 
00143 AP_IMPLEMENT_HOOK_RUN_ALL(int, open_logs,
00144                           (apr_pool_t *pconf, apr_pool_t *plog,
00145                            apr_pool_t *ptemp, server_rec *s),
00146                           (pconf, plog, ptemp, s), OK, DECLINED)
00147 
00148 AP_IMPLEMENT_HOOK_VOID(child_init,
00149                        (apr_pool_t *pchild, server_rec *s),
00150                        (pchild, s))
00151 
00152 AP_IMPLEMENT_HOOK_RUN_FIRST(int, handler, (request_rec *r),
00153                             (r), DECLINED)
00154 
00155 AP_IMPLEMENT_HOOK_RUN_FIRST(int, quick_handler, (request_rec *r, int lookup),
00156                             (r, lookup), DECLINED)
00157 
00158 AP_IMPLEMENT_HOOK_VOID(optional_fn_retrieve, (void), ())
00159 
00160 /****************************************************************
00161  *
00162  * We begin with the functions which deal with the linked list
00163  * of modules which control just about all of the server operation.
00164  */
00165 
00166 /* total_modules is the number of modules that have been linked
00167  * into the server.
00168  */
00169 static int total_modules = 0;
00170 
00171 /* dynamic_modules is the number of modules that have been added
00172  * after the pre-loaded ones have been set up. It shouldn't be larger
00173  * than DYNAMIC_MODULE_LIMIT.
00174  */
00175 static int dynamic_modules = 0;
00176 
00177 AP_DECLARE_DATA module *ap_top_module = NULL;
00178 AP_DECLARE_DATA module **ap_loaded_modules=NULL;
00179 
00180 typedef int (*handler_func)(request_rec *);
00181 typedef void *(*dir_maker_func)(apr_pool_t *, char *);
00182 typedef void *(*merger_func)(apr_pool_t *, void *, void *);
00183 
00184 /* maximum nesting level for config directories */
00185 #ifndef AP_MAX_INCLUDE_DIR_DEPTH
00186 #define AP_MAX_INCLUDE_DIR_DEPTH (128)
00187 #endif
00188 
00189 /* Dealing with config vectors.  These are associated with per-directory,
00190  * per-server, and per-request configuration, and have a void* pointer for
00191  * each modules.  The nature of the structure pointed to is private to the
00192  * module in question... the core doesn't (and can't) know.  However, there
00193  * are defined interfaces which allow it to create instances of its private
00194  * per-directory and per-server structures, and to merge the per-directory
00195  * structures of a directory and its subdirectory (producing a new one in
00196  * which the defaults applying to the base directory have been properly
00197  * overridden).
00198  */
00199 
00200 static ap_conf_vector_t *create_empty_config(apr_pool_t *p)
00201 {
00202     void *conf_vector = apr_pcalloc(p, sizeof(void *) *
00203                                     (total_modules + DYNAMIC_MODULE_LIMIT));
00204     return conf_vector;
00205 }
00206 
00207 static ap_conf_vector_t *create_default_per_dir_config(apr_pool_t *p)
00208 {
00209     void **conf_vector = apr_pcalloc(p, sizeof(void *) *
00210                                      (total_modules + DYNAMIC_MODULE_LIMIT));
00211     module *modp;
00212 
00213     for (modp = ap_top_module; modp; modp = modp->next) {
00214         dir_maker_func df = modp->create_dir_config;
00215 
00216         if (df)
00217             conf_vector[modp->module_index] = (*df)(p, NULL);
00218     }
00219 
00220     return (ap_conf_vector_t *)conf_vector;
00221 }
00222 
00223 AP_CORE_DECLARE(ap_conf_vector_t *) ap_merge_per_dir_configs(apr_pool_t *p,
00224                                            ap_conf_vector_t *base,
00225                                            ap_conf_vector_t *new_conf)
00226 {
00227     void **conf_vector = apr_palloc(p, sizeof(void *) * total_modules);
00228     void **base_vector = (void **)base;
00229     void **new_vector = (void **)new_conf;
00230     module *modp;
00231 
00232     for (modp = ap_top_module; modp; modp = modp->next) {
00233         int i = modp->module_index;
00234 
00235         if (!new_vector[i]) {
00236             conf_vector[i] = base_vector[i];
00237         }
00238         else {
00239             merger_func df = modp->merge_dir_config;
00240             if (df && base_vector[i]) {
00241                 conf_vector[i] = (*df)(p, base_vector[i], new_vector[i]);
00242             }
00243             else
00244                 conf_vector[i] = new_vector[i];
00245         }
00246     }
00247 
00248     return (ap_conf_vector_t *)conf_vector;
00249 }
00250 
00251 static ap_conf_vector_t *create_server_config(apr_pool_t *p, server_rec *s)
00252 {
00253     void **conf_vector = apr_pcalloc(p, sizeof(void *) *
00254                                      (total_modules + DYNAMIC_MODULE_LIMIT));
00255     module *modp;
00256 
00257     for (modp = ap_top_module; modp; modp = modp->next) {
00258         if (modp->create_server_config)
00259             conf_vector[modp->module_index] = (*modp->create_server_config)(p, s);
00260     }
00261 
00262     return (ap_conf_vector_t *)conf_vector;
00263 }
00264 
00265 static void merge_server_configs(apr_pool_t *p, ap_conf_vector_t *base,
00266                                  ap_conf_vector_t *virt)
00267 {
00268     /* Can reuse the 'virt' vector for the spine of it, since we don't
00269      * have to deal with the moral equivalent of .htaccess files here...
00270      */
00271 
00272     void **base_vector = (void **)base;
00273     void **virt_vector = (void **)virt;
00274     module *modp;
00275 
00276     for (modp = ap_top_module; modp; modp = modp->next) {
00277         merger_func df = modp->merge_server_config;
00278         int i = modp->module_index;
00279 
00280         if (!virt_vector[i])
00281             virt_vector[i] = base_vector[i];
00282         else if (df)
00283             virt_vector[i] = (*df)(p, base_vector[i], virt_vector[i]);
00284     }
00285 }
00286 
00287 AP_CORE_DECLARE(ap_conf_vector_t *) ap_create_request_config(apr_pool_t *p)
00288 {
00289     return create_empty_config(p);
00290 }
00291 
00292 AP_CORE_DECLARE(ap_conf_vector_t *) ap_create_conn_config(apr_pool_t *p)
00293 {
00294     return create_empty_config(p);
00295 }
00296 
00297 AP_CORE_DECLARE(ap_conf_vector_t *) ap_create_per_dir_config(apr_pool_t *p)
00298 {
00299     return create_empty_config(p);
00300 }
00301 
00302 static int ap_invoke_filter_init(ap_filter_t *filters)
00303 {
00304     while (filters) {
00305         if (filters->frec->filter_init_func) {
00306             int result = filters->frec->filter_init_func(filters);
00307             if (result != OK) {
00308                 return result;
00309             }
00310         }
00311         filters = filters->next;
00312     } 
00313     return OK;
00314 }
00315 
00316 AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r)
00317 {
00318     const char *handler;
00319     const char *p;
00320     int result;
00321     const char *old_handler = r->handler;
00322 
00323     /*
00324      * The new insert_filter stage makes the most sense here.  We only use
00325      * it when we are going to run the request, so we must insert filters
00326      * if any are available.  Since the goal of this phase is to allow all
00327      * modules to insert a filter if they want to, this filter returns
00328      * void.  I just can't see any way that this filter can reasonably
00329      * fail, either your modules inserts something or it doesn't.  rbb
00330      */
00331     ap_run_insert_filter(r);
00332 
00333     /* Before continuing, allow each filter that is in the two chains to
00334      * run their init function to let them do any magic before we could
00335      * start generating data.
00336      */
00337     result = ap_invoke_filter_init(r->input_filters);
00338     if (result != OK) {
00339         return result;
00340     }
00341     result = ap_invoke_filter_init(r->output_filters);
00342     if (result != OK) {
00343         return result;
00344     }
00345 
00346     if (!r->handler) {
00347         handler = r->content_type ? r->content_type : ap_default_type(r);
00348         if ((p=ap_strchr_c(handler, ';')) != NULL) {
00349             char *new_handler = (char *)apr_pmemdup(r->pool, handler,
00350                                                     p - handler + 1);
00351             char *p2 = new_handler + (p - handler);
00352             handler = new_handler;
00353 
00354             /* MIME type arguments */
00355             while (p2 > handler && p2[-1] == ' ')
00356                 --p2; /* strip trailing spaces */
00357 
00358             *p2='\0';
00359         }
00360 
00361         r->handler = handler;
00362     }
00363 
00364     result = ap_run_handler(r);
00365 
00366     r->handler = old_handler;
00367 
00368     if (result == DECLINED && r->handler && r->filename) {
00369         ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
00370             "handler \"%s\" not found for: %s", r->handler, r->filename);
00371     }
00372 
00373     return result == DECLINED ? HTTP_INTERNAL_SERVER_ERROR : result;
00374 }
00375 
00376 AP_DECLARE(int) ap_method_is_limited(cmd_parms *cmd, const char *method)
00377 {
00378     int methnum;
00379 
00380     methnum = ap_method_number_of(method);
00381 
00382     /*
00383      * A method number either hardcoded into apache or
00384      * added by a module and registered.
00385      */
00386     if (methnum != M_INVALID) {
00387         return (cmd->limited & (AP_METHOD_BIT << methnum)) ? 1 : 0;
00388     }
00389 
00390     return 0; /* not found */
00391 }
00392 
00393 AP_DECLARE(void) ap_register_hooks(module *m, apr_pool_t *p)
00394 {
00395     if (m->register_hooks) {
00396         if (getenv("SHOW_HOOKS")) {
00397             printf("Registering hooks for %s\n", m->name);
00398             apr_hook_debug_enabled = 1;
00399         }
00400 
00401         apr_hook_debug_current = m->name;
00402         m->register_hooks(p);
00403     }
00404 }
00405 
00406 /* One-time setup for precompiled modules --- NOT to be done on restart */
00407 
00408 AP_DECLARE(void) ap_add_module(module *m, apr_pool_t *p)
00409 {
00410     /* This could be called from an AddModule httpd.conf command,
00411      * after the file has been linked and the module structure within it
00412      * teased out...
00413      */
00414 
00415     if (m->version != MODULE_MAGIC_NUMBER_MAJOR) {
00416         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
00417                      "%s: module \"%s\" is not compatible with this "
00418                      "version of Apache (found %d, need %d).",
00419                      ap_server_argv0, m->name, m->version,
00420                      MODULE_MAGIC_NUMBER_MAJOR);
00421         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
00422                      "Please contact the vendor for the correct version.");
00423         exit(1);
00424     }
00425 
00426     if (m->next == NULL) {
00427         m->next = ap_top_module;
00428         ap_top_module = m;
00429     }
00430 
00431     if (m->module_index == -1) {
00432         m->module_index = total_modules++;
00433         dynamic_modules++;
00434 
00435         if (dynamic_modules > DYNAMIC_MODULE_LIMIT) {
00436             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
00437                          "%s: module \"%s\" could not be loaded, because"
00438                          " the dynamic", ap_server_argv0, m->name);
00439             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
00440                          "module limit was reached. Please increase "
00441                          "DYNAMIC_MODULE_LIMIT and recompile.");
00442             exit(1);
00443         }
00444     }
00445 
00446     /* Some C compilers put a complete path into __FILE__, but we want
00447      * only the filename (e.g. mod_includes.c). So check for path
00448      * components (Unix and DOS), and remove them.
00449      */
00450 
00451     if (ap_strrchr_c(m->name, '/'))
00452         m->name = 1 + ap_strrchr_c(m->name, '/');
00453 
00454     if (ap_strrchr_c(m->name, '\\'))
00455         m->name = 1 + ap_strrchr_c(m->name, '\\');
00456 
00457 #ifdef _OSD_POSIX
00458     /* __FILE__ =
00459      * "*POSIX(/home/martin/apache/src/modules/standard/mod_info.c)"
00460      */
00461 
00462     /* We cannot fix the string in-place, because it's const */
00463     if (m->name[strlen(m->name)-1] == ')') {
00464         char *tmp = strdup(m->name); /* FIXME: memory leak, albeit a small one */
00465         tmp[strlen(tmp)-1] = '\0';
00466         m->name = tmp;
00467     }
00468 #endif /*_OSD_POSIX*/
00469 
00470     /*  FIXME: is this the right place to call this?
00471      *  It doesn't appear to be
00472      */
00473     ap_register_hooks(m, p);
00474 }
00475 
00476 /*
00477  * remove_module undoes what add_module did. There are some caveats:
00478  * when the module is removed, its slot is lost so all the current
00479  * per-dir and per-server configurations are invalid. So we should
00480  * only ever call this function when you are invalidating almost
00481  * all our current data. I.e. when doing a restart.
00482  */
00483 
00484 AP_DECLARE(void) ap_remove_module(module *m)
00485 {
00486     module *modp;
00487 
00488     modp = ap_top_module;
00489     if (modp == m) {
00490         /* We are the top module, special case */
00491         ap_top_module = modp->next;
00492         m->next = NULL;
00493     }
00494     else {
00495         /* Not the top module, find use. When found modp will
00496          * point to the module _before_ us in the list
00497          */
00498 
00499         while (modp && modp->next != m) {
00500             modp = modp->next;
00501         }
00502 
00503         if (!modp) {
00504             /* Uh-oh, this module doesn't exist */
00505             ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
00506                          "Cannot remove module %s: not found in module list",
00507                          m->name);
00508             return;
00509         }
00510 
00511         /* Eliminate us from the module list */
00512         modp->next = modp->next->next;
00513     }
00514 
00515     m->module_index = -1; /* simulate being unloaded, should
00516                            * be unnecessary */
00517     dynamic_modules--;
00518     total_modules--;
00519 }
00520 
00521 AP_DECLARE(void) ap_add_loaded_module(module *mod, apr_pool_t *p)
00522 {
00523     module **m;
00524 
00525     /*
00526      *  Add module pointer to top of chained module list
00527      */
00528     ap_add_module(mod, p);
00529 
00530     /*
00531      *  And module pointer to list of loaded modules
00532      *
00533      *  Notes: 1. ap_add_module() would already complain if no more space
00534      *            exists for adding a dynamically loaded module
00535      *         2. ap_add_module() accepts double inclusion, so we have
00536      *            to accept this, too.
00537      */
00538     for (m = ap_loaded_modules; *m != NULL; m++)
00539         ;
00540     *m++ = mod;
00541     *m = NULL;
00542 }
00543 
00544 AP_DECLARE(void) ap_remove_loaded_module(module *mod)
00545 {
00546     module **m;
00547     module **m2;
00548     int done;
00549 
00550     /*
00551      *  Remove module pointer from chained module list
00552      */
00553     ap_remove_module(mod);
00554 
00555     /*
00556      *  Remove module pointer from list of loaded modules
00557      *
00558      *  Note: 1. We cannot determine if the module was successfully
00559      *           removed by ap_remove_module().
00560      *        2. We have not to complain explicity when the module
00561      *           is not found because ap_remove_module() did it
00562      *           for us already.
00563      */
00564     for (m = m2 = ap_loaded_modules, done = 0; *m2 != NULL; m2++) {
00565         if (*m2 == mod && done == 0)
00566             done = 1;
00567         else
00568             *m++ = *m2;
00569     }
00570 
00571     *m = NULL;
00572 }
00573 
00574 AP_DECLARE(void) ap_setup_prelinked_modules(process_rec *process)
00575 {
00576     module **m;
00577     module **m2;
00578 
00579     apr_hook_global_pool=process->pconf;
00580 
00581     /*
00582      *  Initialise total_modules variable and module indices
00583      */
00584     total_modules = 0;
00585     for (m = ap_preloaded_modules; *m != NULL; m++)
00586         (*m)->module_index = total_modules++;
00587 
00588     /*
00589      *  Initialise list of loaded modules
00590      */
00591     ap_loaded_modules = (module **)apr_palloc(process->pool,
00592         sizeof(module *) * (total_modules + DYNAMIC_MODULE_LIMIT + 1));
00593 
00594     if (ap_loaded_modules == NULL) {
00595         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
00596                      "Ouch!  Out of memory in ap_setup_prelinked_modules()!");
00597     }
00598 
00599     for (m = ap_preloaded_modules, m2 = ap_loaded_modules; *m != NULL; )
00600         *m2++ = *m++;
00601 
00602     *m2 = NULL;
00603 
00604     /*
00605      *   Initialize chain of linked (=activate) modules
00606      */
00607     for (m = ap_prelinked_modules; *m != NULL; m++)
00608         ap_add_module(*m, process->pconf);
00609 
00610     apr_hook_sort_all();
00611 }
00612 
00613 AP_DECLARE(const char *) ap_find_module_name(module *m)
00614 {
00615     return m->name;
00616 }
00617 
00618 AP_DECLARE(module *) ap_find_linked_module(const char *name)
00619 {
00620     module *modp;
00621 
00622     for (modp = ap_top_module; modp; modp = modp->next) {
00623         if (strcmp(modp->name, name) == 0)
00624             return modp;
00625     }
00626 
00627     return NULL;
00628 }
00629 
00630 /* Add a named module.  Returns 1 if module found, 0 otherwise.  */
00631 AP_DECLARE(int) ap_add_named_module(const char *name, apr_pool_t *p)
00632 {
00633     module *modp;
00634     int i = 0;
00635 
00636     for (modp = ap_loaded_modules[i]; modp; modp = ap_loaded_modules[++i]) {
00637         if (strcmp(modp->name, name) == 0) {
00638             /* Only add modules that are not already enabled.  */
00639             if (modp->next == NULL) {
00640                 ap_add_module(modp, p);
00641             }
00642 
00643             return 1;
00644         }
00645     }
00646 
00647     return 0;
00648 }
00649 
00650 /*****************************************************************
00651  *
00652  * Resource, access, and .htaccess config files now parsed by a common
00653  * command loop.
00654  *
00655  * Let's begin with the basics; parsing the line and
00656  * invoking the function...
00657  */
00658 
00659 static const char *invoke_cmd(const command_rec *cmd, cmd_parms *parms,
00660                               void *mconfig, const char *args)
00661 {
00662     char *w, *w2, *w3;
00663     const char *errmsg = NULL;
00664 
00665     if ((parms->override & cmd->req_override) == 0)
00666         return apr_pstrcat(parms->pool, cmd->name, " not allowed here", NULL);
00667 
00668     parms->info = cmd->cmd_data;
00669     parms->cmd = cmd;
00670 
00671     switch (cmd->args_how) {
00672     case RAW_ARGS:
00673 #ifdef RESOLVE_ENV_PER_TOKEN
00674         args = ap_resolve_env(parms->pool,args);
00675 #endif
00676         return cmd->AP_RAW_ARGS(parms, mconfig, args);
00677 
00678     case NO_ARGS:
00679         if (*args != 0)
00680             return apr_pstrcat(parms->pool, cmd->name, " takes no arguments",
00681                                NULL);
00682 
00683         return cmd->AP_NO_ARGS(parms, mconfig);
00684 
00685     case TAKE1:
00686         w = ap_getword_conf(parms->pool, &args);
00687 
00688         if (*w == '\0' || *args != 0)
00689             return apr_pstrcat(parms->pool, cmd->name, " takes one argument",
00690                                cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
00691 
00692         return cmd->AP_TAKE1(parms, mconfig, w);
00693 
00694     case TAKE2:
00695         w = ap_getword_conf(parms->pool, &args);
00696         w2 = ap_getword_conf(parms->pool, &args);
00697 
00698         if (*w == '\0' || *w2 == '\0' || *args != 0)
00699             return apr_pstrcat(parms->pool, cmd->name, " takes two arguments",
00700                                cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
00701 
00702         return cmd->AP_TAKE2(parms, mconfig, w, w2);
00703 
00704     case TAKE12:
00705         w = ap_getword_conf(parms->pool, &args);
00706         w2 = ap_getword_conf(parms->pool, &args);
00707 
00708         if (*w == '\0' || *args != 0)
00709             return apr_pstrcat(parms->pool, cmd->name, " takes 1-2 arguments",
00710                                cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
00711 
00712         return cmd->AP_TAKE2(parms, mconfig, w, *w2 ? w2 : NULL);
00713 
00714     case TAKE3:
00715         w = ap_getword_conf(parms->pool, &args);
00716         w2 = ap_getword_conf(parms->pool, &args);
00717         w3 = ap_getword_conf(parms->pool, &args);
00718 
00719         if (*w == '\0' || *w2 == '\0' || *w3 == '\0' || *args != 0)
00720             return apr_pstrcat(parms->pool, cmd->name, " takes three arguments",
00721                                cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
00722 
00723         return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
00724 
00725     case TAKE23:
00726         w = ap_getword_conf(parms->pool, &args);
00727         w2 = ap_getword_conf(parms->pool, &args);
00728         w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
00729 
00730         if (*w == '\0' || *w2 == '\0' || *args != 0)
00731             return apr_pstrcat(parms->pool, cmd->name,
00732                                " takes two or three arguments",
00733                                cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
00734 
00735         return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
00736 
00737     case TAKE123:
00738         w = ap_getword_conf(parms->pool, &args);
00739         w2 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
00740         w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
00741 
00742         if (*w == '\0' || *args != 0)
00743             return apr_pstrcat(parms->pool, cmd->name,
00744                                " takes one, two or three arguments",
00745                                cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
00746 
00747         return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
00748 
00749     case TAKE13:
00750         w = ap_getword_conf(parms->pool, &args);
00751         w2 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
00752         w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
00753 
00754         if (*w == '\0' || (w2 && *w2 && !w3) || *args != 0)
00755             return apr_pstrcat(parms->pool, cmd->name,
00756                                " takes one or three arguments",
00757                                cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
00758 
00759         return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
00760 
00761     case ITERATE:
00762         while (*(w = ap_getword_conf(parms->pool, &args)) != '\0') {
00763 
00764             errmsg = cmd->AP_TAKE1(parms, mconfig, w);
00765 
00766             if (errmsg && strcmp(errmsg, DECLINE_CMD) != 0)
00767                 return errmsg;
00768         }
00769 
00770         return errmsg;
00771 
00772     case ITERATE2:
00773         w = ap_getword_conf(parms->pool, &args);
00774 
00775         if (*w == '\0' || *args == 0)
00776             return apr_pstrcat(parms->pool, cmd->name,
00777                                " requires at least two arguments",
00778                                cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
00779 
00780         while (*(w2 = ap_getword_conf(parms->pool, &args)) != '\0') {
00781 
00782             errmsg = cmd->AP_TAKE2(parms, mconfig, w, w2);
00783 
00784             if (errmsg && strcmp(errmsg, DECLINE_CMD) != 0)
00785                 return errmsg;
00786         }
00787 
00788         return errmsg;
00789 
00790     case FLAG:
00791         w = ap_getword_conf(parms->pool, &args);
00792 
00793         if (*w == '\0' || (strcasecmp(w, "on") && strcasecmp(w, "off")))
00794             return apr_pstrcat(parms->pool, cmd->name, " must be On or Off",
00795                                NULL);
00796 
00797         return cmd->AP_FLAG(parms, mconfig, strcasecmp(w, "off") != 0);
00798 
00799     default:
00800         return apr_pstrcat(parms->pool, cmd->name,
00801                            " is improperly configured internally (server bug)",
00802                            NULL);
00803     }
00804 }
00805 
00806 AP_CORE_DECLARE(const command_rec *) ap_find_command(const char *name,
00807                                                      const command_rec *cmds)
00808 {
00809     while (cmds->name) {
00810         if (!strcasecmp(name, cmds->name))
00811             return cmds;
00812 
00813         ++cmds;
00814     }
00815 
00816     return NULL;
00817 }
00818 
00819 AP_CORE_DECLARE(const command_rec *) ap_find_command_in_modules(
00820                                           const char *cmd_name, module **mod)
00821 {
00822     const command_rec *cmdp;
00823     module *modp;
00824 
00825     for (modp = *mod; modp; modp = modp->next) {
00826         if (modp->cmds && (cmdp = ap_find_command(cmd_name, modp->cmds))) {
00827             *mod = modp;
00828             return cmdp;
00829         }
00830     }
00831 
00832     return NULL;
00833 }
00834 
00835 AP_CORE_DECLARE(void *) ap_set_config_vectors(server_rec *server,
00836                                               ap_conf_vector_t *section_vector,
00837                                               const char *section,
00838                                               module *mod, apr_pool_t *pconf)
00839 {
00840     void *section_config = ap_get_module_config(section_vector, mod);
00841     void *server_config = ap_get_module_config(server->module_config, mod);
00842 
00843     if (!section_config && mod->create_dir_config) {
00844         /* ### need to fix the create_dir_config functions' prototype... */
00845         section_config = (*mod->create_dir_config)(pconf, (char *)section);
00846         ap_set_module_config(section_vector, mod, section_config);
00847     }
00848 
00849     if (!server_config && mod->create_server_config) {
00850         server_config = (*mod->create_server_config)(pconf, server);
00851         ap_set_module_config(server->module_config, mod, server_config);
00852     }
00853 
00854     return section_config;
00855 }
00856 
00857 static const char *execute_now(char *cmd_line, const char *args,
00858                                cmd_parms *parms,
00859                                apr_pool_t *p, apr_pool_t *ptemp,
00860                                ap_directive_t **sub_tree,
00861                                ap_directive_t *parent);
00862 
00863 static const char *ap_build_config_sub(apr_pool_t *p, apr_pool_t *temp_pool,
00864                                        const char *l, cmd_parms *parms,
00865                                        ap_directive_t **current,
00866                                        ap_directive_t **curr_parent,
00867                                        ap_directive_t **conftree)
00868 {
00869     const char *retval = NULL;
00870     const char *args;
00871     char *cmd_name;
00872     ap_directive_t *newdir;
00873     module *mod = ap_top_module;
00874     const command_rec *cmd;
00875 
00876     if (*l == '#' || *l == '\0')
00877         return NULL;
00878 
00879 #if RESOLVE_ENV_PER_TOKEN
00880     args = l;
00881 #else
00882     args = ap_resolve_env(temp_pool, l);
00883 #endif
00884 
00885     cmd_name = ap_getword_conf(p, &args);
00886     if (*cmd_name == '\0') {
00887         /* Note: this branch should not occur. An empty line should have
00888          * triggered the exit further above.
00889          */
00890         return NULL;
00891     }
00892 
00893     if (cmd_name[1] != '/') {
00894         char *lastc = cmd_name + strlen(cmd_name) - 1;
00895         if (*lastc == '>') {
00896             *lastc = '\0' ;
00897         }
00898         if (cmd_name[0] == '<' && *args == '\0') {
00899             args = ">";
00900         }
00901     }
00902 
00903     newdir = apr_pcalloc(p, sizeof(ap_directive_t));
00904     newdir->filename = parms->config_file->name;
00905     newdir->line_num = parms->config_file->line_number;
00906     newdir->directive = cmd_name;
00907     newdir->args = apr_pstrdup(p, args);
00908 
00909     if ((cmd = ap_find_command_in_modules(cmd_name, &mod)) != NULL) {
00910         if (cmd->req_override & EXEC_ON_READ) {
00911             ap_directive_t *sub_tree = NULL;
00912 
00913             parms->err_directive = newdir;
00914             retval = execute_now(cmd_name, args, parms, p, temp_pool,
00915                                  &sub_tree, *curr_parent);
00916             if (*current) {
00917                 (*current)->next = sub_tree;
00918             }
00919             else {
00920                 *current = sub_tree;
00921                 if (*curr_parent) {
00922                     (*curr_parent)->first_child = (*current);
00923                 }
00924                 if (*current) {
00925                     (*current)->parent = (*curr_parent);
00926                 }
00927             }
00928             if (*current) {
00929                 if (!*conftree) {
00930                     /* Before walking *current to the end of the list,
00931                      * set the head to *current.
00932                      */
00933                     *conftree = *current;
00934                 }
00935                 while ((*current)->next != NULL) {
00936                     (*current) = (*current)->next;
00937                     (*current)->parent = (*curr_parent);
00938                 }
00939             }
00940             return retval;
00941         }
00942     }
00943 
00944     if (cmd_name[0] == '<') {
00945         if (cmd_name[1] != '/') {
00946             (*current) = ap_add_node(curr_parent, *current, newdir, 1);
00947         }
00948         else if (*curr_parent == NULL) {
00949             parms->err_directive = newdir;
00950             return apr_pstrcat(p, cmd_name,
00951                                " without matching <", cmd_name + 2,
00952                                " section", NULL);
00953         }
00954         else {
00955             char *bracket = cmd_name + strlen(cmd_name) - 1;
00956 
00957             if (*bracket != '>') {
00958                 parms->err_directive = newdir;
00959                 return apr_pstrcat(p, cmd_name,
00960                                    "> directive missing closing '>'", NULL);
00961             }
00962 
00963             *bracket = '\0';
00964 
00965             if (strcasecmp(cmd_name + 2,
00966                            (*curr_parent)->directive + 1) != 0) {
00967                 parms->err_directive = newdir;
00968                 return apr_pstrcat(p, "Expected </",
00969                                    (*curr_parent)->directive + 1, "> but saw ",
00970                                    cmd_name, ">", NULL);
00971             }
00972 
00973             *bracket = '>';
00974 
00975             /* done with this section; move up a level */
00976             *current = *curr_parent;
00977             *curr_parent = (*current)->parent;
00978         }
00979     }
00980     else {
00981         *current = ap_add_node(curr_parent, *current, newdir, 0);
00982     }
00983 
00984     return retval;
00985 }
00986 
00987 AP_DECLARE(const char *) ap_build_cont_config(apr_pool_t *p,
00988                                               apr_pool_t *temp_pool,
00989                                               cmd_parms *parms,
00990                                               ap_directive_t **current,
00991                                               ap_directive_t **curr_parent,
00992                                               char *orig_directive)
00993 {
00994     char *l;
00995     char *bracket;
00996     const char *retval;
00997     ap_directive_t *sub_tree = NULL;
00998 
00999     /* Since this function can be called recursively, allocate
01000      * the temporary 8k string buffer from the temp_pool rather 
01001      * than the stack to avoid over-running a fixed length stack.
01002      */
01003     l = apr_palloc(temp_pool, MAX_STRING_LEN);
01004 
01005     bracket = apr_pstrcat(p, orig_directive + 1, ">", NULL);
01006     while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) {
01007         if (!memcmp(l, "</", 2)
01008             && (strcasecmp(l + 2, bracket) == 0)
01009             && (*curr_parent == NULL)) {
01010             break;
01011         }
01012         retval = ap_build_config_sub(p, temp_pool, l, parms, current,
01013                                      curr_parent, &sub_tree);
01014         if (retval != NULL)
01015             return retval;
01016 
01017         if (sub_tree == NULL && curr_parent != NULL) {
01018             sub_tree = *curr_parent;
01019         }
01020 
01021         if (sub_tree == NULL && current != NULL) {
01022             sub_tree = *current;
01023         }
01024     }
01025 
01026     *current = sub_tree;
01027     return NULL;
01028 }
01029 
01030 static const char *ap_walk_config_sub(const ap_directive_t *current,
01031                                       cmd_parms *parms,
01032                                       ap_conf_vector_t *section_vector)
01033 {
01034     module *mod = ap_top_module;
01035 
01036     while (1) {
01037         const command_rec *cmd;
01038 
01039         if (!(cmd = ap_find_command_in_modules(current->directive, &mod))) {
01040             parms->err_directive = current;
01041             return apr_pstrcat(parms->pool, "Invalid command '",
01042                                current->directive,
01043                                "', perhaps mis-spelled or defined by a module "
01044                                "not included in the server configuration",
01045                                NULL);
01046         }
01047         else {
01048             void *dir_config = ap_set_config_vectors(parms->server,
01049                                                      section_vector,
01050                                                      parms->path,
01051                                                      mod,
01052                                                      parms->pool);
01053             const char *retval;
01054 
01055             /* Once was enough? */
01056             if (cmd->req_override & EXEC_ON_READ) {
01057                 return NULL;
01058             }
01059 
01060             retval = invoke_cmd(cmd, parms, dir_config, current->args);
01061             if (retval == NULL) {
01062                 return NULL;
01063             }
01064 
01065             if (strcmp(retval, DECLINE_CMD) != 0) {
01066                 /* If the directive in error has already been set, don't
01067                  * replace it.  Otherwise, an error inside a container 
01068                  * will be reported as occuring on the first line of the
01069                  * container.
01070                  */
01071                 if (!parms->err_directive) {
01072                     parms->err_directive = current;
01073                 }
01074 
01075                 return retval;
01076             }
01077 
01078             mod = mod->next; /* Next time around, skip this one */
01079         }
01080     }
01081     /* NOTREACHED */
01082 }
01083 
01084 AP_DECLARE(const char *) ap_walk_config(ap_directive_t *current,
01085                                         cmd_parms *parms,
01086                                         ap_conf_vector_t *section_vector)
01087 {
01088     ap_conf_vector_t *oldconfig = parms->context;
01089 
01090     parms->context = section_vector;
01091 
01092     /* scan through all directives, executing each one */
01093     for (; current != NULL; current = current->next) {
01094         const char *errmsg;
01095 
01096         parms->directive = current;
01097 
01098         /* actually parse the command and execute the correct function */
01099         errmsg = ap_walk_config_sub(current, parms, section_vector);
01100         if (errmsg != NULL) {
01101             /* restore the context (just in case) */
01102             parms->context = oldconfig;
01103             return errmsg;
01104         }
01105     }
01106 
01107     parms->context = oldconfig;
01108     return NULL;
01109 }
01110 
01111 AP_DECLARE(const char *) ap_build_config(cmd_parms *parms,
01112                                          apr_pool_t *p, apr_pool_t *temp_pool,
01113                                          ap_directive_t **conftree)
01114 {
01115     ap_directive_t *current = *conftree;
01116     ap_directive_t *curr_parent = NULL;
01117     char *l = apr_palloc (temp_pool, MAX_STRING_LEN);
01118     const char *errmsg;
01119 
01120     if (current != NULL) {
01121         while (current->next) {
01122             current = current->next;
01123         }
01124     }
01125 
01126     while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) {
01127         errmsg = ap_build_config_sub(p, temp_pool, l, parms,
01128                                      &current, &curr_parent, conftree);
01129         if (errmsg != NULL)
01130             return errmsg;
01131 
01132         if (*conftree == NULL && curr_parent != NULL) {
01133             *conftree = curr_parent;
01134         }
01135 
01136         if (*conftree == NULL && current != NULL) {
01137             *conftree = current;
01138         }
01139     }
01140 
01141     if (curr_parent != NULL) {
01142         errmsg = "";
01143 
01144         while (curr_parent != NULL) {
01145             errmsg = apr_psprintf(p, "%s%s%s:%u: %s> was not closed.",
01146                                   errmsg,
01147                                   *errmsg == '\0' ? "" : APR_EOL_STR,
01148                                   curr_parent->filename,
01149                                   curr_parent->line_num,
01150                                   curr_parent->directive);
01151 
01152             parms->err_directive = curr_parent;
01153             curr_parent = curr_parent->parent;
01154         }
01155 
01156         return errmsg;
01157     }
01158 
01159     return NULL;
01160 }
01161 
01162 /*
01163  * Generic command functions...
01164  */
01165 
01166 AP_DECLARE_NONSTD(const char *) ap_set_string_slot(cmd_parms *cmd,
01167                                                    void *struct_ptr,
01168                                                    const char *arg)
01169 {
01170     int offset = (int)(long)cmd->info;
01171 
01172     *(const char **)((char *)struct_ptr + offset) = arg;
01173 
01174     return NULL;
01175 }
01176 
01177 AP_DECLARE_NONSTD(const char *) ap_set_int_slot(cmd_parms *cmd,
01178                                                 void *struct_ptr,
01179                                                 const char *arg)
01180 {
01181     char *endptr;
01182     char *error_str = NULL;
01183     int offset = (int)(long)cmd->info;
01184 
01185     *(int *)((char*)struct_ptr + offset) = strtol(arg, &endptr, 10);
01186 
01187     if ((*arg == '\0') || (*endptr != '\0')) {
01188         error_str = apr_psprintf(cmd->pool,
01189                      "Invalid value for directive %s, expected integer",
01190                      cmd->directive->directive);
01191     }
01192 
01193     return error_str;
01194 }
01195 
01196 AP_DECLARE_NONSTD(const char *) ap_set_string_slot_lower(cmd_parms *cmd,
01197                                                          void *struct_ptr,
01198                                                          const char *arg_)
01199 {
01200     char *arg = apr_pstrdup(cmd->pool,arg_);
01201     int offset = (int)(long)cmd->info;
01202 
01203     ap_str_tolower(arg);
01204     *(char **)((char *)struct_ptr + offset) = arg;
01205 
01206     return NULL;
01207 }
01208 
01209 AP_DECLARE_NONSTD(const char *) ap_set_flag_slot(cmd_parms *cmd,
01210                                                  void *struct_ptr_v, int arg)
01211 {
01212     int offset = (int)(long)cmd->info;
01213     char *struct_ptr = (char *)struct_ptr_v;
01214 
01215     *(int *)(struct_ptr + offset) = arg ? 1 : 0;
01216 
01217     return NULL;
01218 }
01219 
01220 AP_DECLARE_NONSTD(const char *) ap_set_file_slot(cmd_parms *cmd, void *struct_ptr,
01221                                                  const char *arg)
01222 {
01223     /* Prepend server_root to relative arg.
01224      * This allows most args to be independent of server_root,
01225      * so the server can be moved or mirrored with less pain.
01226      */
01227     const char *path;
01228     int offset = (int)(long)cmd->info;
01229 
01230     path = ap_server_root_relative(cmd->pool, arg);
01231 
01232     if (!path) {
01233         return apr_pstrcat(cmd->pool, "Invalid file path ",
01234                            arg, NULL);
01235     }
01236 
01237     *(const char **) ((char*)struct_ptr + offset) = path;
01238 
01239     return NULL;
01240 }
01241 
01242 AP_DECLARE_NONSTD(const char *) ap_set_deprecated(cmd_parms *cmd,
01243                                                   void *struct_ptr,
01244                                                   const char *arg)
01245 {
01246     return cmd->cmd->errmsg;
01247 }
01248 
01249 /*****************************************************************
01250  *
01251  * Reading whole config files...
01252  */
01253 
01254 static cmd_parms default_parms =
01255 {NULL, 0, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
01256 
01257 AP_DECLARE(char *) ap_server_root_relative(apr_pool_t *p, const char *file)
01258 {
01259     char *newpath = NULL;
01260     apr_status_t rv;
01261     rv = apr_filepath_merge(&newpath, ap_server_root, file,
01262                             APR_FILEPATH_TRUENAME, p);
01263     if (newpath && (rv == APR_SUCCESS || APR_STATUS_IS_EPATHWILD(rv) 
01264                                       || APR_STATUS_IS_ENOENT(rv)
01265                                       || APR_STATUS_IS_ENOTDIR(rv))) {
01266         return newpath;
01267     }
01268     else {
01269         return NULL;
01270     }
01271 }
01272 
01273 AP_DECLARE(const char *) ap_soak_end_container(cmd_parms *cmd, char *directive)
01274 {
01275     char l[MAX_STRING_LEN];
01276     const char *args;
01277     char *cmd_name;
01278 
01279     while(!(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) {
01280 #if RESOLVE_ENV_PER_TOKEN
01281         args = l;
01282 #else
01283         args = ap_resolve_env(cmd->temp_pool, l);
01284 #endif
01285 
01286         cmd_name = ap_getword_conf(cmd->pool, &args);
01287         if (cmd_name[0] == '<') {
01288             if (cmd_name[1] == '/') {
01289                 cmd_name[strlen(cmd_name) - 1] = '\0';
01290 
01291                 if (strcasecmp(cmd_name + 2, directive + 1) != 0) {
01292                     return apr_pstrcat(cmd->pool, "Expected </",
01293                                        directive + 1, "> but saw ",
01294                                        cmd_name, ">", NULL);
01295                 }
01296 
01297                 return NULL; /* found end of container */
01298             }
01299             else {
01300                 const char *msg;
01301 
01302                 if (*args == '\0' && cmd_name[strlen(cmd_name) - 1] == '>') {
01303                     cmd_name[strlen(cmd_name) - 1] = '\0';
01304                 }
01305 
01306                 if ((msg = ap_soak_end_container(cmd, cmd_name)) != NULL) {
01307                     return msg;
01308                 }
01309             }
01310         }
01311     }
01312 
01313     return apr_pstrcat(cmd->pool, "Expected </",
01314                        directive + 1, "> before end of configuration",
01315                        NULL);
01316 }
01317 
01318 static const char *execute_now(char *cmd_line, const char *args,
01319                                cmd_parms *parms,
01320                                apr_pool_t *p, apr_pool_t *ptemp,
01321                                ap_directive_t **sub_tree,
01322                                ap_directive_t *parent)
01323 {
01324     module *mod = ap_top_module;
01325     const command_rec *cmd;
01326 
01327     if (!(cmd = ap_find_command_in_modules(cmd_line, &mod))) {
01328         return apr_pstrcat(parms->pool, "Invalid command '",
01329                            cmd_line,
01330                            "', perhaps mis-spelled or defined by a module "
01331                            "not included in the server configuration",
01332                            NULL);
01333     }
01334     else {
01335         return invoke_cmd(cmd, parms, sub_tree, args);
01336     }
01337 }
01338 
01339 /* This structure and the following functions are needed for the
01340  * table-based config file reading. They are passed to the
01341  * cfg_open_custom() routine.
01342  */
01343 
01344 /* Structure to be passed to cfg_open_custom(): it contains an
01345  * index which is incremented from 0 to nelts on each call to
01346  * cfg_getline() (which in turn calls arr_elts_getstr())
01347  * and an apr_array_header_t pointer for the string array.
01348  */
01349 typedef struct {
01350     apr_array_header_t *array;
01351     int curr_idx;
01352 } arr_elts_param_t;
01353 
01354 
01355 /* arr_elts_getstr() returns the next line from the string array. */
01356 static void *arr_elts_getstr(void *buf, size_t bufsiz, void *param)
01357 {
01358     arr_elts_param_t *arr_param = (arr_elts_param_t *)param;
01359 
01360     /* End of array reached? */
01361     if (++arr_param->curr_idx > arr_param->array->nelts)
01362         return NULL;
01363 
01364     /* return the line */
01365     apr_cpystrn(buf,
01366                 ((char **)arr_param->array->elts)[arr_param->curr_idx - 1],
01367                 bufsiz);
01368 
01369     return buf;
01370 }
01371 
01372 
01373 /* arr_elts_close(): dummy close routine (makes sure no more lines can be read) */
01374 static int arr_elts_close(void *param)
01375 {
01376     arr_elts_param_t *arr_param = (arr_elts_param_t *)param;
01377 
01378     arr_param->curr_idx = arr_param->array->nelts;
01379 
01380     return 0;
01381 }
01382 
01383 static void process_command_config(server_rec *s, apr_array_header_t *arr,
01384                                    ap_directive_t **conftree, apr_pool_t *p,
01385                                    apr_pool_t *ptemp)
01386 {
01387     const char *errmsg;
01388     cmd_parms parms;
01389     arr_elts_param_t arr_parms;
01390 
01391     arr_parms.curr_idx = 0;
01392     arr_parms.array = arr;
01393 
01394     parms = default_parms;
01395     parms.pool = p;
01396     parms.temp_pool = ptemp;
01397     parms.server = s;
01398     parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT);
01399 
01400     parms.config_file = ap_pcfg_open_custom(p, "-c/-C directives",
01401                                             &arr_parms, NULL,
01402                                             arr_elts_getstr, arr_elts_close);
01403 
01404     errmsg = ap_build_config(&parms, p, ptemp, conftree);
01405     if (errmsg) {
01406         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
01407                      "Syntax error in -C/-c directive:");
01408         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
01409                      "%s", errmsg);
01410         exit(1);
01411     }
01412 
01413     ap_cfg_closefile(parms.config_file);
01414 }
01415 
01416 typedef struct {
01417     char *fname;
01418 } fnames;
01419 
01420 static int fname_alphasort(const void *fn1, const void *fn2)
01421 {
01422     const fnames *f1 = fn1;
01423     const fnames *f2 = fn2;
01424 
01425     return strcmp(f1->fname,f2->fname);
01426 }
01427 
01428 static void process_resource_config_nofnmatch(server_rec *s, const char *fname,
01429                                               ap_directive_t **conftree,
01430                                               apr_pool_t *p,
01431                                               apr_pool_t *ptemp,
01432                                               unsigned depth)
01433 {
01434     cmd_parms parms;
01435     ap_configfile_t *cfp;
01436     const char *errmsg;
01437 
01438     if (ap_is_directory(p, fname)) {
01439         apr_dir_t *dirp;
01440         apr_finfo_t dirent;
01441         i