diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/.gdbinit apachen2/src/.gdbinit
--- apachen/src/.gdbinit	Sat Apr 18 21:20:30 1998
+++ apachen2/src/.gdbinit	Sat Apr 18 22:02:44 1998
@@ -13,3 +13,12 @@
 document dump_table
     Print the key/value pairs in a table.
 end
+
+handle SIGUSR1 noprint nostop
+handle SIGUSR2 noprint nostop
+
+handle SIGUSR1 noprint nostop
+handle SIGUSR2 noprint nostop
+
+handle SIGUSR1 noprint nostop
+handle SIGUSR2 noprint nostop
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/Configure apachen2/src/Configure
--- apachen/src/Configure	Mon Apr 20 12:11:30 1998
+++ apachen2/src/Configure	Mon Apr 20 12:13:08 1998
@@ -409,6 +409,7 @@
 	OS='Linux'
 	CFLAGS="$CFLAGS -DLINUX=2"
 	LIBS="$LIBS -lm"
+	OSDIR="os/pthread"
 	;;
     *-linux1)
 	DEF_WANTHSREGEX=yes
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/Makefile.tmpl apachen2/src/Makefile.tmpl
--- apachen/src/Makefile.tmpl	Sat Apr 18 21:20:39 1998
+++ apachen2/src/Makefile.tmpl	Mon Apr 20 12:15:20 1998
@@ -106,9 +106,9 @@
 $(OBJS): Makefile
 
 # DO NOT REMOVE
-buildmark.o: buildmark.c include/conf.h os/unix/os.h include/hsregex.h \
- include/httpd.h include/alloc.h include/buff.h include/ap.h \
- include/util_uri.h
-modules.o: modules.c include/httpd.h include/conf.h os/unix/os.h \
+buildmark.o: buildmark.c include/conf.h os/pthread/os.h \
+ include/hsregex.h include/httpd.h include/alloc.h include/buff.h \
+ include/ap.h include/util_uri.h
+modules.o: modules.c include/httpd.h include/conf.h os/pthread/os.h \
  include/hsregex.h include/alloc.h include/buff.h include/ap.h \
  include/util_uri.h include/http_config.h
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/ap/Makefile.tmpl apachen2/src/ap/Makefile.tmpl
--- apachen/src/ap/Makefile.tmpl	Sat Apr 18 21:20:40 1998
+++ apachen2/src/ap/Makefile.tmpl	Mon Apr 20 12:15:22 1998
@@ -39,21 +39,21 @@
 
 # DO NOT REMOVE
 ap_cpystrn.o: ap_cpystrn.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h
 ap_execve.o: ap_execve.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h
 ap_signal.o: ap_signal.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h
 ap_slack.o: ap_slack.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_log.h
 ap_snprintf.o: ap_snprintf.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h
 ap_strings.o: ap_strings.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/include/conf.h apachen2/src/include/conf.h
--- apachen/src/include/conf.h	Sat Apr 18 21:20:42 1998
+++ apachen2/src/include/conf.h	Sat Apr 18 22:02:44 1998
@@ -378,6 +378,10 @@
 /* flock is faster ... but hasn't been tested on 1.x systems */
 #define USE_FLOCK_SERIALIZED_ACCEPT
 
+#ifdef LTHREAD
+#include <pthread.h>
+#endif
+
 #else
 #define USE_FCNTL_SERIALIZED_ACCEPT
 #endif
@@ -1114,6 +1118,11 @@
 #endif
 #ifdef NEED_DIFFTIME
 extern double difftime(time_t time1, time_t time0);
+#endif
+
+#ifdef LTHREAD
+#undef SIGUSR1
+#define SIGUSR1 SIGWINCH
 #endif
 
 #endif	/* !APACHE_CONF_H */
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/include/http_config.h apachen2/src/include/http_config.h
--- apachen/src/include/http_config.h	Sat Apr 18 21:20:42 1998
+++ apachen2/src/include/http_config.h	Sat Apr 18 22:02:44 1998
@@ -281,6 +281,11 @@
 API_EXPORT(void *) ap_get_module_config(void *conf_vector, module *m);
 API_EXPORT(void) ap_set_module_config(void *conf_vector, module *m, void *val);
 
+#define ap_get_module_config(v,m)	\
+    (((void **)(v))[(m)->module_index])
+#define ap_set_module_config(v,m,val)	\
+    ((((void **)(v))[(m)->module_index]) = (val))
+
 /* Generic command handling function... */
 
 API_EXPORT_NONSTD(const char *) ap_set_string_slot(cmd_parms *, char *, char *);
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/include/httpd.h apachen2/src/include/httpd.h
--- apachen/src/include/httpd.h	Sat Apr 18 21:20:43 1998
+++ apachen2/src/include/httpd.h	Sun Apr 19 00:24:29 1998
@@ -58,6 +58,14 @@
 #ifndef APACHE_HTTPD_H
 #define APACHE_HTTPD_H
 
+#ifdef TOP_FUEL
+#define SINGLE_LISTEN_UNSERIALIZED_ACCEPT
+#define BUFFERED_LOGS
+#define DYNAMIC_MODULE_LIMIT	0
+#define SHARED_TIME
+#define NO_GRACEFUL
+#endif
+
 /*
  * httpd.h: header for simple (ha! not anymore) http daemon
  */
@@ -816,8 +824,8 @@
 extern API_VAR_EXPORT const char ap_month_snames[12][4];
 extern API_VAR_EXPORT const char ap_day_snames[7][4];
 
-API_EXPORT(struct tm *) ap_get_gmtoff(int *tz);
-API_EXPORT(char *) ap_get_time(void);
+API_EXPORT(struct tm *) ap_get_gmtoff(int *tz, struct tm *);
+API_EXPORT(char *) ap_get_time(char *);
 API_EXPORT(char *) ap_ht_time(pool *p, time_t t, const char *fmt, int gmt);
 API_EXPORT(char *) ap_gm_timestr_822(pool *p, time_t t);
 
@@ -970,6 +978,14 @@
 #define OPTIMIZE_TIMEOUTS
 #endif
 
+#ifdef SHARED_TIME
+#ifndef OPTIMIZE_TIMEOUTS
+# error "you need OPTIMIZE_TIMEOUTS for SHARED_TIME"
+#endif
+extern time_t ap_shared_time(time_t *);
+#define time(x) ap_shared_time(x)
+#endif
+
 /* A set of flags which indicate places where the server should raise(SIGSTOP).
  * This is useful for debugging, because you can then attach to that process
  * with gdb and continue.  This is important in cases where one_process
@@ -997,5 +1013,13 @@
 #undef strtoul
 #endif
 #define strtoul strtoul_is_not_a_portable_function_use_strtol_instead
+
+
+#ifdef LTHREAD
+#define DPRINTF(x) fprintf x
+#else
+#define DPRINTF(x) do {} while(0)
+#endif
+
 
 #endif	/* !APACHE_HTTPD_H */
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/include/multithread.h apachen2/src/include/multithread.h
--- apachen/src/include/multithread.h	Sat Apr 18 21:20:43 1998
+++ apachen2/src/include/multithread.h	Mon Apr 20 12:02:05 1998
@@ -41,6 +41,72 @@
 int reset_event(event *event_id);
 void destroy_event(event *event_id);
 
+#elif defined(LTHREAD)
+
+typedef struct {
+    pthread_mutex_t px;
+    pid_t pid;
+} lthread_mutex_t;
+
+extern inline mutex *ap_create_mutex(char *name);
+extern inline mutex *ap_create_mutex(char *name)
+{
+    static const pthread_mutex_t def = PTHREAD_MUTEX_INITIALIZER;
+    lthread_mutex_t *mx;
+    int rc;
+
+    mx = malloc(sizeof(*mx));
+    if (mx == NULL) {
+	fprintf(stderr, "out of memory!\n");
+	abort();
+    }
+
+    mx->px = def;
+    mx->pid = 0;
+    if ((rc = pthread_mutex_init(&mx->px, NULL))) {
+	fprintf(stderr, "pthread_mutex_init: %s\n", strerror(rc));
+	abort();
+    }
+
+    return mx;
+}
+
+extern inline int ap_acquire_mutex(mutex *vmx);
+extern inline int ap_acquire_mutex(mutex *vmx)
+{
+    lthread_mutex_t *mx = vmx;
+    pid_t me = getpid();
+
+    if (mx->pid == me) {
+	return MULTI_OK;
+    }
+    if (pthread_mutex_lock(&mx->px)) {
+	return MULTI_ERR;
+    }
+    mx->pid = me;
+    return MULTI_OK;
+}
+
+extern inline int ap_release_mutex(mutex *vmx);
+extern inline int ap_release_mutex(mutex *vmx)
+{
+    lthread_mutex_t *mx = vmx;
+
+    mx->pid = 0;
+    if (pthread_mutex_unlock(&mx->px)) {
+	return MULTI_ERR;
+    }
+    return MULTI_OK;
+}
+
+extern inline int ap_destroy_mutex(mutex *vmx);
+extern inline int ap_destroy_mutex(mutex *vmx)
+{
+    lthread_mutex_t *mx = vmx;
+    pthread_mutex_destroy(&mx->px);
+    free(mx);
+}
+
 #else /* ndef MULTITHREAD */
 
 #define APACHE_TLS
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/include/scoreboard.h apachen2/src/include/scoreboard.h
--- apachen/src/include/scoreboard.h	Sat Apr 18 21:20:43 1998
+++ apachen2/src/include/scoreboard.h	Sat Apr 18 22:02:44 1998
@@ -134,6 +134,9 @@
 typedef struct {
     int exit_generation;	/* Set by the main process if a graceful
 				   restart is required */
+#ifdef SHARED_TIME
+    time_t right_now;          /* the current time */
+#endif
 } global_score;
 
 /* stuff which the parent generally writes and the children rarely read */
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/main/Makefile.tmpl apachen2/src/main/Makefile.tmpl
--- apachen/src/main/Makefile.tmpl	Sat Apr 18 21:20:43 1998
+++ apachen2/src/main/Makefile.tmpl	Mon Apr 20 12:15:25 1998
@@ -60,28 +60,28 @@
 $(OBJS): Makefile
 
 # DO NOT REMOVE
-alloc.o: alloc.c $(INCDIR)/httpd.h $(INCDIR)/conf.h ../os/unix/os.h \
- $(INCDIR)/hsregex.h $(INCDIR)/alloc.h $(INCDIR)/buff.h \
- $(INCDIR)/ap.h $(INCDIR)/util_uri.h $(INCDIR)/multithread.h \
- $(INCDIR)/http_log.h
-buff.o: buff.c $(INCDIR)/httpd.h $(INCDIR)/conf.h ../os/unix/os.h \
+alloc.o: alloc.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/multithread.h $(INCDIR)/http_log.h
+buff.o: buff.c $(INCDIR)/httpd.h $(INCDIR)/conf.h ../os/pthread/os.h \
  $(INCDIR)/hsregex.h $(INCDIR)/alloc.h $(INCDIR)/buff.h \
  $(INCDIR)/ap.h $(INCDIR)/util_uri.h $(INCDIR)/http_main.h \
  $(INCDIR)/http_log.h
-fnmatch.o: fnmatch.c $(INCDIR)/conf.h ../os/unix/os.h \
+fnmatch.o: fnmatch.c $(INCDIR)/conf.h ../os/pthread/os.h \
  $(INCDIR)/hsregex.h $(INCDIR)/fnmatch.h
 gen_test_char.o: gen_test_char.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h
 gen_uri_delims.o: gen_uri_delims.c
 http_config.o: http_config.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_core.h $(INCDIR)/http_log.h \
  $(INCDIR)/http_request.h $(INCDIR)/http_conf_globals.h \
  $(INCDIR)/http_vhost.h $(INCDIR)/explain.h
 http_core.o: http_core.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_core.h \
  $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
@@ -90,20 +90,13 @@
  $(INCDIR)/util_md5.h $(INCDIR)/md5.h $(INCDIR)/scoreboard.h \
  $(INCDIR)/fnmatch.h
 http_log.o: http_log.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_core.h $(INCDIR)/http_log.h \
  $(INCDIR)/http_main.h
-http_main.o: http_main.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
- $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
- $(INCDIR)/http_main.h $(INCDIR)/http_log.h $(INCDIR)/http_config.h \
- $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
- $(INCDIR)/http_conf_globals.h $(INCDIR)/http_core.h \
- $(INCDIR)/http_vhost.h $(INCDIR)/util_script.h \
- $(INCDIR)/scoreboard.h $(INCDIR)/multithread.h $(INCDIR)/explain.h
+http_main.o: http_main.c
 http_protocol.o: http_protocol.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_core.h \
  $(INCDIR)/http_protocol.h $(INCDIR)/http_main.h \
@@ -111,36 +104,36 @@
  $(INCDIR)/http_log.h $(INCDIR)/util_date.h \
  $(INCDIR)/http_conf_globals.h
 http_request.o: http_request.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_request.h \
  $(INCDIR)/http_core.h $(INCDIR)/http_protocol.h \
  $(INCDIR)/http_log.h $(INCDIR)/http_main.h $(INCDIR)/scoreboard.h \
  $(INCDIR)/fnmatch.h
 http_vhost.o: http_vhost.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
  $(INCDIR)/http_log.h $(INCDIR)/http_vhost.h \
  $(INCDIR)/http_protocol.h
-md5c.o: md5c.c $(INCDIR)/conf.h ../os/unix/os.h $(INCDIR)/hsregex.h \
- $(INCDIR)/md5.h
+md5c.o: md5c.c $(INCDIR)/conf.h ../os/pthread/os.h \
+ $(INCDIR)/hsregex.h $(INCDIR)/md5.h
 rfc1413.o: rfc1413.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_log.h $(INCDIR)/rfc1413.h $(INCDIR)/http_main.h
-util.o: util.c $(INCDIR)/httpd.h $(INCDIR)/conf.h ../os/unix/os.h \
+util.o: util.c $(INCDIR)/httpd.h $(INCDIR)/conf.h ../os/pthread/os.h \
  $(INCDIR)/hsregex.h $(INCDIR)/alloc.h $(INCDIR)/buff.h \
  $(INCDIR)/ap.h $(INCDIR)/util_uri.h $(INCDIR)/http_conf_globals.h \
- $(INCDIR)/http_log.h test_char.h
-util_date.o: util_date.c $(INCDIR)/conf.h ../os/unix/os.h \
+ $(INCDIR)/http_log.h $(INCDIR)/multithread.h test_char.h
+util_date.o: util_date.c $(INCDIR)/conf.h ../os/pthread/os.h \
  $(INCDIR)/hsregex.h $(INCDIR)/util_date.h
 util_md5.o: util_md5.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/util_md5.h $(INCDIR)/md5.h
 util_script.o: util_script.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
  $(INCDIR)/http_main.h $(INCDIR)/http_log.h \
