]> granicus.if.org Git - apache/blob - server/config.c
Add support for type-safe optional functions.
[apache] / server / config.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000 The Apache Software Foundation.  All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  *    if any, must include the following acknowledgment:
21  *       "This product includes software developed by the
22  *        Apache Software Foundation (http://www.apache.org/)."
23  *    Alternately, this acknowledgment may appear in the software itself,
24  *    if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Apache" and "Apache Software Foundation" must
27  *    not be used to endorse or promote products derived from this
28  *    software without prior written permission. For written
29  *    permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  *    nor may "Apache" appear in their name, without prior written
33  *    permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation.  For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  *
54  * Portions of this software are based upon public domain software
55  * originally written at the National Center for Supercomputing Applications,
56  * University of Illinois, Urbana-Champaign.
57  */
58
59 /*
60  * http_config.c: once was auxillary functions for reading httpd's config
61  * file and converting filenames into a namespace
62  *
63  * Rob McCool 
64  * 
65  * Wall-to-wall rewrite for Apache... commands which are part of the
66  * server core can now be found next door in "http_core.c".  Now contains
67  * general command loop, and functions which do bookkeeping for the new
68  * Apache config stuff (modules and configuration vectors).
69  *
70  * rst
71  *
72  */
73
74 #include "apr.h"
75 #include "apr_strings.h"
76 #include "apr_portable.h"
77 #include "apr_file_io.h"
78
79 #if APR_HAVE_STDIO_H
80 #include <stdio.h>
81 #endif
82
83 #define CORE_PRIVATE
84
85 #include "ap_config.h"
86 #include "httpd.h"
87 #include "http_config.h"
88 #include "http_protocol.h"
89 #include "http_core.h"
90 #include "http_log.h"           /* for errors in parse_htaccess */
91 #include "http_request.h"       /* for default_handler (see invoke_handler) */
92 #include "http_main.h"
93 #include "http_vhost.h"
94 #include "util_cfgtree.h"
95 #ifdef HAVE_ARPA_INET_H
96 #include <arpa/inet.h>
97 #endif
98 #ifdef HAVE_STRINGS_H
99 #include <strings.h>
100 #endif
101
102 AP_DECLARE_DATA const char *ap_server_argv0;
103
104 AP_DECLARE_DATA const char *ap_server_root;
105
106 AP_DECLARE_DATA apr_array_header_t *ap_server_pre_read_config;
107 AP_DECLARE_DATA apr_array_header_t *ap_server_post_read_config;
108 AP_DECLARE_DATA apr_array_header_t *ap_server_config_defines;
109
110 AP_DECLARE_DATA ap_directive_t *ap_conftree;
111
112 APR_HOOK_STRUCT(
113                APR_HOOK_LINK(header_parser)
114                APR_HOOK_LINK(pre_config)
115                APR_HOOK_LINK(post_config)
116                APR_HOOK_LINK(open_logs)
117                APR_HOOK_LINK(child_init)
118                APR_HOOK_LINK(handler)
119                APR_HOOK_LINK(optional_fn_retrieve)
120 )
121
122 AP_IMPLEMENT_HOOK_RUN_ALL(int,header_parser,
123                           (request_rec *r),(r),OK,DECLINED)
124 AP_IMPLEMENT_HOOK_VOID(pre_config,
125                        (apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp),
126                        (pconf,plog,ptemp))
127 AP_IMPLEMENT_HOOK_VOID(post_config,
128                        (apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp,
129                         server_rec *s),(pconf,plog,ptemp,s))
130 AP_IMPLEMENT_HOOK_VOID(open_logs,
131                        (apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, 
132                         server_rec *s),(pconf,plog,ptemp,s))
133 AP_IMPLEMENT_HOOK_VOID(child_init,
134                        (apr_pool_t *pchild, server_rec *s),(pchild,s))
135
136 AP_IMPLEMENT_HOOK_RUN_FIRST(int,handler,(request_rec *r),
137                             (r),DECLINED)
138
139 AP_IMPLEMENT_HOOK_VOID(optional_fn_retrieve,(void),())
140
141 /****************************************************************
142  *
143  * We begin with the functions which deal with the linked list
144  * of modules which control just about all of the server operation.
145  */
146
147 /* total_modules is the number of modules that have been linked
148  * into the server.
149  */
150 static int total_modules = 0;
151 /* dynamic_modules is the number of modules that have been added
152  * after the pre-loaded ones have been set up. It shouldn't be larger
153  * than DYNAMIC_MODULE_LIMIT.
154  */
155 static int dynamic_modules = 0;
156 AP_DECLARE_DATA module *top_module = NULL;
157 AP_DECLARE_DATA module **ap_loaded_modules=NULL;
158
159 typedef int (*handler_func) (request_rec *);
160 typedef void *(*dir_maker_func) (apr_pool_t *, char *);
161 typedef void *(*merger_func) (apr_pool_t *, void *, void *);
162
163 /* Dealing with config vectors.  These are associated with per-directory,
164  * per-server, and per-request configuration, and have a void* pointer for
165  * each modules.  The nature of the structure pointed to is private to the
166  * module in question... the core doesn't (and can't) know.  However, there
167  * are defined interfaces which allow it to create instances of its private
168  * per-directory and per-server structures, and to merge the per-directory
169  * structures of a directory and its subdirectory (producing a new one in
170  * which the defaults applying to the base directory have been properly
171  * overridden).
172  */
173
174 #ifndef ap_get_module_config
175 AP_DECLARE(void *) ap_get_module_config(void *conf_vector, module *m)
176 {
177     void **confv = (void **) conf_vector;
178     return confv[m->module_index];
179 }
180 #endif
181
182 #ifndef ap_set_module_config
183 AP_DECLARE(void) ap_set_module_config(void *conf_vector, module *m, void *val)
184 {
185     void **confv = (void **) conf_vector;
186     confv[m->module_index] = val;
187 }
188 #endif
189
190 static void *create_empty_config(apr_pool_t *p)
191 {
192     void **conf_vector = (void **) apr_pcalloc(p, sizeof(void *) *
193                                     (total_modules + DYNAMIC_MODULE_LIMIT));
194     return (void *) conf_vector;
195 }
196
197 static void *create_default_per_dir_config(apr_pool_t *p)
198 {
199     void **conf_vector = (void **) apr_pcalloc(p, sizeof(void *) * (total_modules + DYNAMIC_MODULE_LIMIT));
200     module *modp;
201
202     for (modp = top_module; modp; modp = modp->next) {
203         dir_maker_func df = modp->create_dir_config;
204
205         if (df)
206             conf_vector[modp->module_index] = (*df) (p, NULL);
207     }
208
209     return (void *) conf_vector;
210 }
211
212 void *
213      ap_merge_per_dir_configs(apr_pool_t *p, void *base, void *new)
214 {
215     void **conf_vector = (void **) apr_palloc(p, sizeof(void *) * total_modules);
216     void **base_vector = (void **) base;
217     void **new_vector = (void **) new;
218     module *modp;
219
220     for (modp = top_module; modp; modp = modp->next) {
221         merger_func df = modp->merge_dir_config;
222         int i = modp->module_index;
223
224         if (df && new_vector[i])
225             conf_vector[i] = (*df) (p, base_vector[i], new_vector[i]);
226         else
227             conf_vector[i] = new_vector[i] ? new_vector[i] : base_vector[i];
228     }
229
230     return (void *) conf_vector;
231 }
232
233 static void *create_server_config(apr_pool_t *p, server_rec *s)
234 {
235     void **conf_vector = (void **) apr_pcalloc(p, sizeof(void *) * (total_modules + DYNAMIC_MODULE_LIMIT));
236     module *modp;
237
238     for (modp = top_module; modp; modp = modp->next) {
239         if (modp->create_server_config)
240             conf_vector[modp->module_index] = (*modp->create_server_config) (p, s);
241     }
242
243     return (void *) conf_vector;
244 }
245
246 static void merge_server_configs(apr_pool_t *p, void *base, void *virt)
247 {
248     /* Can reuse the 'virt' vector for the spine of it, since we don't
249      * have to deal with the moral equivalent of .htaccess files here...
250      */
251
252     void **base_vector = (void **) base;
253     void **virt_vector = (void **) virt;
254     module *modp;
255
256     for (modp = top_module; modp; modp = modp->next) {
257         merger_func df = modp->merge_server_config;
258         int i = modp->module_index;
259
260         if (!virt_vector[i])
261             virt_vector[i] = base_vector[i];
262         else if (df)
263             virt_vector[i] = (*df) (p, base_vector[i], virt_vector[i]);
264     }
265 }
266
267 void *ap_create_request_config(apr_pool_t *p)
268 {
269     return create_empty_config(p);
270 }
271
272 void *ap_create_conn_config(apr_pool_t *p)
273 {
274     return create_empty_config(p);
275 }
276
277 AP_CORE_DECLARE(void *) ap_create_per_dir_config(apr_pool_t *p)
278 {
279     return create_empty_config(p);
280 }
281
282 int ap_invoke_handler(request_rec *r)
283 {
284     const char *handler;
285     const char *p;
286     char *p2;
287     int result;
288     char hbuf[MAX_STRING_LEN];
289     const char *old_handler = r->handler;
290
291     if (!r->handler) {
292         handler = r->content_type ? r->content_type : ap_default_type(r);
293         if ((p=ap_strchr_c(handler, ';')) != NULL) {
294             apr_cpystrn(hbuf, handler, sizeof hbuf);
295             p2 = hbuf+(handler-p);
296             handler = hbuf;
297             /* MIME type arguments */
298             while (p2 > handler && p2[-1] == ' ')
299                 --p2;           /* strip trailing spaces */
300             *p2='\0';
301         }
302         r->handler = handler;
303     }
304
305     result = ap_run_handler(r);
306
307     r->handler = old_handler;
308
309     if (result == DECLINED && r->handler && r->filename) {
310         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r,
311             "handler \"%s\" not found for: %s", r->handler, r->filename);
312     }
313     return result == DECLINED ? HTTP_INTERNAL_SERVER_ERROR : result;
314 }
315
316 AP_DECLARE(int) ap_method_is_limited(cmd_parms *cmd, const char *method) {
317     int methnum;
318     int i;
319     char **xmethod;
320
321     methnum = ap_method_number_of(method);
322     /*
323      * The simple case: a method hard-coded into Apache.
324      */
325     if (methnum != M_INVALID) {
326         return (methnum & cmd->limited);
327     }
328     /*
329      * Some extension method we don't know implicitly.
330      */
331     if ((cmd->limited_xmethods == NULL)
332         || (cmd->limited_xmethods->nelts == 0)) {
333         return 0;
334     }
335     xmethod = (char **) cmd->limited_xmethods->elts;
336     for (i = 0; i < cmd->limited_xmethods->nelts; ++i) {
337         if (strcmp(method, xmethod[i]) == 0) {
338             return 1;
339         }
340     }
341     return 0;
342 }
343
344 AP_DECLARE(void) ap_register_hooks(module *m, apr_pool_t *p)
345 {
346     if(m->register_hooks)
347     {
348         if(getenv("SHOW_HOOKS"))
349         {
350             printf("Registering hooks for %s\n",m->name);
351             apr_debug_module_hooks=1;
352         }
353         apr_current_hooking_module=m->name;
354         m->register_hooks(p);
355     }
356 }
357
358 /* One-time setup for precompiled modules --- NOT to be done on restart */
359
360 AP_DECLARE(void) ap_add_module(module *m, apr_pool_t *p)
361 {
362     /* This could be called from an AddModule httpd.conf command,
363      * after the file has been linked and the module structure within it
364      * teased out...
365      */
366
367     if (m->version != MODULE_MAGIC_NUMBER_MAJOR) {
368         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
369                      "%s: module \"%s\" is not compatible with this "
370                      "version of Apache.", ap_server_argv0, m->name);
371         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Please contact the vendor for the correct version.");
372         exit(1);
373     }
374
375     if (m->next == NULL) {
376         m->next = top_module;
377         top_module = m;
378     }
379     if (m->module_index == -1) {
380         m->module_index = total_modules++;
381         dynamic_modules++;
382
383         if (dynamic_modules > DYNAMIC_MODULE_LIMIT) {
384             ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
385                          "%s: module \"%s\" could not be loaded, because"
386                          " the dynamic", ap_server_argv0, m->name);
387             ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
388                          "module limit was reached. Please increase "
389                          "DYNAMIC_MODULE_LIMIT and recompile.");
390             exit(1);
391         }
392     }
393
394     /* Some C compilers put a complete path into __FILE__, but we want
395      * only the filename (e.g. mod_includes.c). So check for path
396      * components (Unix and DOS), and remove them.
397      */
398
399     if (ap_strrchr_c(m->name, '/'))
400         m->name = 1 + ap_strrchr_c(m->name, '/');
401     if (ap_strrchr_c(m->name, '\\'))
402         m->name = 1 + ap_strrchr_c(m->name, '\\');
403
404 #ifdef _OSD_POSIX /* __FILE__="*POSIX(/home/martin/apache/src/modules/standard/mod_info.c)" */
405     /* We cannot fix the string in-place, because it's const */
406     if (m->name[strlen(m->name)-1]==')') {
407         char *tmp = strdup(m->name);    /* FIXME:memory leak, albeit a small one */
408         tmp[strlen(tmp)-1] = '\0';
409         m->name = tmp;
410     }
411 #endif /*_OSD_POSIX*/
412
413     /*  FIXME: is this the right place to call this?
414      *  It doesn't appear to be
415      */
416     ap_register_hooks(m, p);
417 }
418
419 /* 
420  * remove_module undoes what add_module did. There are some caveats:
421  * when the module is removed, its slot is lost so all the current
422  * per-dir and per-server configurations are invalid. So we should
423  * only ever call this function when you are invalidating almost
424  * all our current data. I.e. when doing a restart.
425  */
426
427 AP_DECLARE(void) ap_remove_module(module *m)
428 {
429     module *modp;
430
431     modp = top_module;
432     if (modp == m) {
433         /* We are the top module, special case */
434         top_module = modp->next;
435         m->next = NULL;
436     }
437     else {
438         /* Not the top module, find use. When found modp will
439          * point to the module _before_ us in the list
440          */
441
442         while (modp && modp->next != m) {
443             modp = modp->next;
444         }
445         if (!modp) {
446             /* Uh-oh, this module doesn't exist */
447             ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, NULL,
448                 "Cannot remove module %s: not found in module list",
449                 m->name);
450             return;
451         }
452         /* Eliminate us from the module list */
453         modp->next = modp->next->next;
454     }
455
456     m->module_index = -1;       /* simulate being unloaded, should
457                                  * be unnecessary */
458     dynamic_modules--;
459     total_modules--;
460 }
461
462 AP_DECLARE(void) ap_add_loaded_module(module *mod, apr_pool_t *p)
463 {
464     module **m;
465
466     /* 
467      *  Add module pointer to top of chained module list 
468      */
469     ap_add_module(mod, p);
470
471     /* 
472      *  And module pointer to list of loaded modules 
473      *
474      *  Notes: 1. ap_add_module() would already complain if no more space
475      *            exists for adding a dynamically loaded module
476      *         2. ap_add_module() accepts double inclusion, so we have
477      *            to accept this, too.
478      */
479     for (m = ap_loaded_modules; *m != NULL; m++)
480         ;
481     *m++ = mod;
482     *m = NULL;
483 }
484
485 AP_DECLARE(void) ap_remove_loaded_module(module *mod)
486 {
487     module **m;
488     module **m2;
489     int done;
490
491     /* 
492      *  Remove module pointer from chained module list 
493      */
494     ap_remove_module(mod);
495
496     /* 
497      *  Remove module pointer from list of loaded modules
498      *
499      *  Note: 1. We cannot determine if the module was successfully
500      *           removed by ap_remove_module().
501      *        2. We have not to complain explicity when the module
502      *           is not found because ap_remove_module() did it
503      *           for us already.
504      */
505     for (m = m2 = ap_loaded_modules, done = 0; *m2 != NULL; m2++) {
506         if (*m2 == mod && done == 0)
507             done = 1;
508         else
509             *m++ = *m2;
510     }
511     *m = NULL;
512 }
513
514 AP_DECLARE(void) ap_setup_prelinked_modules(process_rec *process)
515 {
516     module **m;
517     module **m2;
518
519     apr_global_hook_pool=process->pconf;
520
521     /*
522      *  Initialise total_modules variable and module indices
523      */
524     total_modules = 0;
525     for (m = ap_preloaded_modules; *m != NULL; m++)
526         (*m)->module_index = total_modules++;
527
528     /* 
529      *  Initialise list of loaded modules
530      */
531     ap_loaded_modules = (module **)apr_palloc(process->pool,
532         sizeof(module *)*(total_modules+DYNAMIC_MODULE_LIMIT+1));
533     if (ap_loaded_modules == NULL) {
534         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
535                      "Ouch!  Out of memory in ap_setup_prelinked_modules()!");
536     }
537     for (m = ap_preloaded_modules, m2 = ap_loaded_modules; *m != NULL; )
538         *m2++ = *m++;
539     *m2 = NULL;
540
541     /*
542      *   Initialize chain of linked (=activate) modules
543      */
544     for (m = ap_prelinked_modules; *m != NULL; m++)
545         ap_add_module(*m, process->pconf);
546
547     apr_sort_hooks();
548 }
549
550 AP_DECLARE(const char *) ap_find_module_name(module *m)
551 {
552     return m->name;
553 }
554
555 AP_DECLARE(module *) ap_find_linked_module(const char *name)
556 {
557     module *modp;
558
559     for (modp = top_module; modp; modp = modp->next) {
560         if (strcmp(modp->name, name) == 0)
561             return modp;
562     }
563     return NULL;
564 }
565
566 /* Add a named module.  Returns 1 if module found, 0 otherwise.  */
567 AP_DECLARE(int) ap_add_named_module(const char *name, apr_pool_t *p)
568 {
569     module *modp;
570     int i = 0;
571
572     for (modp = ap_loaded_modules[i]; modp; modp = ap_loaded_modules[++i]) {
573         if (strcmp(modp->name, name) == 0) {
574             /* Only add modules that are not already enabled.  */
575             if (modp->next == NULL) {
576                 ap_add_module(modp, p);
577             }
578             return 1;
579         }
580     }
581
582     return 0;
583 }
584
585 /*****************************************************************
586  *
587  * Resource, access, and .htaccess config files now parsed by a common
588  * command loop.
589  *
590  * Let's begin with the basics; parsing the line and
591  * invoking the function...
592  */
593
594 static const char *invoke_cmd(const command_rec *cmd, cmd_parms *parms,
595                               void *mconfig, const char *args)
596 {
597     char *w, *w2, *w3;
598     const char *errmsg;
599
600     if ((parms->override & cmd->req_override) == 0)
601         return apr_pstrcat(parms->pool, cmd->name, " not allowed here", NULL);
602
603     parms->info = cmd->cmd_data;
604     parms->cmd = cmd;
605
606     switch (cmd->args_how) {
607     case RAW_ARGS:
608 #ifdef RESOLVE_ENV_PER_TOKEN
609         args = ap_resolve_env(parms->pool,args);
610 #endif
611         return cmd->AP_RAW_ARGS(parms, mconfig, args);
612
613     case NO_ARGS:
614         if (*args != 0)
615             return apr_pstrcat(parms->pool, cmd->name, " takes no arguments",
616                            NULL);
617
618         return cmd->AP_NO_ARGS(parms, mconfig);
619
620     case TAKE1:
621         w = ap_getword_conf(parms->pool, &args);
622
623         if (*w == '\0' || *args != 0)
624             return apr_pstrcat(parms->pool, cmd->name, " takes one argument",
625                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
626
627         return cmd->AP_TAKE1(parms, mconfig, w);
628
629     case TAKE2:
630         w = ap_getword_conf(parms->pool, &args);
631         w2 = ap_getword_conf(parms->pool, &args);
632
633         if (*w == '\0' || *w2 == '\0' || *args != 0)
634             return apr_pstrcat(parms->pool, cmd->name, " takes two arguments",
635                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
636
637         return cmd->AP_TAKE2(parms, mconfig, w, w2);
638
639     case TAKE12:
640
641         w = ap_getword_conf(parms->pool, &args);
642         w2 = ap_getword_conf(parms->pool, &args);
643
644         if (*w == '\0' || *args != 0)
645             return apr_pstrcat(parms->pool, cmd->name, " takes 1-2 arguments",
646                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
647
648         return cmd->AP_TAKE2(parms, mconfig, w, *w2 ? w2 : NULL);
649
650     case TAKE3:
651
652         w = ap_getword_conf(parms->pool, &args);
653         w2 = ap_getword_conf(parms->pool, &args);
654         w3 = ap_getword_conf(parms->pool, &args);
655
656         if (*w == '\0' || *w2 == '\0' || *w3 == '\0' || *args != 0)
657             return apr_pstrcat(parms->pool, cmd->name, " takes three arguments",
658                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
659
660         return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
661
662     case TAKE23:
663
664         w = ap_getword_conf(parms->pool, &args);
665         w2 = ap_getword_conf(parms->pool, &args);
666         w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
667
668         if (*w == '\0' || *w2 == '\0' || *args != 0)
669             return apr_pstrcat(parms->pool, cmd->name,
670                             " takes two or three arguments",
671                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
672
673         return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
674
675     case TAKE123:
676
677         w = ap_getword_conf(parms->pool, &args);
678         w2 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
679         w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
680
681         if (*w == '\0' || *args != 0)
682             return apr_pstrcat(parms->pool, cmd->name,
683                             " takes one, two or three arguments",
684                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
685
686         return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
687
688     case TAKE13:
689
690         w = ap_getword_conf(parms->pool, &args);
691         w2 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
692         w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
693
694         if (*w == '\0' || (w2 && *w2 && !w3) || *args != 0)
695             return apr_pstrcat(parms->pool, cmd->name,
696                             " takes one or three arguments",
697                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
698
699         return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
700
701     case ITERATE:
702
703         while (*(w = ap_getword_conf(parms->pool, &args)) != '\0')
704             {
705             if ((errmsg = cmd->AP_TAKE1(parms, mconfig, w)))
706                 return errmsg;
707             }
708
709         return NULL;
710
711     case ITERATE2:
712
713         w = ap_getword_conf(parms->pool, &args);
714
715         if (*w == '\0' || *args == 0)
716             return apr_pstrcat(parms->pool, cmd->name,
717                             " requires at least two arguments",
718                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
719
720         while (*(w2 = ap_getword_conf(parms->pool, &args)) != '\0')
721             {
722             if ((errmsg = cmd->AP_TAKE2(parms, mconfig, w, w2)))
723                 return errmsg;
724             }
725
726         return NULL;
727
728     case FLAG:
729
730         w = ap_getword_conf(parms->pool, &args);
731
732         if (*w == '\0' || (strcasecmp(w, "on") && strcasecmp(w, "off")))
733             return apr_pstrcat(parms->pool, cmd->name, " must be On or Off",
734                             NULL);
735
736         return cmd->AP_FLAG(parms, mconfig, strcasecmp(w, "off") != 0);
737
738     default:
739
740         return apr_pstrcat(parms->pool, cmd->name,
741                     " is improperly configured internally (server bug)",
742                         NULL);
743     }
744 }
745
746 AP_CORE_DECLARE(const command_rec *) ap_find_command(const char *name, const command_rec *cmds)
747 {
748     while (cmds->name)
749         if (!strcasecmp(name, cmds->name))
750             return cmds;
751         else
752             ++cmds;
753
754     return NULL;
755 }
756
757 AP_CORE_DECLARE(const command_rec *) ap_find_command_in_modules(const char *cmd_name, module **mod)
758 {
759     const command_rec *cmdp;
760     module *modp;
761
762     for (modp = *mod; modp; modp = modp->next)
763         if (modp->cmds && (cmdp = ap_find_command(cmd_name, modp->cmds))) {
764             *mod = modp;
765             return cmdp;
766         }
767
768     return NULL;
769 }
770
771 AP_CORE_DECLARE(void *) ap_set_config_vectors(cmd_parms *parms, void *config, module *mod)
772 {
773     void *mconfig = ap_get_module_config(config, mod);
774     void *sconfig = ap_get_module_config(parms->server->module_config, mod);
775
776     if (!mconfig && mod->create_dir_config) {
777         mconfig = (*mod->create_dir_config) (parms->pool, parms->path);
778         ap_set_module_config(config, mod, mconfig);
779     }
780
781     if (!sconfig && mod->create_server_config) {
782         sconfig = (*mod->create_server_config) (parms->pool, parms->server);
783         ap_set_module_config(parms->server->module_config, mod, sconfig);
784     }
785     return mconfig;
786 }
787
788 static const char *execute_now(char *cmd_line, const char *args, cmd_parms *parms, 
789                          apr_pool_t *p, apr_pool_t *ptemp,
790                          ap_directive_t **sub_tree, ap_directive_t *parent);
791
792 static const char * ap_build_config_sub(apr_pool_t *p, apr_pool_t *temp_pool,
793                                         const char *l, cmd_parms *parms,
794                                         ap_directive_t **current,
795                                         ap_directive_t **curr_parent,
796                                         ap_directive_t **conftree)
797 {
798     const char *args;
799     char *cmd_name;
800     ap_directive_t *newdir;
801     module *mod = top_module;
802     const command_rec *cmd;
803
804     if (*l == '#' || *l == '\0')
805         return NULL;
806
807 #if RESOLVE_ENV_PER_TOKEN
808     args = l;
809 #else
810     args = ap_resolve_env(temp_pool, l); 
811 #endif
812     cmd_name = ap_getword_conf(p, &args);
813     if (*cmd_name == '\0') {
814         /* Note: this branch should not occur. An empty line should have
815          * triggered the exit further above.
816          */
817         return NULL;
818     }
819
820     newdir = apr_pcalloc(p, sizeof(ap_directive_t));
821     newdir->filename = parms->config_file->name;
822     newdir->line_num = parms->config_file->line_number;
823     newdir->directive = cmd_name;
824     newdir->args = apr_pstrdup(p, args);
825
826     if ((cmd = ap_find_command_in_modules(cmd_name, &mod)) != NULL) {
827         if (cmd->req_override & EXEC_ON_READ) {
828             const char *retval;
829             ap_directive_t *sub_tree = NULL;
830
831             parms->err_directive = newdir;
832             retval = execute_now(cmd_name, args, parms, p, temp_pool, 
833                                  &sub_tree, *curr_parent);
834             if (*current) {
835                 (*current)->next = sub_tree;
836             }
837             else {
838                 (*current) = sub_tree;
839                 if (*curr_parent) {
840                     (*curr_parent)->first_child = (*current);
841                 }
842                 if (*current) {
843                     (*current)->parent = (*curr_parent);
844                 }
845             }
846             if (*current) {
847                 if (!*conftree) {
848                     /* Before walking *current to the end of the list,
849                      * set the head to *current.
850                      */
851                     *conftree = *current;
852                 }
853                 while ((*current)->next != NULL) {
854                     (*current) = (*current)->next;
855                     (*current)->parent = (*curr_parent);
856                 }
857             }
858             return retval;
859         }
860     }
861
862     if (cmd_name[0] == '<') {
863         if (cmd_name[1] != '/') {
864             (*current) = ap_add_node(curr_parent, *current, newdir, 1);
865         }
866         else if (*curr_parent == NULL) {
867             parms->err_directive = newdir;
868             return apr_pstrcat(p, cmd_name,
869                               " without matching <", cmd_name + 2,
870                               " section", NULL);
871         }
872         else {
873             char *bracket = cmd_name + strlen(cmd_name) - 1;
874
875             if (*bracket != '>') {
876                 return apr_pstrcat(p, cmd_name,
877                                   "> directive missing closing '>'", NULL);
878             }
879             *bracket = '\0';
880             if (strcasecmp(cmd_name + 2,
881                             (*curr_parent)->directive + 1) != 0) {
882                 return apr_pstrcat(p, "Expected </",
883                                   (*curr_parent)->directive + 1, "> but saw ",
884                                   cmd_name, ">", NULL);
885             }
886             *bracket = '>';
887
888             /* done with this section; move up a level */
889             *current = *curr_parent;
890             *curr_parent = (*current)->parent;
891         }
892     }
893     else {
894         *current = ap_add_node(curr_parent, *current, newdir, 0);
895     }
896
897     return NULL;
898 }
899
900 const char *ap_build_cont_config(apr_pool_t *p, apr_pool_t *temp_pool,
901                                  cmd_parms *parms,
902                                  ap_directive_t **current,
903                                  ap_directive_t **curr_parent,
904                                  char *orig_directive)
905 {
906     char l[MAX_STRING_LEN];
907     char *bracket;
908     const char *retval;
909     ap_directive_t *sub_tree = NULL;
910
911     bracket = apr_pstrcat(p, orig_directive + 1, ">", NULL);
912     while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) {
913         if (!memcmp(l, "</", 2) &&
914             (strcasecmp(l + 2, bracket) == 0) &&
915             (*curr_parent == NULL)) {
916             break;
917         } 
918         retval = ap_build_config_sub(p, temp_pool, l, parms, current, 
919                                      curr_parent, &sub_tree);
920         if (retval != NULL)
921             return retval;
922         if (sub_tree == NULL && curr_parent != NULL) { 
923             sub_tree = *curr_parent;
924         }
925         if (sub_tree == NULL && current != NULL) {
926             sub_tree = *current;
927         }
928     }
929     *current = sub_tree;
930     return NULL;
931 }
932
933 static const char *ap_walk_config_sub(const ap_directive_t *current,
934                                       cmd_parms *parms, void *config)
935 {
936     module *mod = top_module;
937
938     while (1) {
939         const command_rec *cmd;
940
941         if (!(cmd = ap_find_command_in_modules(current->directive, &mod))) {
942             parms->err_directive = current;
943             return apr_pstrcat(parms->pool, "Invalid command '", 
944                               current->directive,
945                               "', perhaps mis-spelled or defined by a module "
946                               "not included in the server configuration",
947                               NULL);
948         }
949         else {
950             void *mconfig = ap_set_config_vectors(parms,config, mod);
951             const char *retval;
952
953             retval = invoke_cmd(cmd, parms, mconfig, current->args);
954             if (retval == NULL) {
955                 return NULL;
956             }
957             if (strcmp(retval, DECLINE_CMD) != 0) {
958                 /* If the directive in error has already been set, don't
959                  * replace it.  Otherwise, an error inside a container 
960                  * will be reported as occuring on the first line of the
961                  * container.
962                  */
963                 if (!parms->err_directive) {
964                     parms->err_directive = current;
965                 }
966                 return retval;
967             }
968
969             mod = mod->next;    /* Next time around, skip this one */
970         }
971     }
972     /* NOTREACHED */
973 }
974
975 AP_DECLARE(const char *) ap_walk_config(ap_directive_t *current,
976                                         cmd_parms *parms, void *config)
977 {
978     void *oldconfig = parms->context;
979
980     parms->context = config;
981
982     /* scan through all directives, executing each one */
983     for (; current != NULL; current = current->next) {
984         const char *errmsg;
985
986         parms->directive = current;
987
988         /* actually parse the command and execute the correct function */
989         errmsg = ap_walk_config_sub(current, parms, config);
990         if (errmsg != NULL) {
991             /* restore the context (just in case) */
992             parms->context = oldconfig;
993             return errmsg;
994         }
995     }
996
997     parms->context = oldconfig;
998     return NULL;
999 }
1000
1001
1002 AP_DECLARE(const char *) ap_build_config(cmd_parms *parms,
1003                                          apr_pool_t *p, apr_pool_t *temp_pool,
1004                                          ap_directive_t **conftree)
1005 {
1006     ap_directive_t *current = *conftree;
1007     ap_directive_t *curr_parent = NULL;
1008     char l[MAX_STRING_LEN];
1009     const char *errmsg;
1010
1011     if (current != NULL) {
1012         while (current->next) {
1013             current = current->next;
1014         }
1015     }
1016
1017     while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) {
1018
1019         errmsg = ap_build_config_sub(p, temp_pool, l, parms,
1020                                      &current, &curr_parent, conftree);
1021         if (errmsg != NULL)
1022             return errmsg;
1023
1024         if (*conftree == NULL && curr_parent != NULL) { 
1025             *conftree = curr_parent;
1026         }
1027         if (*conftree == NULL && current != NULL) {
1028             *conftree = current;
1029         }
1030     }
1031
1032     if (curr_parent != NULL) {
1033         errmsg = "";
1034         while (curr_parent != NULL) {
1035             errmsg = apr_psprintf(p, "%s%s%s:%u: %s> was not closed.",
1036                                  errmsg,
1037                                  *errmsg == '\0' ? "" : APR_EOL_STR,
1038                                  curr_parent->filename,
1039                                  curr_parent->line_num,
1040                                  curr_parent->directive);
1041             curr_parent = curr_parent->parent;
1042         }
1043         return errmsg;
1044     }
1045
1046     return NULL;
1047 }
1048
1049 /*
1050  * Generic command functions...
1051  */
1052
1053 AP_DECLARE_NONSTD(const char *) ap_set_string_slot(cmd_parms *cmd,
1054                                                    void *struct_ptr,
1055                                                    const char *arg)
1056 {
1057     /* This one's pretty generic... */
1058
1059     int offset = (int) (long) cmd->info;
1060     *(const char **) ((char *)struct_ptr + offset) = arg;
1061     return NULL;
1062 }
1063
1064 AP_DECLARE_NONSTD(const char *) ap_set_string_slot_lower(cmd_parms *cmd,
1065                                                          void *struct_ptr,
1066                                                          const char *arg_)
1067 {
1068     /* This one's pretty generic... */
1069     char *arg=apr_pstrdup(cmd->pool,arg_);
1070
1071     int offset = (int) (long) cmd->info;
1072     ap_str_tolower(arg);
1073     *(char **) ((char *)struct_ptr + offset) = arg;
1074     return NULL;
1075 }
1076
1077 AP_DECLARE_NONSTD(const char *) ap_set_flag_slot(cmd_parms *cmd,
1078                                                  void *struct_ptr_v, int arg)
1079 {
1080     /* This one's pretty generic too... */
1081
1082     int offset = (int) (long) cmd->info;
1083     char *struct_ptr = (char *)struct_ptr_v;
1084     *(int *) (struct_ptr + offset) = arg ? 1 : 0;
1085     return NULL;
1086 }
1087
1088 AP_DECLARE_NONSTD(const char *) ap_set_file_slot(cmd_parms *cmd, void *struct_ptr, 
1089                                                  const char *arg)
1090 {
1091     /* Prepend server_root to relative arg.
1092        This allows .htaccess to be independent of server_root,
1093        so the server can be moved or mirrored with less pain.  */
1094     char *p;
1095     int offset = (int) (long) cmd->info;
1096 #ifndef OS2
1097     arg = ap_os_canonical_filename(cmd->pool, arg);
1098 #endif
1099     if (ap_os_is_path_absolute(arg))
1100         p = apr_pstrdup(cmd->pool, arg);
1101     else
1102         p = ap_make_full_path(cmd->pool, ap_server_root, arg);
1103     *(char **) ((char*)struct_ptr + offset) = p;
1104     return NULL;
1105 }
1106
1107 /*****************************************************************
1108  *
1109  * Reading whole config files...
1110  */
1111
1112 static cmd_parms default_parms =
1113 {NULL, 0, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
1114
1115 AP_DECLARE(const char *) ap_server_root_relative(apr_pool_t *p, const char *file)
1116 {
1117 #ifndef OS2
1118     file = ap_os_canonical_filename(p, file);
1119 #endif
1120     if(ap_os_is_path_absolute(file))
1121         return file;
1122     return ap_make_full_path(p, ap_server_root, file);
1123 }
1124
1125 AP_DECLARE(const char *) ap_soak_end_container(cmd_parms *cmd, char *directive)
1126 {
1127     char l[MAX_STRING_LEN];
1128     const char *args;
1129     char *cmd_name;
1130
1131     while(!(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) {
1132 #if RESOLVE_ENV_PER_TOKEN
1133         args = l;
1134 #else
1135         args = ap_resolve_env(cmd->temp_pool, l);
1136 #endif
1137         cmd_name = ap_getword_conf(cmd->pool, &args);
1138         if (cmd_name[0] == '<') {
1139             if (cmd_name[1] == '/') {
1140                 cmd_name[strlen(cmd_name) - 1] = '\0';
1141                 if (strcasecmp(cmd_name + 2, directive + 1) != 0) {
1142                     return apr_pstrcat(cmd->pool, "Expected </",
1143                                       directive + 1, "> but saw ",
1144                                       cmd_name, ">", NULL);
1145                 }
1146                 break;
1147             }
1148             else {
1149                 ap_soak_end_container(cmd, cmd_name);
1150             }
1151         }
1152     }
1153     return NULL;
1154 }
1155
1156 static const char *execute_now(char *cmd_line, const char *args, cmd_parms *parms, 
1157                          apr_pool_t *p, apr_pool_t *ptemp, 
1158                          ap_directive_t **sub_tree, ap_directive_t *parent)
1159 {
1160     module *mod = top_module;
1161     const command_rec *cmd;
1162
1163     if (!(cmd = ap_find_command_in_modules(cmd_line, &mod))) {
1164         return apr_pstrcat(parms->pool, "Invalid command '", 
1165                           cmd_line,
1166                           "', perhaps mis-spelled or defined by a module "
1167                           "not included in the server configuration",
1168                           NULL);
1169     }
1170     else {
1171         return invoke_cmd(cmd, parms, sub_tree, args);
1172     }
1173 }
1174
1175 /* This structure and the following functions are needed for the
1176  * table-based config file reading. They are passed to the
1177  * cfg_open_custom() routine.
1178  */
1179
1180 /* Structure to be passed to cfg_open_custom(): it contains an
1181  * index which is incremented from 0 to nelts on each call to
1182  * cfg_getline() (which in turn calls arr_elts_getstr())
1183  * and an apr_array_header_t pointer for the string array.
1184  */
1185 typedef struct {
1186     apr_array_header_t *array;
1187     int curr_idx;
1188 } arr_elts_param_t;
1189
1190
1191 /* arr_elts_getstr() returns the next line from the string array. */
1192 static void *arr_elts_getstr(void *buf, size_t bufsiz, void *param)
1193 {
1194     arr_elts_param_t *arr_param = (arr_elts_param_t *) param;
1195
1196     /* End of array reached? */
1197     if (++arr_param->curr_idx > arr_param->array->nelts)
1198         return NULL;
1199
1200     /* return the line */
1201     apr_cpystrn(buf, ((char **) arr_param->array->elts)[arr_param->curr_idx - 1], bufsiz);
1202
1203     return buf;
1204 }
1205
1206
1207 /* arr_elts_close(): dummy close routine (makes sure no more lines can be read) */
1208 static int arr_elts_close(void *param)
1209 {
1210     arr_elts_param_t *arr_param = (arr_elts_param_t *) param;
1211     arr_param->curr_idx = arr_param->array->nelts;
1212     return 0;
1213 }
1214
1215 static void process_command_config(server_rec *s, apr_array_header_t *arr, 
1216                               ap_directive_t **conftree, apr_pool_t *p,
1217                               apr_pool_t *ptemp)
1218 {
1219     const char *errmsg;
1220     cmd_parms parms;
1221     arr_elts_param_t arr_parms;
1222
1223     arr_parms.curr_idx = 0;
1224     arr_parms.array = arr;
1225
1226     parms = default_parms;
1227     parms.pool = p;
1228     parms.temp_pool = ptemp;
1229     parms.server = s;
1230     parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT);
1231
1232     parms.config_file = ap_pcfg_open_custom(p, "-c/-C directives",
1233                               &arr_parms, NULL,
1234                               arr_elts_getstr, arr_elts_close);
1235
1236     errmsg = ap_build_config(&parms, p, ptemp, conftree);
1237     if (errmsg) {
1238         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
1239                      "Syntax error in -C/-c directive:" APR_EOL_STR "%s", 
1240                      errmsg);
1241         exit(1);
1242     }
1243
1244     ap_cfg_closefile(parms.config_file);
1245 }
1246
1247 typedef struct {
1248     char *fname;
1249 } fnames;
1250
1251 static int fname_alphasort(const void *fn1, const void *fn2)
1252 {
1253     const fnames *f1 = fn1;
1254     const fnames *f2 = fn2;
1255
1256     return strcmp(f1->fname,f2->fname);
1257 }
1258
1259 void ap_process_resource_config(server_rec *s, const char *fname, 
1260                                 ap_directive_t **conftree, apr_pool_t *p, 
1261                                 apr_pool_t *ptemp)
1262 {
1263     cmd_parms parms;
1264     apr_finfo_t finfo;
1265     const char *errmsg;
1266     configfile_t *cfp;
1267
1268     fname = ap_server_root_relative(p, fname);
1269
1270     /* don't require conf/httpd.conf if we have a -C or -c switch */
1271     if ((ap_server_pre_read_config->nelts
1272          || ap_server_post_read_config->nelts)
1273         && !(strcmp(fname, ap_server_root_relative(p, SERVER_CONFIG_FILE)))) {
1274         if (apr_stat(&finfo, fname, APR_FINFO_NORM, p) != APR_SUCCESS)
1275             return;
1276     }
1277
1278     /* 
1279      * here we want to check if the candidate file is really a
1280      * directory, and most definitely NOT a symlink (to prevent
1281      * horrible loops).  If so, let's recurse and toss it back into
1282      * the function.
1283      */
1284     if (ap_is_rdirectory(ptemp, fname)) {
1285         apr_dir_t *dirp;
1286         apr_finfo_t dirent;
1287         int current;
1288         apr_array_header_t *candidates = NULL;
1289         fnames *fnew;
1290         apr_status_t rv;
1291         char errmsg[120];
1292
1293         /*
1294          * first course of business is to grok all the directory
1295          * entries here and store 'em away. Recall we need full pathnames
1296          * for this.
1297          */
1298         fprintf(stderr, "Processing config directory: %s\n", fname);
1299         rv = apr_dir_open(&dirp, fname, p);
1300         if (rv != APR_SUCCESS) {
1301             fprintf(stderr, "%s: could not open config directory %s: %s\n",
1302                     ap_server_argv0, fname,
1303                     apr_strerror(rv, errmsg, sizeof errmsg));
1304             exit(1);
1305         }
1306         candidates = apr_make_array(p, 1, sizeof(fnames));
1307         while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) {
1308             /* strip out '.' and '..' */
1309             if (strcmp(dirent.name, ".") &&
1310                 strcmp(dirent.name, "..")) {
1311                 fnew = (fnames *) apr_push_array(candidates);
1312                 fnew->fname = ap_make_full_path(p, fname, dirent.name);
1313             }
1314         }
1315         apr_dir_close(dirp);
1316         if (candidates->nelts != 0) {
1317             qsort((void *) candidates->elts, candidates->nelts,
1318               sizeof(fnames), fname_alphasort);
1319             /*
1320              * Now recurse these... we handle errors and subdirectories
1321              * via the recursion, which is nice
1322              */
1323             for (current = 0; current < candidates->nelts; ++current) {
1324                 fnew = &((fnames *) candidates->elts)[current];
1325                 fprintf(stderr, " Processing config file: %s\n", fnew->fname);
1326                 ap_process_resource_config(s, fnew->fname, conftree, p, ptemp);
1327             }
1328         }
1329         return;
1330     }
1331     
1332     /* GCC's initialization extensions are soooo nice here... */
1333
1334     parms = default_parms;
1335     parms.pool = p;
1336     parms.temp_pool = ptemp;
1337     parms.server = s;
1338     parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT);
1339
1340     if (ap_pcfg_openfile(&cfp, p, fname) != APR_SUCCESS) {
1341         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
1342                      "%s: could not open document config file %s",
1343                      ap_server_argv0, fname);
1344         exit(1);
1345     }
1346
1347     parms.config_file = cfp;
1348
1349     errmsg = ap_build_config(&parms, p, ptemp, conftree);
1350
1351     if (errmsg != NULL) {
1352         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
1353                      "Syntax error on line %d of %s:",
1354                      parms.err_directive->line_num, 
1355                      parms.err_directive->filename);
1356         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
1357                      "%s", errmsg);
1358         exit(1);
1359     }
1360
1361     ap_cfg_closefile(cfp);
1362 }
1363
1364 AP_DECLARE(void)ap_process_config_tree(server_rec *s, ap_directive_t *conftree,
1365                                        apr_pool_t *p, apr_pool_t *ptemp)
1366 {
1367     const char *errmsg;
1368     cmd_parms parms;
1369
1370     parms = default_parms;
1371     parms.pool = p;
1372     parms.temp_pool = ptemp;
1373     parms.server = s;
1374     parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT);
1375     parms.limited = -1;
1376
1377     errmsg = ap_walk_config(conftree, &parms, s->lookup_defaults);
1378     if (errmsg) {
1379         ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, p,
1380                      "Syntax error on line %d of %s:",
1381                      parms.err_directive->line_num,
1382                      parms.err_directive->filename);
1383         ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, p, 
1384                      "%s", errmsg);
1385         exit(1);
1386     }
1387 }
1388
1389 int ap_parse_htaccess(void **result, request_rec *r, int override,
1390                       const char *d, const char *access_name) {
1391     configfile_t *f = NULL;
1392     cmd_parms parms;
1393     char *filename = NULL;
1394     const struct htaccess_result *cache;
1395     struct htaccess_result *new;
1396     void *dc = NULL;
1397     apr_status_t status;
1398
1399 /* firstly, search cache */
1400     for (cache = r->htaccess; cache != NULL; cache = cache->next)
1401         if (cache->override == override && strcmp(cache->dir, d) == 0) {
1402             if (cache->htaccess != NULL)
1403                 *result = cache->htaccess;
1404             return OK;
1405         }
1406
1407     parms = default_parms;
1408     parms.override = override;
1409     parms.pool = r->pool;
1410     parms.temp_pool = r->pool;
1411     parms.server = r->server;
1412     parms.path = apr_pstrdup(r->pool, d);
1413
1414     /* loop through the access names and find the first one */
1415
1416     while (access_name[0]) {
1417         filename = ap_make_full_path(r->pool, d,
1418                                      ap_getword_conf(r->pool, &access_name));
1419         status = ap_pcfg_openfile(&f, r->pool, filename);
1420
1421         if (status == APR_SUCCESS) {
1422             const char *errmsg;
1423             ap_directive_t *temptree = NULL;
1424
1425             dc = ap_create_per_dir_config(r->pool);
1426
1427             parms.config_file = f;
1428             errmsg = ap_build_config(&parms, r->pool, r->pool, &temptree);
1429             if (errmsg == NULL)
1430                 errmsg = ap_walk_config(temptree, &parms, dc);
1431
1432             ap_cfg_closefile(f);
1433
1434             if (errmsg) {
1435                 ap_log_rerror(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, r,
1436                               "%s: %s", filename, errmsg);
1437                 return HTTP_INTERNAL_SERVER_ERROR;
1438             }
1439             *result = dc;
1440             break;
1441         } else {
1442             if (!APR_STATUS_IS_ENOENT(status) && !APR_STATUS_IS_ENOTDIR(status)) {
1443                 ap_log_rerror(APLOG_MARK, APLOG_CRIT, status, r,
1444                               "%s pcfg_openfile: unable to check htaccess file, "
1445                               "ensure it is readable",
1446                               filename);
1447                 apr_table_setn(r->notes, "error-notes",
1448                               "Server unable to read htaccess file, denying "
1449                               "access to be safe");
1450                 return HTTP_FORBIDDEN;
1451             }
1452         }
1453     }
1454
1455 /* cache it */
1456     new = apr_palloc(r->pool, sizeof(struct htaccess_result));
1457     new->dir = parms.path;
1458     new->override = override;
1459     new->htaccess = dc;
1460 /* add to head of list */
1461     new->next = r->htaccess;
1462     r->htaccess = new;
1463
1464     return OK;
1465 }
1466
1467 AP_CORE_DECLARE(const char *) ap_init_virtual_host(apr_pool_t *p, const char *hostname,
1468                               server_rec *main_server, server_rec **ps)
1469 {
1470     server_rec *s = (server_rec *) apr_pcalloc(p, sizeof(server_rec));
1471
1472     /* TODO: this crap belongs in http_core */
1473     s->process = main_server->process;
1474     s->server_admin = NULL;
1475     s->server_hostname = NULL;
1476     s->error_fname = NULL;
1477     s->timeout = 0;
1478     s->keep_alive_timeout = 0;
1479     s->keep_alive = -1;
1480     s->keep_alive_max = -1;
1481     s->error_log = main_server->error_log;
1482     s->loglevel = main_server->loglevel;
1483     /* useful default, otherwise we get a port of 0 on redirects */
1484     s->port = main_server->port;
1485     s->next = NULL;
1486
1487     s->is_virtual = 1;
1488     s->names = apr_make_array(p, 4, sizeof(char **));
1489     s->wild_names = apr_make_array(p, 4, sizeof(char **));
1490
1491     s->module_config = create_empty_config(p);
1492     s->lookup_defaults = ap_create_per_dir_config(p);
1493
1494     s->limit_req_line = main_server->limit_req_line;
1495     s->limit_req_fieldsize = main_server->limit_req_fieldsize;
1496     s->limit_req_fields = main_server->limit_req_fields;
1497
1498     *ps = s;
1499
1500     return ap_parse_vhost_addrs(p, hostname, s);
1501 }
1502
1503
1504 AP_DECLARE(void) ap_fixup_virtual_hosts(apr_pool_t *p, server_rec *main_server)
1505 {
1506     server_rec *virt;
1507
1508     for (virt = main_server->next; virt; virt = virt->next) {
1509         merge_server_configs(p, main_server->module_config,
1510                              virt->module_config);
1511
1512         virt->lookup_defaults =
1513             ap_merge_per_dir_configs(p, main_server->lookup_defaults,
1514                                   virt->lookup_defaults);
1515
1516         if (virt->server_admin == NULL)
1517             virt->server_admin = main_server->server_admin;
1518
1519         if (virt->timeout == 0)
1520             virt->timeout = main_server->timeout;
1521
1522         if (virt->keep_alive_timeout == 0)
1523             virt->keep_alive_timeout = main_server->keep_alive_timeout;
1524
1525         if (virt->keep_alive == -1)
1526             virt->keep_alive = main_server->keep_alive;
1527
1528         if (virt->keep_alive_max == -1)
1529             virt->keep_alive_max = main_server->keep_alive_max;
1530
1531         /* XXX: this is really something that should be dealt with by a
1532          * post-config api phase */
1533         ap_core_reorder_directories(p, virt);
1534     }
1535     ap_core_reorder_directories(p, main_server);
1536 }
1537
1538 /*****************************************************************
1539  *
1540  * Getting *everything* configured... 
1541  */
1542
1543 static void init_config_globals(apr_pool_t *p)
1544 {
1545     /* Global virtual host hash bucket pointers.  Init to null. */
1546     ap_init_vhost_config(p);
1547 }
1548
1549 static server_rec *init_server_config(process_rec *process, apr_pool_t *p)
1550 {
1551     apr_status_t rv;
1552     server_rec *s = (server_rec *) apr_pcalloc(p, sizeof(server_rec));
1553
1554     apr_open_stderr(&s->error_log, p);
1555     s->process = process;
1556     s->port = 0;
1557     s->server_admin = DEFAULT_ADMIN;
1558     s->server_hostname = NULL;
1559     s->error_fname = DEFAULT_ERRORLOG;
1560     s->loglevel = DEFAULT_LOGLEVEL;
1561     s->limit_req_line = DEFAULT_LIMIT_REQUEST_LINE;
1562     s->limit_req_fieldsize = DEFAULT_LIMIT_REQUEST_FIELDSIZE;
1563     s->limit_req_fields = DEFAULT_LIMIT_REQUEST_FIELDS;
1564     s->timeout = DEFAULT_TIMEOUT;     
1565     s->keep_alive_timeout = DEFAULT_KEEPALIVE_TIMEOUT;
1566     s->keep_alive_max = DEFAULT_KEEPALIVE;
1567     s->keep_alive = 1;
1568     s->next = NULL;
1569     s->addrs = apr_pcalloc(p, sizeof(server_addr_rec));
1570     /* NOT virtual host; don't match any real network interface */
1571     rv = apr_getaddrinfo(&s->addrs->host_addr,
1572                          NULL, APR_INET, 0, 0, p);
1573     ap_assert(rv == APR_SUCCESS); /* otherwise: bug or no storage */
1574     s->addrs->host_port = 0;    /* matches any port */
1575     s->addrs->virthost = "";    /* must be non-NULL */
1576     s->names = s->wild_names = NULL;
1577
1578     s->module_config = create_server_config(p, s);
1579     s->lookup_defaults = create_default_per_dir_config(p);
1580
1581     return s;
1582 }
1583
1584
1585 AP_DECLARE(server_rec*) ap_read_config(process_rec *process, apr_pool_t *ptemp,
1586                                        const char *confname, 
1587                                        ap_directive_t **conftree)
1588 {
1589     apr_pool_t *p = process->pconf;
1590     server_rec *s = init_server_config(process, p);
1591
1592     init_config_globals(p);
1593
1594     /* All server-wide config files now have the SAME syntax... */
1595
1596     process_command_config(s, ap_server_pre_read_config, conftree,
1597                                       p, ptemp);
1598
1599     ap_process_resource_config(s, confname, conftree, p, ptemp);
1600
1601     process_command_config(s, ap_server_post_read_config, conftree,
1602                                       p, ptemp);
1603
1604     return s;
1605 }
1606
1607 AP_DECLARE(void) ap_single_module_configure(apr_pool_t *p, server_rec *s, 
1608                                             module *m)
1609 {
1610     if (m->create_server_config)
1611         ap_set_module_config(s->module_config, m,
1612                              (*m->create_server_config)(p, s));
1613     if (m->create_dir_config)
1614         ap_set_module_config(s->lookup_defaults, m,
1615                              (*m->create_dir_config)(p, NULL));
1616 }
1617
1618 AP_DECLARE(void) ap_run_rewrite_args(process_rec *process)
1619 {
1620     module *m;
1621
1622     for (m = top_module; m; m = m->next)
1623         if (m->rewrite_args)
1624             (*m->rewrite_args) (process);
1625 }
1626
1627 AP_DECLARE(void) ap_post_config_hook(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
1628 {
1629     ap_run_post_config(pconf,plog,ptemp,s); 
1630 }
1631
1632 void ap_child_init_hook(apr_pool_t *pchild, server_rec *s)
1633 {
1634     /* TODO: uh this seems ugly, is there a better way? */
1635     /*ap_child_init_alloc();    PUT THIS BACK IN XXXXX */
1636
1637     ap_run_child_init(pchild,s);
1638 }
1639
1640 /********************************************************************
1641  * Configuration directives are restricted in terms of where they may
1642  * appear in the main configuration files and/or .htaccess files according
1643  * to the bitmask req_override in the command_rec structure.
1644  * If any of the overrides set in req_override are also allowed in the
1645  * context in which the command is read, then the command is allowed.
1646  * The context is determined as follows:
1647  *
1648  *    inside *.conf --> override = (RSRC_CONF|OR_ALL)&~(OR_AUTHCFG|OR_LIMIT);
1649  *    within <Directory> or <Location> --> override = OR_ALL|ACCESS_CONF;
1650  *    within .htaccess --> override = AllowOverride for current directory;
1651  *
1652  * the result is, well, a rather confusing set of possibilities for when
1653  * a particular directive is allowed to be used.  This procedure prints
1654  * in English where the given (pc) directive can be used.
1655  */
1656 static void show_overrides(const command_rec *pc, module *pm)
1657 {
1658     int n = 0;
1659
1660     printf("\tAllowed in *.conf ");
1661     if ((pc->req_override & (OR_OPTIONS | OR_FILEINFO | OR_INDEXES)) ||
1662         ((pc->req_override & RSRC_CONF) &&
1663          ((pc->req_override & (ACCESS_CONF | OR_AUTHCFG | OR_LIMIT)))))
1664         printf("anywhere");
1665     else if (pc->req_override & RSRC_CONF)
1666         printf("only outside <Directory>, <Files> or <Location>");
1667     else
1668         printf("only inside <Directory>, <Files> or <Location>");
1669
1670     /* Warn if the directive is allowed inside <Directory> or .htaccess
1671      * but module doesn't support per-dir configuration */
1672
1673     if ((pc->req_override & (OR_ALL | ACCESS_CONF)) && !pm->create_dir_config)
1674         printf(" [no per-dir config]");
1675
1676     if (pc->req_override & OR_ALL) {
1677         printf(" and in .htaccess\n\twhen AllowOverride");
1678
1679         if ((pc->req_override & OR_ALL) == OR_ALL)
1680             printf(" isn't None");
1681         else {
1682             printf(" includes ");
1683
1684             if (pc->req_override & OR_AUTHCFG) {
1685                 if (n++)
1686                     printf(" or ");
1687                 printf("AuthConfig");
1688             }
1689             if (pc->req_override & OR_LIMIT) {
1690                 if (n++)
1691                     printf(" or ");
1692                 printf("Limit");
1693             }
1694             if (pc->req_override & OR_OPTIONS) {
1695                 if (n++)
1696                     printf(" or ");
1697                 printf("Options");
1698             }
1699             if (pc->req_override & OR_FILEINFO) {
1700                 if (n++)
1701                     printf(" or ");
1702                 printf("FileInfo");
1703             }
1704             if (pc->req_override & OR_INDEXES) {
1705                 if (n++)
1706                     printf(" or ");
1707                 printf("Indexes");
1708             }
1709         }
1710     }
1711     printf("\n");
1712 }
1713
1714 /* Show the preloaded configuration directives, the help string explaining
1715  * the directive arguments, in what module they are handled, and in
1716  * what parts of the configuration they are allowed.  Used for httpd -h.
1717  */
1718 AP_DECLARE(void) ap_show_directives()
1719 {
1720     const command_rec *pc;
1721     int n;
1722
1723     for (n = 0; ap_loaded_modules[n]; ++n)
1724         for (pc = ap_loaded_modules[n]->cmds; pc && pc->name; ++pc) {
1725             printf("%s (%s)\n", pc->name, ap_loaded_modules[n]->name);
1726             if (pc->errmsg)
1727                 printf("\t%s\n", pc->errmsg);
1728             show_overrides(pc, ap_loaded_modules[n]);
1729         }
1730 }
1731
1732 /* Show the preloaded module names.  Used for httpd -l. */
1733 AP_DECLARE(void) ap_show_modules()
1734 {
1735     int n;
1736
1737     printf("Compiled in modules:\n");
1738     for (n = 0; ap_loaded_modules[n]; ++n)
1739         printf("  %s\n", ap_loaded_modules[n]->name);
1740 }
1741