@@ -148,6 +141,6 @@
  $(INCDIR)/http_request.h $(INCDIR)/util_script.h \
  $(INCDIR)/util_date.h
 util_uri.o: util_uri.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_log.h $(INCDIR)/http_conf_globals.h uri_delims.h
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/main/alloc.c apachen2/src/main/alloc.c
--- apachen/src/main/alloc.c	Sat Apr 18 21:20:43 1998
+++ apachen2/src/main/alloc.c	Mon Apr 20 12:01:03 1998
@@ -459,10 +459,10 @@
 {
     ap_block_alarms();
 
-    (void) ap_acquire_mutex(alloc_mutex);
+    //(void) ap_acquire_mutex(alloc_mutex);
     while (a->sub_pools)
 	ap_destroy_pool(a->sub_pools);
-    (void) ap_release_mutex(alloc_mutex);
+    //(void) ap_release_mutex(alloc_mutex);
     /* Don't hold the mutex during cleanups. */
     run_cleanups(a->cleanups);
     a->cleanups = NULL;
@@ -865,7 +865,7 @@
     *ps.vbuff.curpos++ = '\0';
     ptr = ps.base;
     /* shrink */
-    ptr = realloc(ptr, ps.vbuff.curpos - ptr);
+    ptr = realloc(ptr, ps.vbuff.curpos - (char *)ptr);
     if (ptr == NULL) {
 	fputs("Ouch!  Out of memory!\n", stderr);
 	exit(1);
@@ -1492,7 +1492,9 @@
     int save_errno;
 
     ap_block_alarms();
-    fd = open(name, flg, mode);
+    do {
+	fd = open(name, flg, mode);
+    } while (fd == -1 && errno == EINTR);
     save_errno = errno;
     if (fd >= 0) {
 	fd = ap_slack(fd, AP_SLACK_HIGH);
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/main/http_config.c apachen2/src/main/http_config.c
--- apachen/src/main/http_config.c	Sat Apr 18 21:20:45 1998
+++ apachen2/src/main/http_config.c	Mon Apr 20 12:01:39 1998
@@ -115,17 +115,21 @@
  * overridden).
  */
 
+#ifndef ap_get_module_config
 API_EXPORT(void *) ap_get_module_config(void *conf_vector, module *m)
 {
     void **confv = (void **) conf_vector;
     return confv[m->module_index];
 }
+#endif
 
+#ifndef ap_set_module_config
 API_EXPORT(void) ap_set_module_config(void *conf_vector, module *m, void *val)
 {
     void **confv = (void **) conf_vector;
     confv[m->module_index] = val;
 }
+#endif
 
 static void *create_empty_config(pool *p)
 {
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/main/http_core.c apachen2/src/main/http_core.c
--- apachen/src/main/http_core.c	Mon Apr 20 12:11:34 1998
+++ apachen2/src/main/http_core.c	Mon Apr 20 12:11:50 1998
@@ -1542,7 +1542,7 @@
     if (err != NULL) return err;
 
     ap_daemons_min_free = atoi (arg);
-    if (ap_daemons_min_free <= 0) {
+    if (ap_daemons_min_free < 0) {
        fprintf(stderr, "WARNING: detected MinSpareServers set to non-positive.\n");
        fprintf(stderr, "Resetting to 1 to avoid almost certain Apache failure.\n");
        fprintf(stderr, "Please read the documentation.\n");
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/main/http_log.c apachen2/src/main/http_log.c
--- apachen/src/main/http_log.c	Mon Apr 20 12:11:35 1998
+++ apachen2/src/main/http_log.c	Mon Apr 20 12:11:50 1998
@@ -315,7 +315,12 @@
     }
 
     if (logf) {
-	len = ap_snprintf(errstr, sizeof(errstr), "[%s] ", ap_get_time());
+	errstr[0] = '[';
+	ap_get_time(errstr+1);
+	len = strlen(errstr);
+	errstr[len++] = ']';
+	errstr[len++] = ' ';
+	errstr[len] = 0;
     } else {
 	len = 0;
     }
@@ -445,8 +450,10 @@
 
 API_EXPORT(void) ap_log_assert (const char *szExp, const char *szFile, int nLine)
 {
+    char timebuf[MAX_STRING_LEN];
+
     fprintf(stderr, "[%s] file %s, line %d, assertion \"%s\" failed\n",
-	    ap_get_time(), szFile, nLine, szExp);
+	    ap_get_time(timebuf), szFile, nLine, szExp);
 #ifndef WIN32
     /* unix assert does an abort leading to a core dump */
     abort();
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/main/http_main.c apachen2/src/main/http_main.c
--- apachen/src/main/http_main.c	Sat Apr 18 21:45:41 1998
+++ apachen2/src/main/http_main.c	Mon Apr 20 12:42:10 1998
@@ -1,3 +1,4 @@
+#ifndef LTHREAD
 /* ====================================================================
  * Copyright (c) 1995-1998 The Apache Group.  All rights reserved.
  *
@@ -5308,3 +5309,9 @@
 
 #endif /* ndef SHARED_CORE_BOOTSTRAP */
 
+#else
+
+extern void http_main_is_not_here(void);
+void http_main_is_not_here(void) {}
+
+#endif
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/main/http_protocol.c apachen2/src/main/http_protocol.c
--- apachen/src/main/http_protocol.c	Sat Apr 18 21:20:50 1998
+++ apachen2/src/main/http_protocol.c	Mon Apr 20 12:01:50 1998
@@ -654,7 +654,7 @@
         }
     }
     /* we've probably got something to do, ignore graceful restart requests */
-#ifdef SIGUSR1
+#if defined(SIGUSR1) && !defined(NO_GRACEFUL)
     signal(SIGUSR1, SIG_IGN);
 #endif                          /* SIGUSR1 */
     ap_bsetflag(conn->client, B_SAFEREAD, 0);
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/main/util.c apachen2/src/main/util.c
--- apachen/src/main/util.c	Sat Apr 18 21:20:52 1998
+++ apachen2/src/main/util.c	Sat Apr 18 22:54:44 1998
@@ -71,6 +71,8 @@
 #include "httpd.h"
 #include "http_conf_globals.h"	/* for user_id & group_id */
 #include "http_log.h"
+#include "multithread.h"
+
 #if defined(SUNOS4)
 /* stdio.h has been read in conf.h already. Add missing prototypes here: */
 extern int fgetc(FILE *);
@@ -108,13 +110,13 @@
     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
 };
 
-API_EXPORT(char *) ap_get_time()
+API_EXPORT(char *) ap_get_time(char *buf)
 {
     time_t t;
     char *time_string;
 
     t = time(NULL);
-    time_string = ctime(&t);
+    time_string = ctime_r(&t, buf);
     time_string[strlen(time_string) - 1] = '\0';
     return (time_string);
 }
@@ -123,41 +125,47 @@
 {
     char ts[MAX_STRING_LEN];
     struct tm *tms;
+    char *res;
+    struct tm tmstore;
 
-    tms = (gmt ? gmtime(&t) : localtime(&t));
+    tms = (gmt ? gmtime_r(&t, &tmstore) : localtime_r(&t, &tmstore));
 
     /* check return code? */
     strftime(ts, MAX_STRING_LEN, fmt, tms);
     ts[MAX_STRING_LEN - 1] = '\0';
-    return ap_pstrdup(p, ts);
+    res = ap_pstrdup(p, ts);
+    return res;
 }
 
 API_EXPORT(char *) ap_gm_timestr_822(pool *p, time_t sec)
 {
     struct tm *tms;
+    char *res;
+    struct tm tmstore;
 
-    tms = gmtime(&sec);
+    tms = gmtime_r(&sec, &tmstore);
 
     /* RFC date format; as strftime '%a, %d %b %Y %T GMT' */
-    return ap_psprintf(p,
+    res = ap_psprintf(p,
 		"%s, %.2d %s %d %.2d:%.2d:%.2d GMT", ap_day_snames[tms->tm_wday],
 		tms->tm_mday, ap_month_snames[tms->tm_mon], tms->tm_year + 1900,
 		tms->tm_hour, tms->tm_min, tms->tm_sec);
+    return res;
 }
 
 /* What a pain in the ass. */
 #if defined(HAVE_GMTOFF)
-API_EXPORT(struct tm *) ap_get_gmtoff(int *tz)
+API_EXPORT(struct tm *) ap_get_gmtoff(int *tz, struct tm *tmstore)
 {
     time_t tt = time(NULL);
     struct tm *t;
 
-    t = localtime(&tt);
+    t = localtime_r(&tt, tmstore);
     *tz = (int) (t->tm_gmtoff / 60);
     return t;
 }
 #else
-API_EXPORT(struct tm *) ap_get_gmtoff(int *tz)
+API_EXPORT(struct tm *) ap_get_gmtoff(int *tz, struct tm *tmstore)
 {
     time_t tt = time(NULL);
     struct tm gmt;
@@ -165,8 +173,8 @@
     int days, hours, minutes;
 
     /* Assume we are never more than 24 hours away. */
-    gmt = *gmtime(&tt);		/* remember gmtime/localtime return ptr to static */
-    t = localtime(&tt);		/* buffer... so be careful */
+    gmtime_r(&tt, &gmt);		/* remember gmtime/localtime return ptr to static */
+    t = localtime_r(&tt, tmstore);	/* buffer... so be careful */
     days = t->tm_yday - gmt.tm_yday;
     hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24)
 	     + t->tm_hour - gmt.tm_hour);
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/modules/proxy/proxy_util.c apachen2/src/modules/proxy/proxy_util.c
--- apachen/src/modules/proxy/proxy_util.c	Sat Apr 18 21:20:58 1998
+++ apachen2/src/modules/proxy/proxy_util.c	Sat Apr 18 22:02:44 1998
@@ -769,9 +769,10 @@
 void ap_proxy_log_uerror(const char *routine, const char *file, const char *err,
 		      server_rec *s)
 {
+    char timebuf[MAX_STRING_LEN];
     char *p, *q;
 
-    q = ap_get_time();
+    q = ap_get_time(timebuf);
     p = strerror(errno);
 
     if (err != NULL) {
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/modules/standard/Makefile.tmpl apachen2/src/modules/standard/Makefile.tmpl
--- apachen/src/modules/standard/Makefile.tmpl	Sat Apr 18 21:20:58 1998
+++ apachen2/src/modules/standard/Makefile.tmpl	Mon Apr 20 12:15:32 1998
@@ -16,184 +16,184 @@
 
 # DO NOT REMOVE
 mod_access.o: mod_access.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_core.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_log.h $(INCDIR)/http_request.h
 mod_actions.o: mod_actions.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_request.h $(INCDIR)/http_core.h \
  $(INCDIR)/http_protocol.h $(INCDIR)/http_main.h \
  $(INCDIR)/http_log.h $(INCDIR)/util_script.h
 mod_alias.o: mod_alias.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h
 mod_asis.o: mod_asis.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_protocol.h \
  $(INCDIR)/http_log.h $(INCDIR)/util_script.h \
  $(INCDIR)/http_main.h $(INCDIR)/http_request.h
 mod_auth.o: mod_auth.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_core.h \
  $(INCDIR)/http_log.h $(INCDIR)/http_protocol.h
 mod_auth_anon.o: mod_auth_anon.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_core.h $(INCDIR)/http_log.h \
  $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h
 mod_auth_db.o: mod_auth_db.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_core.h $(INCDIR)/http_log.h \
  $(INCDIR)/http_protocol.h
 mod_auth_dbm.o: mod_auth_dbm.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_core.h $(INCDIR)/http_log.h \
  $(INCDIR)/http_protocol.h
 mod_autoindex.o: mod_autoindex.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_core.h $(INCDIR)/http_request.h \
  $(INCDIR)/http_protocol.h $(INCDIR)/http_log.h \
  $(INCDIR)/http_main.h $(INCDIR)/util_script.h
 mod_cern_meta.o: mod_cern_meta.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/util_script.h $(INCDIR)/http_log.h \
  $(INCDIR)/http_request.h
 mod_cgi.o: mod_cgi.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_request.h \
  $(INCDIR)/http_core.h $(INCDIR)/http_protocol.h \
  $(INCDIR)/http_main.h $(INCDIR)/http_log.h \
  $(INCDIR)/util_script.h $(INCDIR)/http_conf_globals.h
 mod_digest.o: mod_digest.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_core.h \
  $(INCDIR)/http_log.h $(INCDIR)/http_protocol.h \
  $(INCDIR)/util_md5.h $(INCDIR)/md5.h
 mod_dir.o: mod_dir.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_core.h \
  $(INCDIR)/http_request.h $(INCDIR)/http_protocol.h \
  $(INCDIR)/http_log.h $(INCDIR)/http_main.h \
  $(INCDIR)/util_script.h
 mod_env.o: mod_env.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h
 mod_expires.o: mod_expires.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_log.h
 mod_headers.o: mod_headers.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h
 mod_imap.o: mod_imap.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_request.h \
  $(INCDIR)/http_core.h $(INCDIR)/http_protocol.h \
  $(INCDIR)/http_main.h $(INCDIR)/http_log.h \
  $(INCDIR)/util_script.h
 mod_include.o: mod_include.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_request.h $(INCDIR)/http_core.h \
  $(INCDIR)/http_protocol.h $(INCDIR)/http_log.h \
  $(INCDIR)/http_main.h $(INCDIR)/util_script.h
 mod_info.o: mod_info.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_core.h \
  $(INCDIR)/http_log.h $(INCDIR)/http_main.h \
  $(INCDIR)/http_protocol.h $(INCDIR)/util_script.h \
  $(INCDIR)/http_conf_globals.h
 mod_log_agent.o: mod_log_agent.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h
 mod_log_config.o: mod_log_config.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_core.h $(INCDIR)/http_log.h
 mod_log_referer.o: mod_log_referer.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h
 mod_mime.o: mod_mime.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h
 mod_mime_magic.o: mod_mime_magic.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_request.h $(INCDIR)/http_core.h \
  $(INCDIR)/http_log.h $(INCDIR)/http_protocol.h
 mod_negotiation.o: mod_negotiation.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_request.h $(INCDIR)/http_core.h \
  $(INCDIR)/http_log.h $(INCDIR)/util_script.h
 mod_rewrite.o: mod_rewrite.c mod_rewrite.h $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_request.h $(INCDIR)/http_core.h \
  $(INCDIR)/http_log.h $(INCDIR)/http_vhost.h
 mod_setenvif.o: mod_setenvif.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_core.h $(INCDIR)/http_log.h
 mod_so.o: mod_so.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_log.h
 mod_speling.o: mod_speling.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_core.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_log.h
 mod_status.o: mod_status.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
- ../../os/unix/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ ../../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
  $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
  $(INCDIR)/http_config.h $(INCDIR)/http_core.h \
  $(INCDIR)/http_protocol.h $(INCDIR)/http_main.h \
  $(INCDIR)/util_script.h $(INCDIR)/scoreboard.h \
  $(INCDIR)/http_log.h
 mod_unique_id.o: mod_unique_id.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_log.h $(INCDIR)/multithread.h
 mod_userdir.o: mod_userdir.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h
 mod_usertrack.o: mod_usertrack.c $(INCDIR)/httpd.h \
- $(INCDIR)/conf.h ../../os/unix/os.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/conf.h ../../os/pthread/os.h $(INCDIR)/hsregex.h \
  $(INCDIR)/alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
  $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
  $(INCDIR)/http_core.h
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/modules/standard/mod_cgi.c apachen2/src/modules/standard/mod_cgi.c
--- apachen/src/modules/standard/mod_cgi.c	Sat Apr 18 21:21:01 1998
+++ apachen2/src/modules/standard/mod_cgi.c	Sat Apr 18 22:02:44 1998
@@ -168,6 +168,7 @@
 {
     FILE *f;
     struct stat finfo;
+    char timebuf[MAX_STRING_LEN];
 
     ap_log_error(APLOG_MARK, show_errno|APLOG_ERR, r->server, 
 		"%s, reason: %s", error, r->filename);
@@ -181,7 +182,7 @@
     }
 
     /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */
-    fprintf(f, "%%%% [%s] %s %s%s%s %s\n", ap_get_time(), r->method, r->uri,
+    fprintf(f, "%%%% [%s] %s %s%s%s %s\n", ap_get_time(timebuf), r->method, r->uri,
 	    r->args ? "?" : "", r->args ? r->args : "", r->protocol);
     /* "%% 500 /usr/local/apache/cgi-bin */
     fprintf(f, "%%%% %d %s\n", ret, r->filename);
@@ -216,7 +217,7 @@
     }
 
     /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */
-    fprintf(f, "%%%% [%s] %s %s%s%s %s\n", ap_get_time(), r->method, r->uri,
+    fprintf(f, "%%%% [%s] %s %s%s%s %s\n", ap_get_time(argsbuffer), r->method, r->uri,
 	    r->args ? "?" : "", r->args ? r->args : "", r->protocol);
     /* "%% 500 /usr/local/apache/cgi-bin" */
     fprintf(f, "%%%% %d %s\n", ret, r->filename);
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/modules/standard/mod_include.c apachen2/src/modules/standard/mod_include.c
--- apachen/src/modules/standard/mod_include.c	Sat Apr 18 21:21:05 1998
+++ apachen2/src/modules/standard/mod_include.c	Sat Apr 18 22:02:44 1998
@@ -94,6 +94,13 @@
 #include "util_script.h"
 #endif
 
+#ifdef TOP_FUEL
+#ifdef ap_chdir_file
+#undef ap_chdir_file
+#endif
+#define ap_chdir_file(x) do { } while(0)
+#endif
+
 #define STARTING_SEQUENCE "<!--#"
 #define ENDING_SEQUENCE "-->"
 #define DEFAULT_ERROR_MSG "[an error occurred while processing this directive]"
@@ -113,31 +120,57 @@
 
 /* ------------------------ Environment function -------------------------- */
 
-static void add_include_vars(request_rec *r, char *timefmt)
+static const char INCLUDE_TIME_FORMAT[] = "INCLUDE_TIME_FORMAT";
+
+static const char *get_envvar(request_rec *r, const char *name)
 {
+    const char *res;
+    table *e;
+
+    e = r->subprocess_env;
+    res = ap_table_get(e, name);
+    if (res) {
+	return res;
+    }
+    if (!strcmp(name, "LAST_MODIFIED")) {
+	res = ap_ht_time(r->pool, r->finfo.st_mtime,
+	    ap_table_get(e, INCLUDE_TIME_FORMAT), 0);
+    }
+    else if (!strcmp(name, "DATE_LOCAL")) {
+	res = ap_ht_time(r->pool, r->request_time,
+	    ap_table_get(e, INCLUDE_TIME_FORMAT), 0);
+    }
+    else if (!strcmp(name, "DATE_GMT")) {
+	res = ap_ht_time(r->pool, r->request_time,
+	    ap_table_get(e, INCLUDE_TIME_FORMAT), 1);
+    }
 #ifndef WIN32
-    struct passwd *pw;
+    else if (!strcmp(name, "USER_NAME")) {
+	struct passwd *pw;
+	pw = getpwuid(r->finfo.st_uid);
+	if (pw) {
+	    res = ap_pstrdup(r->pool, pw->pw_name);
+	}
+	else {
+	    res = ap_psprintf(r->pool, "user#%lu",
+			(unsigned long) r->finfo.st_uid);
+	}
+    }
 #endif /* ndef WIN32 */
+    if (res) {
+	ap_table_set(e, name, res);
+    }
+    return res;
+}
+
+static void add_include_vars(request_rec *r)
+{
     table *e = r->subprocess_env;
     char *t;
-    time_t date = r->request_time;
 
-    ap_table_setn(e, "DATE_LOCAL", ap_ht_time(r->pool, date, timefmt, 0));
-    ap_table_setn(e, "DATE_GMT", ap_ht_time(r->pool, date, timefmt, 1));
-    ap_table_setn(e, "LAST_MODIFIED",
-              ap_ht_time(r->pool, r->finfo.st_mtime, timefmt, 0));
+    ap_table_setn(e, INCLUDE_TIME_FORMAT, DEFAULT_TIME_FORMAT);
     ap_table_setn(e, "DOCUMENT_URI", r->uri);
     ap_table_setn(e, "DOCUMENT_PATH_INFO", r->path_info);
-#ifndef WIN32
-    pw = getpwuid(r->finfo.st_uid);
-    if (pw) {
-        ap_table_setn(e, "USER_NAME", ap_pstrdup(r->pool, pw->pw_name));
-    }
-    else {
-        ap_table_setn(e, "USER_NAME", ap_psprintf(r->pool, "user#%lu",
-                    (unsigned long) r->finfo.st_uid));
-    }
-#endif /* ndef WIN32 */
 
     if ((t = strrchr(r->filename, '/'))) {
         ap_table_setn(e, "DOCUMENT_NAME", ++t);
@@ -536,7 +569,7 @@
 		memcpy(var, start_of_var_name, l);
 		var[l] = '\0';
 
-		val = ap_table_get(r->subprocess_env, var);
+		val = get_envvar(r, var);
 		if (val) {
 		    expansion = val;
 		    l = strlen(expansion);
@@ -879,7 +912,7 @@
             return 1;
         }
         if (!strcmp(tag, "var")) {
-            char *val = ap_table_get(r->subprocess_env, tag_val);
+	    const char *val = get_envvar(r, tag_val);
 
             if (val) {
                 ap_rputs(val, r);
@@ -934,16 +967,26 @@
 }
 #endif
 
+
+static void set_timefmt(request_rec *r, char *value)
+{
+    table *e = r->subprocess_env;
+
+    ap_table_setn(e, INCLUDE_TIME_FORMAT, ap_pstrdup(r->pool, value));
+    ap_table_unset(e, "DATE_LOCAL");
+    ap_table_unset(e, "DATE_GMT");
+    ap_table_unset(e, "LAST_MODIFIED");
+}
+
+
 /* error and tf must point to a string with room for at 
  * least MAX_STRING_LEN characters 
  */
-static int handle_config(FILE *in, request_rec *r, char *error, char *tf,
-                         int *sizefmt)
+static int handle_config(FILE *in, request_rec *r, char *error, int *sizefmt)
 {
     char tag[MAX_STRING_LEN];
     char *tag_val;
     char parsed_string[MAX_STRING_LEN];
-    table *env = r->subprocess_env;
 
     while (1) {
         if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 0))) {
@@ -953,13 +996,8 @@
             parse_string(r, tag_val, error, MAX_STRING_LEN, 0);
         }
         else if (!strcmp(tag, "timefmt")) {
-            time_t date = r->request_time;
-
-            parse_string(r, tag_val, tf, MAX_STRING_LEN, 0);
-            ap_table_setn(env, "DATE_LOCAL", ap_ht_time(r->pool, date, tf, 0));
-            ap_table_setn(env, "DATE_GMT", ap_ht_time(r->pool, date, tf, 1));
-            ap_table_setn(env, "LAST_MODIFIED",
-                      ap_ht_time(r->pool, r->finfo.st_mtime, tf, 0));
+            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
+	    set_timefmt(r, parsed_string);
         }
         else if (!strcmp(tag, "sizefmt")) {
             parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
@@ -1072,7 +1110,7 @@
     }
 }
 
-static int handle_flastmod(FILE *in, request_rec *r, const char *error, const char *tf)
+static int handle_flastmod(FILE *in, request_rec *r, const char *error)
 {
     char tag[MAX_STRING_LEN];
     char *tag_val;
@@ -1089,7 +1127,8 @@
         else {
             parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
             if (!find_file(r, "flastmod", tag, parsed_string, &finfo, error)) {
-                ap_rputs(ap_ht_time(r->pool, finfo.st_mtime, tf, 0), r);
+                ap_rputs(ap_ht_time(r->pool, finfo.st_mtime,
+		    ap_table_get(r->subprocess_env, INCLUDE_TIME_FORMAT), 0), r);
             }
         }
     }
@@ -2018,7 +2057,12 @@
                 return -1;
             }
             parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
-            ap_table_setn(r->subprocess_env, var, ap_pstrdup(r->pool, parsed_string));
+	    if (strcmp(var, INCLUDE_TIME_FORMAT)) {
+		ap_table_setn(r->subprocess_env, var, ap_pstrdup(r->pool, parsed_string));
+	    }
+	    else {
+		set_timefmt(r, parsed_string);
+	    }
         }
         else {
             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server,
@@ -2041,6 +2085,11 @@
         return 1;
     }
     else if (!strcmp(tag, "done")) {
+	/* force these to be defined */
+	get_envvar(r, "DATE_LOCAL");
+	get_envvar(r, "DATE_GMT");
+	get_envvar(r, "LAST_MODIFIED");
+	get_envvar(r, "USER_NAME");
         for (i = 0; i < arr->nelts; ++i) {
             ap_rvputs(r, elts[i].key, "=", elts[i].val, "\n", NULL);
         }
@@ -2064,7 +2113,6 @@
 static void send_parsed_content(FILE *f, request_rec *r)
 {
     char directive[MAX_STRING_LEN], error[MAX_STRING_LEN];
-    char timefmt[MAX_STRING_LEN];
     int noexec = ap_allow_options(r) & OPT_INCNOEXEC;
     int ret, sizefmt;
     int if_nesting;
@@ -2072,7 +2120,6 @@
     int conditional_status;
 
     ap_cpystrn(error, DEFAULT_ERROR_MSG, sizeof(error));
-    ap_cpystrn(timefmt, DEFAULT_TIME_FORMAT, sizeof(timefmt));
     sizefmt = SIZEFMT_KMG;
 
 /*  Turn printing on */
@@ -2151,7 +2198,7 @@
                 }
             }
             else if (!strcmp(directive, "config")) {
-                ret = handle_config(f, r, error, timefmt, &sizefmt);
+                ret = handle_config(f, r, error, &sizefmt);
             }
             else if (!strcmp(directive, "set")) {
                 ret = handle_set(f, r, error);
@@ -2166,7 +2213,7 @@
                 ret = handle_fsize(f, r, error, sizefmt);
             }
             else if (!strcmp(directive, "flastmod")) {
-                ret = handle_flastmod(f, r, error, timefmt);
+                ret = handle_flastmod(f, r, error);
             }
             else if (!strcmp(directive, "printenv")) {
                 ret = handle_printenv(f, r, error);
@@ -2311,7 +2358,7 @@
 	 * environment */
         ap_add_common_vars(r);
         ap_add_cgi_vars(r);
-        add_include_vars(r, DEFAULT_TIME_FORMAT);
+        add_include_vars(r);
     }
     /* XXX: this is bogus, at some point we're going to do a subrequest,
      * and when we do it we're going to be subjecting code that doesn't
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/modules/standard/mod_log_config.c apachen2/src/modules/standard/mod_log_config.c
--- apachen/src/modules/standard/mod_log_config.c	Sat Apr 18 21:21:06 1998
+++ apachen2/src/modules/standard/mod_log_config.c	Sun Apr 19 00:02:59 1998
@@ -370,9 +370,10 @@
 {
     int timz;
     struct tm *t;
+    struct tm tmstore;
     char tstr[MAX_STRING_LEN];
 
-    t = ap_get_gmtoff(&timz);
+    t = ap_get_gmtoff(&timz, &tmstore);
 
     if (a && *a) {              /* Custom format */
         strftime(tstr, MAX_STRING_LEN, a, t);
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/modules/standard/mod_rewrite.c apachen2/src/modules/standard/mod_rewrite.c
--- apachen/src/modules/standard/mod_rewrite.c	Sat Apr 18 21:21:13 1998
+++ apachen2/src/modules/standard/mod_rewrite.c	Sat Apr 18 22:55:22 1998
@@ -2976,10 +2976,11 @@
 {
     int timz;
     struct tm *t;
+    struct tm tmstore;
     char tstr[80];
     char sign;
 
-    t = ap_get_gmtoff(&timz);
+    t = ap_get_gmtoff(&timz, &tmstore);
     sign = (timz < 0 ? '-' : '+');
     if(timz < 0)
         timz = -timz;
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/os/pthread/Makefile.tmpl apachen2/src/os/pthread/Makefile.tmpl
--- apachen/src/os/pthread/Makefile.tmpl	Wed Dec 31 16:00:00 1969
+++ apachen2/src/os/pthread/Makefile.tmpl	Mon Apr 20 12:15:20 1998
@@ -0,0 +1,52 @@
+CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS)
+LIBS=$(EXTRA_LIBS) $(LIBS1)
+INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES)
+LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS)
+
+OBJS=	os.o os-inline.o http_main.o
+
+LIB=	libos.a
+
+all:	$(LIB)
+
+$(LIB): $(OBJS)
+	rm -f $@
+	ar cr $@ $(OBJS)
+	$(RANLIB) $@
+
+.c.o:
+	$(CC) -c $(INCLUDES) $(CFLAGS) $(SPACER) $<
+
+clean:
+	rm -f $(OBJS) $(LIB)
+
+distclean: clean
+	-rm -f Makefile
+
+# We really don't expect end users to use this rule.  It works only with
+# gcc, and rebuilds Makefile.tmpl.  You have to re-run Configure after
+# using it.
+depend:
+	cp Makefile.tmpl Makefile.tmpl.bak \
+	    && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.tmpl > Makefile.new \
+	    && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \
+	    && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' Makefile.new \
+		> Makefile.tmpl \
+	    && rm Makefile.new
+
+$(OBJS): Makefile
+
+# DO NOT REMOVE
+http_main.o: http_main.c $(INCDIR)/httpd.h $(INCDIR)/conf.h \
+ ../../os/pthread/os.h $(INCDIR)/hsregex.h $(INCDIR)/alloc.h \
+ $(INCDIR)/buff.h $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_log.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_protocol.h \
+ $(INCDIR)/http_request.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_core.h $(INCDIR)/http_vhost.h \
+ $(INCDIR)/util_script.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/multithread.h $(INCDIR)/explain.h
+os-inline.o: os-inline.c $(INCDIR)/conf.h ../../os/pthread/os.h \
+ $(INCDIR)/hsregex.h
+os.o: os.c $(INCDIR)/conf.h ../../os/pthread/os.h \
+ $(INCDIR)/hsregex.h os.h
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/os/pthread/http_main.c apachen2/src/os/pthread/http_main.c
--- apachen/src/os/pthread/http_main.c	Wed Dec 31 16:00:00 1969
+++ apachen2/src/os/pthread/http_main.c	Mon Apr 20 12:02:15 1998
@@ -0,0 +1,3105 @@
+/* ====================================================================
+ * Copyright (c) 1995-1998 The Apache Group.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+/*
+ * httpd.c: simple http daemon for answering WWW file requests
+ *
+ * 
+ * 03-21-93  Rob McCool wrote original code (up to NCSA HTTPd 1.3)
+ * 
+ * 03-06-95  blong
+ *  changed server number for child-alone processes to 0 and changed name
+ *   of processes
+ *
+ * 03-10-95  blong
+ *      Added numerous speed hacks proposed by Robert S. Thau (rst@ai.mit.edu) 
+ *      including set group before fork, and call gettime before to fork
+ *      to set up libraries.
+ *
+ * 04-14-95  rst / rh
+ *      Brandon's code snarfed from NCSA 1.4, but tinkered to work with the
+ *      Apache server, and also to have child processes do accept() directly.
+ *
+ * April-July '95 rst
+ *      Extensive rework for Apache.
+ */
+
+#ifndef SHARED_CORE_BOOTSTRAP
+#ifndef SHARED_CORE_TIESTATIC
+
+#ifdef SHARED_CORE
+#define REALMAIN ap_main
+#else
+#define REALMAIN main
+#endif
+
+#define CORE_PRIVATE
+
+#include "httpd.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "http_config.h"	/* for read_config */
+#include "http_protocol.h"	/* for read_request */
+#include "http_request.h"	/* for process_request */
+#include "http_conf_globals.h"
+#include "http_core.h"		/* for get_remote_host */
+#include "http_vhost.h"
+#include "util_script.h"	/* to force util_script.c linking */
+#include "util_uri.h"
+#include "scoreboard.h"
+#include "multithread.h"
+#include <sys/stat.h>
+#ifdef USE_SHMGET_SCOREBOARD
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#endif
+#ifdef SecureWare
+#include <sys/security.h>
+#include <sys/audit.h>
+#include <prot.h>
+#endif
+#include <netinet/tcp.h>
+
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>		/* for IRIX, FD_SET calls bzero() */
+#endif
+
+/* This next function is never used. It is here to ensure that if we
+ * make all the modules into shared libraries that core httpd still
+ * includes the full Apache API. Without this function the objects in
+ * main/util_script.c would not be linked into a minimal httpd.
+ * And the extra prototype is to make gcc -Wmissing-prototypes quiet.
+ */
+extern void ap_force_library_loading(void);
+void ap_force_library_loading(void) {
+    ap_add_cgi_vars(NULL);
+}
+
+#include "explain.h"
+
+#if !defined(max)
+#define max(a,b)        (a > b ? a : b)
+#endif
+
+DEF_Explain
+
+/* Defining GPROF when compiling uses the moncontrol() function to
+ * disable gprof profiling in the parent, and enable it only for
+ * request processing in children (or in one_process mode).  It's
+ * absolutely required to get useful gprof results under linux
+ * because the profile itimers and such are disabled across a
+ * fork().  It's probably useful elsewhere as well.
+ */
+#ifdef GPROF
+extern void moncontrol(int);
+#define MONCONTROL(x) moncontrol(x)
+#else
+#define MONCONTROL(x)
+#endif
+
+#ifndef MULTITHREAD
+/* this just need to be anything non-NULL */
+void *ap_dummy_mutex = &ap_dummy_mutex;
+#endif
+
+/*
+ * Actual definitions of config globals... here because this is
+ * for the most part the only code that acts on 'em.  (Hmmm... mod_main.c?)
+ */
+
+int ap_standalone;
+uid_t ap_user_id;
+char *ap_user_name;
+gid_t ap_group_id;
+#ifdef MULTIPLE_GROUPS
+gid_t group_id_list[NGROUPS_MAX];
+#endif
+int ap_max_requests_per_child;
+int ap_threads_per_child;
+int ap_excess_requests_per_child;
+char *ap_pid_fname;
+char *ap_scoreboard_fname;
+char *ap_lock_fname;
+char *ap_server_argv0;
+struct in_addr ap_bind_address;
+int ap_daemons_to_start;
+int ap_daemons_min_free;
+int ap_daemons_max_free;
+int ap_daemons_limit;
+time_t ap_restart_time;
+int ap_suexec_enabled = 0;
+int ap_listenbacklog;
+
+/*
+ * The max child slot ever assigned, preserved across restarts.  Necessary
+ * to deal with MaxClients changes across SIGUSR1 restarts.  We use this
+ * value to optimize routines that have to scan the entire scoreboard.
+ */
+static int max_daemons_limit = -1;
+
+/*
+ * During config time, listeners is treated as a NULL-terminated list.
+ * child_main previously would start at the beginning of the list each time
+ * through the loop, so a socket early on in the list could easily starve out
+ * sockets later on in the list.  The solution is to start at the listener
+ * after the last one processed.  But to do that fast/easily in child_main it's
+ * way more convenient for listeners to be a ring that loops back on itself.
+ * The routine setup_listeners() is called after config time to both open up
+ * the sockets and to turn the NULL-terminated list into a ring that loops back
+ * on itself.
+ *
+ * head_listener is used by each child to keep track of what they consider
+ * to be the "start" of the ring.  It is also set by make_child to ensure
+ * that new children also don't starve any sockets.
+ *
+ * Note that listeners != NULL is ensured by read_config().
+ */
+listen_rec *ap_listeners;
+
+API_VAR_EXPORT char ap_server_root[MAX_STRING_LEN];
+char ap_server_confname[MAX_STRING_LEN];
+char ap_coredump_dir[MAX_STRING_LEN];
+
+array_header *ap_server_pre_read_config;
+array_header *ap_server_post_read_config;
+
+/* stuff that needs thread local store in main */
+typedef struct {
+    JMP_BUF jmpbuffer;
+    int my_pid;           /* it seems silly to call getpid all the time */
+    int volatile exit_after_unblock;
+    conn_rec *volatile current_conn;
+    request_rec *volatile timeout_req;
+    const char *volatile timeout_name;
+    int volatile alarms_blocked;
+    int volatile alarm_pending;
+    void (*volatile alarm_fn) (int);
+    listen_rec *head_listener;
+    int sd;
+    pool *pchild;		/* Pool for httpd child stuff */
+#ifndef MULTITHREAD
+    int my_child_num;
+#endif
+    int volatile usr1_just_die;
+    int volatile deferred_die;
+#ifndef MULTITHREAD
+    /* The following vars are static to avoid getting clobbered by longjmp();
+     * they are really private to child_main. */
+    int srv;
+    int csd;
+    int dupped_csd;
+    int requests_this_child;
+    fd_set main_fds;
+#endif
+} tls_main_t;
+
+static pthread_key_t tls_main_key;
+#define tls()	((tls_main_t *)pthread_getspecific(tls_main_key))
+
+/* *Non*-shared http_main globals... */
+
+static server_rec *server_conf;
+static fd_set listenfds;
+static int listenmaxfd;
+static pid_t pgrp;
+
+/* one_process --- debugging mode variable; can be set from the command line
+ * with the -X flag.  If set, this gets you the child_main loop running
+ * in the process which originally started up (no detach, no make_child),
+ * which is a pretty nice debugging environment.  (You'll get a SIGHUP
+ * early in standalone_main; just continue through.  This is the server
+ * trying to kill off any child processes which it might have lying
+ * around --- Apache doesn't keep track of their pids, it just sends
+ * SIGHUP to the process group, ignoring it in the root process.
+ * Continue through and you'll be fine.).
+ */
+
+static int one_process = 0;
+
+/* set if timeouts are to be handled by the children and not by the parent.
+ * i.e. child_timeouts = !standalone || one_process.
+ */
+static int child_timeouts;
+
+#ifdef DEBUG_SIGSTOP
+int raise_sigstop_flags;
+#endif
+
+#ifndef NO_OTHER_CHILD
+/* used to maintain list of children which aren't part of the scoreboard */
+typedef struct other_child_rec other_child_rec;
+struct other_child_rec {
+    other_child_rec *next;
+    int pid;
+    void (*maintenance) (int, void *, int);
+    void *data;
+    int write_fd;
+};
+static other_child_rec *other_children;
+#endif
+
+static pool *pconf;		/* Pool for config stuff */
+static pool *ptemp;		/* Pool for temporary config stuff */
+static pool *pcommands;	/* Pool for -C and -c switches */
+
+scoreboard *ap_scoreboard_image = NULL;
+
+static pthread_attr_t child_attr;
+
+/* a clean exit from a child with proper cleanup */
+static void __attribute__((noreturn)) clean_child_exit(int code)
+{
+    if (tls()->pchild) {
+	ap_child_exit_modules(tls()->pchild, server_conf);
+	ap_destroy_pool(tls()->pchild);
+    }
+    pthread_exit((void *)code);
+}
+
+/* Default --- no serialization.  Other methods *could* go here,
+ * as #elifs...
+ */
+/* Multithreaded systems don't complete between processes for
+ * the sockets. */
+#define NO_SERIALIZED_ACCEPT
+#define accept_mutex_child_init(x)
+#define accept_mutex_init(x)
+#define accept_mutex_on()
+#define accept_mutex_off()
+
+/* On some architectures it's safe to do unserialized accept()s in the single
+ * Listen case.  But it's never safe to do it in the case where there's
+ * multiple Listen statements.  Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT
+ * when it's safe in the single Listen case.
+ */
+#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
+#define SAFE_ACCEPT(stmt) do {if(ap_listeners->next != ap_listeners) {stmt;}} while(0)
+#else
+#define SAFE_ACCEPT(stmt) do {stmt;} while(0)
+#endif
+
+static void usage(char *bin)
+{
+    char pad[MAX_STRING_LEN];
+    int i;
+
+    for (i = 0; i < strlen(bin); i++)
+	pad[i] = ' ';
+    pad[i] = '\0';
+#ifdef SHARED_CORE
+    fprintf(stderr, "Usage: %s [-L directory] [-d directory] [-f file]\n", bin);
+#else
+    fprintf(stderr, "Usage: %s [-d directory] [-f file]\n", bin);
+#endif
+    fprintf(stderr, "       %s [-C \"directive\"] [-c \"directive\"]\n", pad);
+    fprintf(stderr, "       %s [-v] [-V] [-h] [-l]\n", pad);
+    fprintf(stderr, "Options:\n");
+#ifdef SHARED_CORE
+    fprintf(stderr, "  -L directory     : specify an alternate location for shared object files\n");
+#endif
+    fprintf(stderr, "  -d directory     : specify an alternate initial ServerRoot\n");
+    fprintf(stderr, "  -f file          : specify an alternate ServerConfigFile\n");
+    fprintf(stderr, "  -C \"directive\"   : process directive before reading config files\n");
+    fprintf(stderr, "  -c \"directive\"   : process directive after  reading config files\n");
+    fprintf(stderr, "  -v               : show version number\n");
+    fprintf(stderr, "  -V               : show compile settings\n");
+    fprintf(stderr, "  -h               : list available configuration directives\n");
+    fprintf(stderr, "  -l               : list compiled-in modules\n");
+    exit(1);
+}
+
+/*****************************************************************
+ *
+ * Timeout handling.  DISTINCTLY not thread-safe, but all this stuff
+ * has to change for threads anyway.  Note that this code allows only
+ * one timeout in progress at a time...
+ */
+
+static void timeout(int sig)
+{				/* Also called on SIGPIPE */
+    void *dirconf;
+
+    signal(SIGPIPE, SIG_IGN);	/* Block SIGPIPE */
+    if (tls()->alarms_blocked) {
+	tls()->alarm_pending = 1;
+	return;
+    }
+    if (tls()->exit_after_unblock) {
+	clean_child_exit(0);
+    }
+
+    if (!tls()->current_conn) {
+	ap_longjmp(tls()->jmpbuffer, 1);
+    }
+
+    if (tls()->timeout_req != NULL)
+	dirconf = tls()->timeout_req->per_dir_config;
+    else
+	dirconf = tls()->current_conn->server->lookup_defaults;
+    if (!tls()->current_conn->keptalive) {
+	if (sig == SIGPIPE) {
+	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO,
+			tls()->current_conn->server,
+			"%s client stopped connection before %s completed",
+			ap_get_remote_host(tls()->current_conn, dirconf, REMOTE_NAME),
+			tls()->timeout_name ? tls()->timeout_name : "request");
+	}
+	else {
+	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO,
+			tls()->current_conn->server,
+			"%s timed out for %s",
+			tls()->timeout_name ? tls()->timeout_name : "request",
+			ap_get_remote_host(tls()->current_conn, dirconf, REMOTE_NAME));
+	}
+    }
+
+    if (tls()->timeout_req) {
+	/* Someone has asked for this transaction to just be aborted
+	 * if it times out...
+	 */
+
+	request_rec *log_req = tls()->timeout_req;
+
+	while (log_req->main || log_req->prev) {
+	    /* Get back to original request... */
+	    if (log_req->main)
+		log_req = log_req->main;
+	    else
+		log_req = log_req->prev;
+	}
+
+	if (!tls()->current_conn->keptalive)
+	    ap_log_transaction(log_req);
+
+	ap_bsetflag(tls()->timeout_req->connection->client, B_EOUT, 1);
+	ap_bclose(tls()->timeout_req->connection->client);
+
+	if (!ap_standalone)
+	    exit(0);
+
+	ap_longjmp(tls()->jmpbuffer, 1);
+    }
+    else {			/* abort the connection */
+	ap_bsetflag(tls()->current_conn->client, B_EOUT, 1);
+	tls()->current_conn->aborted = 1;
+    }
+}
+
+/*
+ * These two called from alloc.c to protect its critical sections...
+ * Note that they can nest (as when destroying the sub_pools of a pool
+ * which is itself being cleared); we have to support that here.
+ */
+
+API_EXPORT(void) ap_block_alarms()
+{
+    ++tls()->alarms_blocked;
+}
+
+API_EXPORT(void) ap_unblock_alarms()
+{
+    --tls()->alarms_blocked;
+    if (tls()->alarms_blocked == 0) {
+	if (tls()->exit_after_unblock) {
+	    /* We have a couple race conditions to deal with here, we can't
+	     * allow a timeout that comes in this small interval to allow
+	     * the child to jump back to the main loop.  Instead we block
+	     * alarms again, and then note that tls()->exit_after_unblock is
+	     * being dealt with.  We choose this way to solve this so that
+	     * the common path through unblock_alarms() is really short.
+	     */
+	    ++tls()->alarms_blocked;
+	    tls()->exit_after_unblock = 0;
+	    clean_child_exit(0);
+	}
+	if (tls()->alarm_pending) {
+	    tls()->alarm_pending = 0;
+	    timeout(0);
+	}
+    }
+}
+
+
+static void alrm_handler(int sig)
+{
+    if (tls()->alarm_fn) {
+	(*tls()->alarm_fn) (sig);
+    }
+}
+
+unsigned int ap_set_callback_and_alarm(void (*fn) (int), int x)
+{
+    unsigned int old;
+
+    if (x) {
+	tls()->alarm_fn = fn;
+    }
+#ifndef OPTIMIZE_TIMEOUTS
+    old = alarm(x);
+#else
+    if (child_timeouts) {
+	old = alarm(x);
+    }
+    else {
+	/* Just note the timeout in our scoreboard, no need to call the system.
+	 * We also note that the virtual time has gone forward.
+	 */
+	old = ap_scoreboard_image->servers[tls()->my_child_num].timeout_len;
+	ap_scoreboard_image->servers[tls()->my_child_num].timeout_len = x;
+	++ap_scoreboard_image->servers[tls()->my_child_num].cur_vtime;
+    }
+#endif
+    return (old);
+}
+
+
+/* reset_timeout (request_rec *) resets the timeout in effect,
+ * as long as it hasn't expired already.
+ */
+
+API_EXPORT(void) ap_reset_timeout(request_rec *r)
+{
+    int i;
+
+    if (tls()->timeout_name) {		/* timeout has been set */
+	i = ap_set_callback_and_alarm(tls()->alarm_fn, r->server->timeout);
+	if (i == 0)		/* timeout already expired, so set it back to 0 */
+	    ap_set_callback_and_alarm(tls()->alarm_fn, 0);
+    }
+}
+
+void ap_keepalive_timeout(char *name, request_rec *r)
+{
+    unsigned int to;
+
+    tls()->timeout_req = r;
+    tls()->timeout_name = name;
+
+    if (r->connection->keptalive)
+	to = r->server->keep_alive_timeout;
+    else
+	to = r->server->timeout;
+    ap_set_callback_and_alarm(timeout, to);
+
+}
+
+API_EXPORT(void) ap_hard_timeout(char *name, request_rec *r)
+{
+    tls()->timeout_req = r;
+    tls()->timeout_name = name;
+
+    ap_set_callback_and_alarm(timeout, r->server->timeout);
+
+}
+
+API_EXPORT(void) ap_soft_timeout(char *name, request_rec *r)
+{
+    tls()->timeout_name = name;
+
+    ap_set_callback_and_alarm(timeout, r->server->timeout);
+
+}
+
+API_EXPORT(void) ap_kill_timeout(request_rec *dummy)
+{
+    ap_set_callback_and_alarm(NULL, 0);
+    tls()->timeout_req = NULL;
+    tls()->timeout_name = NULL;
+}
+
+#ifdef SHARED_TIME
+#undef time
+time_t ap_shared_time(time_t *t)
+{
+    time_t res;
+
+    if (child_timeouts || ap_scoreboard_image == NULL) {
+	return time(0);
+    }
+    res = ap_scoreboard_image->global.right_now;
+    if (t) *t = res;
+    return res;
+}
+#endif
+
+/*
+ * More machine-dependent networking gooo... on some systems,
+ * you've got to be *really* sure that all the packets are acknowledged
+ * before closing the connection, since the client will not be able
+ * to see the last response if their TCP buffer is flushed by a RST
+ * packet from us, which is what the server's TCP stack will send
+ * if it receives any request data after closing the connection.
+ *
+ * In an ideal world, this function would be accomplished by simply
+ * setting the socket option SO_LINGER and handling it within the
+ * server's TCP stack while the process continues on to the next request.
+ * Unfortunately, it seems that most (if not all) operating systems
+ * block the server process on close() when SO_LINGER is used.
+ * For those that don't, see USE_SO_LINGER below.  For the rest,
+ * we have created a home-brew lingering_close.
+ *
+ * Many operating systems tend to block, puke, or otherwise mishandle
+ * calls to shutdown only half of the connection.  You should define
+ * NO_LINGCLOSE in conf.h if such is the case for your system.
+ */
+#ifndef MAX_SECS_TO_LINGER
+#define MAX_SECS_TO_LINGER 30
+#endif
+
+#ifdef USE_SO_LINGER
+#define NO_LINGCLOSE		/* The two lingering options are exclusive */
+
+static void sock_enable_linger(int s)
+{
+    struct linger li;
+
+    li.l_onoff = 1;
+    li.l_linger = MAX_SECS_TO_LINGER;
+
+    if (setsockopt(s, SOL_SOCKET, SO_LINGER,
+		   (char *) &li, sizeof(struct linger)) < 0) {
+	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
+	            "setsockopt: (SO_LINGER)");
+	/* not a fatal error */
+    }
+}
+
+#else
+#define sock_enable_linger(s)	/* NOOP */
+#endif /* USE_SO_LINGER */
+
+#ifndef NO_LINGCLOSE
+
+/* Special version of timeout for lingering_close */
+
+static void lingerout(int sig)
+{
+    if (tls()->alarms_blocked) {
+	tls()->alarm_pending = 1;
+	return;
+    }
+
+    if (!tls()->current_conn) {
+	ap_longjmp(tls()->jmpbuffer, 1);
+    }
+    ap_bsetflag(tls()->current_conn->client, B_EOUT, 1);
+    tls()->current_conn->aborted = 1;
+}
+
+static void linger_timeout(void)
+{
+    tls()->timeout_name = "lingering close";
+
+    ap_set_callback_and_alarm(lingerout, MAX_SECS_TO_LINGER);
+}
+
+/* Since many clients will abort a connection instead of closing it,
+ * attempting to log an error message from this routine will only
+ * confuse the webmaster.  There doesn't seem to be any portable way to
+ * distinguish between a dropped connection and something that might be
+ * worth logging.
+ */
+static void lingering_close(request_rec *r)
+{
+    char dummybuf[2048];
+    struct timeval tv;
+    fd_set lfds, fds_read, fds_err;
+    int select_rv = 0;
+    int lsd;
+
+    /* Prevent a slow-drip client from holding us here indefinitely */
+
+    linger_timeout();
+
+    /* Send any leftover data to the client, but never try to again */
+
+    if (ap_bflush(r->connection->client) == -1) {
+	ap_kill_timeout(r);
+	ap_bclose(r->connection->client);
+	return;
+    }
+    ap_bsetflag(r->connection->client, B_EOUT, 1);
+
+    /* Close our half of the connection --- send the client a FIN */
+
+    lsd = r->connection->client->fd;
+
+    if ((shutdown(lsd, 1) != 0) || r->connection->aborted) {
+	ap_kill_timeout(r);
+	ap_bclose(r->connection->client);
+	return;
+    }
+
+    /* Set up to wait for readable data on socket... */
+
+    FD_ZERO(&lfds);
+    FD_SET(lsd, &lfds);
+
+    /* Wait for readable data or error condition on socket;
+     * slurp up any data that arrives...  We exit when we go for 
+     * an interval of tv length without getting any more data, get an
+     * error from select(), get an exception on lsd, get an error or EOF
+     * on a read, or the timer expires.
+     */
+
+    do {
+	/* We use a 2 second timeout because current (Feb 97) browsers
+	 * fail to close a connection after the server closes it.  Thus,
+	 * to avoid keeping the child busy, we are only lingering long enough
+	 * for a client that is actively sending data on a connection.
+	 * This should be sufficient unless the connection is massively
+	 * losing packets, in which case we might have missed the RST anyway.
+	 * These parameters are reset on each pass, since they might be
+	 * changed by select.
+	 */
+	tv.tv_sec = 2;
+	tv.tv_usec = 0;
+	fds_read = lfds;
+	fds_err = lfds;
+
+	select_rv = ap_select(lsd + 1, &fds_read, NULL, &fds_err, &tv);
+    } while ((select_rv > 0) &&	/* Something to see on socket    */
+	     !FD_ISSET(lsd, &fds_err) &&	/* that isn't an error condition */
+	     FD_ISSET(lsd, &fds_read) &&	/* and is worth trying to read   */
+	     (read(lsd, dummybuf, sizeof dummybuf) > 0));
+
+    /* Should now have seen final ack.  Safe to finally kill socket */
+
+    ap_bclose(r->connection->client);
+
+    ap_kill_timeout(r);
+}
+#endif /* ndef NO_LINGCLOSE */
+
+/*****************************************************************
+ * dealing with other children
+ */
+
+#ifndef NO_OTHER_CHILD
+API_EXPORT(void) ap_register_other_child(int pid,
+		       void (*maintenance) (int reason, void *, int status),
+			  void *data, int write_fd)
+{
+    other_child_rec *ocr;
+
+    ocr = ap_palloc(pconf, sizeof(*ocr));
+    ocr->pid = pid;
+    ocr->maintenance = maintenance;
+    ocr->data = data;
+    ocr->write_fd = write_fd;
+    ocr->next = other_children;
+    other_children = ocr;
+}
+
+/* note that since this can be called by a maintenance function while we're
+ * scanning the other_children list, all scanners should protect themself
+ * by loading ocr->next before calling any maintenance function.
+ */
+API_EXPORT(void) ap_unregister_other_child(void *data)
+{
+    other_child_rec **pocr, *nocr;
+
+    for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) {
+	if ((*pocr)->data == data) {
+	    nocr = (*pocr)->next;
+	    (*(*pocr)->maintenance) (OC_REASON_UNREGISTER, (*pocr)->data, -1);
+	    *pocr = nocr;
+	    /* XXX: um, well we've just wasted some space in pconf ? */
+	    return;
+	}
+    }
+}
+
+/* test to ensure that the write_fds are all still writable, otherwise
+ * invoke the maintenance functions as appropriate */
+static void probe_writable_fds(void)
+{
+    fd_set writable_fds;
+    int fd_max;
+    other_child_rec *ocr, *nocr;
+    struct timeval tv;
+    int rc;
+
+    if (other_children == NULL)
+	return;
+
+    fd_max = 0;
+    FD_ZERO(&writable_fds);
+    for (ocr = other_children; ocr; ocr = ocr->next) {
+	if (ocr->write_fd == -1)
+	    continue;
+	FD_SET(ocr->write_fd, &writable_fds);
+	if (ocr->write_fd > fd_max) {
+	    fd_max = ocr->write_fd;
+	}
+    }
+    if (fd_max == 0)
+	return;
+
+    do {
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	rc = ap_select(fd_max + 1, NULL, &writable_fds, NULL, &tv);
+    } while (rc == -1 && errno == EINTR);
+
+    if (rc == -1) {
+	/* XXX: uhh this could be really bad, we could have a bad file
+	 * descriptor due to a bug in one of the maintenance routines */
+	ap_log_unixerr("probe_writable_fds", "select",
+		    "could not probe writable fds", server_conf);
+	return;
+    }
+    if (rc == 0)
+	return;
+
+    for (ocr = other_children; ocr; ocr = nocr) {
+	nocr = ocr->next;
+	if (ocr->write_fd == -1)
+	    continue;
+	if (FD_ISSET(ocr->write_fd, &writable_fds))
+	    continue;
+	(*ocr->maintenance) (OC_REASON_UNWRITABLE, ocr->data, -1);
+    }
+}
+
+/* possibly reap an other_child, return 0 if yes, -1 if not */
+static int reap_other_child(int pid, int status)
+{
+    other_child_rec *ocr, *nocr;
+
+    for (ocr = other_children; ocr; ocr = nocr) {
+	nocr = ocr->next;
+	if (ocr->pid != pid)
+	    continue;
+	ocr->pid = -1;
+	(*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
+	return 0;
+    }
+    return -1;
+}
+#endif
+
+/*****************************************************************
+ *
+ * Dealing with the scoreboard... a lot of these variables are global
+ * only to avoid getting clobbered by the longjmp() that happens when
+ * a hard timeout expires...
+ *
+ * We begin with routines which deal with the file itself... 
+ */
+
+static void reinit_scoreboard(pool *p)
+{
+    ap_assert(!ap_scoreboard_image);
+    ap_scoreboard_image = (scoreboard *) malloc(SCOREBOARD_SIZE);
+    memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE);
+}
+
+API_EXPORT(void) ap_sync_scoreboard_image()
+{
+}
+
+static void reopen_scoreboard(pool *p)
+{
+}
+
+
+API_EXPORT(int) ap_exists_scoreboard_image(void)
+{
+    return (ap_scoreboard_image ? 1 : 0);
+}
+
+static ap_inline void put_scoreboard_info(int child_num,
+				       short_score *new_score_rec)
+{
+}
+
+/* a clean exit from the parent with proper cleanup */
+static void __attribute__((noreturn)) clean_parent_exit(int code)
+{
+    /* Clear the pool - including any registered cleanups */
+    ap_destroy_pool(pconf);
+    exit(code);
+}
+
+int ap_update_child_status(int child_num, int status, request_rec *r)
+{
+    int old_status;
+    short_score *ss;
+
+    if (child_num < 0)
+	return -1;
+
+    ap_sync_scoreboard_image();
+    ss = &ap_scoreboard_image->servers[child_num];
+    old_status = ss->status;
+    ss->status = status;
+#ifdef OPTIMIZE_TIMEOUTS
+    ++ss->cur_vtime;
+#endif
+
+#if defined(STATUS)
+#ifndef OPTIMIZE_TIMEOUTS
+    ss->last_used = time(NULL);
+#endif
+    if (status == SERVER_READY || status == SERVER_DEAD) {
+	/*
+	 * Reset individual counters
+	 */
+	if (status == SERVER_DEAD) {
+	    ss->my_access_count = 0L;
+	    ss->my_bytes_served = 0L;
+	}
+	ss->conn_count = (unsigned short) 0;
+	ss->conn_bytes = (unsigned long) 0;
+    }
+    if (r) {
+	conn_rec *c = r->connection;
+	ap_cpystrn(ss->client, ap_get_remote_host(c, r->per_dir_config,
+			      REMOTE_NOLOOKUP), sizeof(ss->client));
+	ap_cpystrn(ss->request, (r->the_request ? r->the_request :
+			      "NULL"), sizeof(ss->request));
+	ap_cpystrn(ss->vhost, r->server->server_hostname, sizeof(ss->vhost));
+    }
+#endif
+
+    put_scoreboard_info(child_num, ss);
+
+    return old_status;
+}
+
+static void update_scoreboard_global(void)
+{
+}
+
+#if defined(STATUS)
+void ap_time_process_request(int child_num, int status)
+{
+    short_score *ss;
+#if defined(NO_GETTIMEOFDAY) && !defined(NO_TIMES)
+    struct tms tms_blk;
+#endif
+
+    if (child_num < 0)
+	return;
+
+    ap_sync_scoreboard_image();
+    ss = &ap_scoreboard_image->servers[child_num];
+
+    if (status == START_PREQUEST) {
+#if defined(NO_GETTIMEOFDAY)
+#ifndef NO_TIMES
+	if ((ss->start_time = times(&tms_blk)) == -1)
+#endif /* NO_TIMES */
+	    ss->start_time = (clock_t) 0;
+#else
+	if (gettimeofday(&ss->start_time, (struct timezone *) 0) < 0)
+	    ss->start_time.tv_sec =
+		ss->start_time.tv_usec = 0L;
+#endif
+    }
+    else if (status == STOP_PREQUEST) {
+#if defined(NO_GETTIMEOFDAY)
+#ifndef NO_TIMES
+	if ((ss->stop_time = times(&tms_blk)) == -1)
+#endif
+	    ss->stop_time = ss->start_time = (clock_t) 0;
+#else
+	if (gettimeofday(&ss->stop_time, (struct timezone *) 0) < 0)
+	    ss->stop_time.tv_sec =
+		ss->stop_time.tv_usec =
+		ss->start_time.tv_sec =
+		ss->start_time.tv_usec = 0L;
+#endif
+
+    }
+
+    put_scoreboard_info(child_num, ss);
+}
+
+static void increment_counts(int child_num, request_rec *r)
+{
+    long int bs = 0;
+    short_score *ss;
+
+    ap_sync_scoreboard_image();
+    ss = &ap_scoreboard_image->servers[child_num];
+
+    if (r->sent_bodyct)
+	ap_bgetopt(r->connection->client, BO_BYTECT, &bs);
+
+#ifndef NO_TIMES
+    times(&ss->times);
+#endif
+    ss->access_count++;
+    ss->my_access_count++;
+    ss->conn_count++;
+    ss->bytes_served += (unsigned long) bs;
+    ss->my_bytes_served += (unsigned long) bs;
+    ss->conn_bytes += (unsigned long) bs;
+
+    put_scoreboard_info(child_num, ss);
+}
+
+#endif
+
+
+static int find_child_by_pid(int pid)
+{
+    int i;
+
+    for (i = 0; i < max_daemons_limit; ++i)
+	if (ap_scoreboard_image->parent[i].pid == pid)
+	    return i;
+
+    return -1;
+}
+
+static void reclaim_child_processes(int terminate)
+{
+#ifndef MULTITHREAD
+    int i, status;
+    long int waittime = 1024 * 16;	/* in usecs */
+    struct timeval tv;
+    int waitret, tries;
+    int not_dead_yet;
+#ifndef NO_OTHER_CHILD
+    other_child_rec *ocr, *nocr;
+#endif
+
+    ap_sync_scoreboard_image();
+
+    for (tries = terminate ? 4 : 1; tries <= 9; ++tries) {
+	/* don't want to hold up progress any more than 
+	 * necessary, but we need to allow children a few moments to exit.
+	 * Set delay with an exponential backoff.
+	 */
+	tv.tv_sec = waittime / 1000000;
+	tv.tv_usec = waittime % 1000000;
+	waittime = waittime * 4;
+	ap_select(0, NULL, NULL, NULL, &tv);
+
+	/* now see who is done */
+	not_dead_yet = 0;
+	for (i = 0; i < max_daemons_limit; ++i) {
+	    int pid = ap_scoreboard_image->parent[i].pid;
+
+	    if (pid == tls()->my_pid || pid == 0)
+		continue;
+
+	    waitret = waitpid(pid, &status, WNOHANG);
+	    if (waitret == pid || waitret == -1) {
+		ap_scoreboard_image->parent[i].pid = 0;
+		continue;
+	    }
+	    ++not_dead_yet;
+	    switch (tries) {
+	    case 1:     /*  16ms */
+	    case 2:     /*  82ms */
+		break;
+	    case 3:     /* 344ms */
+		/* perhaps it missed the SIGHUP, lets try again */
+		ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
+			    server_conf,
+		    "child process %d did not exit, sending another SIGHUP",
+			    pid);
+		kill(pid, SIGHUP);
+		waittime = 1024 * 16;
+		break;
+	    case 4:     /*  16ms */
+	    case 5:     /*  82ms */
+	    case 6:     /* 344ms */
+		break;
+	    case 7:     /* 1.4sec */
+		/* ok, now it's being annoying */
+		ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
+			    server_conf,
+		   "child process %d still did not exit, sending a SIGTERM",
+			    pid);
+		kill(pid, SIGTERM);
+		break;
+	    case 8:     /*  6 sec */
+		/* die child scum */
+		ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
+		   "child process %d still did not exit, sending a SIGKILL",
+			    pid);
+		kill(pid, SIGKILL);
+		break;
+	    case 9:     /* 14 sec */
+		/* gave it our best shot, but alas...  If this really 
+		 * is a child we are trying to kill and it really hasn't
+		 * exited, we will likely fail to bind to the port
+		 * after the restart.
+		 */
+		ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
+			    "could not make child process %d exit, "
+			    "attempting to continue anyway", pid);
+		break;
+	    }
+	}
+#ifndef NO_OTHER_CHILD
+	for (ocr = other_children; ocr; ocr = nocr) {
+	    nocr = ocr->next;
+	    if (ocr->pid == -1)
+		continue;
+
+	    waitret = waitpid(ocr->pid, &status, WNOHANG);
+	    if (waitret == ocr->pid) {
+		ocr->pid = -1;
+		(*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status);
+	    }
+	    else if (waitret == 0) {
+		(*ocr->maintenance) (OC_REASON_RESTART, ocr->data, -1);
+		++not_dead_yet;
+	    }
+	    else if (waitret == -1) {
+		/* uh what the heck? they didn't call unregister? */
+		ocr->pid = -1;
+		(*ocr->maintenance) (OC_REASON_LOST, ocr->data, -1);
+	    }
+	}
+#endif
+	if (!not_dead_yet) {
+	    /* nothing left to wait for */
+	    break;
+	}
+    }
+#endif /* ndef MULTITHREAD */
+}
+
+
+#if defined(BROKEN_WAIT) || defined(NEED_WAITPID)
+/*
+   Some systems appear to fail to deliver dead children to wait() at times.
+   This sorts them out. In fact, this may have been caused by a race condition
+   in wait_or_timeout(). But this routine is still useful for systems with no
+   waitpid().
+ */
+int reap_children(void)
+{
+    int status, n;
+    int ret = 0;
+
+    for (n = 0; n < max_daemons_limit; ++n) {
+	if (ap_scoreboard_image->servers[n].status != SERVER_DEAD
+	    && waitpid(ap_scoreboard_image->parent[n].pid, &status, WNOHANG)
+	    == -1
+	    && errno == ECHILD) {
+	    ap_sync_scoreboard_image();
+	    ap_update_child_status(n, SERVER_DEAD, NULL);
+	    ret = 1;
+	}
+    }
+    return ret;
+}
+#endif
+
+/* Finally, this routine is used by the caretaker process to wait for
+ * a while...
+ */
+
+/* number of calls to wait_or_timeout between writable probes */
+#ifndef INTERVAL_OF_WRITABLE_PROBES
+#define INTERVAL_OF_WRITABLE_PROBES 10
+#endif
+static int wait_or_timeout_counter;
+
+static int wait_or_timeout(int *status)
+{
+    struct timeval tv;
+    int ret;
+
+    ++wait_or_timeout_counter;
+    if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
+	wait_or_timeout_counter = 0;
+#ifndef NO_OTHER_CHILD
+	probe_writable_fds();
+#endif
+    }
+    ret = waitpid(-1, status, WNOHANG);
+    if (ret == -1 && errno == EINTR) {
+	return -1;
+    }
+    if (ret > 0) {
+	return ret;
+    }
+    tv.tv_sec = SCOREBOARD_MAINTENANCE_INTERVAL / 1000000;
+    tv.tv_usec = SCOREBOARD_MAINTENANCE_INTERVAL % 1000000;
+    ap_select(0, NULL, NULL, NULL, &tv);
+    return -1;
+}
+
+
+/* handle all varieties of core dumping signals */
+static void sig_coredump(int sig)
+{
+    char emsg[256];
+    const char *s;
+
+    /* Must protect against a nested signal, otherwise we could end up in
+     * an infinite loop.
+     */
+    signal(SIGSEGV, SIG_DFL);
+#ifdef SIGBUS
+    signal(SIGBUS, SIG_DFL);
+#endif
+#ifdef SIGABORT
+    signal(SIGABORT, SIG_DFL);
+#endif
+#ifdef SIGABRT
+    signal(SIGABRT, SIG_DFL);
+#endif
+
+    s = "SIGSEGV";
+#ifdef SIGBUS
+    if (sig == SIGBUS) {
+	s = "SIGBUS";
+    }
+#endif
+#ifdef SIGABORT
+    if (sig == SIGABORT) {
+	s = "SIGABORT";
+    }
+#endif
+#ifdef SIGABRT
+    if (sig == SIGABRT) {
+	s = "SIGABRT";
+    }
+#endif
+
+    ap_snprintf(emsg, sizeof(emsg),
+		"httpd: caught %s, attempting to dump core in %s",
+		s, ap_coredump_dir);
+    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf, emsg);
+    chdir(ap_coredump_dir);
+    abort();
+    exit(1);
+}
+
+/*****************************************************************
+ * Connection structures and accounting...
+ */
+
+static void just_die(int sig)
+{				/* SIGHUP to child process??? */
+    /* if alarms are blocked we have to wait to die otherwise we might
+     * end up with corruption in alloc.c's internal structures */
+    if (tls()->alarms_blocked) {
+	tls()->exit_after_unblock = 1;
+    }
+    else {
+	clean_child_exit(0);
+    }
+}
+
+#ifndef NO_GRACEFUL
+static void usr1_handler(int sig)
+{
+    if (tls()->usr1_just_die) {
+	just_die(sig);
+    }
+    tls()->deferred_die = 1;
+}
+#endif
+
+/* volatile just in case */
+static int volatile shutdown_pending;
+static int volatile restart_pending;
+static int volatile is_graceful;
+static int volatile generation;
+
+
+/*
+ * start_shutdown() and start_restart(), below, are a first stab at
+ * functions to initiate shutdown or restart without relying on signals. 
+ * Previously this was initiated in sig_term() and restart() signal handlers, 
+ * but we want to be able to start a shutdown/restart from other sources --
+ * e.g. on Win32, from the service manager. Now the service manager can
+ * call start_shutdown() or start_restart() as appropiate. 
+ *
+ * These should only be called from the parent process itself, since the
+ * parent process will use the shutdown_pending and restart_pending variables
+ * to determine whether to shutdown or restart. The child process should
+ * call signal_parent() directly to tell the parent to die -- this will
+ * cause neither of those variable to be set, which the parent will
+ * assume means something serious is wrong (which it will be, for the
+ * child to force an exit) and so do an exit anyway.
+ */
+
+void ap_start_shutdown(void)
+{
+    if (shutdown_pending == 1) {
+	/* Um, is this _probably_ not an error, if the user has
+	 * tried to do a shutdown twice quickly, so we won't
+	 * worry about reporting it.
+	 */
+	return;
+    }
+    shutdown_pending = 1;
+}
+
+/* do a graceful restart if graceful == 1 */
+void ap_start_restart(int graceful)
+{
+    if (restart_pending == 1) {
+	/* Probably not an error - don't bother reporting it */
+	return;
+    }
+    restart_pending = 1;
+    is_graceful = graceful;
+}
+
+static void sig_term(int sig)
+{
+    ap_start_shutdown();
+}
+
+static void restart(int sig)
+{
+    ap_start_restart(sig == SIGUSR1);
+}
+
+static void set_signals(void)
+{
+#ifndef NO_USE_SIGACTION
+    struct sigaction sa;
+
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+
+    if (!one_process) {
+	sa.sa_handler = sig_coredump;
+#if defined(SA_ONESHOT)
+	sa.sa_flags = SA_ONESHOT;
+#elif defined(SA_RESETHAND)
+	sa.sa_flags = SA_RESETHAND;
+#endif
+	if (sigaction(SIGSEGV, &sa, NULL) < 0)
+	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGSEGV)");
+#ifdef SIGBUS
+	if (sigaction(SIGBUS, &sa, NULL) < 0)
+	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGBUS)");
+#endif
+#ifdef SIGABORT
+	if (sigaction(SIGABORT, &sa, NULL) < 0)
+	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGABORT)");
+#endif
+#ifdef SIGABRT
+	if (sigaction(SIGABRT, &sa, NULL) < 0)
+	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGABRT)");
+#endif
+	sa.sa_flags = 0;
+    }
+    sa.sa_handler = sig_term;
+    if (sigaction(SIGTERM, &sa, NULL) < 0)
+	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGTERM)");
+#ifdef SIGINT
+    if (sigaction(SIGINT, &sa, NULL) < 0)
+        ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGINT)");
+#endif
+#ifdef SIGXCPU
+    sa.sa_handler = SIG_DFL;
+    if (sigaction(SIGXCPU, &sa, NULL) < 0)
+	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXCPU)");
+#endif
+#ifdef SIGXFSZ
+    sa.sa_handler = SIG_DFL;
+    if (sigaction(SIGXFSZ, &sa, NULL) < 0)
+	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXFSZ)");
+#endif
+
+    /* we want to ignore HUPs and USR1 while we're busy processing one */
+    sigaddset(&sa.sa_mask, SIGHUP);
+    sigaddset(&sa.sa_mask, SIGUSR1);
+    sa.sa_handler = restart;
+    if (sigaction(SIGHUP, &sa, NULL) < 0)
+	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGHUP)");
+    if (sigaction(SIGUSR1, &sa, NULL) < 0)
+	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGUSR1)");
+#else
+    if (!one_process) {
+	signal(SIGSEGV, sig_coredump);
+#ifdef SIGBUS
+	signal(SIGBUS, sig_coredump);
+#endif /* SIGBUS */
+#ifdef SIGABORT
+	signal(SIGABORT, sig_coredump);
+#endif /* SIGABORT */
+#ifdef SIGABRT
+	signal(SIGABRT, sig_coredump);
+#endif /* SIGABRT */
+#ifdef SIGXCPU
+	signal(SIGXCPU, SIG_DFL);
+#endif /* SIGXCPU */
+#ifdef SIGXFSZ
+	signal(SIGXFSZ, SIG_DFL);
+#endif /* SIGXFSZ */
+    }
+
+    signal(SIGTERM, sig_term);
+#ifdef SIGHUP
+    signal(SIGHUP, restart);
+#endif /* SIGHUP */
+#ifdef SIGUSR1
+    signal(SIGUSR1, restart);
+#endif /* SIGUSR1 */
+#endif
+}
+
+
+/*****************************************************************
+ * Here follows a long bunch of generic server bookkeeping stuff...
+ */
+
+static void detach(void)
+{
+    int x;
+
+    chdir("/");
+#if !defined(MPE) && !defined(__EMX__)
+/* Don't detach for MPE because child processes can't survive the death of
+   the parent. */
+    if ((x = fork()) > 0)
+	exit(0);
+    else if (x == -1) {
+	perror("fork");
+	fprintf(stderr, "httpd: unable to fork new process\n");
+	exit(1);
+    }
+    RAISE_SIGSTOP(DETACH);
+#endif
+#ifndef NO_SETSID
+    if ((pgrp = setsid()) == -1) {
+	perror("setsid");
+	fprintf(stderr, "httpd: setsid failed\n");
+	exit(1);
+    }
+#elif defined(NEXT) || defined(NEWSOS)
+    if (setpgrp(0, getpid()) == -1 || (pgrp = getpgrp(0)) == -1) {
+	perror("setpgrp");
+	fprintf(stderr, "httpd: setpgrp or getpgrp failed\n");
+	exit(1);
+    }
+#elif defined(__EMX__)
+    /* OS/2 don't support process group IDs */
+    pgrp = getpid();
+#elif defined(MPE)
+    /* MPE uses negative pid for process group */
+    pgrp = -getpid();
+#else
+    if ((pgrp = setpgrp(getpid(), 0)) == -1) {
+	perror("setpgrp");
+	fprintf(stderr, "httpd: setpgrp failed\n");
+	exit(1);
+    }
+#endif
+
+    /* close out the standard file descriptors */
+    if (freopen("/dev/null", "r", stdin) == NULL) {
+	fprintf(stderr, "httpd: unable to replace stdin with /dev/null: %s\n",
+		strerror(errno));
+	/* continue anyhow -- note we can't close out descriptor 0 because we
+	 * have nothing to replace it with, and if we didn't have a descriptor
+	 * 0 the next file would be created with that value ... leading to
+	 * havoc.
+	 */
+    }
+    if (freopen("/dev/null", "w", stdout) == NULL) {
+	fprintf(stderr, "httpd: unable to replace stdout with /dev/null: %s\n",
+		strerror(errno));
+    }
+    /* stderr is a tricky one, we really want it to be the error_log,
+     * but we haven't opened that yet.  So leave it alone for now and it'll
+     * be reopened moments later.
+     */
+}
+
+/* Set group privileges.
+ *
+ * Note that we use the username as set in the config files, rather than
+ * the lookup of to uid --- the same uid may have multiple passwd entries,
+ * with different sets of groups for each.
+ */
+
+static void set_group_privs(void)
+{
+    if (!geteuid()) {
+	char *name;
+
+	/* Get username if passed as a uid */
+
+	if (ap_user_name[0] == '#') {
+	    struct passwd *ent;
+	    uid_t uid = atoi(&ap_user_name[1]);
+
+	    if ((ent = getpwuid(uid)) == NULL) {
+		ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+			 "getpwuid: couldn't determine user name from uid %u, "
+			 "you probably need to modify the User directive",
+			 (unsigned)uid);
+		exit(1);
+	    }
+
+	    name = ent->pw_name;
+	}
+	else
+	    name = ap_user_name;
+
+#ifndef __EMX__
+	/* OS/2 dosen't support groups. */
+
+	/* Reset `groups' attributes. */
+
+	if (initgroups(name, ap_group_id) == -1) {
+	    ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+			"initgroups: unable to set groups for User %s "
+			"and Group %u", name, (unsigned)ap_group_id);
+	    exit(1);
+	}
+#ifdef MULTIPLE_GROUPS
+	if (getgroups(NGROUPS_MAX, group_id_list) == -1) {
+	    ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+			"getgroups: unable to get group list");
+	    exit(1);
+	}
+#endif
+	if (setgid(ap_group_id) == -1) {
+	    ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+			"setgid: unable to set group id to Group %u",
+			(unsigned)ap_group_id);
+	    exit(1);
+	}
+#endif
+    }
+}
+
+/* check to see if we have the 'suexec' setuid wrapper installed */
+static int init_suexec(void)
+{
+    struct stat wrapper;
+
+    if ((stat(SUEXEC_BIN, &wrapper)) != 0)
+	return (ap_suexec_enabled);
+
+    if ((wrapper.st_mode & S_ISUID) && wrapper.st_uid == 0) {
+	ap_suexec_enabled = 1;
+	fprintf(stderr, "Configuring Apache for use with suexec wrapper.\n");
+    }
+    return (ap_suexec_enabled);
+}
+
+/*****************************************************************
+ * Connection structures and accounting...
+ */
+
+
+static conn_rec *new_connection(pool *p, server_rec *server, BUFF *inout,
+			     const struct sockaddr_in *remaddr,
+			     const struct sockaddr_in *saddr,
+			     int child_num)
+{
+    conn_rec *conn = (conn_rec *) ap_pcalloc(p, sizeof(conn_rec));
+
+    /* Got a connection structure, so initialize what fields we can
+     * (the rest are zeroed out by pcalloc).
+     */
+
+    conn->child_num = child_num;
+
+    conn->pool = p;
+    conn->local_addr = *saddr;
+    conn->server = server; /* just a guess for now */
+    ap_update_vhost_given_ip(conn);
+    conn->base_server = conn->server;
+    conn->client = inout;
+
+    conn->remote_addr = *remaddr;
+    conn->remote_ip = ap_pstrdup(conn->pool,
+			      inet_ntoa(conn->remote_addr.sin_addr));
+
+    return conn;
+}
+
+#if defined(TCP_NODELAY) && !defined(MPE)
+static void sock_disable_nagle(int s)
+{
+    /* The Nagle algorithm says that we should delay sending partial
+     * packets in hopes of getting more data.  We don't want to do
+     * this; we are not telnet.  There are bad interactions between
+     * persistent connections and Nagle's algorithm that have very severe
+     * performance penalties.  (Failing to disable Nagle is not much of a
+     * problem with simple HTTP.)
+     *
+     * In spite of these problems, failure here is not a shooting offense.
+     */
+    int just_say_no = 1;
+
+    if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &just_say_no,
+		   sizeof(int)) < 0) {
+	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
+		    "setsockopt: (TCP_NODELAY)");
+    }
+}
+
+#else
+#define sock_disable_nagle(s)	/* NOOP */
+#endif
+
+
+static int make_sock(pool *p, const struct sockaddr_in *server)
+{
+    int s;
+    int one = 1;
+    char addr[512];
+
+    if (server->sin_addr.s_addr != htonl(INADDR_ANY))
+	ap_snprintf(addr, sizeof(addr), "address %s port %d",
+		inet_ntoa(server->sin_addr), ntohs(server->sin_port));
+    else
+	ap_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port));
+
+    /* note that because we're about to slack we don't use psocket */
+    ap_block_alarms();
+    if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+	ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
+		    "make_sock: failed to get a socket for %s", addr);
+	ap_unblock_alarms();
+	exit(1);
+    }
+
+    /* Solaris (probably versions 2.4, 2.5, and 2.5.1 with various levels
+     * of tcp patches) has some really weird bugs where if you dup the
+     * socket now it breaks things across SIGHUP restarts.  It'll either
+     * be unable to bind, or it won't respond.
+     */
+#if defined (SOLARIS2) && SOLARIS2 < 260
+#define WORKAROUND_SOLARIS_BUG
+#endif
+
+    /* PR#1282 Unixware 1.x appears to have the same problem as solaris */
+#if defined (UW) && UW < 200
+#define WORKAROUND_SOLARIS_BUG
+#endif
+
+#ifndef WORKAROUND_SOLARIS_BUG
+    s = ap_slack(s, AP_SLACK_HIGH);
+
+    ap_note_cleanups_for_socket(p, s);	/* arrange to close on exec or restart */
+#endif
+
+#ifndef MPE
+/* MPE does not support SO_REUSEADDR and SO_KEEPALIVE */
+#ifndef _OSD_POSIX
+    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int)) < 0) {
+	ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
+		    "make_sock: for %s, setsockopt: (SO_REUSEADDR)", addr);
+	close(s);
+	ap_unblock_alarms();
+	return -1;
+    }
+#endif /*_OSD_POSIX*/
+    one = 1;
+#ifndef BEOS
+/* BeOS does not support SO_KEEPALIVE */
+    if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(int)) < 0) {
+	ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
+		    "make_sock: for %s, setsockopt: (SO_KEEPALIVE)", addr);
+	close(s);
+	ap_unblock_alarms();
+	return -1;
+    }
+#endif
+#endif
+
+    sock_disable_nagle(s);
+    sock_enable_linger(s);
+
+    /*
+     * To send data over high bandwidth-delay connections at full
+     * speed we must force the TCP window to open wide enough to keep the
+     * pipe full.  The default window size on many systems
+     * is only 4kB.  Cross-country WAN connections of 100ms
+     * at 1Mb/s are not impossible for well connected sites.
+     * If we assume 100ms cross-country latency,
+     * a 4kB buffer limits throughput to 40kB/s.
+     *
+     * To avoid this problem I've added the SendBufferSize directive
+     * to allow the web master to configure send buffer size.
+     *
+     * The trade-off of larger buffers is that more kernel memory
+     * is consumed.  YMMV, know your customers and your network!
+     *
+     * -John Heidemann <johnh@isi.edu> 25-Oct-96
+     *
+     * If no size is specified, use the kernel default.
+     */
+#ifndef BEOS			/* BeOS does not support SO_SNDBUF */
+    if (server_conf->send_buffer_size) {
+	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
+		(char *) &server_conf->send_buffer_size, sizeof(int)) < 0) {
+	    ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
+			"make_sock: failed to set SendBufferSize for %s, "
+			"using default", addr);
+	    /* not a fatal error */
+	}
+    }
+#endif
+
+#ifdef MPE
+/* MPE requires CAP=PM and GETPRIVMODE to bind to ports less than 1024 */
+    if (ntohs(server->sin_port) < 1024)
+	GETPRIVMODE();
+#endif
+    if (bind(s, (struct sockaddr *) server, sizeof(struct sockaddr_in)) == -1) {
+	ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf,
+	    "make_sock: could not bind to %s", addr);
+#ifdef MPE
+	if (ntohs(server->sin_port) < 1024)
+	    GETUSERMODE();
+#endif
+	close(s);
+	ap_unblock_alarms();
+	exit(1);
+    }
+#ifdef MPE
+    if (ntohs(server->sin_port) < 1024)
+	GETUSERMODE();
+#endif
+
+    if (listen(s, ap_listenbacklog) == -1) {
+	ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
+	    "make_sock: unable to listen for connections on %s", addr);
+	close(s);
+	ap_unblock_alarms();
+	exit(1);
+    }
+
+#ifdef WORKAROUND_SOLARIS_BUG
+    s = ap_slack(s, AP_SLACK_HIGH);
+
+    ap_note_cleanups_for_socket(p, s);	/* arrange to close on exec or restart */
+#endif
+    ap_unblock_alarms();
+
+    /* protect various fd_sets */
+    if (s >= FD_SETSIZE) {
+	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
+	    "make_sock: problem listening on %s, filedescriptor (%u) "
+	    "larger than FD_SETSIZE (%u) "
+	    "found, you probably need to rebuild Apache with a "
+	    "larger FD_SETSIZE", addr, s, FD_SETSIZE);
+	close(s);
+	return -1;
+    }
+
+    return s;
+}
+
+
+/*
+ * During a restart we keep track of the old listeners here, so that we
+ * can re-use the sockets.  We have to do this because we won't be able
+ * to re-open the sockets ("Address already in use").
+ *
+ * Unlike the listeners ring, old_listeners is a NULL terminated list.
+ *
+ * copy_listeners() makes the copy, find_listener() finds an old listener
+ * and close_unused_listener() cleans up whatever wasn't used.
+ */
+static listen_rec *old_listeners;
+
+/* unfortunately copy_listeners may be called before listeners is a ring */
+static void copy_listeners(pool *p)
+{
+    listen_rec *lr;
+
+    ap_assert(old_listeners == NULL);
+    if (ap_listeners == NULL) {
+	return;
+    }
+    lr = ap_listeners;
+    do {
+	listen_rec *nr = malloc(sizeof *nr);
+	if (nr == NULL) {
+	    fprintf(stderr, "Ouch!  malloc failed in copy_listeners()\n");
+	    exit(1);
+	}
+	*nr = *lr;
+	ap_kill_cleanups_for_socket(p, nr->fd);
+	nr->next = old_listeners;
+	ap_assert(!nr->used);
+	old_listeners = nr;
+	lr = lr->next;
+    } while (lr && lr != ap_listeners);
+}
+
+
+static int find_listener(listen_rec *lr)
+{
+    listen_rec *or;
+
+    for (or = old_listeners; or; or = or->next) {
+	if (!memcmp(&or->local_addr, &lr->local_addr, sizeof(or->local_addr))) {
+	    or->used = 1;
+	    return or->fd;
+	}
+    }
+    return -1;
+}
+
+
+static void close_unused_listeners(void)
+{
+    listen_rec *or, *next;
+
+    for (or = old_listeners; or; or = next) {
+	next = or->next;
+	if (!or->used)
+	    closesocket(or->fd);
+	free(or);
+    }
+    old_listeners = NULL;
+}
+
+
+/* open sockets, and turn the listeners list into a singly linked ring */
+static void setup_listeners(pool *p)
+{
+    listen_rec *lr;
+    int fd;
+
+    listenmaxfd = -1;
+    FD_ZERO(&listenfds);
+    lr = ap_listeners;
+    for (;;) {
+	fd = find_listener(lr);
+	if (fd < 0) {
+	    fd = make_sock(p, &lr->local_addr);
+	}
+	else {
+	    ap_note_cleanups_for_socket(p, fd);
+	}
+	if (fd >= 0) {
+	    FD_SET(fd, &listenfds);
+	    if (fd > listenmaxfd)
+		listenmaxfd = fd;
+	}
+	lr->fd = fd;
+	if (lr->next == NULL)
+	    break;
+	lr = lr->next;
+    }
+    /* turn the list into a ring */
+    lr->next = ap_listeners;
+    tls()->head_listener = ap_listeners;
+    close_unused_listeners();
+
+#ifdef NO_SERIALIZED_ACCEPT
+    /* warn them about the starvation problem if they're using multiple
+     * sockets
+     */
+    if (ap_listeners->next != ap_listeners) {
+	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_CRIT, NULL,
+		    "You cannot use multiple Listens safely on your system, "
+		    "proceeding anyway.  See src/PORTING, search for "
+		    "SERIALIZED_ACCEPT.");
+    }
+#endif
+}
+
+
+/*
+ * Find a listener which is ready for accept().  This advances the
+ * tls()->head_listener global.
+ */
+static ap_inline listen_rec *find_ready_listener(fd_set * main_fds)
+{
+    listen_rec *lr;
+
+    lr = tls()->head_listener;
+    do {
+	if (FD_ISSET(lr->fd, main_fds)) {
+	    tls()->head_listener = lr->next;
+	    return (lr);
+	}
+	lr = lr->next;
+    } while (lr != tls()->head_listener);
+    return NULL;
+}
+
+
+static void show_compile_settings(void)
+{
+#ifdef SERVER_SUBVERSION
+    printf("Server base version: %s\n", SERVER_BASEVERSION);
+    printf("Server sub-version:  %s\n", SERVER_SUBVERSION);
+    printf("Server built:        %s\n", ap_get_server_built());
+#else
+    printf("Server version: %s\n", ap_get_server_version());
+    printf("Server built:   %s\n", ap_get_server_built());
+#endif
+    printf("Server's Module Magic Number: %u\n", MODULE_MAGIC_NUMBER);
+    printf("Server compiled with....\n");
+#ifdef BIG_SECURITY_HOLE
+    printf(" -D BIG_SECURITY_HOLE\n");
+#endif
+#ifdef SECURITY_HOLE_PASS_AUTHORIZATION
+    printf(" -D SECURITY_HOLE_PASS_AUTHORIZATION\n");
+#endif
+#ifdef HTTPD_ROOT
+    printf(" -D HTTPD_ROOT=\"" HTTPD_ROOT "\"\n");
+#endif
+#ifdef HAVE_MMAP
+    printf(" -D HAVE_MMAP\n");
+#endif
+#ifdef HAVE_SHMGET
+    printf(" -D HAVE_SHMGET\n");
+#endif
+#ifdef USE_MMAP_SCOREBOARD
+    printf(" -D USE_MMAP_SCOREBOARD\n");
+#endif
+#ifdef USE_SHMGET_SCOREBOARD
+    printf(" -D USE_SHMGET_SCOREBOARD\n");
+#endif
+#ifdef USE_OS2_SCOREBOARD
+    printf(" -D USE_OS2_SCOREBOARD\n");
+#endif
+#ifdef USE_POSIX_SCOREBOARD
+    printf(" -D USE_POSIX_SCOREBOARD\n");
+#endif
+#ifdef USE_MMAP_FILES
+    printf(" -D USE_MMAP_FILES\n");
+#ifdef MMAP_SEGMENT_SIZE
+	printf(" -D MMAP_SEGMENT_SIZE=%ld\n",(long)MMAP_SEGMENT_SIZE);
+#endif
+#endif /*USE_MMAP_FILES*/
+#ifdef NO_WRITEV
+    printf(" -D NO_WRITEV\n");
+#endif
+#ifdef NO_LINGCLOSE
+    printf(" -D NO_LINGCLOSE\n");
+#endif
+#ifdef USE_FCNTL_SERIALIZED_ACCEPT
+    printf(" -D USE_FCNTL_SERIALIZED_ACCEPT\n");
+#endif
+#ifdef USE_FLOCK_SERIALIZED_ACCEPT
+    printf(" -D USE_FLOCK_SERIALIZED_ACCEPT\n");
+#endif
+#ifdef USE_USLOCK_SERIALIZED_ACCEPT
+    printf(" -D USE_USLOCK_SERIALIZED_ACCEPT\n");
+#endif
+#ifdef USE_SYSVSEM_SERIALIZED_ACCEPT
+    printf(" -D USE_SYSVSEM_SERIALIZED_ACCEPT\n");
+#endif
+#ifdef USE_PTHREAD_SERIALIZED_ACCEPT
+    printf(" -D USE_PTHREAD_SERIALIZED_ACCEPT\n");
+#endif
+#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
+    printf(" -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT\n");
+#endif
+#ifdef NO_OTHER_CHILD
+    printf(" -D NO_OTHER_CHILD\n");
+#endif
+#ifdef NO_RELIABLE_PIPED_LOGS
+    printf(" -D NO_RELIABLE_PIPED_LOGS\n");
+#endif
+#ifdef BUFFERED_LOGS
+    printf(" -D BUFFERED_LOGS\n");
+#ifdef PIPE_BUF
+	printf(" -D PIPE_BUF=%ld\n",(long)PIPE_BUF);
+#endif
+#endif
+#ifdef MULTITHREAD
+    printf(" -D MULTITHREAD\n");
+#endif
+#ifdef CHARSET_EBCDIC
+    printf(" -D CHARSET_EBCDIC\n");
+#endif
+#ifdef NEED_HASHBANG_EMUL
+    printf(" -D NEED_HASHBANG_EMUL\n");
+#endif
+#ifdef SHARED_CORE
+    printf(" -D SHARED_CORE\n");
+#endif
+}
+
+
+/* Some init code that's common between win32 and unix... well actually
+ * some of it is #ifdef'd but was duplicated before anyhow.  This stuff
+ * is still a mess.
+ */
+static void common_init(void)
+{
+#ifdef AUX3
+    (void) set42sig();
+#endif
+
+#ifdef SecureWare
+    if (set_auth_parameters(argc, argv) < 0)
+	perror("set_auth_parameters");
+    if (getluid() < 0)
+	if (setluid(getuid()) < 0)
+	    perror("setluid");
+    if (setreuid(0, 0) < 0)
+	perror("setreuid");
+#endif
+
+    pconf = ap_init_alloc();
+    ptemp = ap_make_sub_pool(pconf);
+
+    ap_util_init();
+    ap_util_uri_init();
+
+    pcommands = ap_make_sub_pool(NULL);
+    ap_server_pre_read_config  = ap_make_array(pcommands, 1, sizeof(char *));
+    ap_server_post_read_config = ap_make_array(pcommands, 1, sizeof(char *));
+}
+
+/*****************************************************************
+ * Child process main loop.
+ */
+
+
+API_EXPORT(void) ap_child_terminate(request_rec *r)
+{
+    r->connection->keepalive = 0;
+    tls()->requests_this_child = ap_max_requests_per_child = 1;
+}
+
+static void child_main(int child_num_arg)
+{
+    NET_SIZE_T clen;
+    struct sockaddr sa_server;
+    struct sockaddr sa_client;
+    listen_rec *lr;
+    pool *ptrans;
+
+    /* All of initialization is a critical section, we don't care if we're
+     * told to HUP or USR1 before we're done initializing.  For example,
+     * we could be half way through child_init_modules() when a restart
+     * signal arrives, and we'd have no real way to recover gracefully
+     * and exit properly.
+     *
+     * I suppose a module could take forever to initialize, but that would
+     * be either a broken module, or a broken configuration (i.e. network
+     * problems, file locking problems, whatever). -djg
+     */
+    ap_block_alarms();
+
+    tls()->my_pid = getpid();
+    tls()->csd = -1;
+    tls()->dupped_csd = -1;
+    tls()->my_child_num = child_num_arg;
+    tls()->requests_this_child = 0;
+
+    /* Get a sub pool for global allocations in this child, so that
+     * we can have cleanups occur when the child exits.
+     */
+#ifdef LTHREAD
+    tls()->pchild = ap_make_sub_pool(NULL);
+#else
+    tls()->pchild = ap_make_sub_pool(pconf);
+#endif
+
+    /* needs to be done before we switch UIDs so we have permissions */
+    reopen_scoreboard(tls()->pchild);
+    SAFE_ACCEPT(accept_mutex_child_init(tls()->pchild));
+
+    set_group_privs();
+#ifdef MPE
+    /* Only try to switch if we're running as MANAGER.SYS */
+    if (geteuid() == 1 && ap_user_id > 1) {
+	GETPRIVMODE();
+	if (setuid(ap_user_id) == -1) {
+	    GETUSERMODE();
+	    ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+			"setuid: unable to change uid");
+	    exit(1);
+	}
+	GETUSERMODE();
+    }
+#else
+    /* Only try to switch if we're running as root */
+    if (!geteuid() && setuid(ap_user_id) == -1) {
+	ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf,
+		    "setuid: unable to change uid");
+	clean_child_exit(1);
+    }
+#endif
+
+    ap_child_init_modules(tls()->pchild, server_conf);
+
+    /* done with the initialization critical section */
+    ap_unblock_alarms();
+
+    (void) ap_update_child_status(tls()->my_child_num, SERVER_READY, (request_rec *) NULL);
+
+    /*
+     * Setup the jump buffers so that we can return here after
+     * a signal or a timeout (yeah, I know, same thing).
+     */
+    ap_setjmp(tls()->jmpbuffer);
+#ifndef __EMX__
+#ifdef SIGURG
+    signal(SIGURG, timeout);
+#endif
+#endif
+    signal(SIGPIPE, timeout);
+    signal(SIGALRM, alrm_handler);
+
+    ptrans = ap_make_sub_pool(tls()->pchild);
+
+    while (1) {
+	BUFF *conn_io;
+	request_rec *r;
+
+#ifndef NO_GRACEFUL
+	/* Prepare to receive a SIGUSR1 due to graceful restart so that
+	 * we can exit cleanly.  Since we're between connections right
+	 * now it's the right time to exit, but we might be blocked in a
+	 * system call when the graceful restart request is made. */
+	tls()->usr1_just_die = 1;
+	signal(SIGUSR1, usr1_handler);
+#endif
+
+	/*
+	 * (Re)initialize this child to a pre-connection state.
+	 */
+
+	ap_kill_timeout(0);	/* Cancel any outstanding alarms. */
+	tls()->timeout_req = NULL;	/* No request in progress */
+	tls()->current_conn = NULL;
+
+	ap_clear_pool(ptrans);
+
+	ap_sync_scoreboard_image();
+	if (ap_scoreboard_image->global.exit_generation >= generation) {
+	    clean_child_exit(0);
+	}
+
+	if ((ap_max_requests_per_child > 0
+	     && ++tls()->requests_this_child >= ap_max_requests_per_child)) {
+	    clean_child_exit(0);
+	}
+
+	(void) ap_update_child_status(tls()->my_child_num, SERVER_READY, (request_rec *) NULL);
+
+	/*
+	 * Wait for an acceptable connection to arrive.
+	 */
+
+	/* Lock around "accept", if necessary */
+	SAFE_ACCEPT(accept_mutex_on());
+
+	for (;;) {
+	    if (ap_listeners->next != ap_listeners) {
+		/* more than one socket */
+		memcpy(&tls()->main_fds, &listenfds, sizeof(fd_set));
+		tls()->srv = ap_select(listenmaxfd + 1, &tls()->main_fds, NULL, NULL, NULL);
+
+		if (tls()->srv < 0 && errno != EINTR) {
+		    /* Single Unix documents select as returning errnos
+		     * EBADF, EINTR, and EINVAL... and in none of those
+		     * cases does it make sense to continue.  In fact
+		     * on Linux 2.0.x we seem to end up with EFAULT
+		     * occasionally, and we'd loop forever due to it.
+		     */
+		    ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, "select: (listen)");
+		    clean_child_exit(1);
+		}
+
+		if (tls()->srv <= 0)
+		    continue;
+
+		lr = find_ready_listener(&tls()->main_fds);
+		if (lr == NULL)
+		    continue;
+		tls()->sd = lr->fd;
+	    }
+	    else {
+		/* only one socket, just pretend we did the other stuff */
+		tls()->sd = ap_listeners->fd;
+	    }
+
+	    /* if we accept() something we don't want to die, so we have to
+	     * defer the exit
+	     */
+	    tls()->deferred_die = 0;
+	    tls()->usr1_just_die = 0;
+	    for (;;) {
+		clen = sizeof(sa_client);
+		tls()->csd = accept(tls()->sd, &sa_client, &clen);
+		if (tls()->csd >= 0 || errno != EINTR)
+		    break;
+		if (tls()->deferred_die) {
+		    /* we didn't get a socket, and we were told to die */
+		    clean_child_exit(0);
+		}
+	    }
+
+	    if (tls()->csd >= 0)
+		break;		/* We have a socket ready for reading */
+	    else {
+
+		/* Our old behaviour here was to continue after accept()
+		 * errors.  But this leads us into lots of troubles
+		 * because most of the errors are quite fatal.  For
+		 * example, EMFILE can be caused by slow descriptor
+		 * leaks (say in a 3rd party module, or libc).  It's
+		 * foolish for us to continue after an EMFILE.  We also
+		 * seem to tickle kernel bugs on some platforms which
+		 * lead to never-ending loops here.  So it seems best
+		 * to just exit in most cases.
+		 */
+                switch (errno) {
+#ifdef EPROTO
+		    /* EPROTO on certain older kernels really means
+		     * ECONNABORTED, so we need to ignore it for them.
+		     * See discussion in new-httpd archives nh.9701
+		     * search for EPROTO.
+		     *
+		     * Also see nh.9603, search for EPROTO:
+		     * There is potentially a bug in Solaris 2.x x<6,
+		     * and other boxes that implement tcp sockets in
+		     * userland (i.e. on top of STREAMS).  On these
+		     * systems, EPROTO can actually result in a fatal
+		     * loop.  See PR#981 for example.  It's hard to
+		     * handle both uses of EPROTO.
+		     */
+                case EPROTO:
+#endif
+#ifdef ECONNABORTED
+                case ECONNABORTED:
+#endif
+		    /* Linux generates the rest of these, other tcp
+		     * stacks (i.e. bsd) tend to hide them behind
+		     * getsockopt() interfaces.  They occur when
+		     * the net goes sour or the client disconnects
+		     * after the three-way handshake has been done
+		     * in the kernel but before userland has picked
+		     * up the socket.
+		     */
+#ifdef ECONNRESET
+                case ECONNRESET:
+#endif
+#ifdef ETIMEDOUT
+                case ETIMEDOUT:
+#endif
+#ifdef EHOSTUNREACH
+		case EHOSTUNREACH:
+#endif
+#ifdef ENETUNREACH
+		case ENETUNREACH:
+#endif
+                    break;
+
+		default:
+		    ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
+				"accept: (client socket)");
+		    clean_child_exit(1);
+		}
+	    }
+
+	    /* go around again, safe to die */
+	    tls()->usr1_just_die = 1;
+	    if (tls()->deferred_die) {
+		/* ok maybe not, see ya later */
+		clean_child_exit(0);
+	    }
+	    /* or maybe we missed a signal, you never know on systems
+	     * without reliable signals
+	     */
+	    ap_sync_scoreboard_image();
+	    if (ap_scoreboard_image->global.exit_generation >= generation) {
+		clean_child_exit(0);
+	    }
+	}
+
+	SAFE_ACCEPT(accept_mutex_off());	/* unlock after "accept" */
+
+#ifndef NO_GRACEFUL
+	/* We've got a socket, let's at least process one request off the
+	 * socket before we accept a graceful restart request.
+	 */
+	signal(SIGUSR1, SIG_IGN);
+#endif
+
+	ap_note_cleanups_for_fd(ptrans, tls()->csd);
+
+	/* protect various fd_sets */
+	if (tls()->csd >= FD_SETSIZE) {
+	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
+		"[csd] filedescriptor (%u) larger than FD_SETSIZE (%u) "
+		"found, you probably need to rebuild Apache with a "
+		"larger FD_SETSIZE", tls()->csd, FD_SETSIZE);
+	    continue;
+	}
+
+	/*
+	 * We now have a connection, so set it up with the appropriate
+	 * socket options, file descriptors, and read/write buffers.
+	 */
+
+	clen = sizeof(sa_server);
+	if (getsockname(tls()->csd, &sa_server, &clen) < 0) {
+	    ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, "getsockname");
+	    continue;
+	}
+
+	sock_disable_nagle(tls()->csd);
+
+	(void) ap_update_child_status(tls()->my_child_num, SERVER_BUSY_READ,
+				   (request_rec *) NULL);
+
+	conn_io = ap_bcreate(ptrans, B_RDWR | B_SOCKET);
+
+#ifdef B_SFIO
+	(void) sfdisc(conn_io->sf_in, SF_POPDISC);
+	sfdisc(conn_io->sf_in, bsfio_new(conn_io->pool, conn_io));
+	sfsetbuf(conn_io->sf_in, NULL, 0);
+
+	(void) sfdisc(conn_io->sf_out, SF_POPDISC);
+	sfdisc(conn_io->sf_out, bsfio_new(conn_io->pool, conn_io));
+	sfsetbuf(conn_io->sf_out, NULL, 0);
+#endif
+
+	tls()->dupped_csd = tls()->csd;
+#if defined(NEED_DUPPED_CSD)
+	if ((tls()->dupped_csd = dup(tls()->csd)) < 0) {
+	    ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
+			"dup: couldn't duplicate csd");
+	    tls()->dupped_csd = tls()->csd;	/* Oh well... */
+	}
+	ap_note_cleanups_for_fd(ptrans, tls()->dupped_csd);
+
+	/* protect various fd_sets */
+	if (tls()->dupped_csd >= FD_SETSIZE) {
+	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
+		"[dupped_csd] filedescriptor (%u) larger than FD_SETSIZE (%u) "
+		"found, you probably need to rebuild Apache with a "
+		"larger FD_SETSIZE", tls()->dupped_csd, FD_SETSIZE);
+	    continue;
+	}
+#endif
+	ap_bpushfd(conn_io, tls()->csd, tls()->dupped_csd);
+
+	tls()->current_conn = new_connection(ptrans, server_conf, conn_io,
+				          (struct sockaddr_in *) &sa_client,
+				          (struct sockaddr_in *) &sa_server,
+				          tls()->my_child_num);
+
+	/*
+	 * Read and process each request found on our connection
+	 * until no requests are left or we decide to close.
+	 */
+
+	while ((r = ap_read_request(tls()->current_conn)) != NULL) {
+
+	    /* read_request_line has already done a
+	     * signal (SIGUSR1, SIG_IGN);
+	     */
+
+	    (void) ap_update_child_status(tls()->my_child_num, SERVER_BUSY_WRITE, r);
+
+	    ap_process_request(r);
+
+#if defined(STATUS)
+	    increment_counts(tls()->my_child_num, r);
+#endif
+
+	    if (!tls()->current_conn->keepalive || tls()->current_conn->aborted)
+		break;
+
+	    ap_destroy_pool(r->pool);
+	    (void) ap_update_child_status(tls()->my_child_num, SERVER_BUSY_KEEPALIVE,
+				       (request_rec *) NULL);
+
+	    ap_sync_scoreboard_image();
+	    if (ap_scoreboard_image->global.exit_generation >= generation) {
+		ap_bclose(conn_io);
+		clean_child_exit(0);
+	    }
+
+#ifndef NO_GRACEFUL
+	    /* In case we get a graceful restart while we're blocked
+	     * waiting for the request.
+	     *
+	     * XXX: This isn't perfect, we might actually read the
+	     * request and then just die without saying anything to
+	     * the client.  This can be fixed by using tls()->deferred_die
+	     * but you have to teach buff.c about it so that it can handle
+	     * the EINTR properly.
+	     *
+	     * In practice though browsers (have to) expect keepalive
+	     * connections to close before receiving a response because
+	     * of network latencies and server timeouts.
+	     */
+	    tls()->usr1_just_die = 1;
+	    signal(SIGUSR1, usr1_handler);
+#endif
+	}
+
+	/*
+	 * Close the connection, being careful to send out whatever is still
+	 * in our buffers.  If possible, try to avoid a hard close until the
+	 * client has ACKed our FIN and/or has stopped sending us data.
+	 */
+
+#ifdef NO_LINGCLOSE
+	ap_bclose(conn_io);	/* just close it */
+#else
+	if (r && r->connection
+	    && !r->connection->aborted
+	    && r->connection->client
+	    && (r->connection->client->fd >= 0)) {
+
+	    lingering_close(r);
+	}
+	else {
+	    ap_bsetflag(conn_io, B_EOUT, 1);
+	    ap_bclose(conn_io);
+	}
+#endif
+    }
+}
+
+
+static void *child_starter(void *dummy)
+{
+    tls_main_t *t;
+    int rc;
+
+    signal(SIGHUP, just_die);
+    signal(SIGUSR1, just_die);
+    signal(SIGTERM, just_die);
+
+    t = malloc(sizeof(*t));
+    memset(t, 0, sizeof(*t));
+    t->head_listener = ap_listeners;
+    t->usr1_just_die = 1;
+    if ((rc = pthread_setspecific(tls_main_key, t))) {
+	fprintf(stderr, "pthread_setspecific: %s\n", strerror(rc));
+	exit(1);
+    }
+
+    child_main((int)dummy);
+    return NULL;
+}
+
+static int make_child(server_rec *s, int slot, time_t now)
+{
+    pthread_t tid;
+    int rc;
+
+    if (slot + 1 > max_daemons_limit) {
+	max_daemons_limit = slot + 1;
+    }
+
+    if (one_process) {
+	signal(SIGHUP, just_die);
+	signal(SIGINT, just_die);
+	signal(SIGQUIT, SIG_DFL);
+	signal(SIGTERM, just_die);
+	child_main(slot);
+    }
+
+    (void) ap_update_child_status(slot, SERVER_STARTING, (request_rec *) NULL);
+
+    if ((rc = pthread_create(&tid, &child_attr, child_starter, (void *)slot))) {
+	errno = rc;
+	ap_log_error(APLOG_MARK, APLOG_ERR, s, "pthread_create: unable to create new thread");
+
+	/* fork didn't succeed. Fix the scoreboard or else
+	 * it will say SERVER_STARTING forever and ever
+	 */
+	(void) ap_update_child_status(slot, SERVER_DEAD, (request_rec *) NULL);
+
+	/* In case system resources are maxxed out, we don't want
+	   Apache running away with the CPU trying to fork over and
+	   over and over again. */
+	sleep(10);
+
+	return -1;
+    }
+
+    ap_scoreboard_image->parent[slot].last_rtime = now;
+    ap_scoreboard_image->parent[slot].pid = tid;
+
+    return 0;
+}
+
+
+
+/* start up a bunch of children */
+static void startup_children(int number_to_start)
+{
+    int i;
+    time_t now = time(0);
+
+    for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
+	if (ap_scoreboard_image->servers[i].status != SERVER_DEAD) {
+	    continue;
+	}
+	if (make_child(server_conf, i, now) < 0) {
+	    break;
+	}
+	--number_to_start;
+    }
+}
+
+
+/*
+ * idle_spawn_rate is the number of children that will be spawned on the
+ * next maintenance cycle if there aren't enough idle servers.  It is
+ * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
+ * without the need to spawn.
+ */
+static int idle_spawn_rate = 1;
+#ifndef MAX_SPAWN_RATE
+#define MAX_SPAWN_RATE	(32)
+#endif
+static int hold_off_on_exponential_spawning;
+
+static void perform_idle_server_maintenance(void)
+{
+    int i;
+    int to_kill;
+    int idle_count;
+    short_score *ss;
+    time_t now = time(0);
+    int free_length;
+    int free_slots[MAX_SPAWN_RATE];
+    int last_non_dead;
+    int total_non_dead;
+
+    /* initialize the free_list */
+    free_length = 0;
+
+    to_kill = -1;
+    idle_count = 0;
+    last_non_dead = -1;
+    total_non_dead = 0;
+
+#ifdef SHARED_TIME
+    ap_scoreboard_image->global.right_now = now;
+#endif
+
+    ap_sync_scoreboard_image();
+    for (i = 0; i < ap_daemons_limit; ++i) {
+	int status;
+
+	if (i >= max_daemons_limit && free_length == idle_spawn_rate)
+	    break;
+	ss = &ap_scoreboard_image->servers[i];
+	status = ss->status;
+	if (status == SERVER_DEAD) {
+	    /* try to keep children numbers as low as possible */
+	    if (free_length < idle_spawn_rate) {
+		free_slots[free_length] = i;
+		++free_length;
+	    }
+	}
+	else {
+	    /* We consider a starting server as idle because we started it
+	     * at least a cycle ago, and if it still hasn't finished starting
+	     * then we're just going to swamp things worse by forking more.
+	     * So we hopefully won't need to fork more if we count it.
+	     * This depends on the ordering of SERVER_READY and SERVER_STARTING.
+	     */
+	    if (status <= SERVER_READY) {
+		++ idle_count;
+		/* always kill the highest numbered child if we have to...
+		 * no really well thought out reason ... other than observing
+		 * the server behaviour under linux where lower numbered children
+		 * tend to service more hits (and hence are more likely to have
+		 * their data in cpu caches).
+		 */
+		to_kill = i;
+	    }
+
+	    ++total_non_dead;
+	    last_non_dead = i;
+#ifdef OPTIMIZE_TIMEOUTS
+	    if (ss->timeout_len) {
+		/* if it's a live server, with a live timeout then
+		 * start checking its timeout */
+		parent_score *ps = &ap_scoreboard_image->parent[i];
+		if (ss->cur_vtime != ps->last_vtime) {
+		    /* it has made progress, so update its last_rtime,
+		     * last_vtime */
+		    ps->last_rtime = now;
+		    ps->last_vtime = ss->cur_vtime;
+		}
+		else if (ps->last_rtime + ss->timeout_len < now) {
+		    /* no progress, and the timeout length has been exceeded */
+		    ss->timeout_len = 0;
+		    kill(ps->pid, SIGALRM);
+		}
+	    }
+#endif
+	}
+    }
+    max_daemons_limit = last_non_dead + 1;
+    if (idle_count > ap_daemons_max_free) {
+	/* kill off one child... we use SIGUSR1 because that'll cause it to
+	 * shut down gracefully, in case it happened to pick up a request
+	 * while we were counting
+	 */
+	kill(ap_scoreboard_image->parent[to_kill].pid, SIGUSR1);
+	idle_spawn_rate = 1;
+    }
+    else if (idle_count < ap_daemons_min_free) {
+	/* terminate the free list */
+	if (free_length == 0) {
+	    /* only report this condition once */
+	    static int reported = 0;
+
+	    if (!reported) {
+		ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
+			    "server reached MaxClients setting, consider"
+			    " raising the MaxClients setting");
+		reported = 1;
+	    }
+	    idle_spawn_rate = 1;
+	}
+	else {
+	    if (idle_spawn_rate >= 8) {
+		ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
+		    "server seems busy, (you may need "
+		    "to increase StartServers, or Min/MaxSpareServers), "
+		    "spawning %d children, there are %d idle, and "
+		    "%d total children", idle_spawn_rate,
+		    idle_count, total_non_dead);
+	    }
+	    for (i = 0; i < free_length; ++i) {
+		make_child(server_conf, free_slots[i], now);
+	    }
+	    /* the next time around we want to spawn twice as many if this
+	     * wasn't good enough, but not if we've just done a graceful
+	     */
+	    if (hold_off_on_exponential_spawning) {
+		--hold_off_on_exponential_spawning;
+	    }
+	    else if (idle_spawn_rate < MAX_SPAWN_RATE) {
+		idle_spawn_rate *= 2;
+	    }
+	}
+    }
+    else {
+	idle_spawn_rate = 1;
+    }
+}
+
+
+/*****************************************************************
+ * Executive routines.
+ */
+
+#ifndef STANDALONE_MAIN
+#define STANDALONE_MAIN standalone_main
+
+static void standalone_main(int argc, char **argv)
+{
+    int remaining_children_to_start;
+
+    ap_standalone = 1;
+
+    is_graceful = 0;
+    ++generation;
+
+    if (!one_process) {
+#if 0
+	detach();
+#endif
+    }
+    else {
+	MONCONTROL(1);
+    }
+
+    tls()->my_pid = getpid();
+
+    if ((errno = pthread_attr_init(&child_attr))) {
+	ap_log_error(APLOG_MARK, APLOG_CRIT, NULL, "pthread_attr_init");
+	exit(1);
+    }
+
+    do {
+	copy_listeners(pconf);
+	if (!is_graceful) {
+	    ap_restart_time = time(NULL);
+	}
+	ap_clear_pool(pconf);
+	ptemp = ap_make_sub_pool(pconf);
+
+	server_conf = ap_read_config(pconf, ptemp, ap_server_confname);
+	setup_listeners(pconf);
+	ap_open_logs(server_conf, pconf);
+	ap_log_pid(pconf, ap_pid_fname);
+	ap_init_modules(pconf, server_conf);
+	SAFE_ACCEPT(accept_mutex_init(pconf));
+	if (!is_graceful) {
+	    reinit_scoreboard(pconf);
+	}
+#ifdef SHARED_TIME
+	ap_scoreboard_image->global.right_now = time(0);
+#endif
+
+	set_signals();
+
+	if (ap_daemons_max_free < ap_daemons_min_free + 1)	/* Don't thrash... */
+	    ap_daemons_max_free = ap_daemons_min_free + 1;
+
+	/* If we're doing a graceful_restart then we're going to see a lot
+	 * of children exiting immediately when we get into the main loop
+	 * below (because we just sent them SIGUSR1).  This happens pretty
+	 * rapidly... and for each one that exits we'll start a new one until
+	 * we reach at least daemons_min_free.  But we may be permitted to
+	 * start more than that, so we'll just keep track of how many we're
+	 * supposed to start up without the 1 second penalty between each fork.
+	 */
+	remaining_children_to_start = ap_daemons_to_start;
+	if (remaining_children_to_start > ap_daemons_limit) {
+	    remaining_children_to_start = ap_daemons_limit;
+	}
+	if (!is_graceful) {
+	    startup_children(remaining_children_to_start);
+	    remaining_children_to_start = 0;
+	}
+	else {
+	    /* give the system some time to recover before kicking into
+	     * exponential mode */
+	    hold_off_on_exponential_spawning = 10;
+	}
+
+	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
+		    "%s configured -- resuming normal operations",
+		    ap_get_server_version());
+	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
+		    "Server built: %s", ap_get_server_built());
+	restart_pending = shutdown_pending = 0;
+
+	while (!restart_pending && !shutdown_pending) {
+	    int child_slot;
+	    int status;
+	    int pid = wait_or_timeout(&status);
+
+	    /* XXX: if it takes longer than 1 second for all our children
+	     * to start up and get into IDLE state then we may spawn an
+	     * extra child
+	     */
+	    if (pid >= 0) {
+		/* Child died... note that it's gone in the scoreboard. */
+		ap_sync_scoreboard_image();
+		child_slot = find_child_by_pid(pid);
+		Explain2("Reaping child %d slot %d", pid, child_slot);
+		if (child_slot >= 0) {
+		    (void) ap_update_child_status(child_slot, SERVER_DEAD,
+					       (request_rec *) NULL);
+		    if (remaining_children_to_start
+			&& child_slot < ap_daemons_limit) {
+			/* we're still doing a 1-for-1 replacement of dead
+			 * children with new children
+			 */
+			make_child(server_conf, child_slot, time(0));
+			--remaining_children_to_start;
+		    }
+#ifndef NO_OTHER_CHILD
+		}
+		else if (reap_other_child(pid, status) == 0) {
+		    /* handled */
+#endif
+		}
+		else if (is_graceful) {
+		    /* Great, we've probably just lost a slot in the
+		     * scoreboard.  Somehow we don't know about this
+		     * child.
+		     */
+		    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, server_conf,
+				"long lost child came home! (pid %d)", pid);
+		}
+		/* Don't perform idle maintenance when a child dies,
+		 * only do it when there's a timeout.  Remember only a
+		 * finite number of children can die, and it's pretty
+		 * pathological for a lot to die suddenly.
+		 */
+		continue;
+	    }
+	    else if (remaining_children_to_start) {
+		/* we hit a 1 second timeout in which none of the previous
+		 * generation of children needed to be reaped... so assume
+		 * they're all done, and pick up the slack if any is left.
+		 */
+		startup_children(remaining_children_to_start);
+		remaining_children_to_start = 0;
+		/* In any event we really shouldn't do the code below because
+		 * few of the servers we just started are in the IDLE state
+		 * yet, so we'd mistakenly create an extra server.
+		 */
+		continue;
+	    }
+
+	    perform_idle_server_maintenance();
+	}
+
+	if (shutdown_pending) {
+	    /* Time to gracefully shut down:
+	     * Kill child processes, tell them to call child_exit, etc...
+	     */
+	    if (ap_killpg(pgrp, SIGTERM) < 0) {
+		ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGTERM");
+	    }
+	    reclaim_child_processes(1);		/* Start with SIGTERM */
+	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
+			"httpd: caught SIGTERM, shutting down");
+
+	    clean_parent_exit(0);
+	}
+
+	/* we've been told to restart */
+	signal(SIGHUP, SIG_IGN);
+	signal(SIGUSR1, SIG_IGN);
+
+	if (one_process) {
+	    /* not worth thinking about */
+	    clean_parent_exit(0);
+	}
+
+	if (is_graceful) {
+	    int i;
+
+	    /* USE WITH CAUTION:  Graceful restarts are not known to work
+	     * in various configurations on the architectures we support. */
+	    ap_scoreboard_image->global.exit_generation = generation;
+	    update_scoreboard_global();
+
+	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
+			"SIGUSR1 received.  Doing graceful restart");
+
+	    /* kill off the idle ones */
+	    if (ap_killpg(pgrp, SIGUSR1) < 0) {
+		ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGUSR1");
+	    }
+	    /* This is mostly for debugging... so that we know what is still
+	     * gracefully dealing with existing request.
+	     */
+	    ap_sync_scoreboard_image();
+	    for (i = 0; i < ap_daemons_limit; ++i) {
+		if (ap_scoreboard_image->servers[i].status != SERVER_DEAD) {
+		    ap_scoreboard_image->servers[i].status = SERVER_GRACEFUL;
+		}
+	    }
+	}
+	else {
+	    /* Kill 'em off */
+	    if (ap_killpg(pgrp, SIGHUP) < 0) {
+		ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGHUP");
+	    }
+	    reclaim_child_processes(0);		/* Not when just starting up */
+	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf,
+			"SIGHUP received.  Attempting to restart");
+	}
+	++generation;
+    } while (restart_pending);
+
+    /*add_common_vars(NULL);*/
+}				/* standalone_main */
+#else
+/* prototype */
+void STANDALONE_MAIN(int argc, char **argv);
+#endif /* STANDALONE_MAIN */
+
+extern char *optarg;
+extern int optind;
+
+int REALMAIN(int argc, char *argv[])
+{
+    int c;
+
+    {
+	tls_main_t *t;
+
+	if ((c = pthread_key_create(&tls_main_key, NULL))) {
+	    fprintf(stderr, "pthread_key_create: %s\n", strerror(c));
+	    exit(1);
+	}
+	t = malloc(sizeof(*t));
+	memset(t, 0, sizeof(*t));
+	if ((c = pthread_setspecific(tls_main_key, t))) {
+	    fprintf(stderr, "pthread_setspecific: %s\n", strerror(c));
+	    exit(1);
+	}
+    }
+
+    MONCONTROL(0);
+
+    common_init();
+    
+    ap_server_argv0 = argv[0];
+    ap_cpystrn(ap_server_root, HTTPD_ROOT, sizeof(ap_server_root));
+    ap_cpystrn(ap_server_confname, SERVER_CONFIG_FILE, sizeof(ap_server_confname));
+
+    ap_setup_prelinked_modules();
+
+#ifdef DEBUG_SIGSTOP
+    while ((c = getopt(argc, argv, "C:c:Xd:f:vVhlL:Z:")) != -1) {
+#else
+    while ((c = getopt(argc, argv, "C:c:Xd:f:vVhlL:")) != -1) {
+#endif
+	char **new;
+	switch (c) {
+	case 'c':
+	    new = (char **)ap_push_array(ap_server_post_read_config);
+	    *new = ap_pstrdup(pcommands, optarg);
+	    break;
+	case 'C':
+	    new = (char **)ap_push_array(ap_server_pre_read_config);
+	    *new = ap_pstrdup(pcommands, optarg);
+	    break;
+	case 'd':
+	    ap_cpystrn(ap_server_root, optarg, sizeof(ap_server_root));
+	    break;
+	case 'f':
+	    ap_cpystrn(ap_server_confname, optarg, sizeof(ap_server_confname));
+	    break;
+	case 'v':
+	    printf("Server version: %s\n", ap_get_server_version());
+	    printf("Server built:   %s\n", ap_get_server_built());
+	    exit(0);
+	case 'V':
+	    show_compile_settings();
+	    exit(0);
+	case 'h':
+	    ap_show_directives();
+	    exit(0);
+	case 'l':
+	    ap_show_modules();
+	    exit(0);
+	case 'X':
+	    ++one_process;	/* Weird debugging mode. */
+	    break;
+#ifdef DEBUG_SIGSTOP
+	case 'Z':
+	    raise_sigstop_flags = atoi(optarg);
+	    break;
+#endif
+#ifdef SHARED_CORE
+	case 'L':
+	    /* just ignore this option here, because it has only
+	     * effect when SHARED_CORE is used and then it was
+	     * already handled in the Shared Core Bootstrap
+	     * program.
+	     */
+	    break;
+#endif
+	case '?':
+	    usage(argv[0]);
+	}
+    }
+
+#ifdef __EMX__
+    printf("%s \n", ap_get_server_version());
+#endif
+
+    ap_suexec_enabled = init_suexec();
+    server_conf = ap_read_config(pconf, ptemp, ap_server_confname);
+
+    child_timeouts = !ap_standalone || one_process;
+
+    if (!ap_standalone) {
+	fprintf(stderr, "inetd mode not supported\n");
+	exit(1);
+    }
+
+    ap_open_logs(server_conf, pconf);
+    ap_init_modules(pconf, server_conf);
+    STANDALONE_MAIN(argc, argv);
+    exit(0);
+}
+
+
+#else  /* ndef SHARED_CORE_TIESTATIC */
+
+/*
+**  Standalone Tie Program for Shared Core support
+**
+**  It's purpose is to tie the static libraries and 
+**  the shared core library under link-time and  
+**  passing execution control to the real main function
+**  in the shared core library under run-time.
+*/
+
+int main(int argc, char *argv[]) 
+{
+    extern int ap_main(int argc, char *argv[]);
+    return ap_main(argc, argv);
+}
+
+#endif /* ndef SHARED_CORE_TIESTATIC */
+#else  /* ndef SHARED_CORE_BOOTSTRAP */
+
+/*
+**  Standalone Bootstrap Program for Shared Core support
+**
+**  It's purpose is to initialise the LD_LIBRARY_PATH
+**  environment variable therewith the Unix loader is able
+**  to start the Standalone Tie Program (see above)
+**  and then replacing itself with this program by
+**  immediately passing execution to it.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "conf.h"
+#include "httpd.h"
+
+#define VARNAME "LD_LIBRARY_PATH"
+
+#ifndef SHARED_CORE_DIR 
+#define SHARED_CORE_DIR HTTPD_ROOT "/libexec"
+#endif
+
+#ifndef SHARED_CORE_EXECUTABLE_PROGRAM
+#define SHARED_CORE_EXECUTABLE_PROGRAM "libhttpd.ep"
+#endif
+
+int main(int argc, char *argv[], char *envp[]) 
+{
+    extern char *optarg;
+    extern int optind;
+    char prog[MAX_STRING_LEN];
+    char llp_buf[MAX_STRING_LEN];
+    char **llp_slot;
+    char *llp_existing;
+    char *llp_dir;
+    char **envpnew;
+    int c, i, l;
+
+    /* 
+     * parse argument line, 
+     * but only handle the -L option 
+     */
+    llp_dir = SHARED_CORE_DIR;
+    while ((c = getopt(argc, argv, "C:c:Xd:f:vVhlL:Z:")) != -1) {
+	switch (c) {
+	case 'C':
+	case 'c':
+	case 'X':
+	case 'd':
+	case 'f':
+	case 'v':
+	case 'V':
+	case 'h':
+	case 'l':
+	case 'Z':
+	case '?':
+	    break;
+	case 'L':
+	    llp_dir = strdup(optarg);
+	    break;
+	}
+    }
+
+    /* 
+     * create path to SHARED_CORE_EXECUTABLE_PROGRAM
+     */
+    sprintf(prog, "%s/%s", llp_dir, SHARED_CORE_EXECUTABLE_PROGRAM);
+
+    /* 
+     * adjust process environment therewith the Unix loader 
+     * is able to start the SHARED_CORE_EXECUTABLE_PROGRAM.
+     */
+    llp_slot = NULL;
+    llp_existing = NULL;
+    l = strlen(VARNAME);
+    for (i = 0; envp[i] != NULL; i++) {
+	if (strncmp(envp[i], VARNAME "=", l+1) == 0) {
+	    llp_slot = &envp[i];
+	    llp_existing = strchr(envp[i], '=') + 1;
+	}
+    }
+    if (llp_slot == NULL) {
+	envpnew = (char **)malloc(sizeof(char *)*(i + 2));
+	memcpy(envpnew, envp, sizeof(char *)*i);
+	envp = envpnew;
+	llp_slot = &envp[i++];
+	envp[i] = NULL;
+    }
+    if (llp_existing != NULL)
+	 sprintf(llp_buf, "%s=%s:%s", VARNAME, llp_dir, llp_existing);
+    else
+	 sprintf(llp_buf, "%s=%s", VARNAME, llp_dir);
+    *llp_slot = strdup(llp_buf);
+
+    /* 
+     * finally replace our process with 
+     * the SHARED_CORE_EXECUTABLE_PROGRAM
+     */
+    if (execve(prog, argv, envp) == -1) {
+	fprintf(stderr, 
+		"httpd: Unable to exec Shared Core Executable Program `%s'\n",
+		prog);
+	return 1;
+    }
+    else
+	return 0;
+}
+
+#endif /* ndef SHARED_CORE_BOOTSTRAP */
+
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/os/pthread/os-inline.c apachen2/src/os/pthread/os-inline.c
--- apachen/src/os/pthread/os-inline.c	Wed Dec 31 16:00:00 1969
+++ apachen2/src/os/pthread/os-inline.c	Sat Apr 18 22:08:26 1998
@@ -0,0 +1,31 @@
+/*
+ * This file contains functions which can be inlined if the compiler
+ * has an "inline" modifier. Because of this, this file is both a
+ * header file and a compilable module.
+ *
+ * Only inlineable functions should be defined in here. They must all
+ * include the INLINE modifier. 
+ *
+ * If the compiler supports inline, this file will be #included as a
+ * header file from os.h to create all the inline function
+ * definitions. INLINE will be defined to whatever is required on
+ * function definitions to make them inline declarations.
+ *
+ * If the compiler does not support inline, this file will be compiled
+ * as a normal C file into libos.a (along with os.c). In this case
+ * INLINE will _not_ be set so we can use this to test if we are
+ * compiling this source file.  
+ */
+
+#ifndef INLINE
+#define INLINE
+
+/* Anything required only when compiling */
+#include "conf.h"
+
+#endif
+
+INLINE int ap_os_is_path_absolute(const char *file)
+{
+  return file[0] == '/';
+}
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/os/pthread/os.c apachen2/src/os/pthread/os.c
--- apachen/src/os/pthread/os.c	Wed Dec 31 16:00:00 1969
+++ apachen2/src/os/pthread/os.c	Sat Apr 18 22:08:26 1998
@@ -0,0 +1,73 @@
+/*
+ * This file will include OS specific functions which are not inlineable.
+ * Any inlineable functions should be defined in os-inline.c instead.
+ */
+
+#include "conf.h"
+#include "os.h"
+
+
+/* some linkers complain unless there's at least one function in each
+ * .o file... and extra prototype is for gcc -Wmissing-prototypes
+ */
+extern void ap_is_not_here(void);
+void ap_is_not_here(void) {}
+
+/*
+ *  Abstraction layer for loading
+ *  Apache modules under run-time via 
+ *  dynamic shared object (DSO) mechanism
+ */
+
+void *ap_os_dso_load(const char *path)
+{
+#if defined(HPUX) || defined(HPUX10)
+    shl_t handle;
+    handle = shl_load(path, BIND_IMMEDIATE|BIND_VERBOSE|BIND_NOSTART, 0L);
+    return (void *)handle;
+#else
+    return dlopen(path, RTLD_NOW);
+#endif
+}
+
+void ap_os_dso_unload(void *handle) 
+{
+#if defined(HPUX) || defined(HPUX10)
+    shl_unload((shl_t)handle);
+#else
+    dlclose(handle);
+#endif
+    return;
+}
+
+void *ap_os_dso_sym(void *handle, const char *symname)
+{
+#if defined(HPUX) || defined(HPUX10)
+    void *symaddr = NULL;
+    int status;
+
+    errno = 0;
+    status = shl_findsym((shl_t *)&handle, symname, TYPE_PROCEDURE, &symaddr);
+    if (status == -1 && errno == 0) /* try TYPE_DATA instead */
+        status = shl_findsym((shl_t *)&handle, symname, TYPE_DATA, &symaddr);
+    return (status == -1 ? NULL : symaddr);
+#else /* ndef HPUX */
+#ifdef DLSYM_NEEDS_UNDERSCORE
+    char symbol[256];
+    sprintf(symbol, "_%s", symname);
+    return dlsym(handle, symbol);
+#else
+    return dlsym(handle, symname);
+#endif
+#endif /* ndef HPUX */
+}
+
+const char *ap_os_dso_error(void)
+{
+#if defined(HPUX) || defined(HPUX10)
+    return strerror(errno);
+#else
+    return dlerror();
+#endif
+}
+
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/os/pthread/os.h apachen2/src/os/pthread/os.h
--- apachen/src/os/pthread/os.h	Wed Dec 31 16:00:00 1969
+++ apachen2/src/os/pthread/os.h	Sat Apr 18 22:24:36 1998
@@ -0,0 +1,128 @@
+/* ====================================================================
+ * Copyright (c) 1998 The Apache Group.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+#ifndef APACHE_OS_H
+#define APACHE_OS_H
+
+/*
+ * This file in included in all Apache source code. It contains definitions
+ * of facilities available on _this_ operating system (HAVE_* macros),
+ * and prototypes of OS specific functions defined in os.c or os-inline.c
+ */
+
+#if !defined(INLINE) && defined(USE_GNU_INLINE)
+/* Compiler supports inline, so include the inlineable functions as
+ * part of the header
+ */
+#define INLINE extern ap_inline
+#include "os-inline.c"
+
+#else
+
+/* Compiler does not support inline, so prototype the inlineable functions
+ * as normal
+ */
+extern int ap_os_is_path_absolute(const char *f);
+#endif
+
+/*
+ *  Abstraction layer for loading
+ *  Apache modules under run-time via 
+ *  dynamic shared object (DSO) mechanism
+ */
+
+#if defined(HPUX) || defined(HPUX10)
+#define HAVE_DL_H 1
+#endif
+
+#if defined(LINUX) || defined(__FreeBSD__) || defined(SOLARIS2) || \
+    defined(__bsdi__) || defined(IRIX) || defined(SVR4) || defined(OSF1)
+#define HAVE_DLFCN_H 1
+#endif
+
+#ifdef HAVE_DL_H
+#include <dl.h>
+#endif
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#else
+void *dlopen(const char *, int);
+int dlclose(void *);
+void *dlsym(void *, const char *);
+const char *dlerror(void);
+#endif
+
+/* probably on an older system that doesn't support RTLD_NOW or RTLD_LAZY.
+ * The below define is a lie since we are really doing RTLD_LAZY since the
+ * system doesn't support RTLD_NOW.
+ */
+#ifndef RTLD_NOW
+#define RTLD_NOW 1
+#endif
+
+#if defined(__FreeBSD__)
+#define DLSYM_NEEDS_UNDERSCORE
+#endif
+
+#define     ap_os_dso_handle_t  void *
+void *      ap_os_dso_load(const char *);
+void        ap_os_dso_unload(void *);
+void *      ap_os_dso_sym(void *, const char *);
+const char *ap_os_dso_error(void);
+
+#endif	/* !APACHE_OS_H */
diff -Nru -x CVS -x *.orig -x .#* -x *.bak -x Makefile apachen/src/test/rename/apapi.h apachen2/src/test/rename/apapi.h
--- apachen/src/test/rename/apapi.h	Sat Apr 18 21:21:27 1998
+++ apachen2/src/test/rename/apapi.h	Sat Apr 18 22:55:31 1998
@@ -93,13 +93,13 @@
 extern int                  ap_fnmatch(const char *, const char *, int);
 extern int                  ap_get_basic_auth_pw(request_rec *r, char **pw);
 extern long                 ap_get_client_block(request_rec *r, char *buffer, int bufsiz);
-extern struct tm *          ap_get_gmtoff(int *tz);
+extern struct tm *          ap_get_gmtoff(int *tz, struct tm *);
 extern void *               ap_get_module_config(void *conf_vector, module *m);
 extern const char *         ap_get_remote_host(conn_rec *conn, void *dir_config, int type);
 extern const char *         ap_get_remote_logname(request_rec *r);
 extern const char *         ap_get_server_name(const request_rec *r);
 extern unsigned             ap_get_server_port(const request_rec *r);
-extern char *               ap_get_time(void);
+extern char *               ap_get_time(char *);
 extern char *               ap_get_token(pool *p, char **accept_line, int accept_white);
 extern void                 ap_getparents(char *name);
 extern char *               ap_getword(pool *p, const char **line, char stop);
